OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library closureToClassMapper; | 5 library closureToClassMapper; |
6 | 6 |
7 import 'common/names.dart' show Identifiers; | 7 import 'common/names.dart' show Identifiers; |
8 import 'common/resolution.dart' show ParsingContext, Resolution; | 8 import 'common/resolution.dart' show ParsingContext, Resolution; |
9 import 'common/tasks.dart' show CompilerTask; | 9 import 'common/tasks.dart' show CompilerTask; |
10 import 'common.dart'; | 10 import 'common.dart'; |
11 import 'compiler.dart' show Compiler; | 11 import 'compiler.dart' show Compiler; |
12 import 'constants/expressions.dart'; | 12 import 'constants/expressions.dart'; |
13 import 'elements/elements.dart'; | 13 import 'elements/elements.dart'; |
14 import 'elements/entities.dart'; | 14 import 'elements/entities.dart'; |
15 import 'elements/entity_utils.dart' as utils; | 15 import 'elements/entity_utils.dart' as utils; |
16 import 'elements/modelx.dart' | 16 import 'elements/modelx.dart' |
17 show BaseFunctionElementX, ClassElementX, ElementX; | 17 show BaseFunctionElementX, ClassElementX, ElementX; |
18 import 'elements/resolution_types.dart'; | 18 import 'elements/resolution_types.dart'; |
19 import 'elements/types.dart'; | 19 import 'elements/types.dart'; |
20 import 'elements/visitor.dart' show ElementVisitor; | 20 import 'elements/visitor.dart' show ElementVisitor; |
21 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 21 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
22 import 'resolution/tree_elements.dart' show TreeElements; | 22 import 'resolution/tree_elements.dart' show TreeElements; |
23 import 'package:front_end/src/fasta/scanner.dart' show Token; | 23 import 'package:front_end/src/fasta/scanner.dart' show Token; |
24 import 'tree/tree.dart'; | 24 import 'tree/tree.dart'; |
25 import 'util/util.dart'; | 25 import 'util/util.dart'; |
26 import 'world.dart' show ClosedWorldRefiner; | 26 import 'world.dart' show ClosedWorldRefiner; |
27 | 27 |
28 /// Where T is ir.Node or Node. | 28 /// Where T is ir.Node or Node. |
| 29 // TODO(efortuna): Rename this class. |
29 abstract class ClosureClassMaps<T> { | 30 abstract class ClosureClassMaps<T> { |
30 ClosureClassMap getMemberMap(MemberEntity member); | 31 ClosureClassMap getMemberMap(MemberEntity member); |
31 ClosureClassMap getLocalFunctionMap(Local localFunction); | 32 ClosureClassMap getLocalFunctionMap(Local localFunction); |
32 | 33 |
| 34 /// Look up information about the variables that have been mutated and are |
| 35 /// used inside the scope of [node]. |
| 36 // TODO(efortuna): Node for consistency with other interface. |
| 37 ClosureRepresentationInfo getClosureRepresentationInfo(Entity member); |
| 38 |
33 /// Look up information about a loop, in case any variables it declares need | 39 /// Look up information about a loop, in case any variables it declares need |
34 /// to be boxed/snapshotted. | 40 /// to be boxed/snapshotted. |
35 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop(T loopNode); | 41 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop(T loopNode); |
36 | 42 |
37 /// Accessor to the information about closures that the SSA builder will use. | 43 /// Accessor to the information about closures that the SSA builder will use. |
38 ClosureAnalysisInfo getClosureAnalysisInfo(T node); | 44 ClosureAnalysisInfo getClosureAnalysisInfo(T node); |
39 } | 45 } |
40 | 46 |
| 47 /// Class that describes the actual mechanics of how the converted, rewritten |
| 48 /// closure is implemented. For example, for the following closure (named foo |
| 49 /// for convenience): |
| 50 /// |
| 51 /// var foo = (x) => y + x; |
| 52 /// |
| 53 /// We would produce the following class to control access to these variables in |
| 54 /// the following way (modulo naming of variables, assuming that y is modified |
| 55 /// elsewhere in its scope): |
| 56 /// |
| 57 /// class FooClosure { |
| 58 /// int y; |
| 59 /// FooClosure(this.y); |
| 60 /// call(x) => this.y + x; |
| 61 /// } |
| 62 /// |
| 63 /// and then to execute this closure, for example: |
| 64 /// |
| 65 /// var foo = new FooClosure(1); |
| 66 /// foo.call(2); |
| 67 /// |
| 68 /// if y is modified elsewhere within its scope, accesses to y anywhere in the |
| 69 /// code will be controlled via a box object. |
| 70 /// I expect this interface to get simpler in subsequent refactorings. |
| 71 class ClosureRepresentationInfo { |
| 72 const ClosureRepresentationInfo(); |
| 73 |
| 74 /// Accessor to the local environment in which a particular closure node is |
| 75 /// executed. This will encapsulate the value of any variables that have been |
| 76 /// scoped into this context from outside. |
| 77 Local get context => null; |
| 78 |
| 79 /// The original local function before any translation. |
| 80 /// |
| 81 /// Will be null for methods. // TODO(efortuna): last part -- what? |
| 82 Local get closureElement => null; |
| 83 |
| 84 /// Closures are rewritten in the form of classes that |
| 85 /// have fields to control the redirection and editing of variables that are |
| 86 /// "captured" inside a scope (declared in an outer scope but used in an |
| 87 /// inside scope). So this returns the class entity that represents this |
| 88 /// particular rewritten closure. |
| 89 ClassEntity get closureClassEntity => null; |
| 90 |
| 91 /// The function that implements the [local] function as a `call` method on |
| 92 /// the closure class. |
| 93 FunctionEntity get callEntity => null; |
| 94 |
| 95 /// As shown in the example in the comments at the top of this class, we |
| 96 /// create fields in the closure class for each captured variable. This is an |
| 97 /// accessor to that set of fields. |
| 98 List<Local> get createdFieldEntities => const <Local>[]; |
| 99 |
| 100 /// Convenience reference pointer to the element representing `this`. |
| 101 /// It is only set for instance-members. |
| 102 Local get thisLocal => null; |
| 103 |
| 104 /// Convenience pointer to the field entity representation in the closure |
| 105 /// class of the element representing `this`. |
| 106 FieldEntity get thisFieldEntity => null; |
| 107 |
| 108 /// Returns true if this [variable] is used inside a `try` block or a `sync*` |
| 109 /// generator (this is important to know because boxing/redirection needs to |
| 110 /// happen for those local variables). |
| 111 /// |
| 112 /// Variables that are used in a try must be treated as boxed because the |
| 113 /// control flow can be non-linear. |
| 114 /// |
| 115 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 116 /// we rewrite sync* functions. See also comments in |
| 117 /// [ClosureClassMap.useLocal]. |
| 118 // TODO(efortuna): this feels like it should be in the ClosureAnalysisData |
| 119 // section. |
| 120 bool isVariableUsedInTryOrSync(Local variable) => false; |
| 121 |
| 122 /// Loop through every variable that has been captured exclusively in this |
| 123 /// current closure. Each [variable] has been "converted" to a [field] member |
| 124 /// in the closure class. |
| 125 void forEachCreatedField(f(Local variable, FieldEntity field)) {} |
| 126 |
| 127 /// Loop through every variable that has been captured in this closure. This |
| 128 /// consists of all the free variables (variables captured *just* in this |
| 129 /// closure) and all variables captured in nested scopes that we may be |
| 130 /// capturing as well. These nested scopes hold "boxes" to hold the executable |
| 131 /// context for that scope. |
| 132 void forEachCapturedVariable(f(Local from, Local to)) {} |
| 133 |
| 134 /// Loop through each variable that has been boxed in this closure class. Only |
| 135 /// captured variables that are mutated need to be "boxed" (which basically |
| 136 /// puts a thin layer between updates and reads to this variable to ensure tha
t |
| 137 /// every place that accesses it gets the correct updated value). |
| 138 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} |
| 139 } |
| 140 |
41 /// Class that provides a black-box interface to information gleaned from | 141 /// Class that provides a black-box interface to information gleaned from |
42 /// analyzing a closure's characteristics, most commonly used to influence how | 142 /// analyzing a closure's characteristics, most commonly used to influence how |
43 /// code should be generated in SSA builder stage. | 143 /// code should be generated in SSA builder stage. |
44 class ClosureAnalysisInfo { | 144 class ClosureAnalysisInfo { |
45 const ClosureAnalysisInfo(); | 145 const ClosureAnalysisInfo(); |
46 | 146 |
47 /// If true, this closure accesses a variable that was defined in an outside | 147 /// If true, this closure accesses a variable that was defined in an outside |
48 /// scope and this variable gets modified at some point (sometimes we say that | 148 /// scope and this variable gets modified at some point (sometimes we say that |
49 /// variable has been "captured"). In this situation, access to this variable | 149 /// variable has been "captured"). In this situation, access to this variable |
50 /// is controlled via a wrapper (box) so that updates to this variable | 150 /// is controlled via a wrapper (box) so that updates to this variable |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 var value = _closureInfoMap[node]; | 210 var value = _closureInfoMap[node]; |
111 return value == null ? const ClosureAnalysisInfo() : value; | 211 return value == null ? const ClosureAnalysisInfo() : value; |
112 } | 212 } |
113 | 213 |
114 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( | 214 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( |
115 Node loopNode) { | 215 Node loopNode) { |
116 var value = _closureInfoMap[loopNode]; | 216 var value = _closureInfoMap[loopNode]; |
117 return value == null ? const LoopClosureRepresentationInfo() : value; | 217 return value == null ? const LoopClosureRepresentationInfo() : value; |
118 } | 218 } |
119 | 219 |
| 220 ClosureRepresentationInfo getClosureRepresentationInfo(Element member) { |
| 221 return getClosureToClassMapping(member); |
| 222 } |
| 223 |
120 ClosureClassMap getMemberMap(MemberElement member) { | 224 ClosureClassMap getMemberMap(MemberElement member) { |
121 return getClosureToClassMapping(member); | 225 return getClosureToClassMapping(member); |
122 } | 226 } |
123 | 227 |
124 ClosureClassMap getLocalFunctionMap(LocalFunctionElement localFunction) { | 228 ClosureClassMap _getLocalFunctionMap(LocalFunctionElement localFunction) { |
125 return getClosureToClassMapping(localFunction); | 229 return getClosureToClassMapping(localFunction); |
126 } | 230 } |
127 | 231 |
128 /// Returns the [ClosureClassMap] computed for [resolvedAst]. | 232 /// Returns the [ClosureClassMap] computed for [resolvedAst]. |
129 ClosureClassMap getClosureToClassMapping(Element element) { | 233 ClosureClassMap getClosureToClassMapping(Element element) { |
130 return measure(() { | 234 return measure(() { |
131 if (element.isGenerativeConstructorBody) { | 235 if (element.isGenerativeConstructorBody) { |
132 ConstructorBodyElement constructorBody = element; | 236 ConstructorBodyElement constructorBody = element; |
133 element = constructorBody.constructor; | 237 element = constructorBody.constructor; |
134 } | 238 } |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 bool get isTopLevel => true; | 449 bool get isTopLevel => true; |
346 | 450 |
347 get enclosingElement => methodElement; | 451 get enclosingElement => methodElement; |
348 | 452 |
349 accept(ElementVisitor visitor, arg) { | 453 accept(ElementVisitor visitor, arg) { |
350 return visitor.visitClosureClassElement(this, arg); | 454 return visitor.visitClosureClassElement(this, arg); |
351 } | 455 } |
352 } | 456 } |
353 | 457 |
354 /// A local variable that contains the box object holding the [BoxFieldElement] | 458 /// A local variable that contains the box object holding the [BoxFieldElement] |
355 /// fields. | 459 /// fields. // this is a "local variable" corresponding to the executable |
| 460 //context (for a particular BoxFieldElement). |
356 class BoxLocal extends Local { | 461 class BoxLocal extends Local { |
357 final String name; | 462 final String name; |
358 final ExecutableElement executableContext; | 463 final ExecutableElement executableContext; |
359 | 464 |
360 final int hashCode = _nextHashCode = (_nextHashCode + 10007).toUnsigned(30); | 465 final int hashCode = _nextHashCode = (_nextHashCode + 10007).toUnsigned(30); |
361 static int _nextHashCode = 0; | 466 static int _nextHashCode = 0; |
362 | 467 |
363 BoxLocal(this.name, this.executableContext); | 468 BoxLocal(this.name, this.executableContext); |
364 | 469 |
365 @override | 470 @override |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 } | 635 } |
531 if (capturedVariables.isNotEmpty) { | 636 if (capturedVariables.isNotEmpty) { |
532 sb.write(separator); | 637 sb.write(separator); |
533 sb.write('capturedVariables=$capturedVariables'); | 638 sb.write('capturedVariables=$capturedVariables'); |
534 } | 639 } |
535 sb.write(')'); | 640 sb.write(')'); |
536 return sb.toString(); | 641 return sb.toString(); |
537 } | 642 } |
538 } | 643 } |
539 | 644 |
540 class ClosureClassMap { | 645 class ClosureClassMap implements ClosureRepresentationInfo { |
541 /// The local function element before any translation. | 646 /// The local function element before any translation. |
542 /// | 647 /// |
543 /// Will be null for methods. | 648 /// Will be null for methods. |
544 final LocalFunctionElement closureElement; | 649 final LocalFunctionElement closureElement; |
545 | 650 |
546 /// The synthesized closure class for [closureElement]. | 651 /// The synthesized closure class for [closureElement]. |
547 /// | 652 /// |
548 /// The closureClassElement will be null for methods that are not local | 653 /// The closureClassEntity will be null for methods that are not local |
549 /// closures. | 654 /// closures. |
550 final ClosureClassElement closureClassElement; | 655 final ClosureClassElement closureClassEntity; |
551 | 656 |
552 /// The synthesized `call` method of the [ closureClassElement]. | 657 /// The synthesized `call` method of the [ closureClassEntity]. |
553 /// | 658 /// |
554 /// The callElement will be null for methods that are not local closures. | 659 /// The callEntity will be null for methods that are not local closures. |
555 final MethodElement callElement; | 660 final MethodElement callEntity; |
556 | 661 |
557 /// The [thisElement] makes handling 'this' easier by treating it like any | 662 /// The [thisElement] makes handling 'this' easier by treating it like any |
558 /// other argument. It is only set for instance-members. | 663 /// other argument. It is only set for instance-members. |
559 final ThisLocal thisLocal; | 664 final ThisLocal thisLocal; |
560 | 665 |
561 /// Maps free locals, arguments, function elements, and box locals to | 666 /// Maps free locals, arguments, function elements, and box locals to |
562 /// their locations. | 667 /// their locations. |
563 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); | 668 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); |
564 | 669 |
565 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScope] which | 670 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScope] which |
566 /// contains their box and the captured variables that are stored in the box. | 671 /// contains their box and the captured variables that are stored in the box. |
567 /// This map will be empty if the method/closure of this [ClosureData] does | 672 /// This map will be empty if the method/closure of this [ClosureData] does |
568 /// not contain any nested closure. | 673 /// not contain any nested closure. |
569 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 674 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
570 | 675 |
571 /// Variables that are used in a try must be treated as boxed because the | 676 /// Variables that are used in a try must be treated as boxed because the |
572 /// control flow can be non-linear. | 677 /// control flow can be non-linear. |
573 /// | 678 /// |
574 /// Also parameters to a `sync*` generator must be boxed, because of the way | 679 /// Also parameters to a `sync*` generator must be boxed, because of the way |
575 /// we rewrite sync* functions. See also comments in [useLocal]. | 680 /// we rewrite sync* functions. See also comments in [useLocal]. |
576 // TODO(johnniwinther): Add variables to this only if the variable is mutated. | 681 // TODO(johnniwinther): Add variables to this only if the variable is mutated. |
577 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); | 682 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
578 | 683 |
579 ClosureClassMap(this.closureElement, this.closureClassElement, | 684 ClosureClassMap(this.closureElement, this.closureClassEntity, this.callEntity, |
580 this.callElement, this.thisLocal); | 685 this.thisLocal); |
| 686 |
| 687 List<Local> get createdFieldEntities { |
| 688 List<Local> fields = <Local>[]; |
| 689 closureClassEntity.closureFields.forEach((field) { |
| 690 fields.add(field.local); |
| 691 }); |
| 692 return fields; |
| 693 } |
581 | 694 |
582 void addFreeVariable(Local element) { | 695 void addFreeVariable(Local element) { |
583 assert(freeVariableMap[element] == null); | 696 assert(freeVariableMap[element] == null); |
584 freeVariableMap[element] = null; | 697 freeVariableMap[element] = null; |
585 } | 698 } |
586 | 699 |
587 Iterable<Local> get freeVariables => freeVariableMap.keys; | 700 Iterable<Local> get freeVariables => freeVariableMap.keys; |
588 | 701 |
589 bool isFreeVariable(Local element) { | 702 bool isFreeVariable(Local element) { |
590 return freeVariableMap.containsKey(element); | 703 return freeVariableMap.containsKey(element); |
591 } | 704 } |
592 | 705 |
| 706 bool isVariableUsedInTryOrSync(Local variable) => |
| 707 variablesUsedInTryOrGenerator.contains(variable); |
| 708 |
593 void forEachFreeVariable(f(Local variable, FieldEntity field)) { | 709 void forEachFreeVariable(f(Local variable, FieldEntity field)) { |
594 freeVariableMap.forEach(f); | 710 freeVariableMap.forEach(f); |
595 } | 711 } |
596 | 712 |
| 713 FieldEntity get thisFieldEntity => freeVariableMap[thisLocal]; |
| 714 |
597 bool isVariableUsedInTryOrSync(Local variable) => | 715 bool isVariableUsedInTryOrSync(Local variable) => |
598 variablesUsedInTryOrGenerator.contains(variable); | 716 variablesUsedInTryOrGenerator.contains(variable); |
599 | 717 |
600 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 718 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
601 return field.local; | 719 return field.local; |
602 } | 720 } |
603 | 721 |
604 bool get isClosure => closureElement != null; | 722 bool get isClosure => closureElement != null; |
605 | 723 |
606 bool capturingScopesBox(Local variable) { | 724 bool capturingScopesBox(Local variable) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); | 785 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); |
668 | 786 |
669 MemberElement outermostElement; | 787 MemberElement outermostElement; |
670 ExecutableElement executableContext; | 788 ExecutableElement executableContext; |
671 | 789 |
672 // The closureData of the currentFunctionElement. | 790 // The closureData of the currentFunctionElement. |
673 ClosureClassMap closureData; | 791 ClosureClassMap closureData; |
674 | 792 |
675 bool insideClosure = false; | 793 bool insideClosure = false; |
676 | 794 |
| 795 Map<Node, Local> executableContextCache; |
| 796 Map<Node, ClosureScope> closureInfo; |
| 797 |
677 ClosureTranslator(this.compiler, this.closedWorldRefiner, this.elements, | 798 ClosureTranslator(this.compiler, this.closedWorldRefiner, this.elements, |
678 this.closureMappingCache, this.closureInfo); | 799 this.closureMappingCache, this.closureInfo); |
679 | 800 |
680 DiagnosticReporter get reporter => compiler.reporter; | 801 DiagnosticReporter get reporter => compiler.reporter; |
681 | 802 |
682 /// Generate a unique name for the [id]th closure field, with proposed name | 803 /// Generate a unique name for the [id]th closure field, with proposed name |
683 /// [name]. | 804 /// [name]. |
684 /// | 805 /// |
685 /// The result is used as the name of [ClosureFieldElement]s, and must | 806 /// The result is used as the name of [ClosureFieldElement]s, and must |
686 /// therefore be unique to avoid breaking an invariant in the element model | 807 /// therefore be unique to avoid breaking an invariant in the element model |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 if (boxFieldElement == null) { | 892 if (boxFieldElement == null) { |
772 assert(fromElement is! BoxLocal); | 893 assert(fromElement is! BoxLocal); |
773 // The variable has not been boxed. | 894 // The variable has not been boxed. |
774 fieldCaptures.add(fromElement); | 895 fieldCaptures.add(fromElement); |
775 } else { | 896 } else { |
776 // A boxed element. | 897 // A boxed element. |
777 data.freeVariableMap[fromElement] = boxFieldElement; | 898 data.freeVariableMap[fromElement] = boxFieldElement; |
778 boxes.add(boxFieldElement.box); | 899 boxes.add(boxFieldElement.box); |
779 } | 900 } |
780 }); | 901 }); |
781 ClosureClassElement closureClass = data.closureClassElement; | 902 ClosureClassElement closureClass = data.closureClassEntity; |
782 assert(closureClass != null || (fieldCaptures.isEmpty && boxes.isEmpty)); | 903 assert(closureClass != null || (fieldCaptures.isEmpty && boxes.isEmpty)); |
783 | 904 |
784 void addClosureField(Local local, String name) { | 905 void addClosureField(Local local, String name) { |
785 ClosureFieldElement closureField = | 906 ClosureFieldElement closureField = |
786 new ClosureFieldElement(name, local, closureClass); | 907 new ClosureFieldElement(name, local, closureClass); |
787 closureClass.addField(closureField, reporter); | 908 closureClass.addField(closureField, reporter); |
788 data.freeVariableMap[local] = closureField; | 909 data.freeVariableMap[local] = closureField; |
789 } | 910 } |
790 | 911 |
791 // Add the box elements first so we get the same ordering. | 912 // Add the box elements first so we get the same ordering. |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 thisElement = new ThisLocal(member); | 1335 thisElement = new ThisLocal(member); |
1215 } | 1336 } |
1216 closureData = new ClosureClassMap(null, null, null, thisElement); | 1337 closureData = new ClosureClassMap(null, null, null, thisElement); |
1217 if (element is MethodElement) { | 1338 if (element is MethodElement) { |
1218 needsRti = compiler.options.enableTypeAssertions || | 1339 needsRti = compiler.options.enableTypeAssertions || |
1219 compiler.backend.rtiNeed.methodNeedsRti(element); | 1340 compiler.backend.rtiNeed.methodNeedsRti(element); |
1220 } | 1341 } |
1221 } | 1342 } |
1222 closureMappingCache[element] = closureData; | 1343 closureMappingCache[element] = closureData; |
1223 closureMappingCache[element.declaration] = closureData; | 1344 closureMappingCache[element.declaration] = closureData; |
1224 if (closureData.callElement != null) { | 1345 if (closureData.callEntity != null) { |
1225 closureMappingCache[closureData.callElement] = closureData; | 1346 closureMappingCache[closureData.callEntity] = closureData; |
1226 } | 1347 } |
1227 | 1348 |
1228 inNewScope(node, () { | 1349 inNewScope(node, () { |
1229 // If the method needs RTI, or checked mode is set, we need to | 1350 // If the method needs RTI, or checked mode is set, we need to |
1230 // escape the potential type variables used in that closure. | 1351 // escape the potential type variables used in that closure. |
1231 if (needsRti) { | 1352 if (needsRti) { |
1232 analyzeTypeVariables(element.type); | 1353 analyzeTypeVariables(element.type); |
1233 } | 1354 } |
1234 | 1355 |
1235 visitChildren(); | 1356 visitChildren(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1335 /// | 1456 /// |
1336 /// Move the below classes to a JS model eventually. | 1457 /// Move the below classes to a JS model eventually. |
1337 /// | 1458 /// |
1338 abstract class JSEntity implements MemberEntity { | 1459 abstract class JSEntity implements MemberEntity { |
1339 Local get declaredEntity; | 1460 Local get declaredEntity; |
1340 } | 1461 } |
1341 | 1462 |
1342 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1463 abstract class PrivatelyNamedJSEntity implements JSEntity { |
1343 Entity get rootOfScope; | 1464 Entity get rootOfScope; |
1344 } | 1465 } |
OLD | NEW |