Canonicalize the ROOT VAR

This commit is contained in:
Michael Goulet 2023-03-07 04:17:37 +00:00
parent 160c2ebeca
commit 8d13454498
5 changed files with 83 additions and 11 deletions

View File

@ -1356,6 +1356,10 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var)
}
pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
self.inner.borrow_mut().const_unification_table().find(var)
}
/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it

View File

@ -261,12 +261,24 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
self.interner().mk_re_late_bound(self.binder_index, br)
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
let kind = match *t.kind() {
ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
Ok(t) => return self.fold_ty(t),
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
},
ty::Infer(ty::TyVar(mut vid)) => {
// We need to canonicalize the *root* of our ty var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_var(vid);
if root_vid != vid {
t = self.infcx.tcx.mk_ty_var(root_vid);
vid = root_vid;
}
match self.infcx.probe_ty_var(vid) {
Ok(t) => return self.fold_ty(t),
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
}
}
ty::Infer(ty::IntVar(_)) => {
let nt = self.infcx.shallow_resolve(t);
if nt != t {
@ -338,13 +350,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
self.interner().mk_bound(self.binder_index, bt)
}
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
let kind = match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => match self.infcx.probe_const_var(vid)
{
Ok(c) => return self.fold_const(c),
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
},
ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => {
// We need to canonicalize the *root* of our const var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_const_var(vid);
if root_vid != vid {
c = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), c.ty());
vid = root_vid;
}
match self.infcx.probe_const_var(vid) {
Ok(c) => return self.fold_const(c),
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
}
}
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
bug!("fresh var during canonicalization: {c:?}")
}

View File

@ -238,6 +238,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
&& has_changed
&& !self.in_projection_eq_hack
&& !self.search_graph.in_cycle()
&& false
{
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
let canonical_response =

View File

@ -0,0 +1,39 @@
// check-pass
// compile-flags: -Ztrait-solver=next
trait Mirror {
type Item;
}
struct Wrapper<T>(T);
impl<T> Mirror for Wrapper<T> {
type Item = T;
}
fn mirror<T>()
where
Wrapper<T>: Mirror<Item = i32>,
{
}
fn main() {
mirror::<_ /* ?0 */>();
// Solving `<Wrapper<?0> as Mirror>::Item = i32`
// First, we replace the term with a fresh infer var:
// `<Wrapper<?0> as Mirror>::Item = ?1`
// We select the impl candidate on line #6, which leads us to learn that
// `?0 == ?1`.
// That should be reflected in our canonical response, which should have
// `^0 = ^0, ^1 = ^0`
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! We used to return a totally unconstrained response here :< !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Then, during the "equate term" part of the projection solving, we
// instantiate the response from the unconstrained projection predicate,
// and equate `?0 == i32`.
}

View File

@ -0,0 +1,6 @@
// check-pass
// compile-flags: -Ztrait-solver=next
fn main() {
let x: Box<dyn Iterator<Item = ()>> = Box::new(std::iter::empty());
}