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