diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 74929daffe247..91e680cc6f472 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -492,9 +492,26 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let origin = inner.type_variables().var_origin(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); - let u = Ty::new_var(self.tcx(), new_var_id); - debug!("replacing original vid={:?} with new={:?}", vid, u); - Ok(u) + // If we're in the new solver and create a new inference + // variable inside of an alias we eagerly constrain that + // inference variable to prevent unexpected ambiguity errors. + // + // This is incomplete as it pulls down the universe of the + // original inference variable, even though the alias could + // normalize to a type which does not refer to that type at + // all. I don't expect this to cause unexpected errors in + // practice. + // + // cc trait-system-refactor-initiative#108 + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + inner.type_variables().equate(vid, new_var_id); + } + + debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); + Ok(Ty::new_var(self.tcx(), new_var_id)) } } } @@ -614,6 +631,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { universe: self.for_universe, }) .vid; + + // See the comment for type inference variables + // for more details. + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + variable_table.union(vid, new_var_id) + } Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) } } diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs new file mode 100644 index 0000000000000..1673b196dac67 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs @@ -0,0 +1,51 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for a fairly subtle issue with how we +// generalize aliases referencing higher-ranked regions +// which previously caused unexpected ambiguity errors. +// +// The explanations in the test may end up being out of date +// in the future as we may refine our approach to generalization +// going forward. +// +// cc trait-system-refactor-initiative#108 +trait Trait<'a> { + type Assoc; +} + +impl<'a> Trait<'a> for () { + type Assoc = (); +} + +fn foo Trait<'a>>(x: T) -> for<'a> fn(>::Assoc) { + |_| () +} + +fn unconstrained() -> T { + todo!() +} + +fn main() { + // create `?x.0` in the root universe + let mut x = unconstrained(); + + // bump the current universe of the inference context + let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| (); + let _: for<'a> fn(&'a (), &'a ()) = bump; + + // create `?y.1` in a higher universe + let mut y = Default::default(); + + // relate `?x.0` with `for<'a> fn(>::Assoc)` + // -> instantiate `?x.0` with `for<'a> fn(>::Assoc)` + x = foo(y); + + // Constrain `?y.1` to `()` + let _: () = y; + + // `AliasRelate(>::Assoc, <() as Trait<'a>>::Assoc)` + // remains ambiguous unless we somehow constrain `?y_new.0` during + // generalization to be equal to `?y.1`, which is exactly what we + // did to fix this issue. +}