From 861c7ad6e25b721051cfe70104efc9cf64fced81 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Jul 2023 17:52:17 +0000 Subject: [PATCH] Only allow impl lifetimes in RPITIT hidden type that come from self type --- .../src/check/compare_impl_item.rs | 32 +++++++++++++------ .../in-trait/only-mentions-self-lt.bad.stderr | 17 ++++++++++ .../in-trait/only-mentions-self-lt.rs | 21 ++++++++++++ .../in-trait/unconstrained-lt.current.stderr | 16 +++++++--- .../in-trait/unconstrained-lt.next.stderr | 16 +++++++--- .../impl-trait/in-trait/unconstrained-lt.rs | 3 +- 6 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/only-mentions-self-lt.bad.stderr create mode 100644 tests/ui/impl-trait/in-trait/only-mentions-self-lt.rs 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 2999e1fd89ba4..518da2085febd 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1,7 +1,7 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, LocalDefId}; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{ pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan, }; @@ -614,8 +614,8 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ) -> Result<&'tcx FxHashMap>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); - let impl_trait_ref = - tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity(); + let impl_def_id = impl_m.container_id(tcx); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(); let param_env = tcx.param_env(impl_m_def_id); // First, check a few of the same things as `compare_impl_method`, @@ -755,6 +755,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?; + let mut self_type_regions = FxHashSet::default(); + tcx.fold_regions(impl_trait_ref.self_ty(), |re, _| { + if let ty::ReEarlyBound(ebr) = *re { + self_type_regions.insert(ebr.def_id); + } + re + }); + let mut collected_tys = FxHashMap::default(); for (def_id, (ty, substs)) in collected_types { match infcx.fully_resolve((ty, substs)) { @@ -791,14 +799,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // 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 num_impl_substs = tcx.generics_of(impl_def_id).params.len(); let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions { tcx, map, num_trait_substs, num_impl_substs, + self_type_regions: &self_type_regions, def_id, - impl_def_id: impl_m.container_id(tcx), ty, return_span, }) { @@ -888,18 +896,18 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { } } -struct RemapHiddenTyRegions<'tcx> { +struct RemapHiddenTyRegions<'a, 'tcx> { tcx: TyCtxt<'tcx>, map: FxHashMap, ty::Region<'tcx>>, + self_type_regions: &'a FxHashSet, num_trait_substs: usize, num_impl_substs: usize, def_id: DefId, - impl_def_id: DefId, ty: Ty<'tcx>, return_span: Span, } -impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { +impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'_, 'tcx> { type Error = ErrorGuaranteed; fn interner(&self) -> TyCtxt<'tcx> { @@ -929,9 +937,13 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { match region.kind() { // Remap all free regions, which correspond to late-bound regions in the function. ty::ReFree(_) => {} - // 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 Self type, // in which case we don't really need to renumber them. - ty::ReEarlyBound(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {} + ty::ReEarlyBound(ebr) => { + if self.self_type_regions.contains(&ebr.def_id) { + return Ok(region); + } + } _ => return Ok(region), } diff --git a/tests/ui/impl-trait/in-trait/only-mentions-self-lt.bad.stderr b/tests/ui/impl-trait/in-trait/only-mentions-self-lt.bad.stderr new file mode 100644 index 0000000000000..b020cc9767657 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/only-mentions-self-lt.bad.stderr @@ -0,0 +1,17 @@ +error: return type captures more lifetimes than trait definition + --> $DIR/only-mentions-self-lt.rs:12:26 + | +LL | impl<'a> Foo<'a> for () { + | -- this lifetime was captured +LL | fn test(&'a self) -> &'a Self { self } + | ^^^^^^^^ + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/only-mentions-self-lt.rs:7:26 + | +LL | fn test(&'a self) -> impl Sized; + | ^^^^^^^^^^ + = note: hidden type inferred to be `&'a ()` + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/in-trait/only-mentions-self-lt.rs b/tests/ui/impl-trait/in-trait/only-mentions-self-lt.rs new file mode 100644 index 0000000000000..0420e4a922a7a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/only-mentions-self-lt.rs @@ -0,0 +1,21 @@ +// revisions: good bad +//[good] check-pass + +#![feature(return_position_impl_trait_in_trait)] + +trait Foo<'a> { + fn test(&'a self) -> impl Sized; +} + +#[cfg(bad)] +impl<'a> Foo<'a> for () { + fn test(&'a self) -> &'a Self { self } + //[bad]~^ return type captures more lifetimes than trait definition +} + +#[cfg(good)] +impl<'a> Foo<'a> for &'a () { + fn test(&'a self) -> &'a Self { self } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr index bf088ae8b25cc..2b66f3ae91452 100644 --- a/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr @@ -1,9 +1,17 @@ -error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-lt.rs:10:6 +error: return type captures more lifetimes than trait definition + --> $DIR/unconstrained-lt.rs:11:18 | LL | impl<'a, T> Foo for T { - | ^^ unconstrained lifetime parameter + | -- this lifetime was captured +LL | fn test() -> &'a () { &() } + | ^^^^^^ + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/unconstrained-lt.rs:7:18 + | +LL | fn test() -> impl Sized; + | ^^^^^^^^^^ + = note: hidden type inferred to be `&'a ()` error: aborting due to previous error -For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr index bf088ae8b25cc..2b66f3ae91452 100644 --- a/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr @@ -1,9 +1,17 @@ -error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-lt.rs:10:6 +error: return type captures more lifetimes than trait definition + --> $DIR/unconstrained-lt.rs:11:18 | LL | impl<'a, T> Foo for T { - | ^^ unconstrained lifetime parameter + | -- this lifetime was captured +LL | fn test() -> &'a () { &() } + | ^^^^^^ + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/unconstrained-lt.rs:7:18 + | +LL | fn test() -> impl Sized; + | ^^^^^^^^^^ + = note: hidden type inferred to be `&'a ()` error: aborting due to previous error -For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs index f966be43a6ef8..93b7b402b4552 100644 --- a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs @@ -8,9 +8,8 @@ trait Foo { } impl<'a, T> Foo for T { - //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - fn test() -> &'a () { &() } + //~^ ERROR return type captures more lifetimes than trait definition } fn main() {}