Skip to content

Commit d567e4f

Browse files
Error for RPITIT hidden tys that capture more than their trait defn
1 parent 3307274 commit d567e4f

File tree

4 files changed

+130
-39
lines changed

4 files changed

+130
-39
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+109-22
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_middle::ty::{
1919
self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
2020
};
2121
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
22-
use rustc_span::Span;
22+
use rustc_span::{Span, DUMMY_SP};
2323
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
2424
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
2525
use rustc_trait_selection::traits::{
@@ -767,8 +767,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
767767
// contains `def_id`'s early-bound regions.
768768
let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
769769
debug!(?id_substs, ?substs);
770-
let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
771-
std::iter::zip(substs, id_substs).collect();
770+
let map: FxHashMap<_, _> = std::iter::zip(substs, id_substs)
771+
.skip(tcx.generics_of(trait_m.def_id).count())
772+
.filter_map(|(a, b)| Some((a.as_region()?, b.as_region()?)))
773+
.collect();
772774
debug!(?map);
773775

774776
// NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
@@ -793,25 +795,19 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
793795
// same generics.
794796
let num_trait_substs = trait_to_impl_substs.len();
795797
let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
796-
let ty = tcx.fold_regions(ty, |region, _| {
797-
match region.kind() {
798-
// Remap all free regions, which correspond to late-bound regions in the function.
799-
ty::ReFree(_) => {}
800-
// Remap early-bound regions as long as they don't come from the `impl` itself.
801-
ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
802-
_ => return region,
803-
}
804-
let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
805-
else {
806-
return ty::Region::new_error_with_message(tcx, return_span, "expected ReFree to map to ReEarlyBound")
807-
};
808-
ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion {
809-
def_id: e.def_id,
810-
name: e.name,
811-
index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
812-
})
813-
});
814-
debug!(%ty);
798+
let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions {
799+
tcx,
800+
map,
801+
num_trait_substs,
802+
num_impl_substs,
803+
def_id,
804+
impl_def_id: impl_m.container_id(tcx),
805+
ty,
806+
return_span,
807+
}) {
808+
Ok(ty) => ty,
809+
Err(guar) => tcx.ty_error(guar),
810+
};
815811
collected_tys.insert(def_id, ty::EarlyBinder::bind(ty));
816812
}
817813
Err(err) => {
@@ -895,6 +891,97 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
895891
}
896892
}
897893

894+
struct RemapHiddenTyRegions<'tcx> {
895+
tcx: TyCtxt<'tcx>,
896+
map: FxHashMap<ty::Region<'tcx>, ty::Region<'tcx>>,
897+
num_trait_substs: usize,
898+
num_impl_substs: usize,
899+
def_id: DefId,
900+
impl_def_id: DefId,
901+
ty: Ty<'tcx>,
902+
return_span: Span,
903+
}
904+
905+
impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
906+
type Error = ErrorGuaranteed;
907+
908+
fn interner(&self) -> TyCtxt<'tcx> {
909+
self.tcx
910+
}
911+
912+
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
913+
if let ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = *t.kind() {
914+
let mut mapped_substs = Vec::with_capacity(substs.len());
915+
for (arg, v) in std::iter::zip(substs, self.tcx.variances_of(def_id)) {
916+
mapped_substs.push(match (arg.unpack(), v) {
917+
// Skip uncaptured opaque substs
918+
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg,
919+
_ => arg.try_fold_with(self)?,
920+
});
921+
}
922+
Ok(self.tcx.mk_opaque(def_id, self.tcx.mk_substs(&mapped_substs)))
923+
} else {
924+
t.try_super_fold_with(self)
925+
}
926+
}
927+
928+
fn try_fold_region(
929+
&mut self,
930+
region: ty::Region<'tcx>,
931+
) -> Result<ty::Region<'tcx>, Self::Error> {
932+
match region.kind() {
933+
// Remap all free regions, which correspond to late-bound regions in the function.
934+
ty::ReFree(_) => {}
935+
// Remap early-bound regions as long as they don't come from the `impl` itself,
936+
// in which case we don't really need to renumber them.
937+
ty::ReEarlyBound(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {}
938+
_ => return Ok(region),
939+
}
940+
941+
let e = if let Some(region) = self.map.get(&region) {
942+
if let ty::ReEarlyBound(e) = region.kind() { e } else { bug!() }
943+
} else {
944+
let guar = match region.kind() {
945+
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. })
946+
| ty::ReFree(ty::FreeRegion {
947+
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
948+
..
949+
}) => {
950+
let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() {
951+
self.tcx.def_span(opaque_ty.def_id)
952+
} else {
953+
self.return_span
954+
};
955+
self.tcx
956+
.sess
957+
.struct_span_err(
958+
return_span,
959+
"return type captures more lifetimes than trait definition",
960+
)
961+
.span_label(self.tcx.def_span(def_id), "this lifetime was captured")
962+
.span_note(
963+
self.tcx.def_span(self.def_id),
964+
"hidden type must only reference lifetimes captured by this impl trait",
965+
)
966+
.note(format!("hidden type inferred to be `{}`", self.ty))
967+
.emit()
968+
}
969+
_ => self.tcx.sess.delay_span_bug(DUMMY_SP, "should've been able to remap region"),
970+
};
971+
return Err(guar);
972+
};
973+
974+
Ok(ty::Region::new_early_bound(
975+
self.tcx,
976+
ty::EarlyBoundRegion {
977+
def_id: e.def_id,
978+
name: e.name,
979+
index: (e.index as usize - self.num_trait_substs + self.num_impl_substs) as u32,
980+
},
981+
))
982+
}
983+
}
984+
898985
fn report_trait_method_mismatch<'tcx>(
899986
infcx: &InferCtxt<'tcx>,
900987
mut cause: ObligationCause<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
error: `impl` item signature doesn't match `trait` item signature
2-
--> $DIR/signature-mismatch.rs:17:5
1+
error: return type captures more lifetimes than trait definition
2+
--> $DIR/signature-mismatch.rs:17:47
33
|
44
LL | fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
5-
| ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
5+
| - this lifetime was captured
66
...
77
LL | fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99
|
10-
= note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
11-
found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
12-
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
13-
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
10+
note: hidden type must only reference lifetimes captured by this impl trait
11+
--> $DIR/signature-mismatch.rs:11:40
12+
|
13+
LL | fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
= note: hidden type inferred to be `impl Future<Output = Vec<u8>> + '_`
1416

1517
error: aborting due to previous error
1618

Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
error: `impl` item signature doesn't match `trait` item signature
2-
--> $DIR/signature-mismatch.rs:17:5
1+
error: return type captures more lifetimes than trait definition
2+
--> $DIR/signature-mismatch.rs:17:47
33
|
44
LL | fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
5-
| ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
5+
| - this lifetime was captured
66
...
77
LL | fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99
|
10-
= note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
11-
found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
12-
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
13-
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
10+
note: hidden type must only reference lifetimes captured by this impl trait
11+
--> $DIR/signature-mismatch.rs:11:40
12+
|
13+
LL | fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
= note: hidden type inferred to be `impl Future<Output = Vec<u8>> + '_`
1416

1517
error: aborting due to previous error
1618

tests/ui/impl-trait/in-trait/signature-mismatch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub struct Struct;
1515

1616
impl AsyncTrait for Struct {
1717
fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
18-
//~^ ERROR `impl` item signature doesn't match `trait` item signature
18+
//~^ ERROR return type captures more lifetimes than trait definition
1919
async move { buff.to_vec() }
2020
}
2121
}

0 commit comments

Comments
 (0)