@@ -48,6 +48,7 @@ use rustc_ast::{self as ast, *};
48
48
use rustc_ast_pretty:: pprust;
49
49
use rustc_data_structures:: captures:: Captures ;
50
50
use rustc_data_structures:: fingerprint:: Fingerprint ;
51
+ use rustc_data_structures:: fx:: FxIndexSet ;
51
52
use rustc_data_structures:: sorted_map:: SortedMap ;
52
53
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
53
54
use rustc_data_structures:: sync:: Lrc ;
@@ -1398,7 +1399,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1398
1399
} ) ;
1399
1400
hir:: TyKind :: TraitObject ( bounds, lifetime_bound, * kind)
1400
1401
}
1401
- TyKind :: ImplTrait ( def_node_id, bounds) => {
1402
+ TyKind :: ImplTrait ( def_node_id, bounds, precise_capturing ) => {
1402
1403
let span = t. span ;
1403
1404
match itctx {
1404
1405
ImplTraitContext :: OpaqueTy { origin, fn_kind } => self . lower_opaque_impl_trait (
@@ -1408,8 +1409,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1408
1409
bounds,
1409
1410
fn_kind,
1410
1411
itctx,
1412
+ precise_capturing. as_deref ( ) . map ( |( args, _) | args. as_slice ( ) ) ,
1411
1413
) ,
1412
1414
ImplTraitContext :: Universal => {
1415
+ if let Some ( & ( _, span) ) = precise_capturing. as_deref ( ) {
1416
+ self . tcx . dcx ( ) . emit_err ( errors:: NoPreciseCapturesOnApit { span } ) ;
1417
+ } ;
1413
1418
let span = t. span ;
1414
1419
1415
1420
// HACK: pprust breaks strings with newlines when the type
@@ -1520,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1520
1525
bounds : & GenericBounds ,
1521
1526
fn_kind : Option < FnDeclKind > ,
1522
1527
itctx : ImplTraitContext ,
1528
+ precise_capturing_args : Option < & [ PreciseCapturingArg ] > ,
1523
1529
) -> hir:: TyKind < ' hir > {
1524
1530
// Make sure we know that some funky desugaring has been going on here.
1525
1531
// This is a first: there is code in other places like for loop
@@ -1528,42 +1534,59 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1528
1534
// frequently opened issues show.
1529
1535
let opaque_ty_span = self . mark_span_with_reason ( DesugaringKind :: OpaqueTy , span, None ) ;
1530
1536
1531
- let captured_lifetimes_to_duplicate = match origin {
1532
- hir:: OpaqueTyOrigin :: TyAlias { .. } => {
1533
- // type alias impl trait and associated type position impl trait were
1534
- // decided to capture all in-scope lifetimes, which we collect for
1535
- // all opaques during resolution.
1536
- self . resolver
1537
- . take_extra_lifetime_params ( opaque_ty_node_id)
1538
- . into_iter ( )
1539
- . map ( |( ident, id, _) | Lifetime { id, ident } )
1537
+ let captured_lifetimes_to_duplicate =
1538
+ if let Some ( precise_capturing) = precise_capturing_args {
1539
+ // We'll actually validate these later on; all we need is the list of
1540
+ // lifetimes to duplicate during this portion of lowering.
1541
+ precise_capturing
1542
+ . iter ( )
1543
+ . filter_map ( |arg| match arg {
1544
+ PreciseCapturingArg :: Lifetime ( lt) => Some ( * lt) ,
1545
+ PreciseCapturingArg :: Arg ( ..) => None ,
1546
+ } )
1547
+ // Add in all the lifetimes mentioned in the bounds. We will error
1548
+ // them out later, but capturing them here is important to make sure
1549
+ // they actually get resolved in resolve_bound_vars.
1550
+ . chain ( lifetime_collector:: lifetimes_in_bounds ( self . resolver , bounds) )
1540
1551
. collect ( )
1541
- }
1542
- hir:: OpaqueTyOrigin :: FnReturn ( ..) => {
1543
- if matches ! (
1544
- fn_kind. expect( "expected RPITs to be lowered with a FnKind" ) ,
1545
- FnDeclKind :: Impl | FnDeclKind :: Trait
1546
- ) || self . tcx . features ( ) . lifetime_capture_rules_2024
1547
- || span. at_least_rust_2024 ( )
1548
- {
1549
- // return-position impl trait in trait was decided to capture all
1550
- // in-scope lifetimes, which we collect for all opaques during resolution.
1551
- self . resolver
1552
- . take_extra_lifetime_params ( opaque_ty_node_id)
1553
- . into_iter ( )
1554
- . map ( |( ident, id, _) | Lifetime { id, ident } )
1555
- . collect ( )
1556
- } else {
1557
- // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
1558
- // example, we only need to duplicate lifetimes that appear in the
1559
- // bounds, since those are the only ones that are captured by the opaque.
1560
- lifetime_collector:: lifetimes_in_bounds ( self . resolver , bounds)
1552
+ } else {
1553
+ match origin {
1554
+ hir:: OpaqueTyOrigin :: TyAlias { .. } => {
1555
+ // type alias impl trait and associated type position impl trait were
1556
+ // decided to capture all in-scope lifetimes, which we collect for
1557
+ // all opaques during resolution.
1558
+ self . resolver
1559
+ . take_extra_lifetime_params ( opaque_ty_node_id)
1560
+ . into_iter ( )
1561
+ . map ( |( ident, id, _) | Lifetime { id, ident } )
1562
+ . collect ( )
1563
+ }
1564
+ hir:: OpaqueTyOrigin :: FnReturn ( ..) => {
1565
+ if matches ! (
1566
+ fn_kind. expect( "expected RPITs to be lowered with a FnKind" ) ,
1567
+ FnDeclKind :: Impl | FnDeclKind :: Trait
1568
+ ) || self . tcx . features ( ) . lifetime_capture_rules_2024
1569
+ || span. at_least_rust_2024 ( )
1570
+ {
1571
+ // return-position impl trait in trait was decided to capture all
1572
+ // in-scope lifetimes, which we collect for all opaques during resolution.
1573
+ self . resolver
1574
+ . take_extra_lifetime_params ( opaque_ty_node_id)
1575
+ . into_iter ( )
1576
+ . map ( |( ident, id, _) | Lifetime { id, ident } )
1577
+ . collect ( )
1578
+ } else {
1579
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
1580
+ // example, we only need to duplicate lifetimes that appear in the
1581
+ // bounds, since those are the only ones that are captured by the opaque.
1582
+ lifetime_collector:: lifetimes_in_bounds ( self . resolver , bounds)
1583
+ }
1584
+ }
1585
+ hir:: OpaqueTyOrigin :: AsyncFn ( ..) => {
1586
+ unreachable ! ( "should be using `lower_async_fn_ret_ty`" )
1587
+ }
1561
1588
}
1562
- }
1563
- hir:: OpaqueTyOrigin :: AsyncFn ( ..) => {
1564
- unreachable ! ( "should be using `lower_async_fn_ret_ty`" )
1565
- }
1566
- } ;
1589
+ } ;
1567
1590
debug ! ( ?captured_lifetimes_to_duplicate) ;
1568
1591
1569
1592
self . lower_opaque_inner (
@@ -1573,6 +1596,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1573
1596
captured_lifetimes_to_duplicate,
1574
1597
span,
1575
1598
opaque_ty_span,
1599
+ precise_capturing_args,
1576
1600
|this| this. lower_param_bounds ( bounds, itctx) ,
1577
1601
)
1578
1602
}
@@ -1582,9 +1606,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1582
1606
opaque_ty_node_id : NodeId ,
1583
1607
origin : hir:: OpaqueTyOrigin ,
1584
1608
in_trait : bool ,
1585
- captured_lifetimes_to_duplicate : Vec < Lifetime > ,
1609
+ captured_lifetimes_to_duplicate : FxIndexSet < Lifetime > ,
1586
1610
span : Span ,
1587
1611
opaque_ty_span : Span ,
1612
+ precise_capturing_args : Option < & [ PreciseCapturingArg ] > ,
1588
1613
lower_item_bounds : impl FnOnce ( & mut Self ) -> & ' hir [ hir:: GenericBound < ' hir > ] ,
1589
1614
) -> hir:: TyKind < ' hir > {
1590
1615
let opaque_ty_def_id = self . create_def (
@@ -1671,8 +1696,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1671
1696
// Install the remapping from old to new (if any). This makes sure that
1672
1697
// any lifetimes that would have resolved to the def-id of captured
1673
1698
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
1674
- let bounds = this
1675
- . with_remapping ( captured_to_synthesized_mapping, |this| lower_item_bounds ( this) ) ;
1699
+ let ( bounds, precise_capturing_args) =
1700
+ this. with_remapping ( captured_to_synthesized_mapping, |this| {
1701
+ (
1702
+ lower_item_bounds ( this) ,
1703
+ precise_capturing_args. map ( |precise_capturing| {
1704
+ this. lower_precise_capturing_args ( precise_capturing)
1705
+ } ) ,
1706
+ )
1707
+ } ) ;
1676
1708
1677
1709
let generic_params =
1678
1710
this. arena . alloc_from_iter ( synthesized_lifetime_definitions. iter ( ) . map (
@@ -1717,6 +1749,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1717
1749
origin,
1718
1750
lifetime_mapping,
1719
1751
in_trait,
1752
+ precise_capturing_args,
1720
1753
} ;
1721
1754
1722
1755
// Generate an `type Foo = impl Trait;` declaration.
@@ -1749,6 +1782,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1749
1782
)
1750
1783
}
1751
1784
1785
+ fn lower_precise_capturing_args (
1786
+ & mut self ,
1787
+ precise_capturing_args : & [ PreciseCapturingArg ] ,
1788
+ ) -> & ' hir [ hir:: PreciseCapturingArg < ' hir > ] {
1789
+ self . arena . alloc_from_iter ( precise_capturing_args. iter ( ) . map ( |arg| match arg {
1790
+ PreciseCapturingArg :: Lifetime ( lt) => {
1791
+ hir:: PreciseCapturingArg :: Lifetime ( self . lower_lifetime ( lt) )
1792
+ }
1793
+ PreciseCapturingArg :: Arg ( path, id) => {
1794
+ let [ segment] = path. segments . as_slice ( ) else {
1795
+ panic ! ( ) ;
1796
+ } ;
1797
+ let res = self . resolver . get_partial_res ( * id) . map_or ( Res :: Err , |partial_res| {
1798
+ partial_res. full_res ( ) . expect ( "no partial res expected for precise capture arg" )
1799
+ } ) ;
1800
+ hir:: PreciseCapturingArg :: Param ( hir:: PreciseCapturingNonLifetimeArg {
1801
+ hir_id : self . lower_node_id ( * id) ,
1802
+ ident : self . lower_ident ( segment. ident ) ,
1803
+ res : self . lower_res ( res) ,
1804
+ } )
1805
+ }
1806
+ } ) )
1807
+ }
1808
+
1752
1809
fn lower_fn_params_to_names ( & mut self , decl : & FnDecl ) -> & ' hir [ Ident ] {
1753
1810
self . arena . alloc_from_iter ( decl. inputs . iter ( ) . map ( |param| match param. pat . kind {
1754
1811
PatKind :: Ident ( _, ident, _) => self . lower_ident ( ident) ,
@@ -1889,7 +1946,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1889
1946
let opaque_ty_span =
1890
1947
self . mark_span_with_reason ( DesugaringKind :: Async , span, allowed_features) ;
1891
1948
1892
- let captured_lifetimes: Vec < _ > = self
1949
+ let captured_lifetimes = self
1893
1950
. resolver
1894
1951
. take_extra_lifetime_params ( opaque_ty_node_id)
1895
1952
. into_iter ( )
@@ -1903,6 +1960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
1903
1960
captured_lifetimes,
1904
1961
span,
1905
1962
opaque_ty_span,
1963
+ None ,
1906
1964
|this| {
1907
1965
let bound = this. lower_coroutine_fn_output_type_to_bound (
1908
1966
output,
0 commit comments