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

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

Issue 1899373002: Emit forwarding getter/setter when overriding just a getter or setter. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 8 months 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
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/js_field_storage.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 6
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator;
8 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
9 import 'package:analyzer/dart/element/element.dart'; 10 import 'package:analyzer/dart/element/element.dart';
10 import 'package:analyzer/dart/element/type.dart'; 11 import 'package:analyzer/dart/element/type.dart';
11 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; 12 import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
12
13 //TODO(leafp): Remove deprecated dependency 13 //TODO(leafp): Remove deprecated dependency
14 //ignore: DEPRECATED_MEMBER_USE 14 //ignore: DEPRECATED_MEMBER_USE
15 import 'package:analyzer/src/generated/element.dart' 15 import 'package:analyzer/src/generated/element.dart'
16 show DynamicTypeImpl, LocalVariableElementImpl; 16 show DynamicTypeImpl, LocalVariableElementImpl;
17 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
18 import 'package:analyzer/src/generated/resolver.dart' 18 import 'package:analyzer/src/generated/resolver.dart'
19 show TypeProvider, NamespaceBuilder; 19 show TypeProvider, NamespaceBuilder;
20 import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
21 import 'package:analyzer/src/generated/type_system.dart' 20 import 'package:analyzer/src/generated/type_system.dart'
22 show StrongTypeSystemImpl; 21 show StrongTypeSystemImpl;
23 import 'package:analyzer/src/summary/summarize_elements.dart' 22 import 'package:analyzer/src/summary/summarize_elements.dart'
24 show PackageBundleAssembler; 23 show PackageBundleAssembler;
25 import 'package:analyzer/src/task/strong/info.dart' show DynamicInvoke; 24 import 'package:analyzer/src/task/strong/info.dart' show DynamicInvoke;
25 import 'package:source_maps/source_maps.dart';
26 26
27 import '../closure/closure_annotator.dart' show ClosureAnnotator;
27 import '../js_ast/js_ast.dart' as JS; 28 import '../js_ast/js_ast.dart' as JS;
28 import '../js_ast/js_ast.dart' show js; 29 import '../js_ast/js_ast.dart' show js;
29 import '../closure/closure_annotator.dart' show ClosureAnnotator;
30
31 import 'ast_builder.dart' show AstBuilder; 30 import 'ast_builder.dart' show AstBuilder;
32 import 'compiler.dart' 31 import 'compiler.dart'
33 show BuildUnit, CompilerOptions, JSModuleFile, ModuleFormat; 32 show BuildUnit, CompilerOptions, JSModuleFile, ModuleFormat;
34 import 'element_helpers.dart'; 33 import 'element_helpers.dart';
35 import 'element_loader.dart' show ElementLoader; 34 import 'element_loader.dart' show ElementLoader;
36 import 'extension_types.dart' show ExtensionTypeSet; 35 import 'extension_types.dart' show ExtensionTypeSet;
37 import 'js_field_storage.dart' show findFieldsNeedingStorage; 36 import 'js_field_storage.dart' show checkForPropertyOverride, getSuperclasses;
38 import 'js_interop.dart'; 37 import 'js_interop.dart';
38 import 'js_metalet.dart' as JS;
39 import 'js_names.dart' as JS; 39 import 'js_names.dart' as JS;
40 import 'js_metalet.dart' as JS;
41 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; 40 import 'js_typeref_codegen.dart' show JsTypeRefCodegen;
42 import 'module_builder.dart' 41 import 'module_builder.dart'
43 show LegacyModuleBuilder, NodeModuleBuilder, pathToJSIdentifier; 42 show LegacyModuleBuilder, NodeModuleBuilder, pathToJSIdentifier;
44 import 'nullable_type_inference.dart' show NullableTypeInference; 43 import 'nullable_type_inference.dart' show NullableTypeInference;
45 import 'reify_coercions.dart' show CoercionReifier; 44 import 'reify_coercions.dart' show CoercionReifier;
46 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; 45 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless;
47 import 'source_map_printer.dart' show SourceMapPrintingContext; 46 import 'source_map_printer.dart' show SourceMapPrintingContext;
48 import 'package:source_maps/source_maps.dart';
49 47
50 class CodeGenerator extends GeneralizingAstVisitor 48 class CodeGenerator extends GeneralizingAstVisitor
51 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { 49 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference {
52 final AnalysisContext context; 50 final AnalysisContext context;
53 final CompilerOptions options; 51 final CompilerOptions options;
54 final rules = new StrongTypeSystemImpl(); 52 final rules = new StrongTypeSystemImpl();
55 53
56 /// The set of libraries we are currently compiling, and the temporaries used 54 /// The set of libraries we are currently compiling, and the temporaries used
57 /// to refer to them. 55 /// to refer to them.
58 /// 56 ///
59 /// We sometimes special case codegen for a single library, as it simplifies 57 /// We sometimes special case codegen for a single library, as it simplifies
60 /// name scoping requirements. 58 /// name scoping requirements.
61 final _libraries = new Map<LibraryElement, JS.Identifier>(); 59 final _libraries = new Map<LibraryElement, JS.Identifier>();
62 60
63 /// Imported libraries, and the temporaries used to refer to them. 61 /// Imported libraries, and the temporaries used to refer to them.
64 final _imports = new Map<LibraryElement, JS.TemporaryId>(); 62 final _imports = new Map<LibraryElement, JS.TemporaryId>();
65 63
66 /// The list of output module items, in the order they need to be emitted in. 64 /// The list of output module items, in the order they need to be emitted in.
67 final _moduleItems = <JS.ModuleItem>[]; 65 final _moduleItems = <JS.ModuleItem>[];
68 66
69 /// The global extension type table. 67 /// The global extension type table.
70 final ExtensionTypeSet _extensionTypes; 68 final ExtensionTypeSet _extensionTypes;
71 69
72 /// Information that is precomputed for this library, indicates which fields
73 /// need storage slots.
74 HashSet<FieldElement> _fieldsNeedingStorage;
75
76 /// The variable for the target of the current `..` cascade expression. 70 /// The variable for the target of the current `..` cascade expression.
77 /// 71 ///
78 /// Usually a [SimpleIdentifier], but it can also be other expressions 72 /// Usually a [SimpleIdentifier], but it can also be other expressions
79 /// that are safe to evaluate multiple times, such as `this`. 73 /// that are safe to evaluate multiple times, such as `this`.
80 Expression _cascadeTarget; 74 Expression _cascadeTarget;
81 75
82 /// The variable for the current catch clause 76 /// The variable for the current catch clause
83 SimpleIdentifier _catchParameter; 77 SimpleIdentifier _catchParameter;
84 78
85 /// In an async* function, this represents the stream controller parameter. 79 /// In an async* function, this represents the stream controller parameter.
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 } 171 }
178 172
179 return new Tuple2(printer.getText(), sourceMap?.build(unit.name + '.js')); 173 return new Tuple2(printer.getText(), sourceMap?.build(unit.name + '.js'));
180 } 174 }
181 175
182 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { 176 JS.Program _emitModule(List<CompilationUnit> compilationUnits) {
183 if (_moduleItems.isNotEmpty) { 177 if (_moduleItems.isNotEmpty) {
184 throw new StateError('Can only call emitModule once.'); 178 throw new StateError('Can only call emitModule once.');
185 } 179 }
186 180
187 _fieldsNeedingStorage = findFieldsNeedingStorage(
188 compilationUnits.map((u) => u.element), _extensionTypes);
189
190 // Transform the AST to make coercions explicit. 181 // Transform the AST to make coercions explicit.
191 compilationUnits = CoercionReifier.reify(compilationUnits); 182 compilationUnits = CoercionReifier.reify(compilationUnits);
192 183
193 // Initialize our library variables. 184 // Initialize our library variables.
194 var items = <JS.ModuleItem>[]; 185 var items = <JS.ModuleItem>[];
195 for (var unit in compilationUnits) { 186 for (var unit in compilationUnits) {
196 var library = unit.element.library; 187 var library = unit.element.library;
197 if (unit.element != library.definingCompilationUnit) continue; 188 if (unit.element != library.definingCompilationUnit) continue;
198 189
199 var libraryTemp = _isDartRuntime(library) 190 var libraryTemp = _isDartRuntime(library)
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 var body = <JS.Statement>[]; 538 var body = <JS.Statement>[];
548 var extensions = _extensionsToImplement(classElem); 539 var extensions = _extensionsToImplement(classElem);
549 _initExtensionSymbols(classElem, methods, fields, body); 540 _initExtensionSymbols(classElem, methods, fields, body);
550 541
551 // Emit the class, e.g. `core.Object = class Object { ... }` 542 // Emit the class, e.g. `core.Object = class Object { ... }`
552 JS.Expression className = _defineClass(classElem, classExpr, body); 543 JS.Expression className = _defineClass(classElem, classExpr, body);
553 544
554 // Emit things that come after the ES6 `class ... { ... }`. 545 // Emit things that come after the ES6 `class ... { ... }`.
555 _setBaseClass(classElem, className, body); 546 _setBaseClass(classElem, className, body);
556 _defineNamedConstructors(ctors, body, className); 547 _defineNamedConstructors(ctors, body, className);
557 _emitVirtualFields(fields, className, body); 548 _emitVirtualFields(classElem, fields, className, body);
558 _emitClassSignature(methods, classElem, ctors, extensions, className, body); 549 _emitClassSignature(methods, classElem, ctors, extensions, className, body);
559 _defineExtensionMembers(extensions, className, body); 550 _defineExtensionMembers(extensions, className, body);
560 _emitClassMetadata(node.metadata, className, body); 551 _emitClassMetadata(node.metadata, className, body);
561 552
562 JS.Statement classDef = _statement(body); 553 JS.Statement classDef = _statement(body);
563 var typeFormals = classElem.typeParameters; 554 var typeFormals = classElem.typeParameters;
564 if (typeFormals.isNotEmpty) { 555 if (typeFormals.isNotEmpty) {
565 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); 556 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef);
566 } 557 }
567 558
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 var isObject = type.isObject; 758 var isObject = type.isObject;
768 759
769 // Iff no constructor is specified for a class C, it implicitly has a 760 // Iff no constructor is specified for a class C, it implicitly has a
770 // default constructor `C() : super() {}`, unless C is class Object. 761 // default constructor `C() : super() {}`, unless C is class Object.
771 var jsMethods = <JS.Method>[]; 762 var jsMethods = <JS.Method>[];
772 if (ctors.isEmpty && !isObject) { 763 if (ctors.isEmpty && !isObject) {
773 jsMethods.add(_emitImplicitConstructor(node, fields)); 764 jsMethods.add(_emitImplicitConstructor(node, fields));
774 } 765 }
775 766
776 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; 767 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null;
768 var superclasses = getSuperclasses(element);
777 769
778 bool hasIterator = false; 770 bool hasIterator = false;
779 for (var m in node.members) { 771 for (var m in node.members) {
780 if (m is ConstructorDeclaration) { 772 if (m is ConstructorDeclaration) {
781 jsMethods.add(_emitConstructor(m, type, fields, isObject)); 773 jsMethods.add(_emitConstructor(m, type, fields, isObject));
782 } else if (m is MethodDeclaration) { 774 } else if (m is MethodDeclaration) {
783 jsMethods.add(_emitMethodDeclaration(type, m)); 775 jsMethods.add(_emitMethodDeclaration(type, m));
784 776
777 if (m.element is PropertyAccessorElement) {
778 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses));
779 }
780
785 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { 781 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') {
786 hasIterator = true; 782 hasIterator = true;
787 jsMethods.add(_emitIterable(type)); 783 jsMethods.add(_emitIterable(type));
788 } 784 }
789 } else if (m is FieldDeclaration && _extensionTypes.contains(element)) { 785 } else if (m is FieldDeclaration && _extensionTypes.contains(element)) {
790 jsMethods.addAll(_emitNativeFieldAccessors(m)); 786 jsMethods.addAll(_emitNativeFieldAccessors(m));
791 } 787 }
792 } 788 }
793 789
794 // If the type doesn't have an `iterator`, but claims to implement Iterable, 790 // If the type doesn't have an `iterator`, but claims to implement Iterable,
795 // we inject the adaptor method here, as it's less code size to put the 791 // we inject the adaptor method here, as it's less code size to put the
796 // helper on a parent class. This pattern is common in the core libraries 792 // helper on a parent class. This pattern is common in the core libraries
797 // (e.g. IterableMixin<E> and IterableBase<E>). 793 // (e.g. IterableMixin<E> and IterableBase<E>).
798 // 794 //
799 // (We could do this same optimization for any interface with an `iterator` 795 // (We could do this same optimization for any interface with an `iterator`
800 // method, but that's more expensive to check for, so it doesn't seem worth 796 // method, but that's more expensive to check for, so it doesn't seem worth
801 // it. The above case for an explicit `iterator` method will catch those.) 797 // it. The above case for an explicit `iterator` method will catch those.)
802 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { 798 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) {
803 jsMethods.add(_emitIterable(type)); 799 jsMethods.add(_emitIterable(type));
804 } 800 }
805 801
806 return jsMethods.where((m) => m != null).toList(growable: false); 802 return jsMethods.where((m) => m != null).toList(growable: false);
807 } 803 }
808 804
805 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method,
806 InterfaceType type, List<ClassElement> superclasses) {
807 var methodElement = method.element as PropertyAccessorElement;
808 var field = methodElement.variable;
809 if (!field.isSynthetic) return null;
810 var propertyOverrideResult = checkForPropertyOverride(
811 methodElement.variable, superclasses, _extensionTypes);
812
813 // Generate a corresponding virtual getter / setter.
814 var name = _elementMemberName(methodElement,
815 allowExtensions: _extensionTypes.contains(type.element));
816 if (method.isGetter) {
817 // Generate a setter
818 if (field.setter != null || !propertyOverrideResult.foundSetter)
819 return null;
820 var fn = js.call('function(value) { super[#] = value; }', [name]);
821 return new JS.Method(name, fn, isSetter: true);
822 } else {
823 // Generate a getter
824 if (field.getter != null || !propertyOverrideResult.foundGetter)
825 return null;
826 var fn = js.call('function() { return super[#]; }', [name]);
827 return new JS.Method(name, fn, isGetter: true);
828 }
829 }
830
809 bool _implementsIterable(InterfaceType t) => 831 bool _implementsIterable(InterfaceType t) =>
810 t.interfaces.any((i) => i.element.type == types.iterableType); 832 t.interfaces.any((i) => i.element.type == types.iterableType);
811 833
812 /// Support for adapting dart:core Iterable to ES6 versions. 834 /// Support for adapting dart:core Iterable to ES6 versions.
813 /// 835 ///
814 /// This lets them use for-of loops transparently: 836 /// This lets them use for-of loops transparently:
815 /// <https://github.com/lukehoban/es6features#iterators--forof> 837 /// <https://github.com/lukehoban/es6features#iterators--forof>
816 /// 838 ///
817 /// This will return `null` if the adapter was already added on a super type, 839 /// This will return `null` if the adapter was already added on a super type,
818 /// otherwise it returns the adapter code. 840 /// otherwise it returns the adapter code.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 newBaseClass = _emitTypeName(classElem.type.superclass); 905 newBaseClass = _emitTypeName(classElem.type.superclass);
884 } 906 }
885 if (newBaseClass != null) { 907 if (newBaseClass != null) {
886 body.add( 908 body.add(
887 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); 909 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass]));
888 } 910 }
889 } 911 }
890 912
891 /// Emits instance fields, if they are virtual 913 /// Emits instance fields, if they are virtual
892 /// (in other words, they override a getter/setter pair). 914 /// (in other words, they override a getter/setter pair).
893 void _emitVirtualFields(List<FieldDeclaration> fields, 915 void _emitVirtualFields(
894 JS.Expression className, List<JS.Statement> body) { 916 ClassElement classElement,
917 List<FieldDeclaration> fields,
918 JS.Expression className,
919 List<JS.Statement> body) {
920 List<ClassElement> superclasses = getSuperclasses(classElement);
895 for (FieldDeclaration member in fields) { 921 for (FieldDeclaration member in fields) {
896 for (VariableDeclaration field in member.fields.variables) { 922 for (VariableDeclaration field in member.fields.variables) {
897 if (_fieldsNeedingStorage.contains(field.element)) { 923 var propertyOverrideResult = checkForPropertyOverride(
924 field.element, superclasses, _extensionTypes);
925 if (propertyOverrideResult.foundGetter ||
926 propertyOverrideResult.foundSetter) {
898 body.add(_overrideField(className, field.element)); 927 body.add(_overrideField(className, field.element));
899 } 928 }
900 } 929 }
901 } 930 }
902 } 931 }
903 932
904 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, 933 void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
905 List<JS.Statement> body, JS.Expression className) { 934 List<JS.Statement> body, JS.Expression className) {
906 for (ConstructorDeclaration member in ctors) { 935 for (ConstructorDeclaration member in ctors) {
907 if (member.name != null && member.factoryKeyword == null) { 936 if (member.name != null && member.factoryKeyword == null) {
(...skipping 2849 matching lines...) Expand 10 before | Expand all | Expand 10 after
3757 } 3786 }
3758 3787
3759 bool isLibraryPrefix(Expression node) => 3788 bool isLibraryPrefix(Expression node) =>
3760 node is SimpleIdentifier && node.staticElement is PrefixElement; 3789 node is SimpleIdentifier && node.staticElement is PrefixElement;
3761 3790
3762 LibraryElement _getLibrary(AnalysisContext c, String uri) => 3791 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
3763 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 3792 c.computeLibraryElement(c.sourceFactory.forUri(uri));
3764 3793
3765 bool _isDartRuntime(LibraryElement l) => 3794 bool _isDartRuntime(LibraryElement l) =>
3766 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 3795 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/js_field_storage.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698