about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs41
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs21
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs5
-rw-r--r--tests/ui/traits/new-solver/opportunistic-region-resolve.rs19
4 files changed, 75 insertions, 11 deletions
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 29dae67bfca..1b19ed9ad14 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -82,15 +82,40 @@ impl CanonicalVarValues<'_> {
     }
 
     pub fn is_identity_modulo_regions(&self) -> bool {
-        self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
-            ty::GenericArgKind::Lifetime(_) => true,
-            ty::GenericArgKind::Type(ty) => {
-                matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
-            }
-            ty::GenericArgKind::Const(ct) => {
-                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
+        let mut var = ty::BoundVar::from_u32(0);
+        for arg in self.var_values {
+            match arg.unpack() {
+                ty::GenericArgKind::Lifetime(r) => {
+                    if let ty::ReLateBound(ty::INNERMOST, br) = *r
+                        && var == br.var
+                    {
+                        var = var + 1;
+                    } else {
+                        // It's ok if this region var isn't unique
+                    }
+                },
+                ty::GenericArgKind::Type(ty) => {
+                    if let ty::Bound(ty::INNERMOST, bt) = *ty.kind()
+                        && var == bt.var
+                    {
+                        var = var + 1;
+                    } else {
+                        return false;
+                    }
+                }
+                ty::GenericArgKind::Const(ct) => {
+                    if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind()
+                        && var == bc
+                    {
+                        var = var + 1;
+                    } else {
+                        return false;
+                    }
+                }
             }
-        })
+        }
+
+        true
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index 29bdb5ff67d..05248cb9d17 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -208,8 +208,25 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        let r = self.infcx.shallow_resolve(r);
+    fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match self.canonicalize_mode {
+            CanonicalizeMode::Input => {
+                // Don't resolve infer vars in input, since it affects
+                // caching and may cause trait selection bugs which rely
+                // on regions to be equal.
+            }
+            CanonicalizeMode::Response { .. } => {
+                if let ty::ReVar(vid) = *r {
+                    r = self
+                        .infcx
+                        .inner
+                        .borrow_mut()
+                        .unwrap_region_constraints()
+                        .opportunistic_resolve_var(self.infcx.tcx, vid);
+                }
+            }
+        }
+
         let kind = match *r {
             ty::ReLateBound(..) => return r,
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index a8a0e1ebfb4..8592fc164d0 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -263,7 +263,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
             let new_canonical_response =
                 EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
-            if !new_canonical_response.value.var_values.is_identity() {
+            // We only check for modulo regions as we convert all regions in
+            // the input to new existentials, even if they're expected to be
+            // `'static` or a placeholder region.
+            if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
                 bug!(
                     "unstable result: re-canonicalized goal={canonical_goal:#?} \
                     first_response={canonical_response:#?} \
diff --git a/tests/ui/traits/new-solver/opportunistic-region-resolve.rs b/tests/ui/traits/new-solver/opportunistic-region-resolve.rs
new file mode 100644
index 00000000000..2610789cd48
--- /dev/null
+++ b/tests/ui/traits/new-solver/opportunistic-region-resolve.rs
@@ -0,0 +1,19 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(rustc_attrs)]
+
+#[rustc_coinductive]
+trait Trait {}
+
+#[rustc_coinductive]
+trait Indirect {}
+impl<T: Trait + ?Sized> Indirect for T {}
+
+impl<'a> Trait for &'a () where &'a (): Indirect {}
+
+fn impls_trait<T: Trait>() {}
+
+fn main() {
+    impls_trait::<&'static ()>();
+}