3232
3333#![ feature( crate_visibility_modifier) ]
3434#![ feature( box_patterns) ]
35+ #![ feature( let_chains) ]
3536#![ feature( let_else) ]
3637#![ feature( never_type) ]
3738#![ recursion_limit = "256" ]
@@ -135,24 +136,8 @@ struct LoweringContext<'a, 'hir: 'a> {
135136 /// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
136137 in_scope_lifetimes : Vec < ( ParamName , LocalDefId ) > ,
137138
138- /// Used to handle lifetimes appearing in impl-traits. When we lower a lifetime,
139- /// it is inserted in the `FxHashMap`, and the resolution is modified so to point
140- /// to the lifetime parameter impl-trait will generate.
141- /// When traversing `for<...>` binders, they are inserted in the `FxHashSet` so
142- /// we know *not* to rebind the introduced lifetimes.
143- captured_lifetimes : Option < (
144- LocalDefId , // parent def_id for new definitions
145- FxHashMap <
146- LocalDefId , // original parameter id
147- (
148- Span , // Span
149- NodeId , // synthetized parameter id
150- ParamName , // parameter name
151- LifetimeRes , // original resolution
152- ) ,
153- > ,
154- FxHashSet < NodeId > , // traversed binders, to ignore
155- ) > ,
139+ /// Used to handle lifetimes appearing in impl-traits.
140+ captured_lifetimes : Option < LifetimeCaptureContext > ,
156141
157142 current_hir_id_owner : LocalDefId ,
158143 item_local_id_counter : hir:: ItemLocalId ,
@@ -179,6 +164,9 @@ pub enum LifetimeRes {
179164 /// - a TraitRef's ref_id, identifying the `for<...>` binder;
180165 /// - a BareFn type's id;
181166 /// - a Path's id when this path has parenthesized generic args.
167+ ///
168+ /// This information is used for impl-trait lifetime captures, to know when to or not to
169+ /// capture any given lifetime.
182170 binder : NodeId ,
183171 } ,
184172 /// Created a generic parameter for an anonymous lifetime.
@@ -206,6 +194,28 @@ pub enum LifetimeRes {
206194 ElidedAnchor { start : NodeId , end : NodeId } ,
207195}
208196
197+ /// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so
198+ /// to point to the lifetime parameter impl-trait will generate.
199+ /// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not*
200+ /// to rebind the introduced lifetimes.
201+ #[ derive( Debug ) ]
202+ struct LifetimeCaptureContext {
203+ /// parent def_id for new definitions
204+ parent_def_id : LocalDefId ,
205+ /// Set of lifetimes to rebind.
206+ captures : FxHashMap <
207+ LocalDefId , // original parameter id
208+ (
209+ Span , // Span
210+ NodeId , // synthetized parameter id
211+ ParamName , // parameter name
212+ LifetimeRes , // original resolution
213+ ) ,
214+ > ,
215+ /// Traversed binders. The ids in this set should *not* be rebound.
216+ binders_to_ignore : FxHashSet < NodeId > ,
217+ }
218+
209219pub trait ResolverAstLowering {
210220 fn def_key ( & self , id : DefId ) -> DefKey ;
211221
@@ -790,6 +800,45 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
790800 ( lowered_generics, res)
791801 }
792802
803+ /// Setup lifetime capture for and impl-trait.
804+ /// The captures will be added to `captures`.
805+ fn while_capturing_lifetimes < T > (
806+ & mut self ,
807+ parent_def_id : LocalDefId ,
808+ captures : & mut FxHashMap < LocalDefId , ( Span , NodeId , ParamName , LifetimeRes ) > ,
809+ f : impl FnOnce ( & mut Self ) -> T ,
810+ ) -> T {
811+ let lifetime_stash = std:: mem:: replace (
812+ & mut self . captured_lifetimes ,
813+ Some ( LifetimeCaptureContext {
814+ parent_def_id,
815+ captures : std:: mem:: take ( captures) ,
816+ binders_to_ignore : Default :: default ( ) ,
817+ } ) ,
818+ ) ;
819+
820+ let ret = f ( self ) ;
821+
822+ let ctxt = std:: mem:: replace ( & mut self . captured_lifetimes , lifetime_stash) . unwrap ( ) ;
823+ * captures = ctxt. captures ;
824+
825+ ret
826+ }
827+
828+ /// Register a binder to be ignored for lifetime capture.
829+ #[ tracing:: instrument( level = "debug" , skip( self , f) ) ]
830+ #[ inline]
831+ fn with_lifetime_binder < T > ( & mut self , binder : NodeId , f : impl FnOnce ( & mut Self ) -> T ) -> T {
832+ if let Some ( ctxt) = & mut self . captured_lifetimes {
833+ ctxt. binders_to_ignore . insert ( binder) ;
834+ }
835+ let ret = f ( self ) ;
836+ if let Some ( ctxt) = & mut self . captured_lifetimes {
837+ ctxt. binders_to_ignore . remove ( & binder) ;
838+ }
839+ ret
840+ }
841+
793842 fn with_dyn_type_scope < T > ( & mut self , in_scope : bool , f : impl FnOnce ( & mut Self ) -> T ) -> T {
794843 let was_in_dyn_type = self . is_in_dyn_type ;
795844 self . is_in_dyn_type = in_scope;
@@ -1197,25 +1246,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11971246 hir:: TyKind :: Rptr ( lifetime, self . lower_mt ( mt, itctx) )
11981247 }
11991248 TyKind :: BareFn ( ref f) => self . with_in_scope_lifetime_defs ( & f. generic_params , |this| {
1200- if let Some ( ( _, _, binders) ) = & mut this. captured_lifetimes {
1201- binders. insert ( t. id ) ;
1202- }
1203-
1204- let ret = hir:: TyKind :: BareFn ( this. arena . alloc ( hir:: BareFnTy {
1205- generic_params : this. lower_generic_params (
1206- & f. generic_params ,
1207- ImplTraitContext :: Disallowed ( ImplTraitPosition :: Generic ) ,
1208- ) ,
1209- unsafety : this. lower_unsafety ( f. unsafety ) ,
1210- abi : this. lower_extern ( f. ext ) ,
1211- decl : this. lower_fn_decl ( & f. decl , None , FnDeclKind :: Pointer , None ) ,
1212- param_names : this. lower_fn_params_to_names ( & f. decl ) ,
1213- } ) ) ;
1214-
1215- if let Some ( ( _, _, binders) ) = & mut this. captured_lifetimes {
1216- binders. remove ( & t. id ) ;
1217- }
1218- ret
1249+ this. with_lifetime_binder ( t. id , |this| {
1250+ hir:: TyKind :: BareFn ( this. arena . alloc ( hir:: BareFnTy {
1251+ generic_params : this. lower_generic_params (
1252+ & f. generic_params ,
1253+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Generic ) ,
1254+ ) ,
1255+ unsafety : this. lower_unsafety ( f. unsafety ) ,
1256+ abi : this. lower_extern ( f. ext ) ,
1257+ decl : this. lower_fn_decl ( & f. decl , None , FnDeclKind :: Pointer , None ) ,
1258+ param_names : this. lower_fn_params_to_names ( & f. decl ) ,
1259+ } ) )
1260+ } )
12191261 } ) ,
12201262 TyKind :: Never => hir:: TyKind :: Never ,
12211263 TyKind :: Tup ( ref tys) => {
@@ -1366,15 +1408,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13661408
13671409 let mut collected_lifetimes = FxHashMap :: default ( ) ;
13681410 self . with_hir_id_owner ( opaque_ty_node_id, |lctx| {
1369- let capture_framework = if origin == hir:: OpaqueTyOrigin :: TyAlias {
1370- None
1411+ let hir_bounds = if origin == hir:: OpaqueTyOrigin :: TyAlias {
1412+ lower_bounds ( lctx )
13711413 } else {
1372- Some ( ( opaque_ty_def_id, FxHashMap :: default ( ) , FxHashSet :: default ( ) ) )
1414+ lctx. while_capturing_lifetimes (
1415+ opaque_ty_def_id,
1416+ & mut collected_lifetimes,
1417+ lower_bounds,
1418+ )
13731419 } ;
1374- let lifetime_stash = std:: mem:: replace ( & mut lctx. captured_lifetimes , capture_framework) ;
1375- let hir_bounds = lower_bounds ( lctx) ;
1376- collected_lifetimes = std:: mem:: replace ( & mut lctx. captured_lifetimes , lifetime_stash)
1377- . map_or_else ( FxHashMap :: default, |c| c. 1 ) ;
13781420 debug ! ( ?collected_lifetimes) ;
13791421
13801422 let lifetime_defs = lctx. arena . alloc_from_iter ( collected_lifetimes. iter ( ) . map (
@@ -1716,24 +1758,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17161758 debug ! ( ?captures) ;
17171759
17181760 self . with_hir_id_owner ( opaque_ty_node_id, |this| {
1719- let lifetime_stash = std:: mem:: replace (
1720- & mut this. captured_lifetimes ,
1721- Some ( ( opaque_ty_def_id, std:: mem:: take ( & mut captures) , FxHashSet :: default ( ) ) ) ,
1722- ) ;
17231761 debug ! ( "lower_async_fn_ret_ty: lifetimes_to_define={:#?}" , this. lifetimes_to_define) ;
1724-
1725- // We have to be careful to get elision right here. The
1726- // idea is that we create a lifetime parameter for each
1727- // lifetime in the return type. So, given a return type
1728- // like `async fn foo(..) -> &[&u32]`, we lower to `impl
1729- // Future<Output = &'1 [ &'2 u32 ]>`.
1730- //
1731- // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
1732- // hence the elision takes place at the fn site.
17331762 let future_bound =
1734- this. lower_async_fn_output_type_to_future_bound ( output, fn_def_id, span) ;
1763+ this. while_capturing_lifetimes ( opaque_ty_def_id, & mut captures, |this| {
1764+ // We have to be careful to get elision right here. The
1765+ // idea is that we create a lifetime parameter for each
1766+ // lifetime in the return type. So, given a return type
1767+ // like `async fn foo(..) -> &[&u32]`, we lower to `impl
1768+ // Future<Output = &'1 [ &'2 u32 ]>`.
1769+ //
1770+ // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
1771+ // hence the elision takes place at the fn site.
1772+ this. lower_async_fn_output_type_to_future_bound ( output, fn_def_id, span)
1773+ } ) ;
17351774 debug ! ( "lower_async_fn_ret_ty: future_bound={:#?}" , future_bound) ;
1736- captures = std:: mem:: replace ( & mut this. captured_lifetimes , lifetime_stash) . unwrap ( ) . 1 ;
17371775 debug ! ( "lower_async_fn_ret_ty: captures={:#?}" , captures) ;
17381776
17391777 let generic_params =
@@ -1882,22 +1920,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18821920 LifetimeRes :: Param { param, binder } => {
18831921 debug_assert_ne ! ( ident. name, kw:: UnderscoreLifetime ) ;
18841922 let p_name = ParamName :: Plain ( ident) ;
1885- if let Some ( ( parent_def_id, captures, binders) ) = & mut self . captured_lifetimes {
1923+ if let Some ( LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore } ) =
1924+ & mut self . captured_lifetimes
1925+ && !binders_to_ignore. contains ( & binder)
1926+ {
18861927 match captures. entry ( param) {
18871928 Entry :: Occupied ( _) => { }
18881929 Entry :: Vacant ( v) => {
1889- if !binders. contains ( & binder) {
1890- let p_id = self . resolver . next_node_id ( ) ;
1891- self . resolver . create_def (
1892- * parent_def_id,
1893- p_id,
1894- DefPathData :: LifetimeNs ( p_name. ident ( ) . name ) ,
1895- ExpnId :: root ( ) ,
1896- span. with_parent ( None ) ,
1897- ) ;
1898-
1899- v. insert ( ( span, p_id, p_name, res) ) ;
1900- }
1930+ let p_id = self . resolver . next_node_id ( ) ;
1931+ self . resolver . create_def (
1932+ * parent_def_id,
1933+ p_id,
1934+ DefPathData :: LifetimeNs ( p_name. ident ( ) . name ) ,
1935+ ExpnId :: root ( ) ,
1936+ span. with_parent ( None ) ,
1937+ ) ;
1938+
1939+ v. insert ( ( span, p_id, p_name, res) ) ;
19011940 }
19021941 }
19031942 }
@@ -1908,24 +1947,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19081947 // Only items are allowed to introduce fresh lifetimes,
19091948 // so we know `binder` has a `LocalDefId`.
19101949 let binder_def_id = self . resolver . local_def_id ( binder) ;
1911- if let Some ( ( parent_def_id, captures, binders) ) = & mut self . captured_lifetimes {
1950+ if let Some ( LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore } ) =
1951+ & mut self . captured_lifetimes
1952+ && !binders_to_ignore. contains ( & binder)
1953+ {
19121954 match captures. entry ( param) {
19131955 Entry :: Occupied ( o) => param = self . resolver . local_def_id ( o. get ( ) . 1 ) ,
19141956 Entry :: Vacant ( v) => {
1915- if !binders. contains ( & binder) {
1916- let p_id = self . resolver . next_node_id ( ) ;
1917- let p_def_id = self . resolver . create_def (
1918- * parent_def_id,
1919- p_id,
1920- DefPathData :: LifetimeNs ( kw:: UnderscoreLifetime ) ,
1921- ExpnId :: root ( ) ,
1922- span. with_parent ( None ) ,
1923- ) ;
1924-
1925- let p_name = ParamName :: Fresh ( param) ;
1926- v. insert ( ( span, p_id, p_name, res) ) ;
1927- param = p_def_id;
1928- }
1957+ let p_id = self . resolver . next_node_id ( ) ;
1958+ let p_def_id = self . resolver . create_def (
1959+ * parent_def_id,
1960+ p_id,
1961+ DefPathData :: LifetimeNs ( kw:: UnderscoreLifetime ) ,
1962+ ExpnId :: root ( ) ,
1963+ span. with_parent ( None ) ,
1964+ ) ;
1965+
1966+ let p_name = ParamName :: Fresh ( param) ;
1967+ v. insert ( ( span, p_id, p_name, res) ) ;
1968+ param = p_def_id;
19291969 }
19301970 }
19311971 } else if let Some ( introducer) = introducer {
@@ -1948,21 +1988,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19481988 } else {
19491989 hir:: LifetimeName :: Underscore
19501990 } ;
1951- match & mut self . captured_lifetimes {
1952- Some ( ( parent_def_id, captures, binders) ) if !binders. contains ( & binder) => {
1953- let p_id = self . resolver . next_node_id ( ) ;
1954- let p_def_id = self . resolver . create_def (
1955- * parent_def_id,
1956- p_id,
1957- DefPathData :: LifetimeNs ( kw:: UnderscoreLifetime ) ,
1958- ExpnId :: root ( ) ,
1959- span. with_parent ( None ) ,
1960- ) ;
1961- let p_name = ParamName :: Fresh ( p_def_id) ;
1962- captures. insert ( p_def_id, ( span, p_id, p_name, res) ) ;
1963- hir:: LifetimeName :: Param ( p_name)
1964- }
1965- _ => l_name,
1991+ if let Some ( LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore } ) =
1992+ & mut self . captured_lifetimes
1993+ && !binders_to_ignore. contains ( & binder)
1994+ {
1995+ let p_id = self . resolver . next_node_id ( ) ;
1996+ let p_def_id = self . resolver . create_def (
1997+ * parent_def_id,
1998+ p_id,
1999+ DefPathData :: LifetimeNs ( kw:: UnderscoreLifetime ) ,
2000+ ExpnId :: root ( ) ,
2001+ span. with_parent ( None ) ,
2002+ ) ;
2003+ let p_name = ParamName :: Fresh ( p_def_id) ;
2004+ captures. insert ( p_def_id, ( span, p_id, p_name, res) ) ;
2005+ hir:: LifetimeName :: Param ( p_name)
2006+ } else {
2007+ l_name
19662008 }
19672009 }
19682010 LifetimeRes :: Static => hir:: LifetimeName :: Static ,
@@ -2069,16 +2111,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20692111 self . lower_generic_params ( & p. bound_generic_params , itctx. reborrow ( ) ) ;
20702112
20712113 let trait_ref = self . with_in_scope_lifetime_defs ( & p. bound_generic_params , |this| {
2072- if let Some ( ( _, _, binders) ) = & mut this. captured_lifetimes {
2073- binders. insert ( p. trait_ref . ref_id ) ;
2074- }
2075-
2076- let trait_ref = this. lower_trait_ref ( & p. trait_ref , itctx. reborrow ( ) ) ;
2077-
2078- if let Some ( ( _, _, binders) ) = & mut this. captured_lifetimes {
2079- binders. remove ( & p. trait_ref . ref_id ) ;
2080- }
2081- trait_ref
2114+ this. with_lifetime_binder ( p. trait_ref . ref_id , |this| {
2115+ this. lower_trait_ref ( & p. trait_ref , itctx. reborrow ( ) )
2116+ } )
20822117 } ) ;
20832118
20842119 hir:: PolyTraitRef { bound_generic_params, trait_ref, span : self . lower_span ( p. span ) }
0 commit comments