From 1e9fa7eb79072274fbd741f09e9444249e1d4ff0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 15 Sep 2024 16:41:00 -0400 Subject: [PATCH] Don't ICE when RPITIT captures more method args than trait definition --- .../src/check/compare_impl_item.rs | 15 ++++--- compiler/rustc_middle/src/ty/generics.rs | 8 ++-- tests/crashes/129850.rs | 9 ---- .../rpitit-captures-more-method-lifetimes.rs | 16 +++++++ ...itit-captures-more-method-lifetimes.stderr | 42 +++++++++++++++++++ 5 files changed, 73 insertions(+), 17 deletions(-) delete mode 100644 tests/crashes/129850.rs create mode 100644 tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs create mode 100644 tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 388e02b36e0..cc7a0dff34e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -726,7 +726,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( num_trait_args, num_impl_args, def_id, - impl_def_id: impl_m.container_id(tcx), + impl_m_def_id: impl_m.def_id, ty, return_span, }) { @@ -844,12 +844,18 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { struct RemapHiddenTyRegions<'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>>, num_trait_args: usize, num_impl_args: usize, + /// Def id of the RPITIT (GAT) in the *trait*. 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>, + /// Span of the return type. Useful for diagnostics. return_span: Span, } @@ -885,8 +891,7 @@ fn try_fold_region( ty::ReLateParam(_) => {} // 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. - ty::ReEarlyParam(ebr) - if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {} + ty::ReEarlyParam(ebr) if ebr.index as usize >= self.num_impl_args => {} _ => return Ok(region), } @@ -899,7 +904,7 @@ fn try_fold_region( ); } } 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) => { let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() { self.tcx.def_span(opaque_ty.def_id) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index bbc696e0f08..5f9a89c3a5b 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -255,7 +255,9 @@ pub fn region_param( let param = self.param_at(param.index as usize, tcx); match param.kind { 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); match param.kind { 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); match param.kind { GenericParamDefKind::Const { .. } => param, - _ => bug!("expected const parameter, but found another generic parameter"), + _ => bug!("expected const parameter, but found another generic parameter: {param:#?}"), } } diff --git a/tests/crashes/129850.rs b/tests/crashes/129850.rs deleted file mode 100644 index 9c04805587a..00000000000 --- a/tests/crashes/129850.rs +++ /dev/null @@ -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 {} -} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs new file mode 100644 index 00000000000..71a91fe319e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -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; + //~^ 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() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr new file mode 100644 index 00000000000..339e2e6335e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -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; + | ^^^^^^^^^ + | + = 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; + | ^^^^^^^^^^^^^^^^^^^^^^ + = 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; + | ---------------------- 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 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 +