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
),
364 trait SubstitutionExt
<I
: Interner
> {
365 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
;
368 impl<I
: Interner
> SubstitutionExt
<I
> for Substitution
<I
> {
369 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
{
371 .zip(subst
.value
.iter(interner
))
372 .any(|(new
, current
)| MayInvalidate { interner }
.aggregate_generic_args(new
, current
))
376 // This is a struct in case we need to add state at any point like in AntiUnifier
377 struct MayInvalidate
<'i
, I
> {
381 impl<I
: Interner
> MayInvalidate
<'_
, I
> {
382 fn aggregate_generic_args(&mut self, new
: &GenericArg
<I
>, current
: &GenericArg
<I
>) -> bool
{
383 let interner
= self.interner
;
384 match (new
.data(interner
), current
.data(interner
)) {
385 (GenericArgData
::Ty(ty1
), GenericArgData
::Ty(ty2
)) => self.aggregate_tys(ty1
, ty2
),
386 (GenericArgData
::Lifetime(l1
), GenericArgData
::Lifetime(l2
)) => {
387 self.aggregate_lifetimes(l1
, l2
)
389 (GenericArgData
::Const(c1
), GenericArgData
::Const(c2
)) => self.aggregate_consts(c1
, c2
),
390 (GenericArgData
::Ty(_
), _
)
391 | (GenericArgData
::Lifetime(_
), _
)
392 | (GenericArgData
::Const(_
), _
) => panic
!(
393 "mismatched parameter kinds: new={:?} current={:?}",
399 /// Returns true if the two types could be unequal.
400 fn aggregate_tys(&mut self, new
: &Ty
<I
>, current
: &Ty
<I
>) -> bool
{
401 let interner
= self.interner
;
402 match (new
.data(interner
), current
.data(interner
)) {
403 (_
, TyData
::BoundVar(_
)) => {
404 // If the aggregate solution already has an inference
405 // variable here, then no matter what type we produce,
406 // the aggregate cannot get 'more generalized' than it
407 // already is. So return false, we cannot invalidate.
409 // (Note that "inference variables" show up as *bound
410 // variables* here, because we are looking at the
415 (TyData
::BoundVar(_
), _
) => {
416 // If we see a type variable in the potential future
417 // solution, we have to be conservative. We don't know
418 // what type variable will wind up being! Remember
419 // that the future solution could be any instantiation
420 // of `ty0` -- or it could leave this variable
421 // unbound, if the result is true for all types.
423 // (Note that "inference variables" show up as *bound
424 // variables* here, because we are looking at the
429 (TyData
::InferenceVar(_
, _
), _
) | (_
, TyData
::InferenceVar(_
, _
)) => {
431 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
436 (TyData
::Apply(apply1
), TyData
::Apply(apply2
)) => {
437 self.aggregate_application_tys(apply1
, apply2
)
440 (TyData
::Placeholder(p1
), TyData
::Placeholder(p2
)) => {
441 self.aggregate_placeholders(p1
, p2
)
445 TyData
::Alias(AliasTy
::Projection(proj1
)),
446 TyData
::Alias(AliasTy
::Projection(proj2
)),
447 ) => self.aggregate_projection_tys(proj1
, proj2
),
450 TyData
::Alias(AliasTy
::Opaque(opaque_ty1
)),
451 TyData
::Alias(AliasTy
::Opaque(opaque_ty2
)),
452 ) => self.aggregate_opaque_ty_tys(opaque_ty1
, opaque_ty2
),
454 // For everything else, be conservative here and just say we may invalidate.
455 (TyData
::Function(_
), _
)
456 | (TyData
::Dyn(_
), _
)
457 | (TyData
::Apply(_
), _
)
458 | (TyData
::Placeholder(_
), _
)
459 | (TyData
::Alias(_
), _
) => true,
463 /// Returns true if the two consts could be unequal.
464 fn aggregate_lifetimes(&mut self, _
: &Lifetime
<I
>, _
: &Lifetime
<I
>) -> bool
{
468 /// Returns true if the two consts could be unequal.
469 fn aggregate_consts(&mut self, new
: &Const
<I
>, current
: &Const
<I
>) -> bool
{
470 let interner
= self.interner
;
474 } = new
.data(interner
);
477 value
: current_value
,
478 } = current
.data(interner
);
480 if self.aggregate_tys(new_ty
, current_ty
) {
484 match (new_value
, current_value
) {
485 (_
, ConstValue
::BoundVar(_
)) => {
486 // see comment in aggregate_tys
490 (ConstValue
::BoundVar(_
), _
) => {
491 // see comment in aggregate_tys
495 (ConstValue
::InferenceVar(_
), _
) | (_
, ConstValue
::InferenceVar(_
)) => {
497 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
502 (ConstValue
::Placeholder(p1
), ConstValue
::Placeholder(p2
)) => {
503 self.aggregate_placeholders(p1
, p2
)
506 (ConstValue
::Concrete(c1
), ConstValue
::Concrete(c2
)) => {
507 !c1
.const_eq(new_ty
, c2
, interner
)
510 // Only variants left are placeholder = concrete, which always fails
511 (ConstValue
::Placeholder(_
), _
) | (ConstValue
::Concrete(_
), _
) => true,
515 fn aggregate_application_tys(
517 new
: &ApplicationTy
<I
>,
518 current
: &ApplicationTy
<I
>,
522 substitution
: new_substitution
,
526 substitution
: current_substitution
,
529 self.aggregate_name_and_substs(
533 current_substitution
,
537 fn aggregate_placeholders(
539 new
: &PlaceholderIndex
,
540 current
: &PlaceholderIndex
,
545 fn aggregate_projection_tys(
547 new
: &ProjectionTy
<I
>,
548 current
: &ProjectionTy
<I
>,
551 associated_ty_id
: new_name
,
552 substitution
: new_substitution
,
555 associated_ty_id
: current_name
,
556 substitution
: current_substitution
,
559 self.aggregate_name_and_substs(
563 current_substitution
,
567 fn aggregate_opaque_ty_tys(&mut self, new
: &OpaqueTy
<I
>, current
: &OpaqueTy
<I
>) -> bool
{
569 opaque_ty_id
: new_name
,
570 substitution
: new_substitution
,
573 opaque_ty_id
: current_name
,
574 substitution
: current_substitution
,
577 self.aggregate_name_and_substs(
581 current_substitution
,
585 fn aggregate_name_and_substs
<N
>(
588 new_substitution
: &Substitution
<I
>,
590 current_substitution
: &Substitution
<I
>,
593 N
: Copy
+ Eq
+ Debug
,
595 let interner
= self.interner
;
596 if new_name
!= current_name
{
603 new_substitution
.len(interner
),
604 current_substitution
.len(interner
),
605 "does {:?} take {} substitution or {}? can't both be right",
607 new_substitution
.len(interner
),
608 current_substitution
.len(interner
)
613 .zip(current_substitution
.iter(interner
))
614 .any(|(new
, current
)| self.aggregate_generic_args(new
, current
))