1 use crate::normalize_deep
::DeepNormalizer
;
2 use crate::{ExClause, Literal}
;
4 use chalk_derive
::HasInterner
;
5 use chalk_ir
::cast
::Caster
;
6 use chalk_ir
::interner
::Interner
;
8 use chalk_solve
::infer
::ucanonicalize
::UCanonicalized
;
9 use chalk_solve
::infer
::unify
::UnificationResult
;
10 use chalk_solve
::infer
::InferenceTable
;
11 use chalk_solve
::solve
::truncate
;
12 use chalk_solve
::RustIrDatabase
;
15 use std
::marker
::PhantomData
;
17 pub(crate) mod aggregate
;
20 #[derive(Clone, Debug, HasInterner)]
21 pub(crate) struct SlgContext
<I
: Interner
> {
22 phantom
: PhantomData
<I
>,
25 impl<I
: Interner
> SlgContext
<I
> {
26 pub(crate) fn next_subgoal_index(ex_clause
: &ExClause
<I
>) -> usize {
27 // For now, we always pick the last subgoal in the
30 // FIXME(rust-lang-nursery/chalk#80) -- we should be more
31 // selective. For example, we don't want to pick a
32 // negative literal that will flounder, and we don't want
33 // to pick things like `?T: Sized` if we can help it.
34 ex_clause
.subgoals
.len() - 1
37 #[derive(Clone, Debug)]
38 pub(crate) struct SlgContextOps
<'me
, I
: Interner
> {
39 program
: &'me
dyn RustIrDatabase
<I
>,
41 expected_answers
: Option
<usize>,
44 impl<I
: Interner
> SlgContextOps
<'_
, I
> {
46 program
: &dyn RustIrDatabase
<I
>,
48 expected_answers
: Option
<usize>,
49 ) -> SlgContextOps
<'_
, I
> {
57 fn identity_constrained_subst(
59 goal
: &UCanonical
<InEnvironment
<Goal
<I
>>>,
60 ) -> Canonical
<ConstrainedSubst
<I
>> {
61 let (mut infer
, subst
, _
) = InferenceTable
::from_canonical(
62 self.program
.interner(),
68 self.program
.interner(),
71 constraints
: Constraints
::empty(self.program
.interner()),
77 pub(crate) fn program(&self) -> &dyn RustIrDatabase
<I
> {
81 pub(crate) fn max_size(&self) -> usize {
86 /// "Truncation" (called "abstraction" in the papers referenced below)
87 /// refers to the act of modifying a goal or answer that has become
88 /// too large in order to guarantee termination.
90 /// Currently we don't perform truncation (but it might me readded later).
94 /// - Terminating Evaluation of Logic Programs with Finite Three-Valued Models
95 /// - Riguzzi and Swift; ACM Transactions on Computational Logic 2013
96 /// - Radial Restraint
97 /// - Grosof and Swift; 2013
98 pub trait TruncateOps
<I
: Interner
> {
99 /// Check if `subgoal` is too large
100 fn goal_needs_truncation(&mut self, interner
: &I
, subgoal
: &InEnvironment
<Goal
<I
>>) -> bool
;
102 /// Check if `subst` is too large
103 fn answer_needs_truncation(&mut self, interner
: &I
, subst
: &Substitution
<I
>) -> bool
;
106 pub trait ResolventOps
<I
: Interner
> {
107 /// Combines the `goal` (instantiated within `infer`) with the
108 /// given program clause to yield the start of a new strand (a
109 /// canonical ex-clause).
111 /// The bindings in `infer` are unaffected by this operation.
115 environment
: &Environment
<I
>,
116 goal
: &DomainGoal
<I
>,
117 subst
: &Substitution
<I
>,
118 clause
: &ProgramClause
<I
>,
119 ) -> Fallible
<ExClause
<I
>>;
121 fn apply_answer_subst(
124 ex_clause
: &mut ExClause
<I
>,
125 selected_goal
: &InEnvironment
<Goal
<I
>>,
126 answer_table_goal
: &Canonical
<InEnvironment
<Goal
<I
>>>,
127 canonical_answer_subst
: &Canonical
<AnswerSubst
<I
>>,
131 /// Methods for unifying and manipulating terms and binders.
132 pub trait UnificationOps
<I
: Interner
> {
134 fn instantiate_binders_universally(&mut self, interner
: &I
, arg
: &Binders
<Goal
<I
>>) -> Goal
<I
>;
137 fn instantiate_binders_existentially(
140 arg
: &Binders
<Goal
<I
>>,
143 // Used by: logic (but for debugging only)
144 fn debug_ex_clause
<'v
>(&mut self, interner
: &I
, value
: &'v ExClause
<I
>) -> Box
<dyn Debug
+ 'v
>;
147 fn fully_canonicalize_goal(
150 value
: &InEnvironment
<Goal
<I
>>,
151 ) -> (UCanonical
<InEnvironment
<Goal
<I
>>>, UniverseMap
);
154 fn canonicalize_ex_clause(
158 ) -> Canonical
<ExClause
<I
>>;
161 fn canonicalize_constrained_subst(
164 subst
: Substitution
<I
>,
165 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
166 ) -> Canonical
<ConstrainedSubst
<I
>>;
169 fn canonicalize_answer_subst(
172 subst
: Substitution
<I
>,
173 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
174 delayed_subgoals
: Vec
<InEnvironment
<Goal
<I
>>>,
175 ) -> Canonical
<AnswerSubst
<I
>>;
181 value
: &InEnvironment
<Goal
<I
>>,
182 ) -> Option
<InEnvironment
<Goal
<I
>>>;
184 /// First unify the parameters, then add the residual subgoals
185 /// as new subgoals of the ex-clause.
186 /// Also add region constraints.
188 /// If the parameters fail to unify, then `Error` is returned
190 fn unify_generic_args_into_ex_clause(
193 environment
: &Environment
<I
>,
196 ex_clause
: &mut ExClause
<I
>,
201 pub struct TruncatingInferenceTable
<I
: Interner
> {
203 infer
: InferenceTable
<I
>,
206 impl<I
: Interner
> TruncatingInferenceTable
<I
> {
207 pub(crate) fn new(max_size
: usize, infer
: InferenceTable
<I
>) -> Self {
208 Self { max_size, infer }
212 impl<I
: Interner
> TruncateOps
<I
> for TruncatingInferenceTable
<I
> {
213 fn goal_needs_truncation(&mut self, interner
: &I
, subgoal
: &InEnvironment
<Goal
<I
>>) -> bool
{
214 truncate
::needs_truncation(interner
, &mut self.infer
, self.max_size
, &subgoal
)
217 fn answer_needs_truncation(&mut self, interner
: &I
, subst
: &Substitution
<I
>) -> bool
{
218 truncate
::needs_truncation(interner
, &mut self.infer
, self.max_size
, subst
)
222 impl<I
: Interner
> UnificationOps
<I
> for TruncatingInferenceTable
<I
> {
223 fn instantiate_binders_universally(&mut self, interner
: &I
, arg
: &Binders
<Goal
<I
>>) -> Goal
<I
> {
224 self.infer
.instantiate_binders_universally(interner
, arg
)
227 fn instantiate_binders_existentially(
230 arg
: &Binders
<Goal
<I
>>,
232 self.infer
.instantiate_binders_existentially(interner
, arg
)
235 fn debug_ex_clause
<'v
>(&mut self, interner
: &I
, value
: &'v ExClause
<I
>) -> Box
<dyn Debug
+ 'v
> {
236 Box
::new(DeepNormalizer
::normalize_deep(
243 fn fully_canonicalize_goal(
246 value
: &InEnvironment
<Goal
<I
>>,
247 ) -> (UCanonical
<InEnvironment
<Goal
<I
>>>, UniverseMap
) {
248 let canonicalized_goal
= self.infer
.canonicalize(interner
, value
).quantified
;
252 } = self.infer
.u_canonicalize(interner
, &canonicalized_goal
);
253 (quantified
, universes
)
256 fn canonicalize_ex_clause(
260 ) -> Canonical
<ExClause
<I
>> {
261 self.infer
.canonicalize(interner
, value
).quantified
264 fn canonicalize_constrained_subst(
267 subst
: Substitution
<I
>,
268 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
269 ) -> Canonical
<ConstrainedSubst
<I
>> {
275 constraints
: Constraints
::from_iter(interner
, constraints
),
281 fn canonicalize_answer_subst(
284 subst
: Substitution
<I
>,
285 constraints
: Vec
<InEnvironment
<Constraint
<I
>>>,
286 delayed_subgoals
: Vec
<InEnvironment
<Goal
<I
>>>,
287 ) -> Canonical
<AnswerSubst
<I
>> {
293 constraints
: Constraints
::from_iter(interner
, constraints
),
303 value
: &InEnvironment
<Goal
<I
>>,
304 ) -> Option
<InEnvironment
<Goal
<I
>>> {
305 self.infer
.invert(interner
, value
)
308 fn unify_generic_args_into_ex_clause(
311 environment
: &Environment
<I
>,
314 ex_clause
: &mut ExClause
<I
>,
316 let result
= self.infer
.unify(interner
, environment
, a
, b
)?
;
317 Ok(into_ex_clause(interner
, result
, ex_clause
))
322 fn into_ex_clause
<I
: Interner
>(
324 result
: UnificationResult
<I
>,
325 ex_clause
: &mut ExClause
<I
>,
327 ex_clause
.subgoals
.extend(
332 .map(Literal
::Positive
),
336 trait SubstitutionExt
<I
: Interner
> {
337 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
;
340 impl<I
: Interner
> SubstitutionExt
<I
> for Substitution
<I
> {
341 fn may_invalidate(&self, interner
: &I
, subst
: &Canonical
<Substitution
<I
>>) -> bool
{
343 .zip(subst
.value
.iter(interner
))
344 .any(|(new
, current
)| MayInvalidate { interner }
.aggregate_generic_args(new
, current
))
348 // This is a struct in case we need to add state at any point like in AntiUnifier
349 struct MayInvalidate
<'i
, I
> {
353 impl<I
: Interner
> MayInvalidate
<'_
, I
> {
354 fn aggregate_generic_args(&mut self, new
: &GenericArg
<I
>, current
: &GenericArg
<I
>) -> bool
{
355 let interner
= self.interner
;
356 match (new
.data(interner
), current
.data(interner
)) {
357 (GenericArgData
::Ty(ty1
), GenericArgData
::Ty(ty2
)) => self.aggregate_tys(ty1
, ty2
),
358 (GenericArgData
::Lifetime(l1
), GenericArgData
::Lifetime(l2
)) => {
359 self.aggregate_lifetimes(l1
, l2
)
361 (GenericArgData
::Const(c1
), GenericArgData
::Const(c2
)) => self.aggregate_consts(c1
, c2
),
362 (GenericArgData
::Ty(_
), _
)
363 | (GenericArgData
::Lifetime(_
), _
)
364 | (GenericArgData
::Const(_
), _
) => panic
!(
365 "mismatched parameter kinds: new={:?} current={:?}",
371 /// Returns true if the two types could be unequal.
372 fn aggregate_tys(&mut self, new
: &Ty
<I
>, current
: &Ty
<I
>) -> bool
{
373 let interner
= self.interner
;
374 match (new
.kind(interner
), current
.kind(interner
)) {
375 (_
, TyKind
::BoundVar(_
)) => {
376 // If the aggregate solution already has an inference
377 // variable here, then no matter what type we produce,
378 // the aggregate cannot get 'more generalized' than it
379 // already is. So return false, we cannot invalidate.
381 // (Note that "inference variables" show up as *bound
382 // variables* here, because we are looking at the
387 (TyKind
::BoundVar(_
), _
) => {
388 // If we see a type variable in the potential future
389 // solution, we have to be conservative. We don't know
390 // what type variable will wind up being! Remember
391 // that the future solution could be any instantiation
392 // of `ty0` -- or it could leave this variable
393 // unbound, if the result is true for all types.
395 // (Note that "inference variables" show up as *bound
396 // variables* here, because we are looking at the
401 (TyKind
::InferenceVar(_
, _
), _
) | (_
, TyKind
::InferenceVar(_
, _
)) => {
403 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
408 (TyKind
::Placeholder(p1
), TyKind
::Placeholder(p2
)) => {
409 self.aggregate_placeholders(p1
, p2
)
413 TyKind
::Alias(AliasTy
::Projection(proj1
)),
414 TyKind
::Alias(AliasTy
::Projection(proj2
)),
415 ) => self.aggregate_projection_tys(proj1
, proj2
),
418 TyKind
::Alias(AliasTy
::Opaque(opaque_ty1
)),
419 TyKind
::Alias(AliasTy
::Opaque(opaque_ty2
)),
420 ) => self.aggregate_opaque_ty_tys(opaque_ty1
, opaque_ty2
),
422 (TyKind
::Adt(id_a
, substitution_a
), TyKind
::Adt(id_b
, substitution_b
)) => {
423 self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
)
426 TyKind
::AssociatedType(id_a
, substitution_a
),
427 TyKind
::AssociatedType(id_b
, substitution_b
),
428 ) => self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
),
429 (TyKind
::Scalar(scalar_a
), TyKind
::Scalar(scalar_b
)) => scalar_a
!= scalar_b
,
430 (TyKind
::Str
, TyKind
::Str
) => false,
431 (TyKind
::Tuple(arity_a
, substitution_a
), TyKind
::Tuple(arity_b
, substitution_b
)) => {
432 self.aggregate_name_and_substs(arity_a
, substitution_a
, arity_b
, substitution_b
)
435 TyKind
::OpaqueType(id_a
, substitution_a
),
436 TyKind
::OpaqueType(id_b
, substitution_b
),
437 ) => self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
),
438 (TyKind
::Slice(ty_a
), TyKind
::Slice(ty_b
)) => self.aggregate_tys(ty_a
, ty_b
),
439 (TyKind
::FnDef(id_a
, substitution_a
), TyKind
::FnDef(id_b
, substitution_b
)) => {
440 self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
)
442 (TyKind
::Ref(id_a
, lifetime_a
, ty_a
), TyKind
::Ref(id_b
, lifetime_b
, ty_b
)) => {
444 || self.aggregate_lifetimes(lifetime_a
, lifetime_b
)
445 || self.aggregate_tys(ty_a
, ty_b
)
447 (TyKind
::Raw(id_a
, ty_a
), TyKind
::Raw(id_b
, ty_b
)) => {
448 id_a
!= id_b
|| self.aggregate_tys(ty_a
, ty_b
)
450 (TyKind
::Never
, TyKind
::Never
) => false,
451 (TyKind
::Array(ty_a
, const_a
), TyKind
::Array(ty_b
, const_b
)) => {
452 self.aggregate_tys(ty_a
, ty_b
) || self.aggregate_consts(const_a
, const_b
)
454 (TyKind
::Closure(id_a
, substitution_a
), TyKind
::Closure(id_b
, substitution_b
)) => {
455 self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
)
457 (TyKind
::Generator(id_a
, substitution_a
), TyKind
::Generator(id_b
, substitution_b
)) => {
458 self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
)
461 TyKind
::GeneratorWitness(id_a
, substitution_a
),
462 TyKind
::GeneratorWitness(id_b
, substitution_b
),
463 ) => self.aggregate_name_and_substs(id_a
, substitution_a
, id_b
, substitution_b
),
464 (TyKind
::Foreign(id_a
), TyKind
::Foreign(id_b
)) => id_a
!= id_b
,
465 (TyKind
::Error
, TyKind
::Error
) => false,
471 /// Returns true if the two consts could be unequal.
472 fn aggregate_lifetimes(&mut self, _
: &Lifetime
<I
>, _
: &Lifetime
<I
>) -> bool
{
476 /// Returns true if the two consts could be unequal.
477 fn aggregate_consts(&mut self, new
: &Const
<I
>, current
: &Const
<I
>) -> bool
{
478 let interner
= self.interner
;
482 } = new
.data(interner
);
485 value
: current_value
,
486 } = current
.data(interner
);
488 if self.aggregate_tys(new_ty
, current_ty
) {
492 match (new_value
, current_value
) {
493 (_
, ConstValue
::BoundVar(_
)) => {
494 // see comment in aggregate_tys
498 (ConstValue
::BoundVar(_
), _
) => {
499 // see comment in aggregate_tys
503 (ConstValue
::InferenceVar(_
), _
) | (_
, ConstValue
::InferenceVar(_
)) => {
505 "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
510 (ConstValue
::Placeholder(p1
), ConstValue
::Placeholder(p2
)) => {
511 self.aggregate_placeholders(p1
, p2
)
514 (ConstValue
::Concrete(c1
), ConstValue
::Concrete(c2
)) => {
515 !c1
.const_eq(new_ty
, c2
, interner
)
518 // Only variants left are placeholder = concrete, which always fails
519 (ConstValue
::Placeholder(_
), _
) | (ConstValue
::Concrete(_
), _
) => true,
523 fn aggregate_placeholders(
525 new
: &PlaceholderIndex
,
526 current
: &PlaceholderIndex
,
531 fn aggregate_projection_tys(
533 new
: &ProjectionTy
<I
>,
534 current
: &ProjectionTy
<I
>,
537 associated_ty_id
: new_name
,
538 substitution
: new_substitution
,
541 associated_ty_id
: current_name
,
542 substitution
: current_substitution
,
545 self.aggregate_name_and_substs(
549 current_substitution
,
553 fn aggregate_opaque_ty_tys(&mut self, new
: &OpaqueTy
<I
>, current
: &OpaqueTy
<I
>) -> bool
{
555 opaque_ty_id
: new_name
,
556 substitution
: new_substitution
,
559 opaque_ty_id
: current_name
,
560 substitution
: current_substitution
,
563 self.aggregate_name_and_substs(
567 current_substitution
,
571 fn aggregate_name_and_substs
<N
>(
574 new_substitution
: &Substitution
<I
>,
576 current_substitution
: &Substitution
<I
>,
579 N
: Copy
+ Eq
+ Debug
,
581 let interner
= self.interner
;
582 if new_name
!= current_name
{
589 new_substitution
.len(interner
),
590 current_substitution
.len(interner
),
591 "does {:?} take {} substitution or {}? can't both be right",
593 new_substitution
.len(interner
),
594 current_substitution
.len(interner
)
599 .zip(current_substitution
.iter(interner
))
600 .any(|(new
, current
)| self.aggregate_generic_args(new
, current
))