OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../closure.dart'; | 7 import '../closure.dart'; |
8 import '../common.dart'; | 8 import '../common.dart'; |
9 import '../common/tasks.dart'; | 9 import '../common/tasks.dart'; |
10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 | 54 |
55 /// The combined steps of generating our intermediate representation of | 55 /// The combined steps of generating our intermediate representation of |
56 /// closures that need to be rewritten and generating the element model. | 56 /// closures that need to be rewritten and generating the element model. |
57 /// Ultimately these two steps will be split apart with the second step | 57 /// Ultimately these two steps will be split apart with the second step |
58 /// happening later in compilation just before codegen. These steps are | 58 /// happening later in compilation just before codegen. These steps are |
59 /// combined here currently to provide a consistent interface to the rest of | 59 /// combined here currently to provide a consistent interface to the rest of |
60 /// the compiler until we are ready to separate these phases. | 60 /// the compiler until we are ready to separate these phases. |
61 @override | 61 @override |
62 void convertClosures(Iterable<MemberEntity> processedEntities, | 62 void convertClosures(Iterable<MemberEntity> processedEntities, |
63 ClosedWorldRefiner closedWorldRefiner) { | 63 ClosedWorldRefiner closedWorldRefiner) { |
64 var closuresToGenerate = <MemberEntity, Map<ir.TreeNode, ScopeInfo>>{}; | 64 Map<MemberEntity, ClosureModel> closureModels = |
| 65 _computeClosureModels(processedEntities); |
| 66 _createClosureEntities(closureModels, closedWorldRefiner); |
| 67 } |
| 68 |
| 69 // TODO(johnniwinther,efortuna): Compute this during resolution. See |
| 70 // documentation on [convertClosures]. |
| 71 Map<MemberEntity, ClosureModel> _computeClosureModels( |
| 72 Iterable<MemberEntity> processedEntities) { |
| 73 Map<MemberEntity, ClosureModel> closureModels = |
| 74 <MemberEntity, ClosureModel>{}; |
65 | 75 |
66 processedEntities.forEach((MemberEntity kEntity) { | 76 processedEntities.forEach((MemberEntity kEntity) { |
67 MemberEntity entity = _kToJElementMap.toBackendMember(kEntity); | 77 MemberEntity entity = _kToJElementMap.toBackendMember(kEntity); |
68 if (entity.isAbstract) return; | 78 if (entity.isAbstract) return; |
69 if (entity.isField && !entity.isInstanceMember) { | 79 if (entity.isField && !entity.isInstanceMember) { |
70 MemberDefinition definition = _elementMap.getMemberDefinition(entity); | 80 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
71 assert(definition.kind == MemberKind.regular, | 81 assert(definition.kind == MemberKind.regular, |
72 failedAt(entity, "Unexpected member definition $definition")); | 82 failedAt(entity, "Unexpected member definition $definition")); |
73 ir.Field field = definition.node; | 83 ir.Field field = definition.node; |
74 // Skip top-level/static fields without an initializer. | 84 // Skip top-level/static fields without an initializer. |
75 if (field.initializer == null) return; | 85 if (field.initializer == null) return; |
76 } | 86 } |
77 closuresToGenerate[entity] = | 87 closureModels[entity] = _buildClosureModel(entity); |
78 _buildClosureModel(entity, closedWorldRefiner); | |
79 }); | 88 }); |
| 89 return closureModels; |
| 90 } |
80 | 91 |
81 closuresToGenerate.forEach( | 92 void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels, |
82 (MemberEntity member, Map<ir.TreeNode, ScopeInfo> closuresToGenerate) { | 93 ClosedWorldRefiner closedWorldRefiner) { |
| 94 closureModels.forEach((MemberEntity member, ClosureModel model) { |
| 95 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
| 96 if (model.scopeInfo != null) { |
| 97 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap); |
| 98 } |
| 99 |
| 100 model.capturedScopesMap |
| 101 .forEach((ir.Node node, KernelCapturedScope scope) { |
| 102 if (scope is KernelCapturedLoopScope) { |
| 103 _capturedScopesMap[node] = |
| 104 new JsCapturedLoopScope.from(scope, localsMap); |
| 105 } else { |
| 106 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); |
| 107 } |
| 108 }); |
| 109 |
| 110 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = |
| 111 model.closuresToGenerate; |
83 for (ir.TreeNode node in closuresToGenerate.keys) { | 112 for (ir.TreeNode node in closuresToGenerate.keys) { |
84 _produceSyntheticElements( | 113 _produceSyntheticElements( |
85 member, node, closuresToGenerate[node], closedWorldRefiner); | 114 member, node, closuresToGenerate[node], closedWorldRefiner); |
86 } | 115 } |
87 }); | 116 }); |
88 } | 117 } |
89 | 118 |
90 /// Inspect members and mark if those members capture any state that needs to | 119 /// Inspect members and mark if those members capture any state that needs to |
91 /// be marked as free variables. | 120 /// be marked as free variables. |
92 Map<ir.TreeNode, ScopeInfo> _buildClosureModel( | 121 ClosureModel _buildClosureModel(MemberEntity entity) { |
93 MemberEntity entity, ClosedWorldRefiner closedWorldRefiner) { | 122 ClosureModel model = new ClosureModel(); |
94 assert(!_scopeMap.containsKey(entity), | |
95 failedAt(entity, "ScopeInfo already computed for $entity.")); | |
96 Map<ir.TreeNode, ScopeInfo> closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; | |
97 MemberDefinition definition = _elementMap.getMemberDefinition(entity); | 123 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
98 switch (definition.kind) { | 124 switch (definition.kind) { |
99 case MemberKind.regular: | 125 case MemberKind.regular: |
100 case MemberKind.constructor: | 126 case MemberKind.constructor: |
101 break; | 127 break; |
102 default: | 128 default: |
103 failedAt(entity, "Unexpected member definition $definition"); | 129 failedAt(entity, "Unexpected member definition $definition"); |
104 } | 130 } |
105 ir.Node node = definition.node; | 131 ir.Node node = definition.node; |
106 assert(!_scopeMap.containsKey(entity), | 132 CapturedScopeBuilder translator = new CapturedScopeBuilder(model, |
107 failedAt(entity, "CaptureScope already computed for $node.")); | 133 hasThisLocal: entity.isInstanceMember || entity.isConstructor); |
108 CapturedScopeBuilder translator = new CapturedScopeBuilder( | |
109 entity, | |
110 _capturedScopesMap, | |
111 _scopeMap, | |
112 closuresToGenerate, | |
113 _globalLocalsMap.getLocalsMap(entity)); | |
114 if (entity.isField) { | 134 if (entity.isField) { |
115 if (node is ir.Field && node.initializer != null) { | 135 if (node is ir.Field && node.initializer != null) { |
116 translator.translateLazyInitializer(node); | 136 translator.translateLazyInitializer(node); |
117 } | 137 } |
118 } else { | 138 } else { |
119 assert(node is ir.Procedure || node is ir.Constructor); | 139 assert(node is ir.Procedure || node is ir.Constructor); |
120 translator.translateConstructorOrProcedure(node); | 140 translator.translateConstructorOrProcedure(node); |
121 } | 141 } |
122 return closuresToGenerate; | 142 return model; |
123 } | 143 } |
124 | 144 |
125 /// Given what variables are captured at each point, construct closure classes | 145 /// Given what variables are captured at each point, construct closure classes |
126 /// with fields containing the captured variables to replicate the Dart | 146 /// with fields containing the captured variables to replicate the Dart |
127 /// closure semantics in JS. If this closure captures any variables (meaning | 147 /// closure semantics in JS. If this closure captures any variables (meaning |
128 /// the closure accesses a variable that gets accessed at some point), then | 148 /// the closure accesses a variable that gets accessed at some point), then |
129 /// boxForCapturedVariables stores the local context for those variables. | 149 /// boxForCapturedVariables stores the local context for those variables. |
130 /// If no variables are captured, this parameter is null. | 150 /// If no variables are captured, this parameter is null. |
131 void _produceSyntheticElements( | 151 void _produceSyntheticElements( |
132 MemberEntity member, | 152 MemberEntity member, |
133 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, | 153 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, |
134 ScopeInfo info, | 154 KernelScopeInfo info, |
135 ClosedWorldRefiner closedWorldRefiner) { | 155 ClosedWorldRefiner closedWorldRefiner) { |
136 String name = _computeClosureName(node); | 156 String name = _computeClosureName(node); |
137 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); | 157 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
138 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( | 158 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( |
139 name, member.library, info, node.location, localsMap); | 159 name, member.library, info, node.location, localsMap); |
140 | 160 |
141 Entity entity; | 161 Entity entity; |
142 if (node is ir.Member) { | 162 if (node is ir.Member) { |
143 entity = member; | 163 entity = member; |
144 } else { | 164 } else { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 | 253 |
234 @override | 254 @override |
235 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be | 255 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be |
236 // non-null, and we should just test that with an assert. | 256 // non-null, and we should just test that with an assert. |
237 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { | 257 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { |
238 return _closureRepresentationMap[entity] ?? | 258 return _closureRepresentationMap[entity] ?? |
239 const ClosureRepresentationInfo(); | 259 const ClosureRepresentationInfo(); |
240 } | 260 } |
241 } | 261 } |
242 | 262 |
243 class KernelScopeInfo extends ScopeInfo { | 263 class KernelScopeInfo { |
| 264 final Set<ir.VariableDeclaration> localsUsedInTryOrSync; |
| 265 final bool hasThisLocal; |
| 266 final Set<ir.VariableDeclaration> boxedVariables; |
| 267 |
| 268 /// The set of variables that were defined in another scope, but are used in |
| 269 /// this scope. |
| 270 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); |
| 271 |
| 272 KernelScopeInfo(this.hasThisLocal) |
| 273 : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>(), |
| 274 boxedVariables = new Set<ir.VariableDeclaration>(); |
| 275 |
| 276 KernelScopeInfo.from(this.hasThisLocal, KernelScopeInfo info) |
| 277 : localsUsedInTryOrSync = info.localsUsedInTryOrSync, |
| 278 boxedVariables = info.boxedVariables; |
| 279 |
| 280 KernelScopeInfo.withBoxedVariables(this.boxedVariables, |
| 281 this.localsUsedInTryOrSync, this.freeVariables, this.hasThisLocal); |
| 282 |
| 283 String toString() { |
| 284 StringBuffer sb = new StringBuffer(); |
| 285 sb.write('this=$hasThisLocal,'); |
| 286 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); |
| 287 return sb.toString(); |
| 288 } |
| 289 } |
| 290 |
| 291 class JsScopeInfo extends ScopeInfo { |
244 final Set<Local> localsUsedInTryOrSync; | 292 final Set<Local> localsUsedInTryOrSync; |
245 final Local thisLocal; | 293 final Local thisLocal; |
246 final Set<Local> boxedVariables; | 294 final Set<Local> boxedVariables; |
247 | 295 |
248 /// The set of variables that were defined in another scope, but are used in | 296 /// The set of variables that were defined in another scope, but are used in |
249 /// this scope. | 297 /// this scope. |
250 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); | 298 final Set<Local> freeVariables; |
251 | 299 |
252 KernelScopeInfo(this.thisLocal) | 300 JsScopeInfo(this.thisLocal, this.localsUsedInTryOrSync, this.boxedVariables, |
253 : localsUsedInTryOrSync = new Set<Local>(), | 301 this.freeVariables); |
254 boxedVariables = new Set<Local>(); | |
255 | 302 |
256 KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info) | 303 JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap) |
257 : localsUsedInTryOrSync = info.localsUsedInTryOrSync, | 304 : this.thisLocal = |
258 boxedVariables = info.boxedVariables; | 305 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, |
259 | 306 this.localsUsedInTryOrSync = |
260 KernelScopeInfo.withBoxedVariables(this.boxedVariables, | 307 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(), |
261 this.localsUsedInTryOrSync, this.freeVariables, this.thisLocal); | 308 this.boxedVariables = |
| 309 info.boxedVariables.map(localsMap.getLocalVariable).toSet(), |
| 310 this.freeVariables = |
| 311 info.freeVariables.map(localsMap.getLocalVariable).toSet(); |
262 | 312 |
263 void forEachBoxedVariable(f(Local local, FieldEntity field)) { | 313 void forEachBoxedVariable(f(Local local, FieldEntity field)) { |
264 boxedVariables.forEach((Local l) { | 314 boxedVariables.forEach((Local l) { |
265 // TODO(efortuna): add FieldEntities as created. | 315 // TODO(efortuna): add FieldEntities as created. |
266 f(l, null); | 316 f(l, null); |
267 }); | 317 }); |
268 } | 318 } |
269 | 319 |
270 bool localIsUsedInTryOrSync(Local variable) => | 320 bool localIsUsedInTryOrSync(Local variable) => |
271 localsUsedInTryOrSync.contains(variable); | 321 localsUsedInTryOrSync.contains(variable); |
272 | 322 |
273 String toString() { | 323 String toString() { |
274 StringBuffer sb = new StringBuffer(); | 324 StringBuffer sb = new StringBuffer(); |
275 sb.write('this=$thisLocal,'); | 325 sb.write('this=$thisLocal,'); |
276 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); | 326 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); |
277 return sb.toString(); | 327 return sb.toString(); |
278 } | 328 } |
279 | 329 |
280 bool isBoxed(Local variable) => boxedVariables.contains(variable); | 330 bool isBoxed(Local variable) => boxedVariables.contains(variable); |
281 } | 331 } |
282 | 332 |
283 class KernelCapturedScope extends KernelScopeInfo implements CapturedScope { | 333 class KernelCapturedScope extends KernelScopeInfo { |
284 final Local context; | 334 final ir.TreeNode context; |
285 | 335 |
286 KernelCapturedScope( | 336 KernelCapturedScope( |
287 Set<Local> boxedVariables, | 337 Set<ir.VariableDeclaration> boxedVariables, |
288 this.context, | 338 this.context, |
289 Set<Local> localsUsedInTryOrSync, | 339 Set<ir.VariableDeclaration> localsUsedInTryOrSync, |
290 Set<ir.VariableDeclaration> freeVariables, | 340 Set<ir.VariableDeclaration> freeVariables, |
291 Local thisLocal) | 341 bool hasThisLocal) |
292 : super.withBoxedVariables( | 342 : super.withBoxedVariables( |
293 boxedVariables, localsUsedInTryOrSync, freeVariables, thisLocal); | 343 boxedVariables, localsUsedInTryOrSync, freeVariables, hasThisLocal); |
294 | 344 |
295 bool get requiresContextBox => boxedVariables.isNotEmpty; | 345 bool get requiresContextBox => boxedVariables.isNotEmpty; |
296 } | 346 } |
297 | 347 |
298 class KernelCapturedLoopScope extends KernelCapturedScope | 348 class JsCapturedScope extends JsScopeInfo implements CapturedScope { |
299 implements CapturedLoopScope { | 349 final Local context; |
| 350 |
| 351 JsCapturedScope.from( |
| 352 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap) |
| 353 : this.context = localsMap.getLocalVariable(capturedScope.context), |
| 354 super.from(capturedScope, localsMap); |
| 355 |
| 356 bool get requiresContextBox => boxedVariables.isNotEmpty; |
| 357 } |
| 358 |
| 359 class KernelCapturedLoopScope extends KernelCapturedScope { |
| 360 final List<ir.VariableDeclaration> boxedLoopVariables; |
| 361 |
| 362 KernelCapturedLoopScope( |
| 363 Set<ir.VariableDeclaration> boxedVariables, |
| 364 this.boxedLoopVariables, |
| 365 ir.TreeNode context, |
| 366 Set<ir.VariableDeclaration> localsUsedInTryOrSync, |
| 367 Set<ir.VariableDeclaration> freeVariables, |
| 368 bool hasThisLocal) |
| 369 : super(boxedVariables, context, localsUsedInTryOrSync, freeVariables, |
| 370 hasThisLocal); |
| 371 |
| 372 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 373 } |
| 374 |
| 375 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope { |
300 final List<Local> boxedLoopVariables; | 376 final List<Local> boxedLoopVariables; |
301 | 377 |
302 KernelCapturedLoopScope( | 378 JsCapturedLoopScope.from( |
303 Set<Local> boxedVariables, | 379 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap) |
304 this.boxedLoopVariables, | 380 : this.boxedLoopVariables = capturedScope.boxedLoopVariables |
305 Local context, | 381 .map(localsMap.getLocalVariable) |
306 Set<Local> localsUsedInTryOrSync, | 382 .toList(), |
307 Set<ir.VariableDeclaration> freeVariables, | 383 super.from(capturedScope, localsMap); |
308 Local thisLocal) | |
309 : super(boxedVariables, context, localsUsedInTryOrSync, freeVariables, | |
310 thisLocal); | |
311 | 384 |
312 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 385 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
313 } | 386 } |
314 | 387 |
315 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. | 388 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. |
316 class KernelClosureClass extends KernelScopeInfo | 389 class KernelClosureClass extends JsScopeInfo |
317 implements ClosureRepresentationInfo, JClass { | 390 implements ClosureRepresentationInfo, JClass { |
318 final ir.Location location; | 391 final ir.Location location; |
319 | 392 |
320 final String name; | 393 final String name; |
321 final JLibrary library; | 394 final JLibrary library; |
322 | 395 |
323 /// Index into the classData, classList and classEnvironment lists where this | 396 /// Index into the classData, classList and classEnvironment lists where this |
324 /// entity is stored in [JsToFrontendMapImpl]. | 397 /// entity is stored in [JsToFrontendMapImpl]. |
325 int classIndex; | 398 int classIndex; |
326 | 399 |
327 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); | 400 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
328 | 401 |
329 KernelClosureClass.fromScopeInfo(this.name, this.library, | 402 KernelClosureClass.fromScopeInfo(this.name, this.library, |
330 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap) | 403 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap) |
331 : super.from(info.thisLocal, info) { | 404 : super.from(info, localsMap) { |
332 // Make a corresponding field entity in this closure class for every single | 405 // Make a corresponding field entity in this closure class for every single |
333 // freeVariable in the KernelScopeInfo.freeVariable. | 406 // freeVariable in the KernelScopeInfo.freeVariable. |
334 int i = 0; | 407 int i = 0; |
335 for (ir.VariableDeclaration variable in info.freeVariables) { | 408 for (ir.VariableDeclaration variable in info.freeVariables) { |
336 // NOTE: This construction order may be slightly different than the | 409 // NOTE: This construction order may be slightly different than the |
337 // old Element version. The old version did all the boxed items and then | 410 // old Element version. The old version did all the boxed items and then |
338 // all the others. | 411 // all the others. |
339 Local capturedLocal = localsMap.getLocalVariable(variable); | 412 Local capturedLocal = localsMap.getLocalVariable(variable); |
340 if (info.isBoxed(capturedLocal)) { | 413 if (isBoxed(capturedLocal)) { |
341 // TODO(efortuna): Coming soon. | 414 // TODO(efortuna): Coming soon. |
342 } else { | 415 } else { |
343 localToFieldMap[capturedLocal] = new ClosureField( | 416 localToFieldMap[capturedLocal] = new ClosureField( |
344 _getClosureVariableName(capturedLocal.name, i), | 417 _getClosureVariableName(capturedLocal.name, i), |
345 this, | 418 this, |
346 variable.isConst, | 419 variable.isConst, |
347 variable.isFinal || variable.isConst); | 420 variable.isFinal || variable.isConst); |
348 // TODO(efortuna): These probably need to get registered somewhere. | 421 // TODO(efortuna): These probably need to get registered somewhere. |
349 } | 422 } |
350 i++; | 423 i++; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 ClosureClassDefinition(this.cls, this.location); | 488 ClosureClassDefinition(this.cls, this.location); |
416 | 489 |
417 ClassKind get kind => ClassKind.closure; | 490 ClassKind get kind => ClassKind.closure; |
418 | 491 |
419 ir.Node get node => | 492 ir.Node get node => |
420 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); | 493 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); |
421 | 494 |
422 String toString() => | 495 String toString() => |
423 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; | 496 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; |
424 } | 497 } |
| 498 |
| 499 /// Collection of closure data collected for a single member. |
| 500 class ClosureModel { |
| 501 /// Collection [ScopeInfo] data for the member, if any. |
| 502 // TODO(johnniwinther): [scopeInfo] seem to be missing only for fields |
| 503 // without initializers; we shouldn't even create a [ClosureModel] in these |
| 504 // cases. |
| 505 KernelScopeInfo scopeInfo; |
| 506 |
| 507 /// Collected [CapturedScope] data for nodes. |
| 508 Map<ir.Node, KernelCapturedScope> capturedScopesMap = |
| 509 <ir.Node, KernelCapturedScope>{}; |
| 510 |
| 511 /// Collected [ScopeInfo] data for nodes. |
| 512 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = |
| 513 <ir.TreeNode, KernelScopeInfo>{}; |
| 514 } |
OLD | NEW |