2 use crate::normalize_deep
::DeepNormalizer
;
3 use crate::{ExClause, Literal}
;
5 use chalk_derive
::HasInterner
;
6 use chalk_ir
::cast
::Cast
;
7 use chalk_ir
::cast
::Caster
;
8 use chalk_ir
::interner
::Interner
;
10 use chalk_solve
::clauses
::program_clauses_for_goal
;
11 use chalk_solve
::coinductive_goal
::IsCoinductive
;
12 use chalk_solve
::infer
::ucanonicalize
::UCanonicalized
;
13 use chalk_solve
::infer
::unify
::UnificationResult
;
14 use chalk_solve
::infer
::InferenceTable
;
15 use chalk_solve
::solve
::truncate
;
16 use chalk_solve
::RustIrDatabase
;
19 use std
::marker
::PhantomData
;
21 pub(crate) mod aggregate
;
24 #[derive(Clone, Debug, HasInterner)]
25 pub(crate) struct SlgContext
<I
: Interner
> {
26 phantom
: PhantomData
<I
>,
29 #[derive(Clone, Debug)]
30 pub(crate) struct SlgContextOps
<'me
, I
: Interner
> {
31 program
: &'me
dyn RustIrDatabase
<I
>,
33 expected_answers
: Option
<usize>,
36 impl<I
: Interner
> SlgContextOps
<'_
, I
> {
38 program
: &dyn RustIrDatabase
<I
>,
40 expected_answers
: Option
<usize>,
41 ) -> SlgContextOps
<'_
, I
> {
51 pub struct TruncatingInferenceTable
<I
: Interner
> {
53 infer
: InferenceTable
<I
>,
56 impl<I
: Interner
> context
::Context
<I
> for SlgContext
<I
> {
57 type InferenceTable
= TruncatingInferenceTable
<I
>;
60 fn next_subgoal_index(ex_clause
: &ExClause
<I
>) -> usize {
61 // For now, we always pick the last subgoal in the
64 // FIXME(rust-lang-nursery/chalk#80) -- we should be more
65 // selective. For example, we don't want to pick a
66 // negative literal that will flounder, and we don't want
67 // to pick things like `?T: Sized` if we can help it.
68 ex_clause
.subgoals
.len() - 1
72 impl<'me
, I
: Interner
> context
::ContextOps
<I
, SlgContext
<I
>> for SlgContextOps
<'me
, I
> {
73 fn is_coinductive(&self, goal
: &UCanonical
<InEnvironment
<Goal
<I
>>>) -> bool
{
74 goal
.is_coinductive(self.program
)
77 fn map_goal_from_canonical(
80 value
: &Canonical
<InEnvironment
<Goal
<I
>>>,
81 ) -> Canonical
<InEnvironment
<Goal
<I
>>> {
82 use chalk_solve
::infer
::ucanonicalize
::UniverseMapExt
;
83 map
.map_from_canonical(self.program
.interner(), value
)
86 fn map_subst_from_canonical(
89 value
: &Canonical
<AnswerSubst
<I
>>,
90 ) -> Canonical
<AnswerSubst
<I
>> {
91 use chalk_solve
::infer
::ucanonicalize
::UniverseMapExt
;
92 map
.map_from_canonical(self.program
.interner(), value
)
97 environment
: &Environment
<I
>,
99 _infer
: &mut TruncatingInferenceTable
<I
>,
100 ) -> Result
<Vec
<ProgramClause
<I
>>, Floundered
> {
101 let clauses
: Vec
<_
> = program_clauses_for_goal(
105 &CanonicalVarKinds
::empty(self.program
.interner()),
112 fn add_clauses(&self, env
: &Environment
<I
>, clauses
: ProgramClauses
<I
>) -> Environment
<I
> {
113 let interner
= self.interner();
114 env
.add_clauses(interner
, clauses
.iter(interner
).cloned())
117 fn instantiate_ucanonical_goal(
119 arg
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
121 TruncatingInferenceTable
<I
>,
126 let (infer
, subst
, InEnvironment { environment, goal }
) =
127 InferenceTable
::from_canonical(self.program
.interner(), arg
.universes
, &arg
.canonical
);
128 let infer_table
= TruncatingInferenceTable
::new(self.max_size
, infer
);
129 (infer_table
, subst
, environment
, goal
)
132 fn instantiate_ex_clause(
134 num_universes
: usize,
135 canonical_ex_clause
: &Canonical
<ExClause
<I
>>,
136 ) -> (TruncatingInferenceTable
<I
>, ExClause
<I
>) {
137 let (infer
, _subst
, ex_cluse
) = InferenceTable
::from_canonical(
138 self.program
.interner(),
142 let infer_table
= TruncatingInferenceTable
::new(self.max_size
, infer
);
143 (infer_table
, ex_cluse
)
146 fn instantiate_answer_subst(
148 num_universes
: usize,
149 answer
: &Canonical
<AnswerSubst
<I
>>,
151 TruncatingInferenceTable
<I
>,
153 Vec
<InEnvironment
<Constraint
<I
>>>,
154 Vec
<InEnvironment
<Goal
<I
>>>,
164 ) = InferenceTable
::from_canonical(self.program
.interner(), num_universes
, answer
);
165 let infer_table
= TruncatingInferenceTable
::new(self.max_size
, infer
);
169 constraints
.as_slice(self.interner()).to_vec(),
174 fn identity_constrained_subst(
176 goal
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
177 ) -> Canonical
<ConstrainedSubst
<I
>> {
178 let (mut infer
, subst
, _
) = InferenceTable
::from_canonical(
179 self.program
.interner(),
185 self.program
.interner(),
188 constraints
: Constraints
::empty(self.program
.interner()),
194 fn interner(&self) -> &I
{
195 self.program
.interner()
198 fn into_goal(&self, domain_goal
: DomainGoal
<I
>) -> Goal
<I
> {
199 domain_goal
.cast(self.program
.interner())
202 fn is_trivial_constrained_substitution(
204 constrained_subst
: &Canonical
<ConstrainedSubst
<I
>>,
206 let interner
= self.interner();
207 constrained_subst
.value
.subst
.is_identity_subst(interner
)
210 fn is_trivial_substitution(
212 u_canon
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
213 canonical_subst
: &Canonical
<AnswerSubst
<I
>>,
215 let interner
= self.interner();
216 u_canon
.is_trivial_substitution(interner
, canonical_subst
)
220 impl<I
: Interner
> TruncatingInferenceTable
<I
> {
221 fn new(max_size
: usize, infer
: InferenceTable
<I
>) -> Self {
222 Self { max_size, infer }
226 impl<I
: Interner
> context
::TruncateOps
<I
, SlgContext
<I
>> for TruncatingInferenceTable
<I
> {
227 fn goal_needs_truncation(&mut self, interner
: &I
, subgoal
: &InEnvironment
<Goal
<I
>>) -> bool
{
228 truncate
::needs_truncation(interner
, &mut self.infer
, self.max_size
, &subgoal
)
231 fn answer_needs_truncation(&mut self, interner
: &I
, subst
: &Substitution
<I
>) -> bool
{
232 truncate
::needs_truncation(interner
, &mut self.infer
, self.max_size
, subst
)
236 impl<I
: Interner
> context
::InferenceTable
<I
, SlgContext
<I
>> for TruncatingInferenceTable
<I
> {}
238 impl<I
: Interner
> context
::UnificationOps
<I
, SlgContext
<I
>> for TruncatingInferenceTable
<I
> {
239 fn instantiate_binders_universally(&mut self, interner
: &I
, arg
: &Binders
<Goal
<I
>>) -> Goal
<I
> {
240 self.infer
.instantiate_binders_universally(interner
, arg
)
243 fn instantiate_binders_existentially(
246 arg
: &Binders
<Goal
<I
>>,
248 self.infer
.instantiate_binders_existentially(interner
, arg
)
251 fn debug_ex_clause
<'v
>(&mut self, interner
: &I
, value
: &'v ExClause
<I
>) -> Box
<dyn Debug
+ 'v
> {
252 Box
::new(DeepNormalizer
::normalize_deep(
259 fn fully_canonicalize_goal(
262 value
: &InEnvironment
<Goal
<I
>>,
263 ) -> (UCanonical
<InEnvironment
<Goal
<I
>>>, UniverseMap
) {
264 let canonicalized_goal
= self.infer
.canonicalize(interner
, value
).quantified
;
268 } = self.infer
.u_canonicalize(interner
, &canonicalized_goal
);
269 (quantified
, universes
)
272 fn canonicalize_ex_clause(
276 ) -> Canonical
<ExClause
<I
>> {
277 self.infer
.canonicalize(interner
, value
).quantified
280 fn canonicalize_constrained_subst(
283 subst
: Substitution
<I
>,
284 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
285 ) -> Canonical
<ConstrainedSubst
<I
>> {
291 constraints
: Constraints
::from_iter(interner
, constraints
),
297 fn canonicalize_answer_subst(
300 subst
: Substitution
<I
>,
301 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
302 delayed_subgoals
: Vec
<InEnvironment
<Goal
<I
>>>,
303 ) -> Canonical
<AnswerSubst
<I
>> {
309 constraints
: Constraints
::from_iter(interner
, constraints
),
319 value
: &InEnvironment
<Goal
<I
>>,
320 ) -> Option
<InEnvironment
<Goal
<I
>>> {
321 self.infer
.invert(interner
, value
)
324 fn unify_generic_args_into_ex_clause(
327 environment
: &Environment
<I
>,
330 ex_clause
: &mut ExClause
<I
>,
332 let result
= self.infer
.unify(interner
, environment
, a
, b
)?
;
333 Ok(into_ex_clause(interner
, result
, ex_clause
))
338 fn into_ex_clause
<I
: Interner
>(
340 result
: UnificationResult
<I
>,
341 ex_clause
: &mut ExClause
<I
>,
343 ex_clause
.subgoals
.extend(
348 .map(Literal
::Positive
),
352 trait SubstitutionExt
<I
: Interner
> {
353 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
;
356 impl<I
: Interner
> SubstitutionExt
<I
> for Substitution
<I
> {
357 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
{
359 .zip(subst
.value
.iter(interner
))
360 .any(|(new
, current
)| MayInvalidate { interner }
.aggregate_generic_args(new
, current
))
364 // This is a struct in case we need to add state at any point like in AntiUnifier
365 struct MayInvalidate
<'i
, I
> {
369 impl<I
: Interner
> MayInvalidate
<'_
, I
> {
370 fn aggregate_generic_args(&mut self, new
: &GenericArg
<I
>, current
: &GenericArg
<I
>) -> bool
{
371 let interner
= self.interner
;
372 match (new
.data(interner
), current
.data(interner
)) {
373 (GenericArgData
::Ty(ty1
), GenericArgData
::Ty(ty2
)) => self.aggregate_tys(ty1
, ty2
),
374 (GenericArgData
::Lifetime(l1
), GenericArgData
::Lifetime(l2
)) => {
375 self.aggregate_lifetimes(l1
, l2
)
377 (GenericArgData
::Const(c1
), GenericArgData
::Const(c2
)) => self.aggregate_consts(c1
, c2
),
378 (GenericArgData
::Ty(_
), _
)
379 | (GenericArgData
::Lifetime(_
), _
)
380 | (GenericArgData
::Const(_
), _
) => panic
!(
381 "mismatched parameter kinds: new={:?} current={:?}",
387 /// Returns true if the two types could be unequal.
388 fn aggregate_tys(&mut self, new
: &Ty
<I
>, current
: &Ty
<I
>) -> bool
{
389 let interner
= self.interner
;
390 match (new
.data(interner
), current
.data(interner
)) {
391 (_
, TyData
::BoundVar(_
)) => {
392 // If the aggregate solution already has an inference
393 // variable here, then no matter what type we produce,
394 // the aggregate cannot get 'more generalized' than it
395 // already is. So return false, we cannot invalidate.
397 // (Note that "inference variables" show up as *bound
398 // variables* here, because we are looking at the
403 (TyData
::BoundVar(_
), _
) => {
404 // If we see a type variable in the potential future
405 // solution, we have to be conservative. We don't know
406 // what type variable will wind up being! Remember
407 // that the future solution could be any instantiation
408 // of `ty0` -- or it could leave this variable
409 // unbound, if the result is true for all types.
411 // (Note that "inference variables" show up as *bound
412 // variables* here, because we are looking at the
417 (TyData
::InferenceVar(_
, _
), _
) | (_
, TyData
::InferenceVar(_
, _
)) => {
419 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
424 (TyData
::Apply(apply1
), TyData
::Apply(apply2
)) => {
425 self.aggregate_application_tys(apply1
, apply2
)
428 (TyData
::Placeholder(p1
), TyData
::Placeholder(p2
)) => {
429 self.aggregate_placeholders(p1
, p2
)
433 TyData
::Alias(AliasTy
::Projection(proj1
)),
434 TyData
::Alias(AliasTy
::Projection(proj2
)),
435 ) => self.aggregate_projection_tys(proj1
, proj2
),
438 TyData
::Alias(AliasTy
::Opaque(opaque_ty1
)),
439 TyData
::Alias(AliasTy
::Opaque(opaque_ty2
)),
440 ) => self.aggregate_opaque_ty_tys(opaque_ty1
, opaque_ty2
),
442 // For everything else, be conservative here and just say we may invalidate.
443 (TyData
::Function(_
), _
)
444 | (TyData
::Dyn(_
), _
)
445 | (TyData
::Apply(_
), _
)
446 | (TyData
::Placeholder(_
), _
)
447 | (TyData
::Alias(_
), _
) => true,
451 /// Returns true if the two consts could be unequal.
452 fn aggregate_lifetimes(&mut self, _
: &Lifetime
<I
>, _
: &Lifetime
<I
>) -> bool
{
456 /// Returns true if the two consts could be unequal.
457 fn aggregate_consts(&mut self, new
: &Const
<I
>, current
: &Const
<I
>) -> bool
{
458 let interner
= self.interner
;
462 } = new
.data(interner
);
465 value
: current_value
,
466 } = current
.data(interner
);
468 if self.aggregate_tys(new_ty
, current_ty
) {
472 match (new_value
, current_value
) {
473 (_
, ConstValue
::BoundVar(_
)) => {
474 // see comment in aggregate_tys
478 (ConstValue
::BoundVar(_
), _
) => {
479 // see comment in aggregate_tys
483 (ConstValue
::InferenceVar(_
), _
) | (_
, ConstValue
::InferenceVar(_
)) => {
485 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
490 (ConstValue
::Placeholder(p1
), ConstValue
::Placeholder(p2
)) => {
491 self.aggregate_placeholders(p1
, p2
)
494 (ConstValue
::Concrete(c1
), ConstValue
::Concrete(c2
)) => {
495 !c1
.const_eq(new_ty
, c2
, interner
)
498 // Only variants left are placeholder = concrete, which always fails
499 (ConstValue
::Placeholder(_
), _
) | (ConstValue
::Concrete(_
), _
) => true,
503 fn aggregate_application_tys(
505 new
: &ApplicationTy
<I
>,
506 current
: &ApplicationTy
<I
>,
510 substitution
: new_substitution
,
514 substitution
: current_substitution
,
517 self.aggregate_name_and_substs(
521 current_substitution
,
525 fn aggregate_placeholders(
527 new
: &PlaceholderIndex
,
528 current
: &PlaceholderIndex
,
533 fn aggregate_projection_tys(
535 new
: &ProjectionTy
<I
>,
536 current
: &ProjectionTy
<I
>,
539 associated_ty_id
: new_name
,
540 substitution
: new_substitution
,
543 associated_ty_id
: current_name
,
544 substitution
: current_substitution
,
547 self.aggregate_name_and_substs(
551 current_substitution
,
555 fn aggregate_opaque_ty_tys(&mut self, new
: &OpaqueTy
<I
>, current
: &OpaqueTy
<I
>) -> bool
{
557 opaque_ty_id
: new_name
,
558 substitution
: new_substitution
,
561 opaque_ty_id
: current_name
,
562 substitution
: current_substitution
,
565 self.aggregate_name_and_substs(
569 current_substitution
,
573 fn aggregate_name_and_substs
<N
>(
576 new_substitution
: &Substitution
<I
>,
578 current_substitution
: &Substitution
<I
>,
581 N
: Copy
+ Eq
+ Debug
,
583 let interner
= self.interner
;
584 if new_name
!= current_name
{
591 new_substitution
.len(interner
),
592 current_substitution
.len(interner
),
593 "does {:?} take {} substitution or {}? can't both be right",
595 new_substitution
.len(interner
),
596 current_substitution
.len(interner
)
601 .zip(current_substitution
.iter(interner
))
602 .any(|(new
, current
)| self.aggregate_generic_args(new
, current
))