@@ -48,6 +48,7 @@ use rustc_ast::{self as ast, *};
4848use rustc_ast_pretty:: pprust;
4949use rustc_data_structures:: captures:: Captures ;
5050use rustc_data_structures:: fingerprint:: Fingerprint ;
51+ use rustc_data_structures:: fx:: FxIndexSet ;
5152use rustc_data_structures:: sorted_map:: SortedMap ;
5253use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
5354use rustc_data_structures:: sync:: Lrc ;
@@ -1398,7 +1399,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13981399 } ) ;
13991400 hir:: TyKind :: TraitObject ( bounds, lifetime_bound, * kind)
14001401 }
1401- TyKind :: ImplTrait ( def_node_id, bounds) => {
1402+ TyKind :: ImplTrait ( def_node_id, bounds, precise_capturing ) => {
14021403 let span = t. span ;
14031404 match itctx {
14041405 ImplTraitContext :: OpaqueTy { origin, fn_kind } => self . lower_opaque_impl_trait (
@@ -1408,8 +1409,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14081409 bounds,
14091410 fn_kind,
14101411 itctx,
1412+ precise_capturing. as_deref ( ) . map ( |( args, _) | args. as_slice ( ) ) ,
14111413 ) ,
14121414 ImplTraitContext :: Universal => {
1415+ if let Some ( & ( _, span) ) = precise_capturing. as_deref ( ) {
1416+ self . tcx . dcx ( ) . emit_err ( errors:: NoPreciseCapturesOnApit { span } ) ;
1417+ } ;
14131418 let span = t. span ;
14141419
14151420 // HACK: pprust breaks strings with newlines when the type
@@ -1520,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15201525 bounds : & GenericBounds ,
15211526 fn_kind : Option < FnDeclKind > ,
15221527 itctx : ImplTraitContext ,
1528+ precise_capturing_args : Option < & [ PreciseCapturingArg ] > ,
15231529 ) -> hir:: TyKind < ' hir > {
15241530 // Make sure we know that some funky desugaring has been going on here.
15251531 // This is a first: there is code in other places like for loop
@@ -1528,42 +1534,59 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15281534 // frequently opened issues show.
15291535 let opaque_ty_span = self . mark_span_with_reason ( DesugaringKind :: OpaqueTy , span, None ) ;
15301536
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) )
15401551 . 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+ }
15611588 }
1562- }
1563- hir:: OpaqueTyOrigin :: AsyncFn ( ..) => {
1564- unreachable ! ( "should be using `lower_async_fn_ret_ty`" )
1565- }
1566- } ;
1589+ } ;
15671590 debug ! ( ?captured_lifetimes_to_duplicate) ;
15681591
15691592 self . lower_opaque_inner (
@@ -1573,6 +1596,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15731596 captured_lifetimes_to_duplicate,
15741597 span,
15751598 opaque_ty_span,
1599+ precise_capturing_args,
15761600 |this| this. lower_param_bounds ( bounds, itctx) ,
15771601 )
15781602 }
@@ -1582,9 +1606,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15821606 opaque_ty_node_id : NodeId ,
15831607 origin : hir:: OpaqueTyOrigin ,
15841608 in_trait : bool ,
1585- captured_lifetimes_to_duplicate : Vec < Lifetime > ,
1609+ captured_lifetimes_to_duplicate : FxIndexSet < Lifetime > ,
15861610 span : Span ,
15871611 opaque_ty_span : Span ,
1612+ precise_capturing_args : Option < & [ PreciseCapturingArg ] > ,
15881613 lower_item_bounds : impl FnOnce ( & mut Self ) -> & ' hir [ hir:: GenericBound < ' hir > ] ,
15891614 ) -> hir:: TyKind < ' hir > {
15901615 let opaque_ty_def_id = self . create_def (
@@ -1671,8 +1696,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16711696 // Install the remapping from old to new (if any). This makes sure that
16721697 // any lifetimes that would have resolved to the def-id of captured
16731698 // 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+ } ) ;
16761708
16771709 let generic_params =
16781710 this. arena . alloc_from_iter ( synthesized_lifetime_definitions. iter ( ) . map (
@@ -1717,6 +1749,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17171749 origin,
17181750 lifetime_mapping,
17191751 in_trait,
1752+ precise_capturing_args,
17201753 } ;
17211754
17221755 // Generate an `type Foo = impl Trait;` declaration.
@@ -1749,6 +1782,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17491782 )
17501783 }
17511784
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+
17521809 fn lower_fn_params_to_names ( & mut self , decl : & FnDecl ) -> & ' hir [ Ident ] {
17531810 self . arena . alloc_from_iter ( decl. inputs . iter ( ) . map ( |param| match param. pat . kind {
17541811 PatKind :: Ident ( _, ident, _) => self . lower_ident ( ident) ,
@@ -1889,7 +1946,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18891946 let opaque_ty_span =
18901947 self . mark_span_with_reason ( DesugaringKind :: Async , span, allowed_features) ;
18911948
1892- let captured_lifetimes: Vec < _ > = self
1949+ let captured_lifetimes = self
18931950 . resolver
18941951 . take_extra_lifetime_params ( opaque_ty_node_id)
18951952 . into_iter ( )
@@ -1903,6 +1960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19031960 captured_lifetimes,
19041961 span,
19051962 opaque_ty_span,
1963+ None ,
19061964 |this| {
19071965 let bound = this. lower_coroutine_fn_output_type_to_bound (
19081966 output,
0 commit comments