| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 | 2 |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
| 7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| 11 import 'package:analyzer/dart/ast/standard_ast_factory.dart'; | 11 import 'package:analyzer/dart/ast/standard_ast_factory.dart'; |
| 12 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 12 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| 13 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | 13 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
| 14 import 'package:analyzer/dart/element/element.dart'; | 14 import 'package:analyzer/dart/element/element.dart'; |
| 15 import 'package:analyzer/dart/element/type.dart'; | 15 import 'package:analyzer/dart/element/type.dart'; |
| 16 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; | 16 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; |
| 17 import 'package:analyzer/src/dart/element/element.dart' | 17 import 'package:analyzer/src/dart/element/element.dart' |
| 18 show LocalVariableElementImpl; | 18 show FieldElementImpl, LocalVariableElementImpl; |
| 19 import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl; | 19 import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl; |
| 20 import 'package:analyzer/src/dart/sdk/sdk.dart'; | 20 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| 21 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 21 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 22 import 'package:analyzer/src/generated/resolver.dart' | 22 import 'package:analyzer/src/generated/resolver.dart' |
| 23 show TypeProvider, NamespaceBuilder; | 23 show TypeProvider, NamespaceBuilder; |
| 24 import 'package:analyzer/src/generated/type_system.dart' | 24 import 'package:analyzer/src/generated/type_system.dart' |
| 25 show StrongTypeSystemImpl; | 25 show StrongTypeSystemImpl; |
| 26 import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit; | 26 import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit; |
| 27 import 'package:analyzer/src/summary/link.dart' as summary_link; | 27 import 'package:analyzer/src/summary/link.dart' as summary_link; |
| 28 import 'package:analyzer/src/summary/package_bundle_reader.dart'; | 28 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| 29 import 'package:analyzer/src/summary/summarize_ast.dart' | 29 import 'package:analyzer/src/summary/summarize_ast.dart' |
| 30 show serializeAstUnlinked; | 30 show serializeAstUnlinked; |
| 31 import 'package:analyzer/src/summary/summarize_elements.dart' | 31 import 'package:analyzer/src/summary/summarize_elements.dart' |
| 32 show PackageBundleAssembler; | 32 show PackageBundleAssembler; |
| 33 import 'package:analyzer/src/summary/summary_sdk.dart'; | 33 import 'package:analyzer/src/summary/summary_sdk.dart'; |
| 34 import 'package:analyzer/src/task/strong/ast_properties.dart' | 34 import 'package:analyzer/src/task/strong/ast_properties.dart' |
| 35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast; | 35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast; |
| 36 import 'package:path/path.dart' show separator; | 36 import 'package:path/path.dart' show separator; |
| 37 | 37 |
| 38 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 38 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
| 39 import '../js_ast/js_ast.dart' as JS; | 39 import '../js_ast/js_ast.dart' as JS; |
| 40 import '../js_ast/js_ast.dart' show js; | 40 import '../js_ast/js_ast.dart' show js; |
| 41 import 'ast_builder.dart' show AstBuilder; | 41 import 'ast_builder.dart' show AstBuilder; |
| 42 import 'class_property_model.dart'; |
| 42 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; | 43 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; |
| 43 import 'element_helpers.dart'; | 44 import 'element_helpers.dart'; |
| 44 import 'element_loader.dart' show ElementLoader; | 45 import 'element_loader.dart' show ElementLoader; |
| 45 import 'extension_types.dart' show ExtensionTypeSet; | 46 import 'extension_types.dart' show ExtensionTypeSet; |
| 46 import 'js_field_storage.dart' show checkForPropertyOverride, getSuperclasses; | |
| 47 import 'js_interop.dart'; | 47 import 'js_interop.dart'; |
| 48 import 'js_metalet.dart' as JS; | 48 import 'js_metalet.dart' as JS; |
| 49 import 'js_names.dart' as JS; | 49 import 'js_names.dart' as JS; |
| 50 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; | 50 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; |
| 51 import 'module_builder.dart' show pathToJSIdentifier; | 51 import 'module_builder.dart' show pathToJSIdentifier; |
| 52 import 'nullable_type_inference.dart' show NullableTypeInference; | 52 import 'nullable_type_inference.dart' show NullableTypeInference; |
| 53 import 'reify_coercions.dart' show CoercionReifier; | 53 import 'reify_coercions.dart' show CoercionReifier; |
| 54 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; | 54 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; |
| 55 import 'type_utilities.dart'; | 55 import 'type_utilities.dart'; |
| 56 | 56 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 bool _superAllowed = true; | 144 bool _superAllowed = true; |
| 145 | 145 |
| 146 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[]; | 146 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[]; |
| 147 List<JS.Method> _superHelpers = <JS.Method>[]; | 147 List<JS.Method> _superHelpers = <JS.Method>[]; |
| 148 | 148 |
| 149 List<TypeParameterType> _typeParamInConst = null; | 149 List<TypeParameterType> _typeParamInConst = null; |
| 150 | 150 |
| 151 /// Whether we are currently generating code for the body of a `JS()` call. | 151 /// Whether we are currently generating code for the body of a `JS()` call. |
| 152 bool _isInForeignJS = false; | 152 bool _isInForeignJS = false; |
| 153 | 153 |
| 154 /// Information about virtual and overridden fields/getters/setters in the |
| 155 /// class we're currently compiling, or `null` if we aren't compiling a class. |
| 156 ClassPropertyModel _classProperties; |
| 157 |
| 154 CodeGenerator( | 158 CodeGenerator( |
| 155 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) | 159 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) |
| 156 : context = c, | 160 : context = c, |
| 157 types = c.typeProvider, | 161 types = c.typeProvider, |
| 158 _asyncStreamIterator = | 162 _asyncStreamIterator = |
| 159 _getLibrary(c, 'dart:async').getType('StreamIterator').type, | 163 _getLibrary(c, 'dart:async').getType('StreamIterator').type, |
| 160 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), | 164 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), |
| 161 interceptorClass = | 165 interceptorClass = |
| 162 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), | 166 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), |
| 163 dartCoreLibrary = _getLibrary(c, 'dart:core'), | 167 dartCoreLibrary = _getLibrary(c, 'dart:core'), |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 var classElem = resolutionMap.elementDeclaredByClassDeclaration(node); | 745 var classElem = resolutionMap.elementDeclaredByClassDeclaration(node); |
| 742 | 746 |
| 743 // If this class is annotated with `@JS`, then there is nothing to emit. | 747 // If this class is annotated with `@JS`, then there is nothing to emit. |
| 744 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; | 748 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; |
| 745 | 749 |
| 746 // If this is a JavaScript type, emit it now and then exit. | 750 // If this is a JavaScript type, emit it now and then exit. |
| 747 var jsTypeDef = _emitJsType(classElem); | 751 var jsTypeDef = _emitJsType(classElem); |
| 748 if (jsTypeDef != null) return jsTypeDef; | 752 if (jsTypeDef != null) return jsTypeDef; |
| 749 | 753 |
| 750 var ctors = <ConstructorDeclaration>[]; | 754 var ctors = <ConstructorDeclaration>[]; |
| 755 var allFields = <FieldDeclaration>[]; |
| 751 var fields = <FieldDeclaration>[]; | 756 var fields = <FieldDeclaration>[]; |
| 752 var staticFields = <FieldDeclaration>[]; | 757 var staticFields = <FieldDeclaration>[]; |
| 753 var methods = <MethodDeclaration>[]; | 758 var methods = <MethodDeclaration>[]; |
| 754 | 759 |
| 755 // True if a "call" method or getter exists directly on this class. | 760 // True if a "call" method or getter exists directly on this class. |
| 756 // If so, we need to install a Function prototype. | 761 // If so, we need to install a Function prototype. |
| 757 bool isCallable = false; | 762 bool isCallable = false; |
| 758 for (var member in node.members) { | 763 for (var member in node.members) { |
| 759 if (member is ConstructorDeclaration) { | 764 if (member is ConstructorDeclaration) { |
| 760 ctors.add(member); | 765 ctors.add(member); |
| 761 } else if (member is FieldDeclaration) { | 766 } else if (member is FieldDeclaration) { |
| 767 allFields.add(member); |
| 762 (member.isStatic ? staticFields : fields).add(member); | 768 (member.isStatic ? staticFields : fields).add(member); |
| 763 } else if (member is MethodDeclaration) { | 769 } else if (member is MethodDeclaration) { |
| 764 methods.add(member); | 770 methods.add(member); |
| 765 if (member.name.name == 'call' && !member.isSetter) { | 771 if (member.name.name == 'call' && !member.isSetter) { |
| 766 // | 772 // |
| 767 // Make sure "call" has a statically known function type: | 773 // Make sure "call" has a statically known function type: |
| 768 // | 774 // |
| 769 // - if it's a method, then it does because all methods do, | 775 // - if it's a method, then it does because all methods do, |
| 770 // - if it's a getter, check the return type. | 776 // - if it's a getter, check the return type. |
| 771 // | 777 // |
| (...skipping 21 matching lines...) Expand all Loading... |
| 793 | 799 |
| 794 JS.Expression className; | 800 JS.Expression className; |
| 795 if (classElem.typeParameters.isNotEmpty) { | 801 if (classElem.typeParameters.isNotEmpty) { |
| 796 // Generic classes will be defined inside a function that closes over the | 802 // Generic classes will be defined inside a function that closes over the |
| 797 // type parameter. So we can use their local variable name directly. | 803 // type parameter. So we can use their local variable name directly. |
| 798 className = new JS.Identifier(classElem.name); | 804 className = new JS.Identifier(classElem.name); |
| 799 } else { | 805 } else { |
| 800 className = _emitTopLevelName(classElem); | 806 className = _emitTopLevelName(classElem); |
| 801 } | 807 } |
| 802 | 808 |
| 803 var allFields = fields.toList()..addAll(staticFields); | |
| 804 var superclasses = getSuperclasses(classElem); | |
| 805 var virtualFields = <FieldElement, JS.TemporaryId>{}; | |
| 806 var virtualFieldSymbols = <JS.Statement>[]; | |
| 807 var staticFieldOverrides = new HashSet<FieldElement>(); | |
| 808 var extensions = _extensionsToImplement(classElem); | 809 var extensions = _extensionsToImplement(classElem); |
| 809 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 810 var savedClassProperties = _classProperties; |
| 810 virtualFields, virtualFieldSymbols, staticFieldOverrides, extensions); | 811 _classProperties = new ClassPropertyModel.build(classElem, extensions); |
| 811 | 812 |
| 812 var classExpr = _emitClassExpression(classElem, | 813 var classExpr = _emitClassExpression( |
| 813 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 814 classElem, _emitClassMethods(node, ctors, fields), |
| 814 fields: allFields); | 815 fields: allFields); |
| 815 | 816 |
| 816 var body = <JS.Statement>[]; | 817 var body = <JS.Statement>[]; |
| 817 _initExtensionSymbols(classElem, methods, fields, body); | 818 _initExtensionSymbols(classElem, methods, fields, body); |
| 818 _emitSuperHelperSymbols(_superHelperSymbols, body); | 819 _emitSuperHelperSymbols(_superHelperSymbols, body); |
| 819 | 820 |
| 820 // Emit the class, e.g. `core.Object = class Object { ... }` | 821 // Emit the class, e.g. `core.Object = class Object { ... }` |
| 821 _defineClass(classElem, className, classExpr, isCallable, body); | 822 _defineClass(classElem, className, classExpr, isCallable, body); |
| 822 | 823 |
| 823 // Emit things that come after the ES6 `class ... { ... }`. | 824 // Emit things that come after the ES6 `class ... { ... }`. |
| 824 var jsPeerNames = _getJSPeerNames(classElem); | 825 var jsPeerNames = _getJSPeerNames(classElem); |
| 825 JS.Statement deferredBaseClass = | 826 JS.Statement deferredBaseClass = |
| 826 _setBaseClass(classElem, className, jsPeerNames, body); | 827 _setBaseClass(classElem, className, jsPeerNames, body); |
| 827 | 828 |
| 828 _emitClassTypeTests(classElem, className, body); | 829 _emitClassTypeTests(classElem, className, body); |
| 829 | 830 |
| 830 _defineNamedConstructors(ctors, body, className, isCallableTransitive); | 831 _defineNamedConstructors(ctors, body, className, isCallableTransitive); |
| 831 body.addAll(virtualFieldSymbols); | 832 _emitVirtualFieldSymbols(className, body); |
| 832 _emitClassSignature( | 833 _emitClassSignature( |
| 833 methods, allFields, classElem, ctors, extensions, className, body); | 834 methods, allFields, classElem, ctors, extensions, className, body); |
| 834 _defineExtensionMembers(extensions, className, body); | 835 _defineExtensionMembers(extensions, className, body); |
| 835 _emitClassMetadata(node.metadata, className, body); | 836 _emitClassMetadata(node.metadata, className, body); |
| 836 | 837 |
| 837 JS.Statement classDef = _statement(body); | 838 JS.Statement classDef = _statement(body); |
| 838 | 839 |
| 839 var typeFormals = classElem.typeParameters; | 840 var typeFormals = classElem.typeParameters; |
| 840 if (typeFormals.isNotEmpty) { | 841 if (typeFormals.isNotEmpty) { |
| 841 classDef = _defineClassTypeArguments( | 842 classDef = _defineClassTypeArguments( |
| 842 classElem, typeFormals, classDef, className, deferredBaseClass); | 843 classElem, typeFormals, classDef, className, deferredBaseClass); |
| 843 } | 844 } |
| 844 | 845 |
| 845 body = <JS.Statement>[classDef]; | 846 body = <JS.Statement>[classDef]; |
| 846 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body); | 847 _emitStaticFields(staticFields, classElem, body); |
| 847 for (var peer in jsPeerNames) { | 848 for (var peer in jsPeerNames) { |
| 848 _registerExtensionType(classElem, peer, body); | 849 _registerExtensionType(classElem, peer, body); |
| 849 } | 850 } |
| 851 |
| 852 _classProperties = savedClassProperties; |
| 850 return _statement(body); | 853 return _statement(body); |
| 851 } | 854 } |
| 852 | 855 |
| 853 /// Emits code to support a class with a "call" method and an unnamed | 856 /// Emits code to support a class with a "call" method and an unnamed |
| 854 /// constructor. | 857 /// constructor. |
| 855 /// | 858 /// |
| 856 /// This ensures instances created by the unnamed constructor are functions. | 859 /// This ensures instances created by the unnamed constructor are functions. |
| 857 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. | 860 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. |
| 858 JS.Expression _emitCallableClass( | 861 JS.Expression _emitCallableClass( |
| 859 JS.ClassExpression classExpr, ConstructorElement unnamedCtor) { | 862 JS.ClassExpression classExpr, ConstructorElement unnamedCtor) { |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 } | 1060 } |
| 1058 | 1061 |
| 1059 void _emitSuperHelperSymbols( | 1062 void _emitSuperHelperSymbols( |
| 1060 List<JS.TemporaryId> superHelperSymbols, List<JS.Statement> body) { | 1063 List<JS.TemporaryId> superHelperSymbols, List<JS.Statement> body) { |
| 1061 for (var id in superHelperSymbols) { | 1064 for (var id in superHelperSymbols) { |
| 1062 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)])); | 1065 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)])); |
| 1063 } | 1066 } |
| 1064 superHelperSymbols.clear(); | 1067 superHelperSymbols.clear(); |
| 1065 } | 1068 } |
| 1066 | 1069 |
| 1067 void _registerPropertyOverrides( | 1070 void _emitVirtualFieldSymbols( |
| 1068 ClassElement classElem, | 1071 JS.Expression className, List<JS.Statement> body) { |
| 1069 JS.Expression className, | 1072 _classProperties.virtualFields.forEach((field, virtualField) { |
| 1070 List<ClassElement> superclasses, | 1073 body.add(js.statement('const # = Symbol(#.name + "." + #.toString());', |
| 1071 List<FieldDeclaration> fields, | 1074 [virtualField, className, _declareMemberName(field.getter)])); |
| 1072 Map<FieldElement, JS.TemporaryId> virtualFields, | 1075 }); |
| 1073 List<JS.Statement> virtualFieldSymbols, | |
| 1074 Set<FieldElement> staticFieldOverrides, | |
| 1075 Iterable<ExecutableElement> extensionMembers) { | |
| 1076 var extensionNames = | |
| 1077 new HashSet<String>.from(extensionMembers.map((e) => e.name)); | |
| 1078 for (var field in fields) { | |
| 1079 for (VariableDeclaration fieldDecl in field.fields.variables) { | |
| 1080 var field = fieldDecl.element as FieldElement; | |
| 1081 var overrideInfo = checkForPropertyOverride(field, superclasses); | |
| 1082 if (overrideInfo.foundGetter || | |
| 1083 overrideInfo.foundSetter || | |
| 1084 extensionNames.contains(field.name)) { | |
| 1085 if (field.isStatic) { | |
| 1086 staticFieldOverrides.add(field); | |
| 1087 } else { | |
| 1088 var virtualField = new JS.TemporaryId(field.name); | |
| 1089 virtualFields[field] = virtualField; | |
| 1090 virtualFieldSymbols.add(js.statement( | |
| 1091 'const # = Symbol(#.name + "." + #.toString());', | |
| 1092 [virtualField, className, _declareMemberName(field.getter)])); | |
| 1093 } | |
| 1094 } | |
| 1095 } | |
| 1096 } | |
| 1097 } | 1076 } |
| 1098 | 1077 |
| 1099 void _defineClass(ClassElement classElem, JS.Expression className, | 1078 void _defineClass(ClassElement classElem, JS.Expression className, |
| 1100 JS.ClassExpression classExpr, bool isCallable, List<JS.Statement> body) { | 1079 JS.ClassExpression classExpr, bool isCallable, List<JS.Statement> body) { |
| 1101 JS.Expression callableClass; | 1080 JS.Expression callableClass; |
| 1102 if (isCallable && classElem.unnamedConstructor != null) { | 1081 if (isCallable && classElem.unnamedConstructor != null) { |
| 1103 callableClass = | 1082 callableClass = |
| 1104 _emitCallableClass(classExpr, classElem.unnamedConstructor); | 1083 _emitCallableClass(classExpr, classElem.unnamedConstructor); |
| 1105 } | 1084 } |
| 1106 | 1085 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1298 [value], js.statement('{ this.# = #; }', [name, value])); | 1277 [value], js.statement('{ this.# = #; }', [name, value])); |
| 1299 method = new JS.Method(_declareMemberName(field.setter), fn, | 1278 method = new JS.Method(_declareMemberName(field.setter), fn, |
| 1300 isSetter: true); | 1279 isSetter: true); |
| 1301 jsMethods.add(method); | 1280 jsMethods.add(method); |
| 1302 } | 1281 } |
| 1303 } | 1282 } |
| 1304 } | 1283 } |
| 1305 return jsMethods; | 1284 return jsMethods; |
| 1306 } | 1285 } |
| 1307 | 1286 |
| 1308 List<JS.Method> _emitClassMethods( | 1287 List<JS.Method> _emitClassMethods(ClassDeclaration node, |
| 1309 ClassDeclaration node, | 1288 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) { |
| 1310 List<ConstructorDeclaration> ctors, | |
| 1311 List<FieldDeclaration> fields, | |
| 1312 List<ClassElement> superclasses, | |
| 1313 Map<FieldElement, JS.TemporaryId> virtualFields) { | |
| 1314 var element = resolutionMap.elementDeclaredByClassDeclaration(node); | 1289 var element = resolutionMap.elementDeclaredByClassDeclaration(node); |
| 1315 var type = element.type; | 1290 var type = element.type; |
| 1316 var isObject = type.isObject; | 1291 var isObject = type.isObject; |
| 1292 var virtualFields = _classProperties.virtualFields; |
| 1317 | 1293 |
| 1318 // Iff no constructor is specified for a class C, it implicitly has a | 1294 // Iff no constructor is specified for a class C, it implicitly has a |
| 1319 // default constructor `C() : super() {}`, unless C is class Object. | 1295 // default constructor `C() : super() {}`, unless C is class Object. |
| 1320 var jsMethods = <JS.Method>[]; | 1296 var jsMethods = <JS.Method>[]; |
| 1321 if (isObject) { | 1297 if (isObject) { |
| 1322 // Implements Dart constructor behavior. | 1298 // Implements Dart constructor behavior. |
| 1323 // | 1299 // |
| 1324 // Because of ES6 constructor restrictions (`this` is not available until | 1300 // Because of ES6 constructor restrictions (`this` is not available until |
| 1325 // `super` is called), we cannot emit an actual ES6 `constructor` on our | 1301 // `super` is called), we cannot emit an actual ES6 `constructor` on our |
| 1326 // classes and preserve the Dart initialization order. | 1302 // classes and preserve the Dart initialization order. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1347 | 1323 |
| 1348 bool hasIterator = false; | 1324 bool hasIterator = false; |
| 1349 for (var m in node.members) { | 1325 for (var m in node.members) { |
| 1350 if (m is ConstructorDeclaration) { | 1326 if (m is ConstructorDeclaration) { |
| 1351 jsMethods | 1327 jsMethods |
| 1352 .add(_emitConstructor(m, type, fields, virtualFields, isObject)); | 1328 .add(_emitConstructor(m, type, fields, virtualFields, isObject)); |
| 1353 } else if (m is MethodDeclaration) { | 1329 } else if (m is MethodDeclaration) { |
| 1354 jsMethods.add(_emitMethodDeclaration(type, m)); | 1330 jsMethods.add(_emitMethodDeclaration(type, m)); |
| 1355 | 1331 |
| 1356 if (m.element is PropertyAccessorElement) { | 1332 if (m.element is PropertyAccessorElement) { |
| 1357 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); | 1333 jsMethods.add(_emitSuperAccessorWrapper(m, type)); |
| 1358 } | 1334 } |
| 1359 | 1335 |
| 1360 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 1336 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { |
| 1361 hasIterator = true; | 1337 hasIterator = true; |
| 1362 jsMethods.add(_emitIterable(type)); | 1338 jsMethods.add(_emitIterable(type)); |
| 1363 } | 1339 } |
| 1364 } else if (m is FieldDeclaration) { | 1340 } else if (m is FieldDeclaration) { |
| 1365 if (_extensionTypes.isNativeClass(element)) { | 1341 if (_extensionTypes.isNativeClass(element)) { |
| 1366 jsMethods.addAll(_emitNativeFieldAccessors(m)); | 1342 jsMethods.addAll(_emitNativeFieldAccessors(m)); |
| 1367 continue; | 1343 continue; |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 result.add(new JS.Method(name, setter, isSetter: true)); | 1544 result.add(new JS.Method(name, setter, isSetter: true)); |
| 1569 } | 1545 } |
| 1570 | 1546 |
| 1571 return result; | 1547 return result; |
| 1572 } | 1548 } |
| 1573 | 1549 |
| 1574 /// Emit a getter or setter that simply forwards to the superclass getter or | 1550 /// Emit a getter or setter that simply forwards to the superclass getter or |
| 1575 /// setter. This is needed because in ES6, if you only override a getter | 1551 /// setter. This is needed because in ES6, if you only override a getter |
| 1576 /// (alternatively, a setter), then there is an implicit override of the | 1552 /// (alternatively, a setter), then there is an implicit override of the |
| 1577 /// setter (alternatively, the getter) that does nothing. | 1553 /// setter (alternatively, the getter) that does nothing. |
| 1578 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, | 1554 JS.Method _emitSuperAccessorWrapper( |
| 1579 InterfaceType type, List<ClassElement> superclasses) { | 1555 MethodDeclaration method, InterfaceType type) { |
| 1580 var methodElement = method.element as PropertyAccessorElement; | 1556 var methodElement = method.element as PropertyAccessorElement; |
| 1581 var field = methodElement.variable; | 1557 var field = methodElement.variable; |
| 1582 if (!field.isSynthetic) return null; | 1558 if (!field.isSynthetic) return null; |
| 1583 var propertyOverrideResult = | |
| 1584 checkForPropertyOverride(methodElement.variable, superclasses); | |
| 1585 | 1559 |
| 1586 // Generate a corresponding virtual getter / setter. | 1560 // Generate a corresponding virtual getter / setter. |
| 1587 var name = _declareMemberName(methodElement); | 1561 var name = _declareMemberName(methodElement); |
| 1588 if (method.isGetter) { | 1562 if (method.isGetter) { |
| 1589 // Generate a setter | 1563 if (field.setter == null && |
| 1590 if (field.setter != null || !propertyOverrideResult.foundSetter) | 1564 _classProperties.inheritedSetters.contains(field.name)) { |
| 1591 return null; | 1565 // Generate a setter that forwards to super. |
| 1592 var fn = js.call('function(value) { super[#] = value; }', [name]); | 1566 var fn = js.call('function(value) { super[#] = value; }', [name]); |
| 1593 return new JS.Method(name, fn, isSetter: true); | 1567 return new JS.Method(name, fn, isSetter: true); |
| 1568 } |
| 1594 } else { | 1569 } else { |
| 1595 // Generate a getter | 1570 if (field.getter == null && |
| 1596 if (field.getter != null || !propertyOverrideResult.foundGetter) | 1571 _classProperties.inheritedGetters.contains(field.name)) { |
| 1597 return null; | 1572 // Generate a getter that forwards to super. |
| 1598 var fn = js.call('function() { return super[#]; }', [name]); | 1573 var fn = js.call('function() { return super[#]; }', [name]); |
| 1599 return new JS.Method(name, fn, isGetter: true); | 1574 return new JS.Method(name, fn, isGetter: true); |
| 1575 } |
| 1600 } | 1576 } |
| 1577 return null; |
| 1601 } | 1578 } |
| 1602 | 1579 |
| 1603 bool _implementsIterable(InterfaceType t) => | 1580 bool _implementsIterable(InterfaceType t) => |
| 1604 t.interfaces.any((i) => i.element.type == types.iterableType); | 1581 t.interfaces.any((i) => i.element.type == types.iterableType); |
| 1605 | 1582 |
| 1606 /// Support for adapting dart:core Iterable to ES6 versions. | 1583 /// Support for adapting dart:core Iterable to ES6 versions. |
| 1607 /// | 1584 /// |
| 1608 /// This lets them use for-of loops transparently: | 1585 /// This lets them use for-of loops transparently: |
| 1609 /// <https://github.com/lukehoban/es6features#iterators--forof> | 1586 /// <https://github.com/lukehoban/es6features#iterators--forof> |
| 1610 /// | 1587 /// |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1704 args.add(_emitCallableClassConstructor(member.element)); | 1681 args.add(_emitCallableClassConstructor(member.element)); |
| 1705 } | 1682 } |
| 1706 | 1683 |
| 1707 body.add(_callHelperStatement(code, args)); | 1684 body.add(_callHelperStatement(code, args)); |
| 1708 } | 1685 } |
| 1709 } | 1686 } |
| 1710 } | 1687 } |
| 1711 | 1688 |
| 1712 /// Emits static fields for a class, and initialize them eagerly if possible, | 1689 /// Emits static fields for a class, and initialize them eagerly if possible, |
| 1713 /// otherwise define them as lazy properties. | 1690 /// otherwise define them as lazy properties. |
| 1714 void _emitStaticFields( | 1691 void _emitStaticFields(List<FieldDeclaration> staticFields, |
| 1715 List<FieldDeclaration> staticFields, | 1692 ClassElement classElem, List<JS.Statement> body) { |
| 1716 Set<FieldElement> staticFieldOverrides, | |
| 1717 ClassElement classElem, | |
| 1718 List<JS.Statement> body) { | |
| 1719 var lazyStatics = <VariableDeclaration>[]; | 1693 var lazyStatics = <VariableDeclaration>[]; |
| 1720 for (FieldDeclaration member in staticFields) { | 1694 for (FieldDeclaration member in staticFields) { |
| 1721 for (VariableDeclaration field in member.fields.variables) { | 1695 for (VariableDeclaration field in member.fields.variables) { |
| 1722 JS.Statement eagerField = | 1696 JS.Statement eagerField = _emitConstantStaticField(classElem, field); |
| 1723 _emitConstantStaticField(classElem, field, staticFieldOverrides); | |
| 1724 if (eagerField != null) { | 1697 if (eagerField != null) { |
| 1725 body.add(eagerField); | 1698 body.add(eagerField); |
| 1726 } else { | 1699 } else { |
| 1727 lazyStatics.add(field); | 1700 lazyStatics.add(field); |
| 1728 } | 1701 } |
| 1729 } | 1702 } |
| 1730 } | 1703 } |
| 1731 if (lazyStatics.isNotEmpty) { | 1704 if (lazyStatics.isNotEmpty) { |
| 1732 body.add(_emitLazyFields(classElem, lazyStatics)); | 1705 body.add(_emitLazyFields(classElem, lazyStatics)); |
| 1733 } | 1706 } |
| (...skipping 2187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3921 /// dependencies are safe to refer to while we are initializing the class, | 3894 /// dependencies are safe to refer to while we are initializing the class, |
| 3922 /// then we can initialize it eagerly: | 3895 /// then we can initialize it eagerly: |
| 3923 /// | 3896 /// |
| 3924 /// // Baz must be const constructor, and the name "Baz" must be defined | 3897 /// // Baz must be const constructor, and the name "Baz" must be defined |
| 3925 /// // by this point. | 3898 /// // by this point. |
| 3926 /// Foo.bar = dart.const(new Baz(42)); | 3899 /// Foo.bar = dart.const(new Baz(42)); |
| 3927 /// | 3900 /// |
| 3928 /// Otherwise, we'll need to generate a lazy-static field. That ensures | 3901 /// Otherwise, we'll need to generate a lazy-static field. That ensures |
| 3929 /// correct visible behavior, as well as avoiding referencing something that | 3902 /// correct visible behavior, as well as avoiding referencing something that |
| 3930 /// isn't defined yet (because it is defined later in the module). | 3903 /// isn't defined yet (because it is defined later in the module). |
| 3931 JS.Statement _emitConstantStaticField(ClassElement classElem, | 3904 JS.Statement _emitConstantStaticField( |
| 3932 VariableDeclaration field, Set<FieldElement> staticFieldOverrides) { | 3905 ClassElement classElem, VariableDeclaration field) { |
| 3933 PropertyInducingElement element = field.element; | 3906 PropertyInducingElement element = field.element; |
| 3934 assert(element.isStatic); | 3907 assert(element.isStatic); |
| 3935 | 3908 |
| 3936 _loader.startCheckingReferences(); | 3909 _loader.startCheckingReferences(); |
| 3937 JS.Expression jsInit = _visitInitializer(field); | 3910 JS.Expression jsInit = _visitInitializer(field); |
| 3938 bool isLoaded = _loader.finishCheckingReferences(); | 3911 bool isLoaded = _loader.finishCheckingReferences(); |
| 3939 | 3912 |
| 3940 bool eagerInit = | 3913 bool eagerInit = |
| 3941 isLoaded && (field.isConst || _constants.isFieldInitConstant(field)); | 3914 isLoaded && (field.isConst || _constants.isFieldInitConstant(field)); |
| 3942 | 3915 |
| 3943 var fieldName = field.name.name; | 3916 var fieldName = field.name.name; |
| 3944 if (eagerInit && | 3917 if (eagerInit && |
| 3945 !JS.invalidStaticFieldName(fieldName) && | 3918 !JS.invalidStaticFieldName(fieldName) && |
| 3946 !staticFieldOverrides.contains(element)) { | 3919 !_classProperties.staticFieldOverrides.contains(element)) { |
| 3947 return annotate( | 3920 return annotate( |
| 3948 js.statement('#.# = #;', [ | 3921 js.statement('#.# = #;', [ |
| 3949 _emitTopLevelName(classElem), | 3922 _emitTopLevelName(classElem), |
| 3950 _emitMemberName(fieldName, isStatic: true), | 3923 _emitMemberName(fieldName, isStatic: true), |
| 3951 jsInit | 3924 jsInit |
| 3952 ]), | 3925 ]), |
| 3953 field, | 3926 field, |
| 3954 field.element); | 3927 field.element); |
| 3955 } | 3928 } |
| 3956 | 3929 |
| (...skipping 945 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4902 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', | 4875 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', |
| 4903 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) | 4876 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) |
| 4904 ]); | 4877 ]); |
| 4905 } | 4878 } |
| 4906 return _callHelper('#(#, #)', | 4879 return _callHelper('#(#, #)', |
| 4907 [_emitDynamicOperationName('dload'), _visit(target), name]); | 4880 [_emitDynamicOperationName('dload'), _visit(target), name]); |
| 4908 } | 4881 } |
| 4909 | 4882 |
| 4910 var jsTarget = _emitTarget(target, member, isStatic); | 4883 var jsTarget = _emitTarget(target, member, isStatic); |
| 4911 bool isSuper = jsTarget is JS.Super; | 4884 bool isSuper = jsTarget is JS.Super; |
| 4912 | 4885 if (isSuper && |
| 4913 if (isSuper && member is FieldElement && !member.isSynthetic) { | 4886 !member.isSynthetic && |
| 4914 // If super.x is actually a field, then x is an instance property since | 4887 member is FieldElementImpl && |
| 4888 !member.isVirtual) { |
| 4889 // If super.x is a sealed field, then x is an instance property since |
| 4915 // subclasses cannot override x. | 4890 // subclasses cannot override x. |
| 4916 jsTarget = new JS.This(); | 4891 jsTarget = new JS.This(); |
| 4917 } | 4892 } |
| 4918 | 4893 |
| 4919 JS.Expression result; | 4894 JS.Expression result; |
| 4920 if (member != null && member is MethodElement && !isStatic) { | 4895 if (member != null && member is MethodElement && !isStatic) { |
| 4921 // Tear-off methods: explicitly bind it. | 4896 // Tear-off methods: explicitly bind it. |
| 4922 if (isSuper) { | 4897 if (isSuper) { |
| 4923 result = _callHelper('bind(this, #, #.#)', [name, jsTarget, name]); | 4898 result = _callHelper('bind(this, #, #.#)', [name, jsTarget, name]); |
| 4924 } else if (_isObjectMemberCall(target, memberName)) { | 4899 } else if (_isObjectMemberCall(target, memberName)) { |
| (...skipping 891 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5816 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5791 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5817 var prefix = targetIdentifier.staticElement as PrefixElement; | 5792 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5818 | 5793 |
| 5819 // The library the prefix is referring to must come from a deferred import. | 5794 // The library the prefix is referring to must come from a deferred import. |
| 5820 var containingLibrary = resolutionMap | 5795 var containingLibrary = resolutionMap |
| 5821 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5796 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 5822 .library; | 5797 .library; |
| 5823 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5798 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5824 return imports.length == 1 && imports[0].isDeferred; | 5799 return imports.length == 1 && imports[0].isDeferred; |
| 5825 } | 5800 } |
| OLD | NEW |