chalk_engine/
slg.rs

1use crate::ExClause;
2
3use chalk_derive::HasInterner;
4use chalk_ir::interner::Interner;
5use chalk_ir::*;
6use chalk_solve::infer::InferenceTable;
7use chalk_solve::RustIrDatabase;
8
9use std::fmt::Debug;
10use std::marker::PhantomData;
11
12pub(crate) mod aggregate;
13mod resolvent;
14
15#[derive(Clone, Debug, HasInterner)]
16pub(crate) struct SlgContext<I: Interner> {
17    phantom: PhantomData<I>,
18}
19
20impl<I: Interner> SlgContext<I> {
21    pub(crate) fn next_subgoal_index(ex_clause: &ExClause<I>) -> usize {
22        // For now, we always pick the last subgoal in the
23        // list.
24        //
25        // FIXME(rust-lang-nursery/chalk#80) -- we should be more
26        // selective. For example, we don't want to pick a
27        // negative literal that will flounder, and we don't want
28        // to pick things like `?T: Sized` if we can help it.
29        ex_clause.subgoals.len() - 1
30    }
31}
32#[derive(Clone, Debug)]
33pub(crate) struct SlgContextOps<'me, I: Interner> {
34    program: &'me dyn RustIrDatabase<I>,
35    max_size: usize,
36    expected_answers: Option<usize>,
37}
38
39impl<I: Interner> SlgContextOps<'_, I> {
40    pub(crate) fn new(
41        program: &dyn RustIrDatabase<I>,
42        max_size: usize,
43        expected_answers: Option<usize>,
44    ) -> SlgContextOps<'_, I> {
45        SlgContextOps {
46            program,
47            max_size,
48            expected_answers,
49        }
50    }
51
52    fn identity_constrained_subst(
53        &self,
54        goal: &UCanonical<InEnvironment<Goal<I>>>,
55    ) -> Canonical<ConstrainedSubst<I>> {
56        let (mut infer, subst, _) = InferenceTable::from_canonical(
57            self.program.interner(),
58            goal.universes,
59            goal.canonical.clone(),
60        );
61        infer
62            .canonicalize(
63                self.program.interner(),
64                ConstrainedSubst {
65                    subst,
66                    constraints: Constraints::empty(self.program.interner()),
67                },
68            )
69            .quantified
70    }
71
72    pub(crate) fn program(&self) -> &dyn RustIrDatabase<I> {
73        self.program
74    }
75
76    pub(crate) fn max_size(&self) -> usize {
77        self.max_size
78    }
79
80    pub(crate) fn unification_database(&self) -> &dyn UnificationDatabase<I> {
81        self.program.unification_database()
82    }
83}
84
85pub trait ResolventOps<I: Interner> {
86    /// Combines the `goal` (instantiated within `infer`) with the
87    /// given program clause to yield the start of a new strand (a
88    /// canonical ex-clause).
89    ///
90    /// The bindings in `infer` are unaffected by this operation.
91    fn resolvent_clause(
92        &mut self,
93        ops: &dyn UnificationDatabase<I>,
94        interner: I,
95        environment: &Environment<I>,
96        goal: &DomainGoal<I>,
97        subst: &Substitution<I>,
98        clause: &ProgramClause<I>,
99    ) -> Fallible<ExClause<I>>;
100
101    fn apply_answer_subst(
102        &mut self,
103        interner: I,
104        unification_database: &dyn UnificationDatabase<I>,
105        ex_clause: &mut ExClause<I>,
106        selected_goal: &InEnvironment<Goal<I>>,
107        answer_table_goal: &Canonical<InEnvironment<Goal<I>>>,
108        canonical_answer_subst: Canonical<AnswerSubst<I>>,
109    ) -> Fallible<()>;
110}
111
112trait SubstitutionExt<I: Interner> {
113    fn may_invalidate(&self, interner: I, subst: &Canonical<Substitution<I>>) -> bool;
114}
115
116impl<I: Interner> SubstitutionExt<I> for Substitution<I> {
117    fn may_invalidate(&self, interner: I, subst: &Canonical<Substitution<I>>) -> bool {
118        self.iter(interner)
119            .zip(subst.value.iter(interner))
120            .any(|(new, current)| MayInvalidate { interner }.aggregate_generic_args(new, current))
121    }
122}
123
124// This is a struct in case we need to add state at any point like in AntiUnifier
125struct MayInvalidate<I> {
126    interner: I,
127}
128
129impl<I: Interner> MayInvalidate<I> {
130    fn aggregate_generic_args(&mut self, new: &GenericArg<I>, current: &GenericArg<I>) -> bool {
131        let interner = self.interner;
132        match (new.data(interner), current.data(interner)) {
133            (GenericArgData::Ty(ty1), GenericArgData::Ty(ty2)) => self.aggregate_tys(ty1, ty2),
134            (GenericArgData::Lifetime(l1), GenericArgData::Lifetime(l2)) => {
135                self.aggregate_lifetimes(l1, l2)
136            }
137            (GenericArgData::Const(c1), GenericArgData::Const(c2)) => self.aggregate_consts(c1, c2),
138            (GenericArgData::Ty(_), _)
139            | (GenericArgData::Lifetime(_), _)
140            | (GenericArgData::Const(_), _) => panic!(
141                "mismatched parameter kinds: new={:?} current={:?}",
142                new, current
143            ),
144        }
145    }
146
147    /// Returns true if the two types could be unequal.
148    fn aggregate_tys(&mut self, new: &Ty<I>, current: &Ty<I>) -> bool {
149        let interner = self.interner;
150        match (new.kind(interner), current.kind(interner)) {
151            (_, TyKind::BoundVar(_)) => {
152                // If the aggregate solution already has an inference
153                // variable here, then no matter what type we produce,
154                // the aggregate cannot get 'more generalized' than it
155                // already is. So return false, we cannot invalidate.
156                //
157                // (Note that "inference variables" show up as *bound
158                // variables* here, because we are looking at the
159                // canonical form.)
160                false
161            }
162
163            (TyKind::BoundVar(_), _) => {
164                // If we see a type variable in the potential future
165                // solution, we have to be conservative. We don't know
166                // what type variable will wind up being! Remember
167                // that the future solution could be any instantiation
168                // of `ty0` -- or it could leave this variable
169                // unbound, if the result is true for all types.
170                //
171                // (Note that "inference variables" show up as *bound
172                // variables* here, because we are looking at the
173                // canonical form.)
174                true
175            }
176
177            (TyKind::InferenceVar(_, _), _) | (_, TyKind::InferenceVar(_, _)) => {
178                panic!(
179                    "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
180                    new, current,
181                );
182            }
183
184            (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) => {
185                self.aggregate_placeholders(p1, p2)
186            }
187
188            (
189                TyKind::Alias(AliasTy::Projection(proj1)),
190                TyKind::Alias(AliasTy::Projection(proj2)),
191            ) => self.aggregate_projection_tys(proj1, proj2),
192
193            (
194                TyKind::Alias(AliasTy::Opaque(opaque_ty1)),
195                TyKind::Alias(AliasTy::Opaque(opaque_ty2)),
196            ) => self.aggregate_opaque_ty_tys(opaque_ty1, opaque_ty2),
197
198            (TyKind::Adt(id_a, substitution_a), TyKind::Adt(id_b, substitution_b)) => {
199                self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b)
200            }
201            (
202                TyKind::AssociatedType(id_a, substitution_a),
203                TyKind::AssociatedType(id_b, substitution_b),
204            ) => self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b),
205            (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a != scalar_b,
206            (TyKind::Str, TyKind::Str) => false,
207            (TyKind::Tuple(arity_a, substitution_a), TyKind::Tuple(arity_b, substitution_b)) => {
208                self.aggregate_name_and_substs(arity_a, substitution_a, arity_b, substitution_b)
209            }
210            (
211                TyKind::OpaqueType(id_a, substitution_a),
212                TyKind::OpaqueType(id_b, substitution_b),
213            ) => self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b),
214            (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.aggregate_tys(ty_a, ty_b),
215            (TyKind::FnDef(id_a, substitution_a), TyKind::FnDef(id_b, substitution_b)) => {
216                self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b)
217            }
218            (TyKind::Ref(id_a, lifetime_a, ty_a), TyKind::Ref(id_b, lifetime_b, ty_b)) => {
219                id_a != id_b
220                    || self.aggregate_lifetimes(lifetime_a, lifetime_b)
221                    || self.aggregate_tys(ty_a, ty_b)
222            }
223            (TyKind::Raw(id_a, ty_a), TyKind::Raw(id_b, ty_b)) => {
224                id_a != id_b || self.aggregate_tys(ty_a, ty_b)
225            }
226            (TyKind::Never, TyKind::Never) => false,
227            (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) => {
228                self.aggregate_tys(ty_a, ty_b) || self.aggregate_consts(const_a, const_b)
229            }
230            (TyKind::Closure(id_a, substitution_a), TyKind::Closure(id_b, substitution_b)) => {
231                self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b)
232            }
233            (TyKind::Coroutine(id_a, substitution_a), TyKind::Coroutine(id_b, substitution_b)) => {
234                self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b)
235            }
236            (
237                TyKind::CoroutineWitness(id_a, substitution_a),
238                TyKind::CoroutineWitness(id_b, substitution_b),
239            ) => self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b),
240            (TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a != id_b,
241            (TyKind::Error, TyKind::Error) => false,
242
243            (_, _) => true,
244        }
245    }
246
247    /// Returns true if the two consts could be unequal.
248    fn aggregate_lifetimes(&mut self, _: &Lifetime<I>, _: &Lifetime<I>) -> bool {
249        true
250    }
251
252    /// Returns true if the two consts could be unequal.
253    fn aggregate_consts(&mut self, new: &Const<I>, current: &Const<I>) -> bool {
254        let interner = self.interner;
255        let ConstData {
256            ty: new_ty,
257            value: new_value,
258        } = new.data(interner);
259        let ConstData {
260            ty: current_ty,
261            value: current_value,
262        } = current.data(interner);
263
264        if self.aggregate_tys(new_ty, current_ty) {
265            return true;
266        }
267
268        match (new_value, current_value) {
269            (_, ConstValue::BoundVar(_)) => {
270                // see comment in aggregate_tys
271                false
272            }
273
274            (ConstValue::BoundVar(_), _) => {
275                // see comment in aggregate_tys
276                true
277            }
278
279            (ConstValue::InferenceVar(_), _) | (_, ConstValue::InferenceVar(_)) => {
280                panic!(
281                    "unexpected free inference variable in may-invalidate: {:?} vs {:?}",
282                    new, current,
283                );
284            }
285
286            (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) => {
287                self.aggregate_placeholders(p1, p2)
288            }
289
290            (ConstValue::Concrete(c1), ConstValue::Concrete(c2)) => {
291                !c1.const_eq(new_ty, c2, interner)
292            }
293
294            // Only variants left are placeholder = concrete, which always fails
295            (ConstValue::Placeholder(_), _) | (ConstValue::Concrete(_), _) => true,
296        }
297    }
298
299    fn aggregate_placeholders(
300        &mut self,
301        new: &PlaceholderIndex,
302        current: &PlaceholderIndex,
303    ) -> bool {
304        new != current
305    }
306
307    fn aggregate_projection_tys(
308        &mut self,
309        new: &ProjectionTy<I>,
310        current: &ProjectionTy<I>,
311    ) -> bool {
312        let ProjectionTy {
313            associated_ty_id: new_name,
314            substitution: new_substitution,
315        } = new;
316        let ProjectionTy {
317            associated_ty_id: current_name,
318            substitution: current_substitution,
319        } = current;
320
321        self.aggregate_name_and_substs(
322            new_name,
323            new_substitution,
324            current_name,
325            current_substitution,
326        )
327    }
328
329    fn aggregate_opaque_ty_tys(&mut self, new: &OpaqueTy<I>, current: &OpaqueTy<I>) -> bool {
330        let OpaqueTy {
331            opaque_ty_id: new_name,
332            substitution: new_substitution,
333        } = new;
334        let OpaqueTy {
335            opaque_ty_id: current_name,
336            substitution: current_substitution,
337        } = current;
338
339        self.aggregate_name_and_substs(
340            new_name,
341            new_substitution,
342            current_name,
343            current_substitution,
344        )
345    }
346
347    fn aggregate_name_and_substs<N>(
348        &mut self,
349        new_name: N,
350        new_substitution: &Substitution<I>,
351        current_name: N,
352        current_substitution: &Substitution<I>,
353    ) -> bool
354    where
355        N: Copy + Eq + Debug,
356    {
357        let interner = self.interner;
358        if new_name != current_name {
359            return true;
360        }
361
362        let name = new_name;
363
364        assert_eq!(
365            new_substitution.len(interner),
366            current_substitution.len(interner),
367            "does {:?} take {} substitution or {}? can't both be right",
368            name,
369            new_substitution.len(interner),
370            current_substitution.len(interner)
371        );
372
373        new_substitution
374            .iter(interner)
375            .zip(current_substitution.iter(interner))
376            .any(|(new, current)| self.aggregate_generic_args(new, current))
377    }
378}