@@ -37,6 +37,9 @@ pub struct Body {
37
37
pub pats : Arena < Pat > ,
38
38
pub bindings : Arena < Binding > ,
39
39
pub labels : Arena < Label > ,
40
+ /// Id of the closure/generator that owns the corresponding binding. If a binding is owned by the
41
+ /// top level expression, it will not be listed in here.
42
+ pub binding_owners : FxHashMap < BindingId , ExprId > ,
40
43
/// The patterns for the function's parameters. While the parameter types are
41
44
/// part of the function signature, the patterns are not (they don't change
42
45
/// the external type of the function).
@@ -118,7 +121,8 @@ impl Body {
118
121
let _p = profile:: span ( "body_with_source_map_query" ) ;
119
122
let mut params = None ;
120
123
121
- let ( file_id, module, body, is_async_fn) = {
124
+ let mut is_async_fn = false ;
125
+ let InFile { file_id, value : body } = {
122
126
match def {
123
127
DefWithBodyId :: FunctionId ( f) => {
124
128
let data = db. function_data ( f) ;
@@ -138,31 +142,27 @@ impl Body {
138
142
} ) ,
139
143
)
140
144
} ) ;
141
- (
142
- src. file_id ,
143
- f. module ( db) ,
144
- src. value . body ( ) . map ( ast:: Expr :: from) ,
145
- data. has_async_kw ( ) ,
146
- )
145
+ is_async_fn = data. has_async_kw ( ) ;
146
+ src. map ( |it| it. body ( ) . map ( ast:: Expr :: from) )
147
147
}
148
148
DefWithBodyId :: ConstId ( c) => {
149
149
let c = c. lookup ( db) ;
150
150
let src = c. source ( db) ;
151
- ( src. file_id , c . module ( db ) , src . value . body ( ) , false )
151
+ src. map ( |it| it . body ( ) )
152
152
}
153
153
DefWithBodyId :: StaticId ( s) => {
154
154
let s = s. lookup ( db) ;
155
155
let src = s. source ( db) ;
156
- ( src. file_id , s . module ( db ) , src . value . body ( ) , false )
156
+ src. map ( |it| it . body ( ) )
157
157
}
158
158
DefWithBodyId :: VariantId ( v) => {
159
- let e = v. parent . lookup ( db) ;
160
159
let src = v. parent . child_source ( db) ;
161
- let variant = & src. value [ v. local_id ] ;
162
- ( src. file_id , e. container , variant. expr ( ) , false )
160
+ src. map ( |it| it[ v. local_id ] . expr ( ) )
163
161
}
162
+ DefWithBodyId :: InTypeConstId ( c) => c. lookup ( db) . id . map ( |_| c. source ( db) . expr ( ) ) ,
164
163
}
165
164
} ;
165
+ let module = def. module ( db) ;
166
166
let expander = Expander :: new ( db, file_id, module) ;
167
167
let ( mut body, source_map) =
168
168
Body :: new ( db, def, expander, params, body, module. krate , is_async_fn) ;
@@ -209,14 +209,24 @@ impl Body {
209
209
}
210
210
211
211
fn shrink_to_fit ( & mut self ) {
212
- let Self { _c : _, body_expr : _, block_scopes, exprs, labels, params, pats, bindings } =
213
- self ;
212
+ let Self {
213
+ _c : _,
214
+ body_expr : _,
215
+ block_scopes,
216
+ exprs,
217
+ labels,
218
+ params,
219
+ pats,
220
+ bindings,
221
+ binding_owners,
222
+ } = self ;
214
223
block_scopes. shrink_to_fit ( ) ;
215
224
exprs. shrink_to_fit ( ) ;
216
225
labels. shrink_to_fit ( ) ;
217
226
params. shrink_to_fit ( ) ;
218
227
pats. shrink_to_fit ( ) ;
219
228
bindings. shrink_to_fit ( ) ;
229
+ binding_owners. shrink_to_fit ( ) ;
220
230
}
221
231
222
232
pub fn walk_bindings_in_pat ( & self , pat_id : PatId , mut f : impl FnMut ( BindingId ) ) {
@@ -260,6 +270,17 @@ impl Body {
260
270
f ( pat_id) ;
261
271
self . walk_pats_shallow ( pat_id, |p| self . walk_pats ( p, f) ) ;
262
272
}
273
+
274
+ pub fn is_binding_upvar ( & self , binding : BindingId , relative_to : ExprId ) -> bool {
275
+ match self . binding_owners . get ( & binding) {
276
+ Some ( x) => {
277
+ // We assign expression ids in a way that outer closures will receive
278
+ // a lower id
279
+ x. into_raw ( ) < relative_to. into_raw ( )
280
+ }
281
+ None => true ,
282
+ }
283
+ }
263
284
}
264
285
265
286
impl Default for Body {
@@ -272,6 +293,7 @@ impl Default for Body {
272
293
labels : Default :: default ( ) ,
273
294
params : Default :: default ( ) ,
274
295
block_scopes : Default :: default ( ) ,
296
+ binding_owners : Default :: default ( ) ,
275
297
_c : Default :: default ( ) ,
276
298
}
277
299
}
0 commit comments