]>
Commit | Line | Data |
---|---|---|
5869c6ff | 1 | use crate::ExClause; |
1b1a35ee | 2 | |
f035d41b | 3 | use chalk_derive::HasInterner; |
f035d41b XL |
4 | use chalk_ir::interner::Interner; |
5 | use chalk_ir::*; | |
1b1a35ee | 6 | use chalk_solve::infer::InferenceTable; |
1b1a35ee XL |
7 | use chalk_solve::RustIrDatabase; |
8 | ||
9 | use std::fmt::Debug; | |
f035d41b XL |
10 | use std::marker::PhantomData; |
11 | ||
12 | pub(crate) mod aggregate; | |
13 | mod resolvent; | |
14 | ||
f035d41b XL |
15 | #[derive(Clone, Debug, HasInterner)] |
16 | pub(crate) struct SlgContext<I: Interner> { | |
17 | phantom: PhantomData<I>, | |
18 | } | |
19 | ||
29967ef6 XL |
20 | impl<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 | } | |
f035d41b XL |
32 | #[derive(Clone, Debug)] |
33 | pub(crate) struct SlgContextOps<'me, I: Interner> { | |
34 | program: &'me dyn RustIrDatabase<I>, | |
35 | max_size: usize, | |
36 | expected_answers: Option<usize>, | |
37 | } | |
38 | ||
39 | impl<I: Interner> SlgContextOps<'_, I> { | |
1b1a35ee XL |
40 | pub(crate) fn new( |
41 | program: &dyn RustIrDatabase<I>, | |
f035d41b XL |
42 | max_size: usize, |
43 | expected_answers: Option<usize>, | |
1b1a35ee | 44 | ) -> SlgContextOps<'_, I> { |
f035d41b XL |
45 | SlgContextOps { |
46 | program, | |
47 | max_size, | |
48 | expected_answers, | |
49 | } | |
50 | } | |
f035d41b XL |
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, | |
5869c6ff | 59 | goal.canonical.clone(), |
f035d41b XL |
60 | ); |
61 | infer | |
62 | .canonicalize( | |
63 | self.program.interner(), | |
5869c6ff | 64 | ConstrainedSubst { |
f035d41b | 65 | subst, |
1b1a35ee | 66 | constraints: Constraints::empty(self.program.interner()), |
f035d41b XL |
67 | }, |
68 | ) | |
69 | .quantified | |
70 | } | |
71 | ||
29967ef6 XL |
72 | pub(crate) fn program(&self) -> &dyn RustIrDatabase<I> { |
73 | self.program | |
f035d41b XL |
74 | } |
75 | ||
29967ef6 XL |
76 | pub(crate) fn max_size(&self) -> usize { |
77 | self.max_size | |
f035d41b | 78 | } |
29967ef6 | 79 | |
5869c6ff XL |
80 | pub(crate) fn unification_database(&self) -> &dyn UnificationDatabase<I> { |
81 | self.program.unification_database() | |
82 | } | |
29967ef6 | 83 | } |
f035d41b | 84 | |
29967ef6 XL |
85 | pub 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, | |
5869c6ff | 93 | ops: &dyn UnificationDatabase<I>, |
29967ef6 XL |
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, | |
5869c6ff | 104 | unification_database: &dyn UnificationDatabase<I>, |
29967ef6 XL |
105 | ex_clause: &mut ExClause<I>, |
106 | selected_goal: &InEnvironment<Goal<I>>, | |
107 | answer_table_goal: &Canonical<InEnvironment<Goal<I>>>, | |
5869c6ff | 108 | canonical_answer_subst: Canonical<AnswerSubst<I>>, |
29967ef6 XL |
109 | ) -> Fallible<()>; |
110 | } | |
111 | ||
f035d41b XL |
112 | trait SubstitutionExt<I: Interner> { |
113 | fn may_invalidate(&self, interner: &I, subst: &Canonical<Substitution<I>>) -> bool; | |
114 | } | |
115 | ||
116 | impl<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 | |
125 | struct MayInvalidate<'i, I> { | |
126 | interner: &'i I, | |
127 | } | |
128 | ||
129 | impl<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; | |
29967ef6 XL |
150 | match (new.kind(interner), current.kind(interner)) { |
151 | (_, TyKind::BoundVar(_)) => { | |
f035d41b XL |
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 | ||
29967ef6 | 163 | (TyKind::BoundVar(_), _) => { |
f035d41b XL |
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 | ||
29967ef6 | 177 | (TyKind::InferenceVar(_, _), _) | (_, TyKind::InferenceVar(_, _)) => { |
f035d41b XL |
178 | panic!( |
179 | "unexpected free inference variable in may-invalidate: {:?} vs {:?}", | |
180 | new, current, | |
181 | ); | |
182 | } | |
183 | ||
29967ef6 | 184 | (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) => { |
f035d41b XL |
185 | self.aggregate_placeholders(p1, p2) |
186 | } | |
187 | ||
188 | ( | |
29967ef6 XL |
189 | TyKind::Alias(AliasTy::Projection(proj1)), |
190 | TyKind::Alias(AliasTy::Projection(proj2)), | |
f035d41b XL |
191 | ) => self.aggregate_projection_tys(proj1, proj2), |
192 | ||
193 | ( | |
29967ef6 XL |
194 | TyKind::Alias(AliasTy::Opaque(opaque_ty1)), |
195 | TyKind::Alias(AliasTy::Opaque(opaque_ty2)), | |
f035d41b XL |
196 | ) => self.aggregate_opaque_ty_tys(opaque_ty1, opaque_ty2), |
197 | ||
29967ef6 XL |
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::Generator(id_a, substitution_a), TyKind::Generator(id_b, substitution_b)) => { | |
234 | self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b) | |
235 | } | |
236 | ( | |
237 | TyKind::GeneratorWitness(id_a, substitution_a), | |
238 | TyKind::GeneratorWitness(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, | |
f035d41b XL |
244 | } |
245 | } | |
246 | ||
5869c6ff | 247 | /// Returns true if the two consts could be unequal. |
f035d41b XL |
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 | ||
f035d41b XL |
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 | } |