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 |