]> git.proxmox.com Git - rustc.git/blame - vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / vendor / chalk-solve-0.14.0 / src / solve / slg / aggregate.rs
CommitLineData
f035d41b
XL
1use crate::ext::*;
2use crate::infer::InferenceTable;
3use crate::solve::slg::SlgContextOps;
4use crate::solve::slg::SubstitutionExt;
5use crate::solve::{Guidance, Solution};
6use chalk_ir::cast::Cast;
7use chalk_ir::interner::Interner;
8use chalk_ir::*;
9
10use chalk_engine::context::{self, AnswerResult, ContextOps};
11use chalk_engine::CompleteAnswer;
12use std::fmt::Debug;
13
14/// Methods for combining solutions to yield an aggregate solution.
15pub trait AggregateOps<I: Interner> {
16 fn make_solution(
17 &self,
18 root_goal: &UCanonical<InEnvironment<Goal<I>>>,
19 answers: impl context::AnswerStream<I>,
20 should_continue: impl std::ops::Fn() -> bool,
21 ) -> Option<Solution<I>>;
22}
23
24/// Draws as many answers as it needs from `answers` (but
25/// no more!) in order to come up with a solution.
26impl<I: Interner> AggregateOps<I> for SlgContextOps<'_, I> {
27 fn make_solution(
28 &self,
29 root_goal: &UCanonical<InEnvironment<Goal<I>>>,
30 mut answers: impl context::AnswerStream<I>,
31 should_continue: impl std::ops::Fn() -> bool,
32 ) -> Option<Solution<I>> {
33 let interner = self.program.interner();
34 let CompleteAnswer { subst, ambiguous } = match answers.next_answer(|| should_continue()) {
35 AnswerResult::NoMoreSolutions => {
36 // No answers at all
37 return None;
38 }
39 AnswerResult::Answer(answer) => answer,
40 AnswerResult::Floundered => CompleteAnswer {
41 subst: self.identity_constrained_subst(root_goal),
42 ambiguous: true,
43 },
44 AnswerResult::QuantumExceeded => {
45 return Some(Solution::Ambig(Guidance::Unknown));
46 }
47 };
48
49 // Exactly 1 unconditional answer?
50 let next_answer = answers.peek_answer(|| should_continue());
51 if next_answer.is_quantum_exceeded() {
52 if subst.value.subst.is_identity_subst(interner) {
53 return Some(Solution::Ambig(Guidance::Unknown));
54 } else {
55 return Some(Solution::Ambig(Guidance::Suggested(
56 subst.map(interner, |cs| cs.subst),
57 )));
58 }
59 }
60 if next_answer.is_no_more_solutions() && !ambiguous {
61 return Some(Solution::Unique(subst));
62 }
63
64 // Otherwise, we either have >1 answer, or else we have
65 // ambiguity. Either way, we are only going to be giving back
66 // **guidance**, and with guidance, the caller doesn't get
67 // back any region constraints. So drop them from our `subst`
68 // variable.
69 //
70 // FIXME-- there is actually a 3rd possibility. We could have
71 // >1 answer where all the answers have the same substitution,
72 // but different region constraints. We should collapse those
73 // cases into an `OR` region constraint at some point, but I
74 // leave that for future work. This is basically
75 // rust-lang/rust#21974.
76 let mut subst = subst.map(interner, |cs| cs.subst);
77
78 // Extract answers and merge them into `subst`. Stop once we have
79 // a trivial subst (or run out of answers).
80 let mut num_answers = 1;
81 let guidance = loop {
82 if subst.value.is_empty(interner) || is_trivial(interner, &subst) {
83 break Guidance::Unknown;
84 }
85
86 if !answers
87 .any_future_answer(|ref mut new_subst| new_subst.may_invalidate(interner, &subst))
88 {
89 break Guidance::Definite(subst);
90 }
91
92 if let Some(expected_answers) = self.expected_answers {
93 if num_answers >= expected_answers {
94 panic!("Too many answers for solution.");
95 }
96 }
97
98 let new_subst = match answers.next_answer(|| should_continue()) {
99 AnswerResult::Answer(answer1) => answer1.subst,
100 AnswerResult::Floundered => {
101 // FIXME: this doesn't trigger for any current tests
102 self.identity_constrained_subst(root_goal)
103 }
104 AnswerResult::NoMoreSolutions => {
105 break Guidance::Definite(subst);
106 }
107 AnswerResult::QuantumExceeded => {
108 break Guidance::Suggested(subst);
109 }
110 };
111 subst = merge_into_guidance(interner, &root_goal.canonical, subst, &new_subst);
112 num_answers += 1;
113 };
114
115 if let Some(expected_answers) = self.expected_answers {
116 assert_eq!(
117 expected_answers, num_answers,
118 "Not enough answers for solution."
119 );
120 }
121 Some(Solution::Ambig(guidance))
122 }
123}
124
125/// Given a current substitution used as guidance for `root_goal`, and
126/// a new possible answer to `root_goal`, returns a new set of
127/// guidance that encompasses both of them. This is often more general
128/// than the old guidance. For example, if we had a guidance of `?0 =
129/// u32` and the new answer is `?0 = i32`, then the guidance would
130/// become `?0 = ?X` (where `?X` is some fresh variable).
131fn merge_into_guidance<I: Interner>(
132 interner: &I,
133 root_goal: &Canonical<InEnvironment<Goal<I>>>,
134 guidance: Canonical<Substitution<I>>,
135 answer: &Canonical<ConstrainedSubst<I>>,
136) -> Canonical<Substitution<I>> {
137 let mut infer = InferenceTable::new();
138 let Canonical {
139 value: ConstrainedSubst {
140 subst: subst1,
141 constraints: _,
142 },
143 binders: _,
144 } = answer;
145
146 // Collect the types that the two substitutions have in
147 // common.
148 let aggr_generic_args: Vec<_> = guidance
149 .value
150 .iter(interner)
151 .zip(subst1.iter(interner))
152 .enumerate()
153 .map(|(index, (p1, p2))| {
154 // We have two values for some variable X that
155 // appears in the root goal. Find out the universe
156 // of X.
157 let universe = *root_goal.binders.as_slice(interner)[index].skip_kind();
158
159 match p1.data(interner) {
160 GenericArgData::Ty(_) => (),
161 GenericArgData::Lifetime(_) => {
162 // Ignore the lifetimes from the substitution: we're just
163 // creating guidance here anyway.
164 return infer
165 .new_variable(universe)
166 .to_lifetime(interner)
167 .cast(interner);
168 }
169 GenericArgData::Const(_) => (),
170 };
171
172 // Combine the two types into a new type.
173 let mut aggr = AntiUnifier {
174 infer: &mut infer,
175 universe,
176 interner,
177 };
178 aggr.aggregate_generic_args(p1, p2)
179 })
180 .collect();
181
182 let aggr_subst = Substitution::from(interner, aggr_generic_args);
183
184 infer.canonicalize(interner, &aggr_subst).quantified
185}
186
187fn is_trivial<I: Interner>(interner: &I, subst: &Canonical<Substitution<I>>) -> bool {
188 // A subst is trivial if..
189 subst
190 .value
191 .iter(interner)
192 .enumerate()
193 .all(|(index, parameter)| {
194 let is_trivial = |b: Option<BoundVar>| match b {
195 None => false,
196 Some(bound_var) => {
197 if let Some(index1) = bound_var.index_if_innermost() {
198 index == index1
199 } else {
200 false
201 }
202 }
203 };
204
205 match parameter.data(interner) {
206 // All types and consts are mapped to distinct variables. Since this
207 // has been canonicalized, those will also be the first N
208 // variables.
209 GenericArgData::Ty(t) => is_trivial(t.bound_var(interner)),
210 GenericArgData::Const(t) => is_trivial(t.bound_var(interner)),
211
212 // And no lifetime mappings. (This is too strict, but we never
213 // product substs with lifetimes.)
214 GenericArgData::Lifetime(_) => false,
215 }
216 })
217}
218
219/// [Anti-unification] is the act of taking two things that do not
220/// unify and finding a minimal generalization of them. So for
221/// example `Vec<u32>` anti-unified with `Vec<i32>` might be
222/// `Vec<?X>`. This is a **very simplistic** anti-unifier.
223///
224/// [Anti-unification]: https://en.wikipedia.org/wiki/Anti-unification_(computer_science)
225struct AntiUnifier<'infer, 'intern, I: Interner> {
226 infer: &'infer mut InferenceTable<I>,
227 universe: UniverseIndex,
228 interner: &'intern I,
229}
230
231impl<I: Interner> AntiUnifier<'_, '_, I> {
232 fn aggregate_tys(&mut self, ty0: &Ty<I>, ty1: &Ty<I>) -> Ty<I> {
233 let interner = self.interner;
234 match (ty0.data(interner), ty1.data(interner)) {
235 // If we see bound things on either side, just drop in a
236 // fresh variable. This means we will sometimes
237 // overgeneralize. So for example if we have two
238 // solutions that are both `(X, X)`, we just produce `(Y,
239 // Z)` in all cases.
240 (TyData::InferenceVar(_, _), TyData::InferenceVar(_, _)) => self.new_ty_variable(),
241
242 // Ugh. Aggregating two types like `for<'a> fn(&'a u32,
243 // &'a u32)` and `for<'a, 'b> fn(&'a u32, &'b u32)` seems
244 // kinda hard. Don't try to be smart for now, just plop a
245 // variable in there and be done with it.
246 (TyData::BoundVar(_), TyData::BoundVar(_))
247 | (TyData::Function(_), TyData::Function(_))
248 | (TyData::Dyn(_), TyData::Dyn(_)) => self.new_ty_variable(),
249
250 (TyData::Apply(apply1), TyData::Apply(apply2)) => {
251 self.aggregate_application_tys(apply1, apply2)
252 }
253
254 (
255 TyData::Alias(AliasTy::Projection(proj1)),
256 TyData::Alias(AliasTy::Projection(proj2)),
257 ) => self.aggregate_projection_tys(proj1, proj2),
258
259 (
260 TyData::Alias(AliasTy::Opaque(opaque_ty1)),
261 TyData::Alias(AliasTy::Opaque(opaque_ty2)),
262 ) => self.aggregate_opaque_ty_tys(opaque_ty1, opaque_ty2),
263
264 (TyData::Placeholder(placeholder1), TyData::Placeholder(placeholder2)) => {
265 self.aggregate_placeholder_tys(placeholder1, placeholder2)
266 }
267
268 // Mismatched base kinds.
269 (TyData::InferenceVar(_, _), _)
270 | (TyData::BoundVar(_), _)
271 | (TyData::Dyn(_), _)
272 | (TyData::Function(_), _)
273 | (TyData::Apply(_), _)
274 | (TyData::Alias(_), _)
275 | (TyData::Placeholder(_), _) => self.new_ty_variable(),
276 }
277 }
278
279 fn aggregate_application_tys(
280 &mut self,
281 apply1: &ApplicationTy<I>,
282 apply2: &ApplicationTy<I>,
283 ) -> Ty<I> {
284 let interner = self.interner;
285 let ApplicationTy {
286 name: name1,
287 substitution: substitution1,
288 } = apply1;
289 let ApplicationTy {
290 name: name2,
291 substitution: substitution2,
292 } = apply2;
293
294 self.aggregate_name_and_substs(name1, substitution1, name2, substitution2)
295 .map(|(&name, substitution)| {
296 TyData::Apply(ApplicationTy { name, substitution }).intern(interner)
297 })
298 .unwrap_or_else(|| self.new_ty_variable())
299 }
300
301 fn aggregate_placeholder_tys(
302 &mut self,
303 index1: &PlaceholderIndex,
304 index2: &PlaceholderIndex,
305 ) -> Ty<I> {
306 let interner = self.interner;
307 if index1 != index2 {
308 self.new_ty_variable()
309 } else {
310 TyData::Placeholder(index1.clone()).intern(interner)
311 }
312 }
313
314 fn aggregate_projection_tys(
315 &mut self,
316 proj1: &ProjectionTy<I>,
317 proj2: &ProjectionTy<I>,
318 ) -> Ty<I> {
319 let interner = self.interner;
320 let ProjectionTy {
321 associated_ty_id: name1,
322 substitution: substitution1,
323 } = proj1;
324 let ProjectionTy {
325 associated_ty_id: name2,
326 substitution: substitution2,
327 } = proj2;
328
329 self.aggregate_name_and_substs(name1, substitution1, name2, substitution2)
330 .map(|(&associated_ty_id, substitution)| {
331 TyData::Alias(AliasTy::Projection(ProjectionTy {
332 associated_ty_id,
333 substitution,
334 }))
335 .intern(interner)
336 })
337 .unwrap_or_else(|| self.new_ty_variable())
338 }
339
340 fn aggregate_opaque_ty_tys(
341 &mut self,
342 opaque_ty1: &OpaqueTy<I>,
343 opaque_ty2: &OpaqueTy<I>,
344 ) -> Ty<I> {
345 let OpaqueTy {
346 opaque_ty_id: name1,
347 substitution: substitution1,
348 } = opaque_ty1;
349 let OpaqueTy {
350 opaque_ty_id: name2,
351 substitution: substitution2,
352 } = opaque_ty2;
353
354 self.aggregate_name_and_substs(name1, substitution1, name2, substitution2)
355 .map(|(&opaque_ty_id, substitution)| {
356 TyData::Alias(AliasTy::Opaque(OpaqueTy {
357 opaque_ty_id,
358 substitution,
359 }))
360 .intern(self.interner)
361 })
362 .unwrap_or_else(|| self.new_ty_variable())
363 }
364
365 fn aggregate_name_and_substs<N>(
366 &mut self,
367 name1: N,
368 substitution1: &Substitution<I>,
369 name2: N,
370 substitution2: &Substitution<I>,
371 ) -> Option<(N, Substitution<I>)>
372 where
373 N: Copy + Eq + Debug,
374 {
375 let interner = self.interner;
376 if name1 != name2 {
377 return None;
378 }
379
380 let name = name1;
381
382 assert_eq!(
383 substitution1.len(interner),
384 substitution2.len(interner),
385 "does {:?} take {} substitution or {}? can't both be right",
386 name,
387 substitution1.len(interner),
388 substitution2.len(interner)
389 );
390
391 let substitution = Substitution::from(
392 interner,
393 substitution1
394 .iter(interner)
395 .zip(substitution2.iter(interner))
396 .map(|(p1, p2)| self.aggregate_generic_args(p1, p2)),
397 );
398
399 Some((name, substitution))
400 }
401
402 fn aggregate_generic_args(&mut self, p1: &GenericArg<I>, p2: &GenericArg<I>) -> GenericArg<I> {
403 let interner = self.interner;
404 match (p1.data(interner), p2.data(interner)) {
405 (GenericArgData::Ty(ty1), GenericArgData::Ty(ty2)) => {
406 self.aggregate_tys(ty1, ty2).cast(interner)
407 }
408 (GenericArgData::Lifetime(l1), GenericArgData::Lifetime(l2)) => {
409 self.aggregate_lifetimes(l1, l2).cast(interner)
410 }
411 (GenericArgData::Const(c1), GenericArgData::Const(c2)) => {
412 self.aggregate_consts(c1, c2).cast(interner)
413 }
414 (GenericArgData::Ty(_), _)
415 | (GenericArgData::Lifetime(_), _)
416 | (GenericArgData::Const(_), _) => {
417 panic!("mismatched parameter kinds: p1={:?} p2={:?}", p1, p2)
418 }
419 }
420 }
421
422 fn aggregate_lifetimes(&mut self, l1: &Lifetime<I>, l2: &Lifetime<I>) -> Lifetime<I> {
423 let interner = self.interner;
424 match (l1.data(interner), l2.data(interner)) {
425 (LifetimeData::InferenceVar(_), _) | (_, LifetimeData::InferenceVar(_)) => {
426 self.new_lifetime_variable()
427 }
428
429 (LifetimeData::BoundVar(_), _) | (_, LifetimeData::BoundVar(_)) => {
430 self.new_lifetime_variable()
431 }
432
433 (LifetimeData::Placeholder(_), LifetimeData::Placeholder(_)) => {
434 if l1 == l2 {
435 l1.clone()
436 } else {
437 self.new_lifetime_variable()
438 }
439 }
440
441 (LifetimeData::Phantom(..), _) | (_, LifetimeData::Phantom(..)) => unreachable!(),
442 }
443 }
444
445 fn aggregate_consts(&mut self, c1: &Const<I>, c2: &Const<I>) -> Const<I> {
446 let interner = self.interner;
447
448 // It would be nice to check that c1 and c2 have the same type, even though
449 // on this stage of solving they should already have the same type.
450
451 let ConstData {
452 ty: c1_ty,
453 value: c1_value,
454 } = c1.data(interner);
455 let ConstData {
456 ty: _c2_ty,
457 value: c2_value,
458 } = c2.data(interner);
459
460 let ty = c1_ty.clone();
461
462 match (c1_value, c2_value) {
463 (ConstValue::InferenceVar(_), _) | (_, ConstValue::InferenceVar(_)) => {
464 self.new_const_variable(ty)
465 }
466
467 (ConstValue::BoundVar(_), _) | (_, ConstValue::BoundVar(_)) => {
468 self.new_const_variable(ty.clone())
469 }
470
471 (ConstValue::Placeholder(_), ConstValue::Placeholder(_)) => {
472 if c1 == c2 {
473 c1.clone()
474 } else {
475 self.new_const_variable(ty)
476 }
477 }
478 (ConstValue::Concrete(e1), ConstValue::Concrete(e2)) => {
479 if e1.const_eq(&ty, e2, interner) {
480 c1.clone()
481 } else {
482 self.new_const_variable(ty)
483 }
484 }
485
486 (ConstValue::Placeholder(_), _) | (_, ConstValue::Placeholder(_)) => {
487 self.new_const_variable(ty)
488 }
489 }
490 }
491
492 fn new_ty_variable(&mut self) -> Ty<I> {
493 let interner = self.interner;
494 self.infer.new_variable(self.universe).to_ty(interner)
495 }
496
497 fn new_lifetime_variable(&mut self) -> Lifetime<I> {
498 let interner = self.interner;
499 self.infer.new_variable(self.universe).to_lifetime(interner)
500 }
501
502 fn new_const_variable(&mut self, ty: Ty<I>) -> Const<I> {
503 let interner = self.interner;
504 self.infer
505 .new_variable(self.universe)
506 .to_const(interner, ty)
507 }
508}
509
510/// Test the equivalent of `Vec<i32>` vs `Vec<u32>`
511#[test]
512fn vec_i32_vs_vec_u32() {
513 use chalk_integration::interner::ChalkIr;
514 let mut infer: InferenceTable<ChalkIr> = InferenceTable::new();
515 let mut anti_unifier = AntiUnifier {
516 infer: &mut infer,
517 universe: UniverseIndex::root(),
518 interner: &ChalkIr,
519 };
520
521 let ty = anti_unifier.aggregate_tys(
522 &ty!(apply (item 0) (apply (item 1))),
523 &ty!(apply (item 0) (apply (item 2))),
524 );
525 assert_eq!(ty!(apply (item 0) (infer 0)), ty);
526}
527
528/// Test the equivalent of `Vec<i32>` vs `Vec<i32>`
529#[test]
530fn vec_i32_vs_vec_i32() {
531 use chalk_integration::interner::ChalkIr;
532 let interner = &ChalkIr;
533 let mut infer: InferenceTable<ChalkIr> = InferenceTable::new();
534 let mut anti_unifier = AntiUnifier {
535 interner,
536 infer: &mut infer,
537 universe: UniverseIndex::root(),
538 };
539
540 let ty = anti_unifier.aggregate_tys(
541 &ty!(apply (item 0) (apply (item 1))),
542 &ty!(apply (item 0) (apply (item 1))),
543 );
544 assert_eq!(ty!(apply (item 0) (apply (item 1))), ty);
545}
546
547/// Test the equivalent of `Vec<X>` vs `Vec<Y>`
548#[test]
549fn vec_x_vs_vec_y() {
550 use chalk_integration::interner::ChalkIr;
551 let interner = &ChalkIr;
552 let mut infer: InferenceTable<ChalkIr> = InferenceTable::new();
553 let mut anti_unifier = AntiUnifier {
554 interner,
555 infer: &mut infer,
556 universe: UniverseIndex::root(),
557 };
558
559 // Note that the `var 0` and `var 1` in these types would be
560 // referring to canonicalized free variables, not variables in
561 // `infer`.
562 let ty = anti_unifier.aggregate_tys(
563 &ty!(apply (item 0) (infer 0)),
564 &ty!(apply (item 0) (infer 1)),
565 );
566
567 // But this `var 0` is from `infer.
568 assert_eq!(ty!(apply (item 0) (infer 0)), ty);
569}