Skip to content

Commit

Permalink
Rollup merge of rust-lang#108583 - compiler-errors:rpitit-default-met…
Browse files Browse the repository at this point in the history
…hod-with-nested-rpitits, r=spastorino

Account for binders correctly when adding default RPITIT method assumption

As of rust-lang#108203, we install extra projection predicates into the param-env of a default trait method when it has return-position `impl Trait` (or is async).

The implementation didn't account for the fact that it's walking into and out of binders, so we just need to shift all the debruijn indices accordingly when constructing the projection predicates.

Fixes rust-lang#108579

r? types
  • Loading branch information
matthiaskrgr committed Mar 7, 2023
2 parents 23beda4 + b7e0ca9 commit 6363588
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
25 changes: 24 additions & 1 deletion compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}

Expand Down Expand Up @@ -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 {
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
Original file line number Diff line number Diff line change
@@ -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() {}
11 changes: 11 additions & 0 deletions tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 6363588

Please sign in to comment.