about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-02-28 21:34:04 +0000
committerMichael Goulet <michael@errs.io>2023-02-28 21:34:59 +0000
commitb7e0ca993d0d1d15ed211ceec53ee4ffe526cb16 (patch)
treef9942e95ca65d9eba37f5f06be2506d48a966674
parent31f858d9a511f24fedb8ed997b28304fec809630 (diff)
downloadrust-b7e0ca993d0d1d15ed211ceec53ee4ffe526cb16.tar.gz
rust-b7e0ca993d0d1d15ed211ceec53ee4ffe526cb16.zip
Shift vars for default RPITIT methods correctly
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs25
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs14
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr11
3 files changed, 49 insertions, 1 deletions
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 18159778a8e..70c9de91fbf 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -142,12 +142,14 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
         && tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer
     {
         let sig = tcx.fn_sig(def_id).subst_identity();
-        sig.visit_with(&mut ImplTraitInTraitFinder {
+        // We accounted for the binder of the fn sig, so skip the binder.
+        sig.skip_binder().visit_with(&mut ImplTraitInTraitFinder {
             tcx,
             fn_def_id: def_id,
             bound_vars: sig.bound_vars(),
             predicates: &mut predicates,
             seen: FxHashSet::default(),
+            depth: ty::INNERMOST,
         });
     }
 
@@ -244,15 +246,36 @@ struct ImplTraitInTraitFinder<'a, 'tcx> {
     fn_def_id: DefId,
     bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
     seen: FxHashSet<DefId>,
+    depth: ty::DebruijnIndex,
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+        &mut self,
+        binder: &ty::Binder<'tcx, T>,
+    ) -> std::ops::ControlFlow<Self::BreakTy> {
+        self.depth.shift_in(1);
+        let binder = binder.super_visit_with(self);
+        self.depth.shift_out(1);
+        binder
+    }
+
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
         if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
             && self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
             && self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id
             && self.seen.insert(alias_ty.def_id)
         {
+            // We have entered some binders as we've walked into the
+            // bounds of the RPITIT. Shift these binders back out when
+            // constructing the top-level projection predicate.
+            let alias_ty = self.tcx.fold_regions(alias_ty, |re, _| {
+                if let ty::ReLateBound(index, bv) = re.kind() {
+                    self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv)
+                } else {
+                    re
+                }
+            });
             self.predicates.push(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
new file mode 100644
index 00000000000..5cf90c5d93c
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
+
+trait Trait {
+    type Type;
+
+    // Check that we're adjusting bound vars correctly when installing the default
+    // method projection assumptions.
+    fn method(&self) -> impl Trait<Type = impl Sized + '_>;
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr
new file mode 100644
index 00000000000..7c7ebcdb7e7
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-method-binder-shifting.rs:3:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+