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 // 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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'; |
OLD | NEW |