Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(870)

Side by Side Diff: pkg/dev_compiler/lib/src/compiler/code_generator.dart

Issue 2571363002: fixes #27385, implement virtual fields in DDC (Closed)
Patch Set: rebase Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698