| Index: pkg/dev_compiler/lib/src/compiler/code_generator.dart
|
| diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
|
| index 078f18e1eec2dc0a2b0d292ceb06c11a046c12d7..137c16e3485725f6dc062423f7c7c362b29e9180 100644
|
| --- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart
|
| +++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
|
| @@ -15,7 +15,7 @@ import 'package:analyzer/dart/element/element.dart';
|
| import 'package:analyzer/dart/element/type.dart';
|
| import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
|
| import 'package:analyzer/src/dart/element/element.dart'
|
| - show LocalVariableElementImpl;
|
| + show FieldElementImpl, LocalVariableElementImpl;
|
| import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl;
|
| import 'package:analyzer/src/dart/sdk/sdk.dart';
|
| import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
|
| @@ -39,11 +39,11 @@ import '../closure/closure_annotator.dart' show ClosureAnnotator;
|
| import '../js_ast/js_ast.dart' as JS;
|
| import '../js_ast/js_ast.dart' show js;
|
| import 'ast_builder.dart' show AstBuilder;
|
| +import 'class_property_model.dart';
|
| import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile;
|
| import 'element_helpers.dart';
|
| import 'element_loader.dart' show ElementLoader;
|
| import 'extension_types.dart' show ExtensionTypeSet;
|
| -import 'js_field_storage.dart' show checkForPropertyOverride, getSuperclasses;
|
| import 'js_interop.dart';
|
| import 'js_metalet.dart' as JS;
|
| import 'js_names.dart' as JS;
|
| @@ -151,6 +151,10 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| /// Whether we are currently generating code for the body of a `JS()` call.
|
| bool _isInForeignJS = false;
|
|
|
| + /// Information about virtual and overridden fields/getters/setters in the
|
| + /// class we're currently compiling, or `null` if we aren't compiling a class.
|
| + ClassPropertyModel _classProperties;
|
| +
|
| CodeGenerator(
|
| AnalysisContext c, this.summaryData, this.options, this._extensionTypes)
|
| : context = c,
|
| @@ -748,6 +752,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| if (jsTypeDef != null) return jsTypeDef;
|
|
|
| var ctors = <ConstructorDeclaration>[];
|
| + var allFields = <FieldDeclaration>[];
|
| var fields = <FieldDeclaration>[];
|
| var staticFields = <FieldDeclaration>[];
|
| var methods = <MethodDeclaration>[];
|
| @@ -759,6 +764,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| if (member is ConstructorDeclaration) {
|
| ctors.add(member);
|
| } else if (member is FieldDeclaration) {
|
| + allFields.add(member);
|
| (member.isStatic ? staticFields : fields).add(member);
|
| } else if (member is MethodDeclaration) {
|
| methods.add(member);
|
| @@ -800,17 +806,12 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| className = _emitTopLevelName(classElem);
|
| }
|
|
|
| - var allFields = fields.toList()..addAll(staticFields);
|
| - var superclasses = getSuperclasses(classElem);
|
| - var virtualFields = <FieldElement, JS.TemporaryId>{};
|
| - var virtualFieldSymbols = <JS.Statement>[];
|
| - var staticFieldOverrides = new HashSet<FieldElement>();
|
| var extensions = _extensionsToImplement(classElem);
|
| - _registerPropertyOverrides(classElem, className, superclasses, allFields,
|
| - virtualFields, virtualFieldSymbols, staticFieldOverrides, extensions);
|
| + var savedClassProperties = _classProperties;
|
| + _classProperties = new ClassPropertyModel.build(classElem, extensions);
|
|
|
| - var classExpr = _emitClassExpression(classElem,
|
| - _emitClassMethods(node, ctors, fields, superclasses, virtualFields),
|
| + var classExpr = _emitClassExpression(
|
| + classElem, _emitClassMethods(node, ctors, fields),
|
| fields: allFields);
|
|
|
| var body = <JS.Statement>[];
|
| @@ -828,7 +829,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| _emitClassTypeTests(classElem, className, body);
|
|
|
| _defineNamedConstructors(ctors, body, className, isCallableTransitive);
|
| - body.addAll(virtualFieldSymbols);
|
| + _emitVirtualFieldSymbols(className, body);
|
| _emitClassSignature(
|
| methods, allFields, classElem, ctors, extensions, className, body);
|
| _defineExtensionMembers(extensions, className, body);
|
| @@ -843,10 +844,12 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| }
|
|
|
| body = <JS.Statement>[classDef];
|
| - _emitStaticFields(staticFields, staticFieldOverrides, classElem, body);
|
| + _emitStaticFields(staticFields, classElem, body);
|
| for (var peer in jsPeerNames) {
|
| _registerExtensionType(classElem, peer, body);
|
| }
|
| +
|
| + _classProperties = savedClassProperties;
|
| return _statement(body);
|
| }
|
|
|
| @@ -1064,36 +1067,12 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| superHelperSymbols.clear();
|
| }
|
|
|
| - void _registerPropertyOverrides(
|
| - ClassElement classElem,
|
| - JS.Expression className,
|
| - List<ClassElement> superclasses,
|
| - List<FieldDeclaration> fields,
|
| - Map<FieldElement, JS.TemporaryId> virtualFields,
|
| - List<JS.Statement> virtualFieldSymbols,
|
| - Set<FieldElement> staticFieldOverrides,
|
| - Iterable<ExecutableElement> extensionMembers) {
|
| - var extensionNames =
|
| - new HashSet<String>.from(extensionMembers.map((e) => e.name));
|
| - for (var field in fields) {
|
| - for (VariableDeclaration fieldDecl in field.fields.variables) {
|
| - var field = fieldDecl.element as FieldElement;
|
| - var overrideInfo = checkForPropertyOverride(field, superclasses);
|
| - if (overrideInfo.foundGetter ||
|
| - overrideInfo.foundSetter ||
|
| - extensionNames.contains(field.name)) {
|
| - if (field.isStatic) {
|
| - staticFieldOverrides.add(field);
|
| - } else {
|
| - var virtualField = new JS.TemporaryId(field.name);
|
| - virtualFields[field] = virtualField;
|
| - virtualFieldSymbols.add(js.statement(
|
| - 'const # = Symbol(#.name + "." + #.toString());',
|
| - [virtualField, className, _declareMemberName(field.getter)]));
|
| - }
|
| - }
|
| - }
|
| - }
|
| + void _emitVirtualFieldSymbols(
|
| + JS.Expression className, List<JS.Statement> body) {
|
| + _classProperties.virtualFields.forEach((field, virtualField) {
|
| + body.add(js.statement('const # = Symbol(#.name + "." + #.toString());',
|
| + [virtualField, className, _declareMemberName(field.getter)]));
|
| + });
|
| }
|
|
|
| void _defineClass(ClassElement classElem, JS.Expression className,
|
| @@ -1305,15 +1284,12 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| return jsMethods;
|
| }
|
|
|
| - List<JS.Method> _emitClassMethods(
|
| - ClassDeclaration node,
|
| - List<ConstructorDeclaration> ctors,
|
| - List<FieldDeclaration> fields,
|
| - List<ClassElement> superclasses,
|
| - Map<FieldElement, JS.TemporaryId> virtualFields) {
|
| + List<JS.Method> _emitClassMethods(ClassDeclaration node,
|
| + List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) {
|
| var element = resolutionMap.elementDeclaredByClassDeclaration(node);
|
| var type = element.type;
|
| var isObject = type.isObject;
|
| + var virtualFields = _classProperties.virtualFields;
|
|
|
| // Iff no constructor is specified for a class C, it implicitly has a
|
| // default constructor `C() : super() {}`, unless C is class Object.
|
| @@ -1354,7 +1330,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| jsMethods.add(_emitMethodDeclaration(type, m));
|
|
|
| if (m.element is PropertyAccessorElement) {
|
| - jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses));
|
| + jsMethods.add(_emitSuperAccessorWrapper(m, type));
|
| }
|
|
|
| if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') {
|
| @@ -1575,29 +1551,32 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| /// setter. This is needed because in ES6, if you only override a getter
|
| /// (alternatively, a setter), then there is an implicit override of the
|
| /// setter (alternatively, the getter) that does nothing.
|
| - JS.Method _emitSuperAccessorWrapper(MethodDeclaration method,
|
| - InterfaceType type, List<ClassElement> superclasses) {
|
| + JS.Method _emitSuperAccessorWrapper(
|
| + MethodDeclaration method, InterfaceType type) {
|
| var methodElement = method.element as PropertyAccessorElement;
|
| var field = methodElement.variable;
|
| if (!field.isSynthetic) return null;
|
| - var propertyOverrideResult =
|
| - checkForPropertyOverride(methodElement.variable, superclasses);
|
|
|
| // Generate a corresponding virtual getter / setter.
|
| var name = _declareMemberName(methodElement);
|
| if (method.isGetter) {
|
| - // Generate a setter
|
| - if (field.setter != null || !propertyOverrideResult.foundSetter)
|
| - return null;
|
| - var fn = js.call('function(value) { super[#] = value; }', [name]);
|
| - return new JS.Method(name, fn, isSetter: true);
|
| + var setter = field.setter;
|
| + if ((setter == null || setter.isAbstract) &&
|
| + _classProperties.inheritedSetters.contains(field.name)) {
|
| + // Generate a setter that forwards to super.
|
| + var fn = js.call('function(value) { super[#] = value; }', [name]);
|
| + return new JS.Method(name, fn, isSetter: true);
|
| + }
|
| } else {
|
| - // Generate a getter
|
| - if (field.getter != null || !propertyOverrideResult.foundGetter)
|
| - return null;
|
| - var fn = js.call('function() { return super[#]; }', [name]);
|
| - return new JS.Method(name, fn, isGetter: true);
|
| + var getter = field.getter;
|
| + if ((getter == null || getter.isAbstract) &&
|
| + _classProperties.inheritedGetters.contains(field.name)) {
|
| + // Generate a getter that forwards to super.
|
| + var fn = js.call('function() { return super[#]; }', [name]);
|
| + return new JS.Method(name, fn, isGetter: true);
|
| + }
|
| }
|
| + return null;
|
| }
|
|
|
| bool _implementsIterable(InterfaceType t) =>
|
| @@ -1711,16 +1690,12 @@ class CodeGenerator extends GeneralizingAstVisitor
|
|
|
| /// Emits static fields for a class, and initialize them eagerly if possible,
|
| /// otherwise define them as lazy properties.
|
| - void _emitStaticFields(
|
| - List<FieldDeclaration> staticFields,
|
| - Set<FieldElement> staticFieldOverrides,
|
| - ClassElement classElem,
|
| - List<JS.Statement> body) {
|
| + void _emitStaticFields(List<FieldDeclaration> staticFields,
|
| + ClassElement classElem, List<JS.Statement> body) {
|
| var lazyStatics = <VariableDeclaration>[];
|
| for (FieldDeclaration member in staticFields) {
|
| for (VariableDeclaration field in member.fields.variables) {
|
| - JS.Statement eagerField =
|
| - _emitConstantStaticField(classElem, field, staticFieldOverrides);
|
| + JS.Statement eagerField = _emitConstantStaticField(classElem, field);
|
| if (eagerField != null) {
|
| body.add(eagerField);
|
| } else {
|
| @@ -3928,8 +3903,8 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| /// Otherwise, we'll need to generate a lazy-static field. That ensures
|
| /// correct visible behavior, as well as avoiding referencing something that
|
| /// isn't defined yet (because it is defined later in the module).
|
| - JS.Statement _emitConstantStaticField(ClassElement classElem,
|
| - VariableDeclaration field, Set<FieldElement> staticFieldOverrides) {
|
| + JS.Statement _emitConstantStaticField(
|
| + ClassElement classElem, VariableDeclaration field) {
|
| PropertyInducingElement element = field.element;
|
| assert(element.isStatic);
|
|
|
| @@ -3943,7 +3918,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| var fieldName = field.name.name;
|
| if (eagerInit &&
|
| !JS.invalidStaticFieldName(fieldName) &&
|
| - !staticFieldOverrides.contains(element)) {
|
| + !_classProperties.staticFieldOverrides.contains(element)) {
|
| return annotate(
|
| js.statement('#.# = #;', [
|
| _emitTopLevelName(classElem),
|
| @@ -4909,9 +4884,11 @@ class CodeGenerator extends GeneralizingAstVisitor
|
|
|
| var jsTarget = _emitTarget(target, member, isStatic);
|
| bool isSuper = jsTarget is JS.Super;
|
| -
|
| - if (isSuper && member is FieldElement && !member.isSynthetic) {
|
| - // If super.x is actually a field, then x is an instance property since
|
| + if (isSuper &&
|
| + !member.isSynthetic &&
|
| + member is FieldElementImpl &&
|
| + !member.isVirtual) {
|
| + // If super.x is a sealed field, then x is an instance property since
|
| // subclasses cannot override x.
|
| jsTarget = new JS.This();
|
| }
|
|
|