about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-04-03 20:54:23 -0400
committerMichael Goulet <michael@errs.io>2024-04-15 16:45:01 -0400
commit647b672f16f6db2f156b69668ca963ec28016464 (patch)
tree0175352daadabeb2b349edda5ae2a30ca5ecda90
parenta076eae0d27915f352d92db1b63661e62750d7ae (diff)
downloadrust-647b672f16f6db2f156b69668ca963ec28016464.tar.gz
rust-647b672f16f6db2f156b69668ca963ec28016464.zip
Begin AST lowering for precise captures
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs79
-rw-r--r--tests/ui/impl-trait/precise-capturing/higher-ranked.rs18
-rw-r--r--tests/ui/impl-trait/precise-capturing/higher-ranked.stderr11
-rw-r--r--tests/ui/impl-trait/precise-capturing/outlives.rs16
-rw-r--r--tests/ui/impl-trait/precise-capturing/outlives.stderr11
5 files changed, 106 insertions, 29 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index a4470622972..32b2f7c86ca 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1399,7 +1399,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
             }
             TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
-                assert!(precise_capturing.is_none(), "precise captures not supported yet!");
                 let span = t.span;
                 match itctx {
                     ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
@@ -1409,8 +1408,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         bounds,
                         fn_kind,
                         itctx,
+                        precise_capturing.as_deref(),
                     ),
                     ImplTraitContext::Universal => {
+                        assert!(
+                            precise_capturing.is_none(),
+                            "TODO: precise captures not supported on universals!"
+                        );
                         let span = t.span;
 
                         // HACK: pprust breaks strings with newlines when the type
@@ -1521,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         bounds: &GenericBounds,
         fn_kind: Option<FnDeclKind>,
         itctx: ImplTraitContext,
+        precise_capturing: Option<&ast::GenericArgs>,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1529,40 +1534,56 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let captured_lifetimes_to_duplicate = match origin {
-            hir::OpaqueTyOrigin::TyAlias { .. } => {
-                // type alias impl trait and associated type position impl trait were
-                // decided to capture all in-scope lifetimes, which we collect for
-                // all opaques during resolution.
-                self.resolver
-                    .take_extra_lifetime_params(opaque_ty_node_id)
-                    .into_iter()
-                    .map(|(ident, id, _)| Lifetime { id, ident })
-                    .collect()
-            }
-            hir::OpaqueTyOrigin::FnReturn(..) => {
-                if matches!(
-                    fn_kind.expect("expected RPITs to be lowered with a FnKind"),
-                    FnDeclKind::Impl | FnDeclKind::Trait
-                ) || self.tcx.features().lifetime_capture_rules_2024
-                    || span.at_least_rust_2024()
-                {
-                    // return-position impl trait in trait was decided to capture all
-                    // in-scope lifetimes, which we collect for all opaques during resolution.
+        let captured_lifetimes_to_duplicate = if let Some(precise_capturing) = precise_capturing {
+            let ast::GenericArgs::AngleBracketed(precise_capturing) = precise_capturing else {
+                panic!("we only parse angle-bracketed args")
+            };
+            // We'll actually validate these later on; all we need is the list of
+            // lifetimes to duplicate during this portion of lowering.
+            precise_capturing
+                .args
+                .iter()
+                .filter_map(|arg| match arg {
+                    ast::AngleBracketedArg::Arg(ast::GenericArg::Lifetime(lt)) => Some(*lt),
+                    _ => None,
+                })
+                .collect()
+        } else {
+            match origin {
+                hir::OpaqueTyOrigin::TyAlias { .. } => {
+                    // type alias impl trait and associated type position impl trait were
+                    // decided to capture all in-scope lifetimes, which we collect for
+                    // all opaques during resolution.
                     self.resolver
                         .take_extra_lifetime_params(opaque_ty_node_id)
                         .into_iter()
                         .map(|(ident, id, _)| Lifetime { id, ident })
                         .collect()
-                } else {
-                    // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
-                    // example, we only need to duplicate lifetimes that appear in the
-                    // bounds, since those are the only ones that are captured by the opaque.
-                    lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
                 }
-            }
-            hir::OpaqueTyOrigin::AsyncFn(..) => {
-                unreachable!("should be using `lower_async_fn_ret_ty`")
+                hir::OpaqueTyOrigin::FnReturn(..) => {
+                    if matches!(
+                        fn_kind.expect("expected RPITs to be lowered with a FnKind"),
+                        FnDeclKind::Impl | FnDeclKind::Trait
+                    ) || self.tcx.features().lifetime_capture_rules_2024
+                        || span.at_least_rust_2024()
+                    {
+                        // return-position impl trait in trait was decided to capture all
+                        // in-scope lifetimes, which we collect for all opaques during resolution.
+                        self.resolver
+                            .take_extra_lifetime_params(opaque_ty_node_id)
+                            .into_iter()
+                            .map(|(ident, id, _)| Lifetime { id, ident })
+                            .collect()
+                    } else {
+                        // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+                        // example, we only need to duplicate lifetimes that appear in the
+                        // bounds, since those are the only ones that are captured by the opaque.
+                        lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
+                    }
+                }
+                hir::OpaqueTyOrigin::AsyncFn(..) => {
+                    unreachable!("should be using `lower_async_fn_ret_ty`")
+                }
             }
         };
         debug!(?captured_lifetimes_to_duplicate);
diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
new file mode 100644
index 00000000000..c9faaaed968
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+
+// Show how precise captures allow us to skip capturing a higher-ranked lifetime
+
+#![feature(lifetime_capture_rules_2024, precise_capturing)]
+//~^ WARN the feature `precise_capturing` is incomplete
+
+trait Trait<'a> {
+    type Item;
+}
+
+impl Trait<'_> for () {
+    type Item = Vec<()>;
+}
+
+fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
+
+fn main() {}
\ No newline at end of file
diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr b/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
new file mode 100644
index 00000000000..e48d6d42af0
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
@@ -0,0 +1,11 @@
+warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/higher-ranked.rs:5:41
+   |
+LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
+   |                                         ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/impl-trait/precise-capturing/outlives.rs b/tests/ui/impl-trait/precise-capturing/outlives.rs
new file mode 100644
index 00000000000..71e6333934e
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/outlives.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+
+// Show that precise captures allow us to skip a lifetime param for outlives
+
+#![feature(lifetime_capture_rules_2024, precise_capturing)]
+//~^ WARN the feature `precise_capturing` is incomplete
+
+fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { }
+
+fn outlives<'a, T: 'a>(_: T) {}
+
+fn test<'a, 'b>() {
+    outlives::<'a, _>(hello::<'a, 'b>());
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/outlives.stderr b/tests/ui/impl-trait/precise-capturing/outlives.stderr
new file mode 100644
index 00000000000..405c09cccd9
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/outlives.stderr
@@ -0,0 +1,11 @@
+warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/outlives.rs:5:41
+   |
+LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
+   |                                         ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+