From 8d13454498cf422c95352e96c1459f6904acde7b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 Mar 2023 04:17:37 +0000 Subject: [PATCH 1/2] Canonicalize the ROOT VAR --- compiler/rustc_infer/src/infer/mod.rs | 4 ++ .../src/solve/canonical/canonicalize.rs | 44 ++++++++++++++----- .../rustc_trait_selection/src/solve/mod.rs | 1 + .../canonical-ty-var-eq-in-response.rs | 39 ++++++++++++++++ .../new-solver/deduce-ty-from-object.rs | 6 +++ 5 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs create mode 100644 tests/ui/traits/new-solver/deduce-ty-from-object.rs diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 387843ee69333..92037f89c6922 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs index c048d4a2aad76..48d78f685eef4 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs @@ -261,12 +261,24 @@ impl<'tcx> TypeFolder> 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> 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:?}") } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 57b6a45273718..43fd415e871e1 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -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 = diff --git a/tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs b/tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs new file mode 100644 index 0000000000000..d1c6b1077e8ef --- /dev/null +++ b/tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs @@ -0,0 +1,39 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +trait Mirror { + type Item; +} + +struct Wrapper(T); +impl Mirror for Wrapper { + type Item = T; +} + +fn mirror() +where + Wrapper: Mirror, +{ +} + +fn main() { + mirror::<_ /* ?0 */>(); + + // Solving ` as Mirror>::Item = i32` + + // First, we replace the term with a fresh infer var: + // ` 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`. +} diff --git a/tests/ui/traits/new-solver/deduce-ty-from-object.rs b/tests/ui/traits/new-solver/deduce-ty-from-object.rs new file mode 100644 index 0000000000000..7398bce7b61cf --- /dev/null +++ b/tests/ui/traits/new-solver/deduce-ty-from-object.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +fn main() { + let x: Box> = Box::new(std::iter::empty()); +} From 3bfcfd079d41ba73228d382677688cd3ce088545 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 Mar 2023 17:25:45 +0000 Subject: [PATCH 2/2] fix var equality issue with old canonicalizer --- .../src/infer/canonical/canonicalizer.rs | 26 ++++++++++++++++--- .../src/solve/canonical/canonicalize.rs | 1 - 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 678c4a0beb63e..a29403cce2f95 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -376,9 +376,18 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { + 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; + } + debug!("canonical: type var found with vid {:?}", vid); match self.infcx.probe_ty_var(vid) { // `t` could be a float / int variable; canonicalize that instead. @@ -469,9 +478,18 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, mut ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { + ty::ConstKind::Infer(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 { + ct = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), ct.ty()); + vid = root_vid; + } + debug!("canonical: const var found with vid {:?}", vid); match self.infcx.probe_const_var(vid) { Ok(c) => { diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs index 48d78f685eef4..981a8f45e4542 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs @@ -267,7 +267,6 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { // 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);