Fix subst issues with RPITIT
This commit is contained in:
parent
b8c35ca26b
commit
c1aa9bf849
@ -551,15 +551,40 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
|
||||
let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
debug!(?id_substs, ?substs);
|
||||
let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
|
||||
substs.iter().enumerate().map(|(index, arg)| (arg, id_substs[index])).collect();
|
||||
std::iter::zip(substs, id_substs).collect();
|
||||
debug!(?map);
|
||||
|
||||
// NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
|
||||
// region substs that are synthesized during AST lowering. These are substs
|
||||
// that are appended to the parent substs (trait and trait method). However,
|
||||
// we're trying to infer the unsubstituted type value of the RPITIT inside
|
||||
// the *impl*, so we can later use the impl's method substitutions to normalize
|
||||
// an RPITIT to a concrete type.
|
||||
//
|
||||
// Due to the design of RPITITs, during AST lowering, we have no idea that
|
||||
// an impl method is satisfying a trait method with RPITITs in it. Therefore,
|
||||
// we don't have a list ofearly-bound region substs for the RPITIT in the impl.
|
||||
// Since early region parameters are index-based, we can't just rebase these
|
||||
// (trait method) early-bound region substs onto the impl, since region
|
||||
// parameters are index-based, and there's no guarantee that the indices from
|
||||
// the trait substs and impl substs line up -- so we subtract the number of
|
||||
// trait substs and add the number of impl substs to *renumber* these early-
|
||||
// bound regions to their corresponding indices in the impl's substitutions list.
|
||||
//
|
||||
// Also, we only need to account for a difference in trait and impl substs,
|
||||
// since we previously enforce that the trait method and impl method have the
|
||||
// same generics.
|
||||
let num_trait_substs = trait_to_impl_substs.len();
|
||||
let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
|
||||
let ty = tcx.fold_regions(ty, |region, _| {
|
||||
if let ty::ReFree(_) = region.kind() {
|
||||
map[®ion.into()].expect_region()
|
||||
} else {
|
||||
region
|
||||
}
|
||||
let ty::ReFree(_) = region.kind() else { return region; };
|
||||
let ty::ReEarlyBound(e) = map[®ion.into()].expect_region().kind()
|
||||
else { bug!("expected ReFree to map to ReEarlyBound"); };
|
||||
tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: e.def_id,
|
||||
name: e.name,
|
||||
index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
|
||||
}))
|
||||
});
|
||||
debug!(%ty);
|
||||
collected_tys.insert(def_id, ty);
|
||||
|
@ -606,9 +606,21 @@ fn fold_binder<T: TypeFoldable<'tcx>>(
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
|
||||
fn region_param_out_of_range(data: ty::EarlyBoundRegion, substs: &[GenericArg<'_>]) -> ! {
|
||||
bug!(
|
||||
"Region parameter out of range when substituting in region {} (index={})",
|
||||
"Region parameter out of range when substituting in region {} (index={}, substs = {:?})",
|
||||
data.name,
|
||||
data.index,
|
||||
substs,
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! {
|
||||
bug!(
|
||||
"Unexpected parameter {:?} when substituting in region {} (index={})",
|
||||
other,
|
||||
data.name,
|
||||
data.index
|
||||
)
|
||||
@ -624,7 +636,8 @@ fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
|
||||
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
|
||||
match rk {
|
||||
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
|
||||
_ => region_param_out_of_range(data),
|
||||
Some(other) => region_param_invalid(data, other),
|
||||
None => region_param_out_of_range(data, self.substs),
|
||||
}
|
||||
}
|
||||
_ => r,
|
||||
|
@ -2254,7 +2254,10 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
|
||||
}
|
||||
|
||||
let impl_fn_def_id = leaf_def.item.def_id;
|
||||
let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
|
||||
// Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
|
||||
// since `data.substs` are the impl substs.
|
||||
let impl_fn_substs =
|
||||
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
|
||||
|
||||
let cause = ObligationCause::new(
|
||||
obligation.cause.span,
|
||||
|
18
src/test/ui/impl-trait/in-trait/issue-102301.rs
Normal file
18
src/test/ui/impl-trait/in-trait/issue-102301.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(return_position_impl_trait_in_trait)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<T> {
|
||||
fn foo<F2: Foo<T>>(self) -> impl Foo<T>;
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo<u8> for Bar {
|
||||
fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user