about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-01-10 23:41:43 +0000
committerMichael Goulet <michael@errs.io>2023-01-12 21:01:34 +0000
commit1de196fef308c236aee8804c7b452ad5f5bbaf88 (patch)
tree23aede873e7e4efb361bac0f14fdb15e592ed56a
parent5a31d5ebe253827f971352b5cac43884a35c6aaa (diff)
downloadrust-1de196fef308c236aee8804c7b452ad5f5bbaf88.tar.gz
rust-1de196fef308c236aee8804c7b452ad5f5bbaf88.zip
HACK: Handle escaping bound vars from the canonical query
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs90
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs2
2 files changed, 89 insertions, 3 deletions
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index f7e4c821569..0d811d333be 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -7,8 +7,8 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
-    TypeVisitor,
+    self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
 use hir::def::DefKind;
@@ -1106,6 +1106,17 @@ impl<'tcx, T> Binder<'tcx, T> {
         if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
     }
 
+    pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option<T>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        if !self.0.has_escaping_bound_vars() {
+            Some(self.skip_binder())
+        } else {
+            self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok()
+        }
+    }
+
     /// Splits the contents into two things that share the same binder
     /// level as the original, returning two distinct binders.
     ///
@@ -1135,6 +1146,81 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
     }
 }
 
+struct SkipBindersAt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    index: ty::DebruijnIndex,
+}
+
+impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
+    type Error = ();
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+    where
+        T: ty::TypeFoldable<'tcx>,
+    {
+        self.index.shift_in(1);
+        let value = t.try_map_bound(|t| t.try_fold_with(self));
+        self.index.shift_out(1);
+        value
+    }
+
+    fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        if !ty.has_escaping_bound_vars() {
+            Ok(ty)
+        } else if let ty::Bound(index, bv) = *ty.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
+            }
+        } else {
+            ty.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        if !r.has_escaping_bound_vars() {
+            Ok(r)
+        } else if let ty::ReLateBound(index, bv) = r.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
+            }
+        } else {
+            r.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+        if !ct.has_escaping_bound_vars() {
+            Ok(ct)
+        } else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_const(
+                    ty::ConstKind::Bound(index.shifted_out(1), bv),
+                    ct.ty().try_fold_with(self)?,
+                ))
+            }
+        } else {
+            ct.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+        if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
+    }
+}
+
 /// Represents the projection of an associated type.
 ///
 /// For a projection, this would be `<Ty as Trait<...>>::N`.
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 35bb68b6fce..042ba96b379 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -213,7 +213,7 @@ impl<'tcx> EvalCtxt<'tcx> {
         // recanonicalizing.
         let Goal { param_env, predicate } = canonical_goal.value;
 
-        if let Some(kind) = predicate.kind().no_bound_vars() {
+        if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) {
             match kind {
                 ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
                     canonical_goal.unchecked_rebind(Goal { param_env, predicate }),