From 2d74d8f333d77bf53f8ebd590459c61316a4a324 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Oct 2024 15:53:48 +0000 Subject: [PATCH] Actually capture all in-scope lifetimes. --- .../src/collect/resolve_bound_vars.rs | 72 ++++++++----------- .../impl-trait-in-trait.rs | 1 + .../impl-trait-in-trait.stderr | 27 +++++++ .../precise-capturing/capturing-implicit.rs | 5 +- .../capturing-implicit.stderr | 14 +++- .../bound-lifetime-through-dyn-trait.rs | 3 - .../bound-lifetime-through-dyn-trait.stderr | 46 ++---------- 7 files changed, 75 insertions(+), 93 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 104710dd035..9483439ae4e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -557,37 +557,29 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result { /// like async desugaring. #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { - let mut captures = FxIndexMap::default(); + let captures = RefCell::new(FxIndexMap::default()); let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); if capture_all_in_scope_lifetimes { - let mut create_def_for_duplicated_param = |original_lifetime: LocalDefId, def| { - captures.entry(def).or_insert_with(|| { - let name = self.tcx.item_name(original_lifetime.to_def_id()); - let span = self.tcx.def_span(original_lifetime); - let feed = self.tcx.create_def(opaque.def_id, name, DefKind::LifetimeParam); - feed.def_span(span); - feed.def_ident_span(Some(span)); - feed.def_id() - }); + let lifetime_ident = |def_id: LocalDefId| { + let name = self.tcx.item_name(def_id.to_def_id()); + let span = self.tcx.def_span(def_id); + Ident::new(name, span) }; // We list scopes outwards, this causes us to see lifetime parameters in reverse // declaration order. In order to make it consistent with what `generics_of` might // give, we will reverse the IndexMap after early captures. let mut scope = self.scope; + let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; loop { match *scope { Scope::Binder { ref bound_vars, s, .. } => { - for (&original_lifetime, &(mut def)) in bound_vars.iter().rev() { + for (&original_lifetime, &def) in bound_vars.iter().rev() { if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { - if let Err(guar) = - self.check_lifetime_is_capturable(opaque.def_id, def, None) - { - def = ResolvedArg::Error(guar); - } - create_def_for_duplicated_param(original_lifetime, def); + let ident = lifetime_ident(original_lifetime); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); } } scope = s; @@ -598,10 +590,9 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { let parent_generics = self.tcx.generics_of(parent_item); for param in parent_generics.own_params.iter().rev() { if let ty::GenericParamDefKind::Lifetime = param.kind { - create_def_for_duplicated_param( - param.def_id.expect_local(), - ResolvedArg::EarlyBound(param.def_id.expect_local()), - ); + let def = ResolvedArg::EarlyBound(param.def_id.expect_local()); + let ident = lifetime_ident(param.def_id.expect_local()); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); } } opt_parent_item = parent_generics.parent.and_then(DefId::as_local); @@ -609,14 +600,9 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { break; } - Scope::Opaque { captures: outer_captures, .. } => { - for (_, &duplicated_param) in outer_captures.borrow().iter().rev() { - create_def_for_duplicated_param( - duplicated_param, - ResolvedArg::EarlyBound(duplicated_param), - ); - } - break; + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + scope = s; } Scope::Body { .. } => { @@ -631,11 +617,9 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { } } } - captures.reverse(); + captures.borrow_mut().reverse(); } - let captures = RefCell::new(captures); - let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -643,6 +627,7 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { }); let captures = captures.into_inner().into_iter().collect(); + debug!(?captures); self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures); } @@ -1297,7 +1282,7 @@ fn resolve_lifetime_ref( }; if let Some(mut def) = result { - def = self.remap_opaque_captures(opaque_capture_scopes, def, lifetime_ref.ident); + def = self.remap_opaque_captures(&opaque_capture_scopes, def, lifetime_ref.ident); if let ResolvedArg::EarlyBound(..) = def { // Do not free early-bound regions, only late-bound ones. @@ -1396,7 +1381,7 @@ fn check_lifetime_is_capturable( &self, opaque_def_id: LocalDefId, lifetime: ResolvedArg, - span: Option, + capture_span: Span, ) -> Result<(), ErrorGuaranteed> { let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); @@ -1416,10 +1401,8 @@ fn check_lifetime_is_capturable( }; let decl_span = self.tcx.def_span(lifetime_def_id); - let (span, label) = if let Some(span) = span - && span != decl_span - { - (span, None) + let (span, label) = if capture_span != decl_span { + (capture_span, None) } else { let opaque_span = self.tcx.def_span(opaque_def_id); (opaque_span, Some(opaque_span)) @@ -1435,19 +1418,22 @@ fn check_lifetime_is_capturable( Err(guar) } + #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] fn remap_opaque_captures( &self, - opaque_capture_scopes: Vec<(LocalDefId, &RefCell>)>, + opaque_capture_scopes: &Vec<(LocalDefId, &RefCell>)>, mut lifetime: ResolvedArg, ident: Ident, ) -> ResolvedArg { - for (opaque_def_id, captures) in opaque_capture_scopes.into_iter().rev() { + if let Some(&(opaque_def_id, _)) = opaque_capture_scopes.last() { if let Err(guar) = - self.check_lifetime_is_capturable(opaque_def_id, lifetime, Some(ident.span)) + self.check_lifetime_is_capturable(opaque_def_id, lifetime, ident.span) { - return ResolvedArg::Error(guar); + lifetime = ResolvedArg::Error(guar); } + } + for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); @@ -1976,7 +1962,7 @@ fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) } }; - lifetime = self.remap_opaque_captures(opaque_capture_scopes, lifetime, lifetime_ref.ident); + lifetime = self.remap_opaque_captures(&opaque_capture_scopes, lifetime, lifetime_ref.ident); self.insert_lifetime(lifetime_ref, lifetime); } diff --git a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs index 982a757a1e9..0d3e6f9c8e3 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs @@ -2,6 +2,7 @@ trait IntFactory { fn stream(self) -> impl IntFactory; + //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream` } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr new file mode 100644 index 00000000000..0ed54415b9e --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr @@ -0,0 +1,27 @@ +error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream` + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing function signature of `IntFactory::stream`... + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires looking up late bound vars inside `IntFactory::stream`... + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle +note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}` + --> $DIR/impl-trait-in-trait.rs:4:24 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs index 2ec2fed93d7..5ef8542d862 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs @@ -6,8 +6,9 @@ #![rustc_variance_of_opaques] fn foo(x: &()) -> impl IntoIterator + use<> { - //~^ ERROR [] - //~| ERROR [] + //~^ ERROR ['_: o] + //~| ERROR ['_: o] + //~| ERROR `impl Trait` captures lifetime parameter [*x] } diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr index 02cf8c5fdf2..b14ed20bd36 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr @@ -1,14 +1,22 @@ -error: [] +error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list + --> $DIR/capturing-implicit.rs:8:11 + | +LL | fn foo(x: &()) -> impl IntoIterator + use<> { + | ^ -------------------------------------------- lifetime captured due to being mentioned in the bounds of the `impl Trait` + | | + | this lifetime parameter is captured + +error: ['_: o] --> $DIR/capturing-implicit.rs:8:19 | LL | fn foo(x: &()) -> impl IntoIterator + use<> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [] +error: ['_: o] --> $DIR/capturing-implicit.rs:8:44 | LL | fn foo(x: &()) -> impl IntoIterator + use<> { | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs index e1757ff9152..df589473a84 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs @@ -5,7 +5,6 @@ impl Captures<'_> for T {} fn dyn_hoops() -> dyn for<'a> Iterator> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - //~| ERROR return type cannot have an unboxed trait object loop {} } @@ -13,9 +12,7 @@ pub fn main() { //~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature type Opaque = impl Sized; fn define() -> Opaque { - //~^ ERROR the size for values of type `(dyn Iterator> + 'static)` let x: Opaque = dyn_hoops::<()>(); - //~^ ERROR the size for values of type `(dyn Iterator> + 'static)` x } } diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr index ed44b96d7eb..59d9ff86c6e 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr @@ -10,57 +10,19 @@ note: lifetime declared here LL | fn dyn_hoops() -> dyn for<'a> Iterator> { | ^^ -error[E0746]: return type cannot have an unboxed trait object - --> $DIR/bound-lifetime-through-dyn-trait.rs:6:29 - | -LL | fn dyn_hoops() -> dyn for<'a> Iterator> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | -help: consider returning an `impl Trait` instead of a `dyn Trait` - | -LL | fn dyn_hoops() -> impl for<'a> Iterator> { - | ~~~~ -help: alternatively, box the return type, and wrap all of the returned values in `Box::new` - | -LL ~ fn dyn_hoops() -> Box Iterator>> { -LL | -LL | -LL ~ Box::new(loop {}) - | - error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature - --> $DIR/bound-lifetime-through-dyn-trait.rs:12:8 + --> $DIR/bound-lifetime-through-dyn-trait.rs:11:8 | LL | pub fn main() { | ^^^^ | = note: consider moving the opaque type's declaration and defining uses into a separate module note: this opaque type is in the signature - --> $DIR/bound-lifetime-through-dyn-trait.rs:14:19 + --> $DIR/bound-lifetime-through-dyn-trait.rs:13:19 | LL | type Opaque = impl Sized; | ^^^^^^^^^^ -error[E0277]: the size for values of type `(dyn Iterator> + 'static)` cannot be known at compilation time - --> $DIR/bound-lifetime-through-dyn-trait.rs:15:20 - | -LL | fn define() -> Opaque { - | ^^^^^^ doesn't have a size known at compile-time -... -LL | x - | - return type was inferred to be `(dyn Iterator> + 'static)` here - | - = help: the trait `Sized` is not implemented for `(dyn Iterator> + 'static)` +error: aborting due to 2 previous errors -error[E0277]: the size for values of type `(dyn Iterator> + 'static)` cannot be known at compilation time - --> $DIR/bound-lifetime-through-dyn-trait.rs:17:25 - | -LL | let x: Opaque = dyn_hoops::<()>(); - | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn Iterator> + 'static)` - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0277, E0657, E0746. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0657`.