Skip to content

Commit a25d6e6

Browse files
committed
generalize hr aliases: constrain new infer vars
1 parent 3111015 commit a25d6e6

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

compiler/rustc_infer/src/infer/relate/generalize.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,26 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
492492
let origin = inner.type_variables().var_origin(vid);
493493
let new_var_id =
494494
inner.type_variables().new_var(self.for_universe, origin);
495-
let u = Ty::new_var(self.tcx(), new_var_id);
496-
debug!("replacing original vid={:?} with new={:?}", vid, u);
497-
Ok(u)
495+
// If we're in the new solver and create a new inference
496+
// variable inside of an alias we eagerly constrain that
497+
// inference variable to prevent unexpected ambiguity errors.
498+
//
499+
// This is incomplete as it pulls down the universe of the
500+
// original inference variable, even though the alias could
501+
// normalize to a type which does not refer to that type at
502+
// all. I don't expect this to cause unexpected errors in
503+
// practice.
504+
//
505+
// cc trait-system-refactor-initiative#108
506+
if self.infcx.next_trait_solver()
507+
&& !self.infcx.intercrate
508+
&& self.in_alias
509+
{
510+
inner.type_variables().equate(vid, new_var_id);
511+
}
512+
513+
debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
514+
Ok(Ty::new_var(self.tcx(), new_var_id))
498515
}
499516
}
500517
}
@@ -614,6 +631,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
614631
universe: self.for_universe,
615632
})
616633
.vid;
634+
635+
// See the comment for type inference variables
636+
// for more details.
637+
if self.infcx.next_trait_solver()
638+
&& !self.infcx.intercrate
639+
&& self.in_alias
640+
{
641+
variable_table.union(vid, new_var_id)
642+
}
617643
Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
618644
}
619645
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//@ compile-flags: -Znext-solver
2+
//@ check-pass
3+
4+
// A regression test for a fairly subtle issue with how we
5+
// generalize aliases referencing higher-ranked regions
6+
// which previously caused unexpected ambiguity errors.
7+
//
8+
// The explanations in the test may end up being out of date
9+
// in the future as we may refine our approach to generalization
10+
// going forward.
11+
//
12+
// cc trait-system-refactor-initiative#108
13+
trait Trait<'a> {
14+
type Assoc;
15+
}
16+
17+
impl<'a> Trait<'a> for () {
18+
type Assoc = ();
19+
}
20+
21+
fn foo<T: for<'a> Trait<'a>>(x: T) -> for<'a> fn(<T as Trait<'a>>::Assoc) {
22+
|_| ()
23+
}
24+
25+
fn unconstrained<T>() -> T {
26+
todo!()
27+
}
28+
29+
fn main() {
30+
// create `?x.0` in the root universe
31+
let mut x = unconstrained();
32+
33+
// bump the current universe of the inference context
34+
let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| ();
35+
let _: for<'a> fn(&'a (), &'a ()) = bump;
36+
37+
// create `?y.1` in a higher universe
38+
let mut y = Default::default();
39+
40+
// relate `?x.0` with `for<'a> fn(<?y.1 as Trait<'a>>::Assoc)`
41+
// -> instantiate `?x.0` with `for<'a> fn(<?y_new.0 as Trait<'a>>::Assoc)`
42+
x = foo(y);
43+
44+
// Constrain `?y.1` to `()`
45+
let _: () = y;
46+
47+
// `AliasRelate(<?y_new.0 as Trait<'a>>::Assoc, <() as Trait<'a>>::Assoc)`
48+
// remains ambiguous unless we somehow constrain `?y_new.0` during
49+
// generalization to be equal to `?y.1`, which is exactly what we
50+
// did to fix this issue.
51+
}

0 commit comments

Comments
 (0)