1 use crate::clauses
::program_clauses_for_goal
;
2 use crate::coinductive_goal
::IsCoinductive
;
3 use crate::infer
::ucanonicalize
::UCanonicalized
;
4 use crate::infer
::unify
::UnificationResult
;
5 use crate::infer
::InferenceTable
;
6 use crate::solve
::truncate
;
7 use crate::RustIrDatabase
;
8 use chalk_derive
::HasInterner
;
9 use chalk_engine
::context
;
10 use chalk_engine
::{ExClause, Literal}
;
11 use chalk_ir
::cast
::Cast
;
12 use chalk_ir
::cast
::Caster
;
13 use chalk_ir
::interner
::Interner
;
16 use std
::fmt
::{Debug, Display}
;
17 use std
::marker
::PhantomData
;
19 pub(crate) mod aggregate
;
23 pub enum SubstitutionResult
<S
> {
29 impl<S
> SubstitutionResult
<S
> {
30 pub fn as_ref(&self) -> SubstitutionResult
<&S
> {
32 SubstitutionResult
::Definite(subst
) => SubstitutionResult
::Definite(subst
),
33 SubstitutionResult
::Ambiguous(subst
) => SubstitutionResult
::Ambiguous(subst
),
34 SubstitutionResult
::Floundered
=> SubstitutionResult
::Floundered
,
37 pub fn map
<U
, F
: FnOnce(S
) -> U
>(self, f
: F
) -> SubstitutionResult
<U
> {
39 SubstitutionResult
::Definite(subst
) => SubstitutionResult
::Definite(f(subst
)),
40 SubstitutionResult
::Ambiguous(subst
) => SubstitutionResult
::Ambiguous(f(subst
)),
41 SubstitutionResult
::Floundered
=> SubstitutionResult
::Floundered
,
46 impl<S
: Display
> Display
for SubstitutionResult
<S
> {
47 fn fmt(&self, fmt
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
49 SubstitutionResult
::Definite(subst
) => write
!(fmt
, "{}", subst
),
50 SubstitutionResult
::Ambiguous(subst
) => write
!(fmt
, "Ambiguous({})", subst
),
51 SubstitutionResult
::Floundered
=> write
!(fmt
, "Floundered"),
56 #[derive(Clone, Debug, HasInterner)]
57 pub(crate) struct SlgContext
<I
: Interner
> {
58 phantom
: PhantomData
<I
>,
61 #[derive(Clone, Debug)]
62 pub(crate) struct SlgContextOps
<'me
, I
: Interner
> {
63 program
: &'me
dyn RustIrDatabase
<I
>,
65 expected_answers
: Option
<usize>,
68 impl<I
: Interner
> SlgContextOps
<'_
, I
> {
69 pub(crate) fn new
<'p
>(
70 program
: &'p
dyn RustIrDatabase
<I
>,
72 expected_answers
: Option
<usize>,
73 ) -> SlgContextOps
<'p
, I
> {
83 pub struct TruncatingInferenceTable
<I
: Interner
> {
85 infer
: InferenceTable
<I
>,
88 impl<I
: Interner
> context
::Context
<I
> for SlgContext
<I
> {
89 type InferenceTable
= TruncatingInferenceTable
<I
>;
92 fn next_subgoal_index(ex_clause
: &ExClause
<I
>) -> usize {
93 // For now, we always pick the last subgoal in the
96 // FIXME(rust-lang-nursery/chalk#80) -- we should be more
97 // selective. For example, we don't want to pick a
98 // negative literal that will flounder, and we don't want
99 // to pick things like `?T: Sized` if we can help it.
100 ex_clause
.subgoals
.len() - 1
104 impl<'me
, I
: Interner
> context
::ContextOps
<I
, SlgContext
<I
>> for SlgContextOps
<'me
, I
> {
105 fn is_coinductive(&self, goal
: &UCanonical
<InEnvironment
<Goal
<I
>>>) -> bool
{
106 goal
.is_coinductive(self.program
)
109 fn map_goal_from_canonical(
112 value
: &Canonical
<InEnvironment
<Goal
<I
>>>,
113 ) -> Canonical
<InEnvironment
<Goal
<I
>>> {
114 use crate::infer
::ucanonicalize
::UniverseMapExt
;
115 map
.map_from_canonical(self.program
.interner(), value
)
118 fn map_subst_from_canonical(
121 value
: &Canonical
<AnswerSubst
<I
>>,
122 ) -> Canonical
<AnswerSubst
<I
>> {
123 use crate::infer
::ucanonicalize
::UniverseMapExt
;
124 map
.map_from_canonical(self.program
.interner(), value
)
129 environment
: &Environment
<I
>,
130 goal
: &DomainGoal
<I
>,
131 _infer
: &mut TruncatingInferenceTable
<I
>,
132 ) -> Result
<Vec
<ProgramClause
<I
>>, Floundered
> {
133 let clauses
: Vec
<_
> = program_clauses_for_goal(self.program
, environment
, goal
)?
;
139 fn add_clauses(&self, env
: &Environment
<I
>, clauses
: ProgramClauses
<I
>) -> Environment
<I
> {
140 let interner
= self.interner();
141 env
.add_clauses(interner
, clauses
.iter(interner
).cloned())
144 fn instantiate_ucanonical_goal(
146 arg
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
148 TruncatingInferenceTable
<I
>,
153 let (infer
, subst
, InEnvironment { environment, goal }
) =
154 InferenceTable
::from_canonical(self.program
.interner(), arg
.universes
, &arg
.canonical
);
155 let infer_table
= TruncatingInferenceTable
::new(self.max_size
, infer
);
156 (infer_table
, subst
, environment
, goal
)
159 fn instantiate_ex_clause(
161 num_universes
: usize,
162 canonical_ex_clause
: &Canonical
<ExClause
<I
>>,
163 ) -> (TruncatingInferenceTable
<I
>, ExClause
<I
>) {
164 let (infer
, _subst
, ex_cluse
) = InferenceTable
::from_canonical(
165 self.program
.interner(),
169 let infer_table
= TruncatingInferenceTable
::new(self.max_size
, infer
);
170 (infer_table
, ex_cluse
)
173 fn instantiate_answer_subst(
175 num_universes
: usize,
176 answer
: &Canonical
<AnswerSubst
<I
>>,
178 TruncatingInferenceTable
<I
>,
180 Vec
<InEnvironment
<Constraint
<I
>>>,
181 Vec
<InEnvironment
<Goal
<I
>>>,
191 ) = InferenceTable
::from_canonical(self.program
.interner(), num_universes
, answer
);
192 let infer_table
= TruncatingInferenceTable
::new(self.max_size
, infer
);
193 (infer_table
, subst
, constraints
, delayed_subgoals
)
196 fn identity_constrained_subst(
198 goal
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
199 ) -> Canonical
<ConstrainedSubst
<I
>> {
200 let (mut infer
, subst
, _
) = InferenceTable
::from_canonical(
201 self.program
.interner(),
207 self.program
.interner(),
216 fn interner(&self) -> &I
{
217 self.program
.interner()
220 fn into_goal(&self, domain_goal
: DomainGoal
<I
>) -> Goal
<I
> {
221 domain_goal
.cast(self.program
.interner())
224 fn is_trivial_constrained_substitution(
226 constrained_subst
: &Canonical
<ConstrainedSubst
<I
>>,
228 let interner
= self.interner();
229 constrained_subst
.value
.subst
.is_identity_subst(interner
)
232 fn is_trivial_substitution(
234 u_canon
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
235 canonical_subst
: &Canonical
<AnswerSubst
<I
>>,
237 let interner
= self.interner();
238 u_canon
.is_trivial_substitution(interner
, canonical_subst
)
242 impl<I
: Interner
> TruncatingInferenceTable
<I
> {
243 fn new(max_size
: usize, infer
: InferenceTable
<I
>) -> Self {
244 Self { max_size, infer }
248 impl<I
: Interner
> context
::TruncateOps
<I
, SlgContext
<I
>> for TruncatingInferenceTable
<I
> {
249 fn goal_needs_truncation(&mut self, interner
: &I
, subgoal
: &InEnvironment
<Goal
<I
>>) -> bool
{
250 truncate
::needs_truncation(interner
, &mut self.infer
, self.max_size
, &subgoal
)
253 fn answer_needs_truncation(&mut self, interner
: &I
, subst
: &Substitution
<I
>) -> bool
{
254 truncate
::needs_truncation(interner
, &mut self.infer
, self.max_size
, subst
)
258 impl<I
: Interner
> context
::InferenceTable
<I
, SlgContext
<I
>> for TruncatingInferenceTable
<I
> {}
260 impl<I
: Interner
> context
::UnificationOps
<I
, SlgContext
<I
>> for TruncatingInferenceTable
<I
> {
261 fn instantiate_binders_universally(&mut self, interner
: &I
, arg
: &Binders
<Goal
<I
>>) -> Goal
<I
> {
262 self.infer
.instantiate_binders_universally(interner
, arg
)
265 fn instantiate_binders_existentially(
268 arg
: &Binders
<Goal
<I
>>,
270 self.infer
.instantiate_binders_existentially(interner
, arg
)
273 fn debug_ex_clause
<'v
>(&mut self, interner
: &I
, value
: &'v ExClause
<I
>) -> Box
<dyn Debug
+ 'v
> {
274 Box
::new(self.infer
.normalize_deep(interner
, value
))
277 fn fully_canonicalize_goal(
280 value
: &InEnvironment
<Goal
<I
>>,
281 ) -> (UCanonical
<InEnvironment
<Goal
<I
>>>, UniverseMap
) {
282 let canonicalized_goal
= self.infer
.canonicalize(interner
, value
).quantified
;
286 } = self.infer
.u_canonicalize(interner
, &canonicalized_goal
);
287 (quantified
, universes
)
290 fn canonicalize_ex_clause(
294 ) -> Canonical
<ExClause
<I
>> {
295 self.infer
.canonicalize(interner
, value
).quantified
298 fn canonicalize_constrained_subst(
301 subst
: Substitution
<I
>,
302 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
303 ) -> Canonical
<ConstrainedSubst
<I
>> {
305 .canonicalize(interner
, &ConstrainedSubst { subst, constraints }
)
309 fn canonicalize_answer_subst(
312 subst
: Substitution
<I
>,
313 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
314 delayed_subgoals
: Vec
<InEnvironment
<Goal
<I
>>>,
315 ) -> Canonical
<AnswerSubst
<I
>> {
331 value
: &InEnvironment
<Goal
<I
>>,
332 ) -> Option
<InEnvironment
<Goal
<I
>>> {
333 self.infer
.invert(interner
, value
)
336 fn unify_generic_args_into_ex_clause(
339 environment
: &Environment
<I
>,
342 ex_clause
: &mut ExClause
<I
>,
344 let result
= self.infer
.unify(interner
, environment
, a
, b
)?
;
345 Ok(into_ex_clause(interner
, result
, ex_clause
))
350 fn into_ex_clause
<I
: Interner
>(
352 result
: UnificationResult
<I
>,
353 ex_clause
: &mut ExClause
<I
>,
355 ex_clause
.subgoals
.extend(
360 .map(Literal
::Positive
),
362 ex_clause
.constraints
.extend(result
.constraints
);
365 trait SubstitutionExt
<I
: Interner
> {
366 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
;
369 impl<I
: Interner
> SubstitutionExt
<I
> for Substitution
<I
> {
370 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
{
372 .zip(subst
.value
.iter(interner
))
373 .any(|(new
, current
)| MayInvalidate { interner }
.aggregate_generic_args(new
, current
))
377 // This is a struct in case we need to add state at any point like in AntiUnifier
378 struct MayInvalidate
<'i
, I
> {
382 impl<I
: Interner
> MayInvalidate
<'_
, I
> {
383 fn aggregate_generic_args(&mut self, new
: &GenericArg
<I
>, current
: &GenericArg
<I
>) -> bool
{
384 let interner
= self.interner
;
385 match (new
.data(interner
), current
.data(interner
)) {
386 (GenericArgData
::Ty(ty1
), GenericArgData
::Ty(ty2
)) => self.aggregate_tys(ty1
, ty2
),
387 (GenericArgData
::Lifetime(l1
), GenericArgData
::Lifetime(l2
)) => {
388 self.aggregate_lifetimes(l1
, l2
)
390 (GenericArgData
::Const(c1
), GenericArgData
::Const(c2
)) => self.aggregate_consts(c1
, c2
),
391 (GenericArgData
::Ty(_
), _
)
392 | (GenericArgData
::Lifetime(_
), _
)
393 | (GenericArgData
::Const(_
), _
) => panic
!(
394 "mismatched parameter kinds: new={:?} current={:?}",
400 /// Returns true if the two types could be unequal.
401 fn aggregate_tys(&mut self, new
: &Ty
<I
>, current
: &Ty
<I
>) -> bool
{
402 let interner
= self.interner
;
403 match (new
.data(interner
), current
.data(interner
)) {
404 (_
, TyData
::BoundVar(_
)) => {
405 // If the aggregate solution already has an inference
406 // variable here, then no matter what type we produce,
407 // the aggregate cannot get 'more generalized' than it
408 // already is. So return false, we cannot invalidate.
410 // (Note that "inference variables" show up as *bound
411 // variables* here, because we are looking at the
416 (TyData
::BoundVar(_
), _
) => {
417 // If we see a type variable in the potential future
418 // solution, we have to be conservative. We don't know
419 // what type variable will wind up being! Remember
420 // that the future solution could be any instantiation
421 // of `ty0` -- or it could leave this variable
422 // unbound, if the result is true for all types.
424 // (Note that "inference variables" show up as *bound
425 // variables* here, because we are looking at the
430 (TyData
::InferenceVar(_
, _
), _
) | (_
, TyData
::InferenceVar(_
, _
)) => {
432 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
437 (TyData
::Apply(apply1
), TyData
::Apply(apply2
)) => {
438 self.aggregate_application_tys(apply1
, apply2
)
441 (TyData
::Placeholder(p1
), TyData
::Placeholder(p2
)) => {
442 self.aggregate_placeholders(p1
, p2
)
446 TyData
::Alias(AliasTy
::Projection(proj1
)),
447 TyData
::Alias(AliasTy
::Projection(proj2
)),
448 ) => self.aggregate_projection_tys(proj1
, proj2
),
451 TyData
::Alias(AliasTy
::Opaque(opaque_ty1
)),
452 TyData
::Alias(AliasTy
::Opaque(opaque_ty2
)),
453 ) => self.aggregate_opaque_ty_tys(opaque_ty1
, opaque_ty2
),
455 // For everything else, be conservative here and just say we may invalidate.
456 (TyData
::Function(_
), _
)
457 | (TyData
::Dyn(_
), _
)
458 | (TyData
::Apply(_
), _
)
459 | (TyData
::Placeholder(_
), _
)
460 | (TyData
::Alias(_
), _
) => true,
464 /// Returns true if the two consts could be unequal.
465 fn aggregate_lifetimes(&mut self, _
: &Lifetime
<I
>, _
: &Lifetime
<I
>) -> bool
{
469 /// Returns true if the two consts could be unequal.
470 fn aggregate_consts(&mut self, new
: &Const
<I
>, current
: &Const
<I
>) -> bool
{
471 let interner
= self.interner
;
475 } = new
.data(interner
);
478 value
: current_value
,
479 } = current
.data(interner
);
481 if self.aggregate_tys(new_ty
, current_ty
) {
485 match (new_value
, current_value
) {
486 (_
, ConstValue
::BoundVar(_
)) => {
487 // see comment in aggregate_tys
491 (ConstValue
::BoundVar(_
), _
) => {
492 // see comment in aggregate_tys
496 (ConstValue
::InferenceVar(_
), _
) | (_
, ConstValue
::InferenceVar(_
)) => {
498 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
503 (ConstValue
::Placeholder(p1
), ConstValue
::Placeholder(p2
)) => {
504 self.aggregate_placeholders(p1
, p2
)
507 (ConstValue
::Concrete(c1
), ConstValue
::Concrete(c2
)) => {
508 !c1
.const_eq(new_ty
, c2
, interner
)
511 // Only variants left are placeholder = concrete, which always fails
512 (ConstValue
::Placeholder(_
), _
) | (ConstValue
::Concrete(_
), _
) => true,
516 fn aggregate_application_tys(
518 new
: &ApplicationTy
<I
>,
519 current
: &ApplicationTy
<I
>,
523 substitution
: new_substitution
,
527 substitution
: current_substitution
,
530 self.aggregate_name_and_substs(
534 current_substitution
,
538 fn aggregate_placeholders(
540 new
: &PlaceholderIndex
,
541 current
: &PlaceholderIndex
,
546 fn aggregate_projection_tys(
548 new
: &ProjectionTy
<I
>,
549 current
: &ProjectionTy
<I
>,
552 associated_ty_id
: new_name
,
553 substitution
: new_substitution
,
556 associated_ty_id
: current_name
,
557 substitution
: current_substitution
,
560 self.aggregate_name_and_substs(
564 current_substitution
,
568 fn aggregate_opaque_ty_tys(&mut self, new
: &OpaqueTy
<I
>, current
: &OpaqueTy
<I
>) -> bool
{
570 opaque_ty_id
: new_name
,
571 substitution
: new_substitution
,
574 opaque_ty_id
: current_name
,
575 substitution
: current_substitution
,
578 self.aggregate_name_and_substs(
582 current_substitution
,
586 fn aggregate_name_and_substs
<N
>(
589 new_substitution
: &Substitution
<I
>,
591 current_substitution
: &Substitution
<I
>,
594 N
: Copy
+ Eq
+ Debug
,
596 let interner
= self.interner
;
597 if new_name
!= current_name
{
604 new_substitution
.len(interner
),
605 current_substitution
.len(interner
),
606 "does {:?} take {} substitution or {}? can't both be right",
608 new_substitution
.len(interner
),
609 current_substitution
.len(interner
)
614 .zip(current_substitution
.iter(interner
))
615 .any(|(new
, current
)| self.aggregate_generic_args(new
, current
))