Skip to content

Commit

Permalink
generalize hr aliases: constrain new infer vars
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed May 6, 2024
1 parent 3111015 commit e9f3a59
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 3 deletions.
32 changes: 29 additions & 3 deletions compiler/rustc_infer/src/infer/relate/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
}
Expand Down Expand Up @@ -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()))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<T: for<'a> Trait<'a>>(x: T) -> for<'a> fn(<T as Trait<'a>>::Assoc) {
|_| ()
}

fn unconstrained<T>() -> 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(<?y.1 as Trait<'a>>::Assoc)`
// -> instantiate `?x.0` with `for<'a> fn(<?y_new.0 as Trait<'a>>::Assoc)`
x = foo(y);

// Constrain `?y.1` to `()`
let _: () = y;

// `AliasRelate(<?y_new.0 as Trait<'a>>::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.
}

0 comments on commit e9f3a59

Please sign in to comment.