Rollup merge of #130412 - compiler-errors:rpitit-overcapture, r=jieyouxu

Don't ICE when RPITIT captures more method args than trait definition

Make sure we don't ICE when an RPITIT captures more method args than the trait definition, which is not allowed. This was because we were using the wrong def id for error reporting.

Due to the default lifetime capture rules of RPITITs (capturing everything in scope), this is only doable if we use precise capturing, which isn't currently allowed for RPITITs anyways but we still end up reaching the relevant codepaths.

Fixes #129850
This commit is contained in:
Matthias Krüger 2024-09-16 18:34:01 +02:00 committed by GitHub
commit 4e68d06b52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 73 additions and 17 deletions

View File

@ -726,7 +726,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
num_trait_args, num_trait_args,
num_impl_args, num_impl_args,
def_id, def_id,
impl_def_id: impl_m.container_id(tcx), impl_m_def_id: impl_m.def_id,
ty, ty,
return_span, return_span,
}) { }) {
@ -844,12 +844,18 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
struct RemapHiddenTyRegions<'tcx> { struct RemapHiddenTyRegions<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
/// Map from early/late params of the impl to identity regions of the RPITIT (GAT)
/// in the trait.
map: FxIndexMap<ty::Region<'tcx>, ty::Region<'tcx>>, map: FxIndexMap<ty::Region<'tcx>, ty::Region<'tcx>>,
num_trait_args: usize, num_trait_args: usize,
num_impl_args: usize, num_impl_args: usize,
/// Def id of the RPITIT (GAT) in the *trait*.
def_id: DefId, def_id: DefId,
impl_def_id: DefId, /// Def id of the impl method which owns the opaque hidden type we're remapping.
impl_m_def_id: DefId,
/// The hidden type we're remapping. Useful for diagnostics.
ty: Ty<'tcx>, ty: Ty<'tcx>,
/// Span of the return type. Useful for diagnostics.
return_span: Span, return_span: Span,
} }
@ -885,8 +891,7 @@ fn try_fold_region(
ty::ReLateParam(_) => {} ty::ReLateParam(_) => {}
// Remap early-bound regions as long as they don't come from the `impl` itself, // Remap early-bound regions as long as they don't come from the `impl` itself,
// in which case we don't really need to renumber them. // in which case we don't really need to renumber them.
ty::ReEarlyParam(ebr) ty::ReEarlyParam(ebr) if ebr.index as usize >= self.num_impl_args => {}
if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {}
_ => return Ok(region), _ => return Ok(region),
} }
@ -899,7 +904,7 @@ fn try_fold_region(
); );
} }
} else { } else {
let guar = match region.opt_param_def_id(self.tcx, self.tcx.parent(self.def_id)) { let guar = match region.opt_param_def_id(self.tcx, self.impl_m_def_id) {
Some(def_id) => { Some(def_id) => {
let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() { let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() {
self.tcx.def_span(opaque_ty.def_id) self.tcx.def_span(opaque_ty.def_id)

View File

@ -255,7 +255,9 @@ pub fn region_param(
let param = self.param_at(param.index as usize, tcx); let param = self.param_at(param.index as usize, tcx);
match param.kind { match param.kind {
GenericParamDefKind::Lifetime => param, GenericParamDefKind::Lifetime => param,
_ => bug!("expected lifetime parameter, but found another generic parameter"), _ => {
bug!("expected lifetime parameter, but found another generic parameter: {param:#?}")
}
} }
} }
@ -264,7 +266,7 @@ pub fn type_param(&'tcx self, param: ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx Generi
let param = self.param_at(param.index as usize, tcx); let param = self.param_at(param.index as usize, tcx);
match param.kind { match param.kind {
GenericParamDefKind::Type { .. } => param, GenericParamDefKind::Type { .. } => param,
_ => bug!("expected type parameter, but found another generic parameter"), _ => bug!("expected type parameter, but found another generic parameter: {param:#?}"),
} }
} }
@ -273,7 +275,7 @@ pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &'tcx Ge
let param = self.param_at(param.index as usize, tcx); let param = self.param_at(param.index as usize, tcx);
match param.kind { match param.kind {
GenericParamDefKind::Const { .. } => param, GenericParamDefKind::Const { .. } => param,
_ => bug!("expected const parameter, but found another generic parameter"), _ => bug!("expected const parameter, but found another generic parameter: {param:#?}"),
} }
} }

View File

@ -1,9 +0,0 @@
//@ known-bug: rust-lang/rust#129850
pub trait Foo2 {
fn bar<'a: 'a>(&'a mut self) -> impl Sized + use<'static>;
}
impl Foo2 for () {
fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a {}
}

View File

@ -0,0 +1,16 @@
// Make sure we don't ICE when an RPITIT captures more method args than the
// trait definition, which is not allowed. Due to the default lifetime capture
// rules of RPITITs, this is only doable if we use precise capturing.
pub trait Foo {
fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
//~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
}
impl Foo for () {
fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {}
//~^ ERROR return type captures more lifetimes than trait definition
//~| WARN impl trait in impl method signature does not match trait method signature
}
fn main() {}

View File

@ -0,0 +1,42 @@
error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
--> $DIR/rpitit-captures-more-method-lifetimes.rs:6:53
|
LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
| ^^^^^^^^^
|
= note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope
error: return type captures more lifetimes than trait definition
--> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40
|
LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {}
| --- ^^^^^^^^^^^^^^^^
| |
| this lifetime was captured
|
note: hidden type must only reference lifetimes captured by this impl trait
--> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40
|
LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: hidden type inferred to be `impl Sized + 'im`
warning: impl trait in impl method signature does not match trait method signature
--> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40
|
LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
| ---------------------- return type from trait method defined here
...
LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {}
| ^^^^^^^^^^^^^^^^
|
= note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
= note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
= note: `#[warn(refining_impl_trait_reachable)]` on by default
help: replace the return type so that it matches the trait
|
LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized {}
| ~~~~~~~~~~
error: aborting due to 2 previous errors; 1 warning emitted