Skip to content

Commit 647b672

Browse files
Begin AST lowering for precise captures
1 parent a076eae commit 647b672

File tree

5 files changed

+106
-29
lines changed

5 files changed

+106
-29
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13991399
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
14001400
}
14011401
TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
1402-
assert!(precise_capturing.is_none(), "precise captures not supported yet!");
14031402
let span = t.span;
14041403
match itctx {
14051404
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
@@ -1409,8 +1408,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14091408
bounds,
14101409
fn_kind,
14111410
itctx,
1411+
precise_capturing.as_deref(),
14121412
),
14131413
ImplTraitContext::Universal => {
1414+
assert!(
1415+
precise_capturing.is_none(),
1416+
"TODO: precise captures not supported on universals!"
1417+
);
14141418
let span = t.span;
14151419

14161420
// HACK: pprust breaks strings with newlines when the type
@@ -1521,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15211525
bounds: &GenericBounds,
15221526
fn_kind: Option<FnDeclKind>,
15231527
itctx: ImplTraitContext,
1528+
precise_capturing: Option<&ast::GenericArgs>,
15241529
) -> hir::TyKind<'hir> {
15251530
// Make sure we know that some funky desugaring has been going on here.
15261531
// This is a first: there is code in other places like for loop
@@ -1529,40 +1534,56 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15291534
// frequently opened issues show.
15301535
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
15311536

1532-
let captured_lifetimes_to_duplicate = match origin {
1533-
hir::OpaqueTyOrigin::TyAlias { .. } => {
1534-
// type alias impl trait and associated type position impl trait were
1535-
// decided to capture all in-scope lifetimes, which we collect for
1536-
// all opaques during resolution.
1537-
self.resolver
1538-
.take_extra_lifetime_params(opaque_ty_node_id)
1539-
.into_iter()
1540-
.map(|(ident, id, _)| Lifetime { id, ident })
1541-
.collect()
1542-
}
1543-
hir::OpaqueTyOrigin::FnReturn(..) => {
1544-
if matches!(
1545-
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
1546-
FnDeclKind::Impl | FnDeclKind::Trait
1547-
) || self.tcx.features().lifetime_capture_rules_2024
1548-
|| span.at_least_rust_2024()
1549-
{
1550-
// return-position impl trait in trait was decided to capture all
1551-
// in-scope lifetimes, which we collect for all opaques during resolution.
1537+
let captured_lifetimes_to_duplicate = if let Some(precise_capturing) = precise_capturing {
1538+
let ast::GenericArgs::AngleBracketed(precise_capturing) = precise_capturing else {
1539+
panic!("we only parse angle-bracketed args")
1540+
};
1541+
// We'll actually validate these later on; all we need is the list of
1542+
// lifetimes to duplicate during this portion of lowering.
1543+
precise_capturing
1544+
.args
1545+
.iter()
1546+
.filter_map(|arg| match arg {
1547+
ast::AngleBracketedArg::Arg(ast::GenericArg::Lifetime(lt)) => Some(*lt),
1548+
_ => None,
1549+
})
1550+
.collect()
1551+
} else {
1552+
match origin {
1553+
hir::OpaqueTyOrigin::TyAlias { .. } => {
1554+
// type alias impl trait and associated type position impl trait were
1555+
// decided to capture all in-scope lifetimes, which we collect for
1556+
// all opaques during resolution.
15521557
self.resolver
15531558
.take_extra_lifetime_params(opaque_ty_node_id)
15541559
.into_iter()
15551560
.map(|(ident, id, _)| Lifetime { id, ident })
15561561
.collect()
1557-
} else {
1558-
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
1559-
// example, we only need to duplicate lifetimes that appear in the
1560-
// bounds, since those are the only ones that are captured by the opaque.
1561-
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
15621562
}
1563-
}
1564-
hir::OpaqueTyOrigin::AsyncFn(..) => {
1565-
unreachable!("should be using `lower_async_fn_ret_ty`")
1563+
hir::OpaqueTyOrigin::FnReturn(..) => {
1564+
if matches!(
1565+
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
1566+
FnDeclKind::Impl | FnDeclKind::Trait
1567+
) || self.tcx.features().lifetime_capture_rules_2024
1568+
|| span.at_least_rust_2024()
1569+
{
1570+
// return-position impl trait in trait was decided to capture all
1571+
// in-scope lifetimes, which we collect for all opaques during resolution.
1572+
self.resolver
1573+
.take_extra_lifetime_params(opaque_ty_node_id)
1574+
.into_iter()
1575+
.map(|(ident, id, _)| Lifetime { id, ident })
1576+
.collect()
1577+
} else {
1578+
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
1579+
// example, we only need to duplicate lifetimes that appear in the
1580+
// bounds, since those are the only ones that are captured by the opaque.
1581+
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
1582+
}
1583+
}
1584+
hir::OpaqueTyOrigin::AsyncFn(..) => {
1585+
unreachable!("should be using `lower_async_fn_ret_ty`")
1586+
}
15661587
}
15671588
};
15681589
debug!(?captured_lifetimes_to_duplicate);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ check-pass
2+
3+
// Show how precise captures allow us to skip capturing a higher-ranked lifetime
4+
5+
#![feature(lifetime_capture_rules_2024, precise_capturing)]
6+
//~^ WARN the feature `precise_capturing` is incomplete
7+
8+
trait Trait<'a> {
9+
type Item;
10+
}
11+
12+
impl Trait<'_> for () {
13+
type Item = Vec<()>;
14+
}
15+
16+
fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
17+
18+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/higher-ranked.rs:5:41
3+
|
4+
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ check-pass
2+
3+
// Show that precise captures allow us to skip a lifetime param for outlives
4+
5+
#![feature(lifetime_capture_rules_2024, precise_capturing)]
6+
//~^ WARN the feature `precise_capturing` is incomplete
7+
8+
fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { }
9+
10+
fn outlives<'a, T: 'a>(_: T) {}
11+
12+
fn test<'a, 'b>() {
13+
outlives::<'a, _>(hello::<'a, 'b>());
14+
}
15+
16+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/outlives.rs:5:41
3+
|
4+
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+

0 commit comments

Comments
 (0)