about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2024-10-27 15:53:48 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2024-10-30 16:22:23 +0000
commit2d74d8f333d77bf53f8ebd590459c61316a4a324 (patch)
treecd17e493cb7a9a943c31c9f2c4928700723ddb72
parent8f6e0a6a4b03c212c0434de417a274d50b7ab0e5 (diff)
downloadrust-2d74d8f333d77bf53f8ebd590459c61316a4a324.tar.gz
rust-2d74d8f333d77bf53f8ebd590459c61316a4a324.zip
Actually capture all in-scope lifetimes.
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs72
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs1
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr27
-rw-r--r--tests/ui/impl-trait/precise-capturing/capturing-implicit.rs5
-rw-r--r--tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr14
-rw-r--r--tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs3
-rw-r--r--tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr46
7 files changed, 75 insertions, 93 deletions
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 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     /// 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 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, '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 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, '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 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, '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 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, '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 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         };
 
         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 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         &self,
         opaque_def_id: LocalDefId,
         lifetime: ResolvedArg,
-        span: Option<Span>,
+        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 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         };
 
         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 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         Err(guar)
     }
 
+    #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)]
     fn remap_opaque_captures(
         &self,
-        opaque_capture_scopes: Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>,
+        opaque_capture_scopes: &Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>,
         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 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             }
         };
 
-        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<stream(..): Send>;
+    //~^ 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<stream(..): Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing function signature of `IntFactory::stream`...
+  --> $DIR/impl-trait-in-trait.rs:4:5
+   |
+LL |     fn stream(self) -> impl IntFactory<stream(..): Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+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<stream(..): Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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<stream(..): Send>;
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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<Item = impl Sized> + 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<Item = impl Sized> + 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<Item = impl Sized> + use<> {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: []
+error: ['_: o]
   --> $DIR/capturing-implicit.rs:8:44
    |
 LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + 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<T> Captures<'_> for T {}
 
 fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
     //~^ 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<Item = impl Captures<'_>> + 'static)`
         let x: Opaque = dyn_hoops::<()>();
-        //~^ ERROR the size for values of type `(dyn Iterator<Item = impl Captures<'_>> + '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<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
    |                                     ^^
 
-error[E0746]: return type cannot have an unboxed trait object
-  --> $DIR/bound-lifetime-through-dyn-trait.rs:6:29
-   |
-LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-help: consider returning an `impl Trait` instead of a `dyn Trait`
-   |
-LL | fn dyn_hoops<T: Sized>() -> impl for<'a> Iterator<Item = impl Captures<'a>> {
-   |                             ~~~~
-help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
-   |
-LL ~ fn dyn_hoops<T: Sized>() -> Box<dyn for<'a> Iterator<Item = impl Captures<'a>>> {
-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<Item = impl Captures<'_>> + '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<Item = impl Captures<'_>> + 'static)` here
-   |
-   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Captures<'_>> + 'static)`
-
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Captures<'_>> + '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<Item = impl Captures<'_>> + 'static)`
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 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`.