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