| 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'; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 } | 172 } |
| 173 | 173 |
| 174 Expression get initializer { | 174 Expression get initializer { |
| 175 throw new SpannableAssertionFailure( | 175 throw new SpannableAssertionFailure( |
| 176 local, 'Should not access initializer of ClosureFieldElement.'); | 176 local, 'Should not access initializer of ClosureFieldElement.'); |
| 177 } | 177 } |
| 178 | 178 |
| 179 bool get isInstanceMember => true; | 179 bool get isInstanceMember => true; |
| 180 bool get isAssignable => false; | 180 bool get isAssignable => false; |
| 181 | 181 |
| 182 DartType computeType(Resolution resolution) => type; | 182 ResolutionDartType computeType(Resolution resolution) => type; |
| 183 | 183 |
| 184 DartType get type { | 184 ResolutionDartType get type { |
| 185 if (local is LocalElement) { | 185 if (local is LocalElement) { |
| 186 LocalElement element = local; | 186 LocalElement element = local; |
| 187 return element.type; | 187 return element.type; |
| 188 } | 188 } |
| 189 return const DynamicType(); | 189 return const ResolutionDynamicType(); |
| 190 } | 190 } |
| 191 | 191 |
| 192 String toString() => "ClosureFieldElement($name)"; | 192 String toString() => "ClosureFieldElement($name)"; |
| 193 | 193 |
| 194 accept(ElementVisitor visitor, arg) { | 194 accept(ElementVisitor visitor, arg) { |
| 195 return visitor.visitClosureFieldElement(this, arg); | 195 return visitor.visitClosureFieldElement(this, arg); |
| 196 } | 196 } |
| 197 | 197 |
| 198 Element get analyzableElement => closureClass.methodElement.analyzableElement; | 198 Element get analyzableElement => closureClass.methodElement.analyzableElement; |
| 199 | 199 |
| 200 @override | 200 @override |
| 201 List<FunctionElement> get nestedClosures => const <FunctionElement>[]; | 201 List<FunctionElement> get nestedClosures => const <FunctionElement>[]; |
| 202 | 202 |
| 203 @override | 203 @override |
| 204 bool get hasConstant => false; | 204 bool get hasConstant => false; |
| 205 | 205 |
| 206 @override | 206 @override |
| 207 ConstantExpression get constant => null; | 207 ConstantExpression get constant => null; |
| 208 } | 208 } |
| 209 | 209 |
| 210 // TODO(ahe): These classes continuously cause problems. We need to find | 210 // TODO(ahe): These classes continuously cause problems. We need to find |
| 211 // a more general solution. | 211 // a more general solution. |
| 212 class ClosureClassElement extends ClassElementX { | 212 class ClosureClassElement extends ClassElementX { |
| 213 DartType rawType; | 213 ResolutionDartType rawType; |
| 214 DartType thisType; | 214 ResolutionDartType thisType; |
| 215 FunctionType callType; | 215 ResolutionFunctionType callType; |
| 216 | 216 |
| 217 /// Node that corresponds to this closure, used for source position. | 217 /// Node that corresponds to this closure, used for source position. |
| 218 final FunctionExpression node; | 218 final FunctionExpression node; |
| 219 | 219 |
| 220 /** | 220 /** |
| 221 * The element for the declaration of the function expression. | 221 * The element for the declaration of the function expression. |
| 222 */ | 222 */ |
| 223 final LocalFunctionElement methodElement; | 223 final LocalFunctionElement methodElement; |
| 224 | 224 |
| 225 final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[]; | 225 final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[]; |
| 226 | 226 |
| 227 ClosureClassElement( | 227 ClosureClassElement( |
| 228 this.node, String name, Compiler compiler, LocalFunctionElement closure) | 228 this.node, String name, Compiler compiler, LocalFunctionElement closure) |
| 229 : this.methodElement = closure, | 229 : this.methodElement = closure, |
| 230 super( | 230 super( |
| 231 name, | 231 name, |
| 232 closure.compilationUnit, | 232 closure.compilationUnit, |
| 233 // By assigning a fresh class-id we make sure that the hashcode | 233 // By assigning a fresh class-id we make sure that the hashcode |
| 234 // is unique, but also emit closure classes after all other | 234 // is unique, but also emit closure classes after all other |
| 235 // classes (since the emitter sorts classes by their id). | 235 // classes (since the emitter sorts classes by their id). |
| 236 compiler.idGenerator.getNextFreeId(), | 236 compiler.idGenerator.getNextFreeId(), |
| 237 STATE_DONE) { | 237 STATE_DONE) { |
| 238 JavaScriptBackend backend = compiler.backend; | 238 JavaScriptBackend backend = compiler.backend; |
| 239 ClassElement superclass = methodElement.isInstanceMember | 239 ClassElement superclass = methodElement.isInstanceMember |
| 240 ? backend.helpers.boundClosureClass | 240 ? backend.helpers.boundClosureClass |
| 241 : backend.helpers.closureClass; | 241 : backend.helpers.closureClass; |
| 242 superclass.ensureResolved(compiler.resolution); | 242 superclass.ensureResolved(compiler.resolution); |
| 243 supertype = superclass.thisType; | 243 supertype = superclass.thisType; |
| 244 interfaces = const Link<DartType>(); | 244 interfaces = const Link<ResolutionDartType>(); |
| 245 thisType = rawType = new InterfaceType(this); | 245 thisType = rawType = new ResolutionInterfaceType(this); |
| 246 allSupertypesAndSelf = | 246 allSupertypesAndSelf = |
| 247 superclass.allSupertypesAndSelf.extendClass(thisType); | 247 superclass.allSupertypesAndSelf.extendClass(thisType); |
| 248 callType = methodElement.type; | 248 callType = methodElement.type; |
| 249 } | 249 } |
| 250 | 250 |
| 251 Iterable<ClosureFieldElement> get closureFields => _closureFields; | 251 Iterable<ClosureFieldElement> get closureFields => _closureFields; |
| 252 | 252 |
| 253 void addField(ClosureFieldElement field, DiagnosticReporter listener) { | 253 void addField(ClosureFieldElement field, DiagnosticReporter listener) { |
| 254 _closureFields.add(field); | 254 _closureFields.add(field); |
| 255 addMember(field, listener); | 255 addMember(field, listener); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 TypedElement, | 296 TypedElement, |
| 297 CapturedVariable, | 297 CapturedVariable, |
| 298 FieldElement, | 298 FieldElement, |
| 299 PrivatelyNamedJSEntity { | 299 PrivatelyNamedJSEntity { |
| 300 final BoxLocal box; | 300 final BoxLocal box; |
| 301 | 301 |
| 302 BoxFieldElement(String name, this.variableElement, BoxLocal box) | 302 BoxFieldElement(String name, this.variableElement, BoxLocal box) |
| 303 : this.box = box, | 303 : this.box = box, |
| 304 super(name, ElementKind.FIELD, box.executableContext); | 304 super(name, ElementKind.FIELD, box.executableContext); |
| 305 | 305 |
| 306 DartType computeType(Resolution resolution) => type; | 306 ResolutionDartType computeType(Resolution resolution) => type; |
| 307 | 307 |
| 308 DartType get type => variableElement.type; | 308 ResolutionDartType get type => variableElement.type; |
| 309 | 309 |
| 310 @override | 310 @override |
| 311 Entity get declaredEntity => variableElement; | 311 Entity get declaredEntity => variableElement; |
| 312 @override | 312 @override |
| 313 Entity get rootOfScope => box; | 313 Entity get rootOfScope => box; |
| 314 | 314 |
| 315 final VariableElement variableElement; | 315 final VariableElement variableElement; |
| 316 | 316 |
| 317 accept(ElementVisitor visitor, arg) { | 317 accept(ElementVisitor visitor, arg) { |
| 318 return visitor.visitBoxFieldElement(this, arg); | 318 return visitor.visitBoxFieldElement(this, arg); |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 closureData.variablesUsedInTryOrGenerator.add(variable); | 745 closureData.variablesUsedInTryOrGenerator.add(variable); |
| 746 } | 746 } |
| 747 } else if (variable is LocalParameterElement && | 747 } else if (variable is LocalParameterElement && |
| 748 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { | 748 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { |
| 749 // Parameters in a sync* function are shared between each Iterator created | 749 // Parameters in a sync* function are shared between each Iterator created |
| 750 // by the Iterable returned by the function, therefore they must be boxed. | 750 // by the Iterable returned by the function, therefore they must be boxed. |
| 751 closureData.variablesUsedInTryOrGenerator.add(variable); | 751 closureData.variablesUsedInTryOrGenerator.add(variable); |
| 752 } | 752 } |
| 753 } | 753 } |
| 754 | 754 |
| 755 void useTypeVariableAsLocal(TypeVariableType typeVariable) { | 755 void useTypeVariableAsLocal(ResolutionTypeVariableType typeVariable) { |
| 756 useLocal(new TypeVariableLocal(typeVariable, outermostElement)); | 756 useLocal(new TypeVariableLocal(typeVariable, outermostElement)); |
| 757 } | 757 } |
| 758 | 758 |
| 759 void declareLocal(LocalVariableElement element) { | 759 void declareLocal(LocalVariableElement element) { |
| 760 scopeVariables.add(element); | 760 scopeVariables.add(element); |
| 761 } | 761 } |
| 762 | 762 |
| 763 void registerNeedsThis() { | 763 void registerNeedsThis() { |
| 764 if (closureData.thisLocal != null) { | 764 if (closureData.thisLocal != null) { |
| 765 useLocal(closureData.thisLocal); | 765 useLocal(closureData.thisLocal); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 793 visit(arguments); | 793 visit(arguments); |
| 794 } | 794 } |
| 795 } else { | 795 } else { |
| 796 visit(definition); | 796 visit(definition); |
| 797 } | 797 } |
| 798 } | 798 } |
| 799 } | 799 } |
| 800 | 800 |
| 801 visitTypeAnnotation(TypeAnnotation node) { | 801 visitTypeAnnotation(TypeAnnotation node) { |
| 802 MemberElement member = executableContext.memberContext; | 802 MemberElement member = executableContext.memberContext; |
| 803 DartType type = elements.getType(node); | 803 ResolutionDartType type = elements.getType(node); |
| 804 // TODO(karlklose,johnniwinther): if the type is null, the annotation is | 804 // TODO(karlklose,johnniwinther): if the type is null, the annotation is |
| 805 // from a parameter which has been analyzed before the method has been | 805 // from a parameter which has been analyzed before the method has been |
| 806 // resolved and the result has been thrown away. | 806 // resolved and the result has been thrown away. |
| 807 if (compiler.options.enableTypeAssertions && | 807 if (compiler.options.enableTypeAssertions && |
| 808 type != null && | 808 type != null && |
| 809 type.containsTypeVariables) { | 809 type.containsTypeVariables) { |
| 810 if (insideClosure && member.isFactoryConstructor) { | 810 if (insideClosure && member.isFactoryConstructor) { |
| 811 // This is a closure in a factory constructor. Since there is no | 811 // This is a closure in a factory constructor. Since there is no |
| 812 // [:this:], we have to mark the type arguments as free variables to | 812 // [:this:], we have to mark the type arguments as free variables to |
| 813 // capture them in the closure. | 813 // capture them in the closure. |
| 814 type.forEachTypeVariable((TypeVariableType variable) { | 814 type.forEachTypeVariable((ResolutionTypeVariableType variable) { |
| 815 useTypeVariableAsLocal(variable); | 815 useTypeVariableAsLocal(variable); |
| 816 }); | 816 }); |
| 817 } | 817 } |
| 818 if (member.isInstanceMember && !member.isField) { | 818 if (member.isInstanceMember && !member.isField) { |
| 819 // In checked mode, using a type variable in a type annotation may lead | 819 // In checked mode, using a type variable in a type annotation may lead |
| 820 // to a runtime type check that needs to access the type argument and | 820 // to a runtime type check that needs to access the type argument and |
| 821 // therefore the closure needs a this-element, if it is not in a field | 821 // therefore the closure needs a this-element, if it is not in a field |
| 822 // initializer; field initatializers are evaluated in a context where | 822 // initializer; field initatializers are evaluated in a context where |
| 823 // the type arguments are available in locals. | 823 // the type arguments are available in locals. |
| 824 registerNeedsThis(); | 824 registerNeedsThis(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 851 } else if (element != null && element.isTypeVariable) { | 851 } else if (element != null && element.isTypeVariable) { |
| 852 TypeVariableElement variable = element; | 852 TypeVariableElement variable = element; |
| 853 analyzeType(variable.type); | 853 analyzeType(variable.type); |
| 854 } else if (node.receiver == null && | 854 } else if (node.receiver == null && |
| 855 Elements.isInstanceSend(node, elements)) { | 855 Elements.isInstanceSend(node, elements)) { |
| 856 registerNeedsThis(); | 856 registerNeedsThis(); |
| 857 } else if (node.isSuperCall) { | 857 } else if (node.isSuperCall) { |
| 858 registerNeedsThis(); | 858 registerNeedsThis(); |
| 859 } else if (node.isTypeTest || node.isTypeCast) { | 859 } else if (node.isTypeTest || node.isTypeCast) { |
| 860 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; | 860 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; |
| 861 DartType type = elements.getType(annotation); | 861 ResolutionDartType type = elements.getType(annotation); |
| 862 analyzeType(type); | 862 analyzeType(type); |
| 863 } else if (node.isTypeTest) { | 863 } else if (node.isTypeTest) { |
| 864 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 864 ResolutionDartType type = |
| 865 elements.getType(node.typeAnnotationFromIsCheckOrCast); |
| 865 analyzeType(type); | 866 analyzeType(type); |
| 866 } else if (node.isTypeCast) { | 867 } else if (node.isTypeCast) { |
| 867 DartType type = elements.getType(node.arguments.head); | 868 ResolutionDartType type = elements.getType(node.arguments.head); |
| 868 analyzeType(type); | 869 analyzeType(type); |
| 869 } | 870 } |
| 870 node.visitChildren(this); | 871 node.visitChildren(this); |
| 871 } | 872 } |
| 872 | 873 |
| 873 visitSendSet(SendSet node) { | 874 visitSendSet(SendSet node) { |
| 874 Element element = elements[node]; | 875 Element element = elements[node]; |
| 875 if (Elements.isLocal(element)) { | 876 if (Elements.isLocal(element)) { |
| 876 mutatedVariables.add(element); | 877 mutatedVariables.add(element); |
| 877 if (compiler.options.enableTypeAssertions) { | 878 if (compiler.options.enableTypeAssertions) { |
| 878 TypedElement typedElement = element; | 879 TypedElement typedElement = element; |
| 879 analyzeTypeVariables(typedElement.type); | 880 analyzeTypeVariables(typedElement.type); |
| 880 } | 881 } |
| 881 } | 882 } |
| 882 super.visitSendSet(node); | 883 super.visitSendSet(node); |
| 883 } | 884 } |
| 884 | 885 |
| 885 visitNewExpression(NewExpression node) { | 886 visitNewExpression(NewExpression node) { |
| 886 DartType type = elements.getType(node); | 887 ResolutionDartType type = elements.getType(node); |
| 887 analyzeType(type); | 888 analyzeType(type); |
| 888 node.visitChildren(this); | 889 node.visitChildren(this); |
| 889 } | 890 } |
| 890 | 891 |
| 891 visitLiteralList(LiteralList node) { | 892 visitLiteralList(LiteralList node) { |
| 892 DartType type = elements.getType(node); | 893 ResolutionDartType type = elements.getType(node); |
| 893 analyzeType(type); | 894 analyzeType(type); |
| 894 node.visitChildren(this); | 895 node.visitChildren(this); |
| 895 } | 896 } |
| 896 | 897 |
| 897 visitLiteralMap(LiteralMap node) { | 898 visitLiteralMap(LiteralMap node) { |
| 898 DartType type = elements.getType(node); | 899 ResolutionDartType type = elements.getType(node); |
| 899 analyzeType(type); | 900 analyzeType(type); |
| 900 node.visitChildren(this); | 901 node.visitChildren(this); |
| 901 } | 902 } |
| 902 | 903 |
| 903 void analyzeTypeVariables(DartType type) { | 904 void analyzeTypeVariables(ResolutionDartType type) { |
| 904 type.forEachTypeVariable((TypeVariableType typeVariable) { | 905 type.forEachTypeVariable((ResolutionTypeVariableType typeVariable) { |
| 905 // Field initializers are inlined and access the type variable as | 906 // Field initializers are inlined and access the type variable as |
| 906 // normal parameters. | 907 // normal parameters. |
| 907 if (!outermostElement.isField && !outermostElement.isConstructor) { | 908 if (!outermostElement.isField && !outermostElement.isConstructor) { |
| 908 registerNeedsThis(); | 909 registerNeedsThis(); |
| 909 } else { | 910 } else { |
| 910 useTypeVariableAsLocal(typeVariable); | 911 useTypeVariableAsLocal(typeVariable); |
| 911 } | 912 } |
| 912 }); | 913 }); |
| 913 } | 914 } |
| 914 | 915 |
| 915 void analyzeType(DartType type) { | 916 void analyzeType(ResolutionDartType type) { |
| 916 // TODO(johnniwinther): Find out why this can be null. | 917 // TODO(johnniwinther): Find out why this can be null. |
| 917 if (type == null) return; | 918 if (type == null) return; |
| 918 if (outermostElement.isClassMember && | 919 if (outermostElement.isClassMember && |
| 919 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { | 920 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { |
| 920 if (outermostElement.isConstructor || outermostElement.isField) { | 921 if (outermostElement.isConstructor || outermostElement.isField) { |
| 921 analyzeTypeVariables(type); | 922 analyzeTypeVariables(type); |
| 922 } else if (outermostElement.isInstanceMember) { | 923 } else if (outermostElement.isInstanceMember) { |
| 923 if (type.containsTypeVariables) { | 924 if (type.containsTypeVariables) { |
| 924 registerNeedsThis(); | 925 registerNeedsThis(); |
| 925 } | 926 } |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1111 thisElement = new ThisLocal(element); | 1112 thisElement = new ThisLocal(element); |
| 1112 } | 1113 } |
| 1113 closureData = new ClosureClassMap(null, null, null, thisElement); | 1114 closureData = new ClosureClassMap(null, null, null, thisElement); |
| 1114 } | 1115 } |
| 1115 closureMappingCache[element.declaration] = closureData; | 1116 closureMappingCache[element.declaration] = closureData; |
| 1116 if (closureData.callElement != null) { | 1117 if (closureData.callElement != null) { |
| 1117 closureMappingCache[closureData.callElement] = closureData; | 1118 closureMappingCache[closureData.callElement] = closureData; |
| 1118 } | 1119 } |
| 1119 | 1120 |
| 1120 inNewScope(node, () { | 1121 inNewScope(node, () { |
| 1121 DartType type = element.type; | 1122 ResolutionDartType type = element.type; |
| 1122 // If the method needs RTI, or checked mode is set, we need to | 1123 // If the method needs RTI, or checked mode is set, we need to |
| 1123 // escape the potential type variables used in that closure. | 1124 // escape the potential type variables used in that closure. |
| 1124 if (element is FunctionElement && | 1125 if (element is FunctionElement && |
| 1125 (compiler.backend.methodNeedsRti(element) || | 1126 (compiler.backend.methodNeedsRti(element) || |
| 1126 compiler.options.enableTypeAssertions)) { | 1127 compiler.options.enableTypeAssertions)) { |
| 1127 analyzeTypeVariables(type); | 1128 analyzeTypeVariables(type); |
| 1128 } | 1129 } |
| 1129 | 1130 |
| 1130 visitChildren(); | 1131 visitChildren(); |
| 1131 }); | 1132 }); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1189 // An `await for` loop is enclosed in an implicit try-finally. | 1190 // An `await for` loop is enclosed in an implicit try-finally. |
| 1190 bool oldInTryStatement = inTryStatement; | 1191 bool oldInTryStatement = inTryStatement; |
| 1191 inTryStatement = true; | 1192 inTryStatement = true; |
| 1192 visitLoop(node); | 1193 visitLoop(node); |
| 1193 inTryStatement = oldInTryStatement; | 1194 inTryStatement = oldInTryStatement; |
| 1194 } | 1195 } |
| 1195 } | 1196 } |
| 1196 | 1197 |
| 1197 /// A type variable as a local variable. | 1198 /// A type variable as a local variable. |
| 1198 class TypeVariableLocal implements Local { | 1199 class TypeVariableLocal implements Local { |
| 1199 final TypeVariableType typeVariable; | 1200 final ResolutionTypeVariableType typeVariable; |
| 1200 final ExecutableElement executableContext; | 1201 final ExecutableElement executableContext; |
| 1201 | 1202 |
| 1202 TypeVariableLocal(this.typeVariable, this.executableContext); | 1203 TypeVariableLocal(this.typeVariable, this.executableContext); |
| 1203 | 1204 |
| 1204 String get name => typeVariable.name; | 1205 String get name => typeVariable.name; |
| 1205 | 1206 |
| 1206 int get hashCode => typeVariable.hashCode; | 1207 int get hashCode => typeVariable.hashCode; |
| 1207 | 1208 |
| 1208 bool operator ==(other) { | 1209 bool operator ==(other) { |
| 1209 if (other is! TypeVariableLocal) return false; | 1210 if (other is! TypeVariableLocal) return false; |
| 1210 return typeVariable == other.typeVariable; | 1211 return typeVariable == other.typeVariable; |
| 1211 } | 1212 } |
| 1212 } | 1213 } |
| 1213 | 1214 |
| 1214 /// | 1215 /// |
| 1215 /// Move the below classes to a JS model eventually. | 1216 /// Move the below classes to a JS model eventually. |
| 1216 /// | 1217 /// |
| 1217 abstract class JSEntity implements Entity { | 1218 abstract class JSEntity implements Entity { |
| 1218 Entity get declaredEntity; | 1219 Entity get declaredEntity; |
| 1219 } | 1220 } |
| 1220 | 1221 |
| 1221 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1222 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1222 Entity get rootOfScope; | 1223 Entity get rootOfScope; |
| 1223 } | 1224 } |
| OLD | NEW |