| 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 |