| 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 | 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/resolution_accessors.dart'; |
| 13 import 'package:analyzer/dart/element/element.dart'; | 14 import 'package:analyzer/dart/element/element.dart'; |
| 14 import 'package:analyzer/dart/element/type.dart'; | 15 import 'package:analyzer/dart/element/type.dart'; |
| 15 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; | 16 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; |
| 16 import 'package:analyzer/src/dart/element/element.dart' | 17 import 'package:analyzer/src/dart/element/element.dart' |
| 17 show LocalVariableElementImpl; | 18 show LocalVariableElementImpl; |
| 18 import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl; | 19 import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl; |
| 19 import 'package:analyzer/src/dart/sdk/sdk.dart'; | 20 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| 20 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 21 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 21 import 'package:analyzer/src/generated/resolver.dart' | 22 import 'package:analyzer/src/generated/resolver.dart' |
| 22 show TypeProvider, NamespaceBuilder; | 23 show TypeProvider, NamespaceBuilder; |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 | 186 |
| 186 var module = _emitModule(compilationUnits); | 187 var module = _emitModule(compilationUnits); |
| 187 var dartApiSummary = _summarizeModule(compilationUnits); | 188 var dartApiSummary = _summarizeModule(compilationUnits); |
| 188 | 189 |
| 189 return new JSModuleFile(unit.name, errors, options, module, dartApiSummary); | 190 return new JSModuleFile(unit.name, errors, options, module, dartApiSummary); |
| 190 } | 191 } |
| 191 | 192 |
| 192 List<int> _summarizeModule(List<CompilationUnit> units) { | 193 List<int> _summarizeModule(List<CompilationUnit> units) { |
| 193 if (!options.summarizeApi) return null; | 194 if (!options.summarizeApi) return null; |
| 194 | 195 |
| 195 if (!units.any((u) => u.element.librarySource.isInSystemLibrary)) { | 196 if (!units.any((u) => elementForCompilationUnit(u).librarySource.isInSystemL
ibrary)) { |
| 196 var sdk = context.sourceFactory.dartSdk; | 197 var sdk = context.sourceFactory.dartSdk; |
| 197 summaryData.addBundle( | 198 summaryData.addBundle( |
| 198 null, | 199 null, |
| 199 sdk is SummaryBasedDartSdk | 200 sdk is SummaryBasedDartSdk |
| 200 ? sdk.bundle | 201 ? sdk.bundle |
| 201 : (sdk as FolderBasedDartSdk).getSummarySdkBundle(true)); | 202 : (sdk as FolderBasedDartSdk).getSummarySdkBundle(true)); |
| 202 } | 203 } |
| 203 | 204 |
| 204 var assembler = new PackageBundleAssembler(); | 205 var assembler = new PackageBundleAssembler(); |
| 205 assembler.recordDependencies(summaryData); | 206 assembler.recordDependencies(summaryData); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 227 } | 228 } |
| 228 | 229 |
| 229 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { | 230 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { |
| 230 if (_moduleItems.isNotEmpty) { | 231 if (_moduleItems.isNotEmpty) { |
| 231 throw new StateError('Can only call emitModule once.'); | 232 throw new StateError('Can only call emitModule once.'); |
| 232 } | 233 } |
| 233 | 234 |
| 234 // Transform the AST to make coercions explicit. | 235 // Transform the AST to make coercions explicit. |
| 235 compilationUnits = CoercionReifier.reify(compilationUnits); | 236 compilationUnits = CoercionReifier.reify(compilationUnits); |
| 236 | 237 |
| 237 if (compilationUnits.any((u) => _isDartRuntime(u.element.library))) { | 238 if (compilationUnits.any((u) => _isDartRuntime(elementForCompilationUnit(u).
library))) { |
| 238 // Don't allow these to be renamed when we're building the SDK. | 239 // Don't allow these to be renamed when we're building the SDK. |
| 239 // There is JS code in dart:* that depends on their names. | 240 // There is JS code in dart:* that depends on their names. |
| 240 _runtimeModule = new JS.Identifier('dart'); | 241 _runtimeModule = new JS.Identifier('dart'); |
| 241 _extensionSymbolsModule = new JS.Identifier('dartx'); | 242 _extensionSymbolsModule = new JS.Identifier('dartx'); |
| 242 } else { | 243 } else { |
| 243 // Otherwise allow these to be renamed so users can write them. | 244 // Otherwise allow these to be renamed so users can write them. |
| 244 _runtimeModule = new JS.TemporaryId('dart'); | 245 _runtimeModule = new JS.TemporaryId('dart'); |
| 245 _extensionSymbolsModule = new JS.TemporaryId('dartx'); | 246 _extensionSymbolsModule = new JS.TemporaryId('dartx'); |
| 246 } | 247 } |
| 247 _typeTable = new TypeTable(_runtimeModule); | 248 _typeTable = new TypeTable(_runtimeModule); |
| 248 | 249 |
| 249 // Initialize our library variables. | 250 // Initialize our library variables. |
| 250 var items = <JS.ModuleItem>[]; | 251 var items = <JS.ModuleItem>[]; |
| 251 for (var unit in compilationUnits) { | 252 for (var unit in compilationUnits) { |
| 252 var library = unit.element.library; | 253 var library = elementForCompilationUnit(unit).library; |
| 253 if (unit.element != library.definingCompilationUnit) continue; | 254 if (unit.element != library.definingCompilationUnit) continue; |
| 254 | 255 |
| 255 var libraryTemp = _isDartRuntime(library) | 256 var libraryTemp = _isDartRuntime(library) |
| 256 ? _runtimeModule | 257 ? _runtimeModule |
| 257 : new JS.TemporaryId(jsLibraryName(_libraryRoot, library)); | 258 : new JS.TemporaryId(jsLibraryName(_libraryRoot, library)); |
| 258 _libraries[library] = libraryTemp; | 259 _libraries[library] = libraryTemp; |
| 259 items.add(new JS.ExportDeclaration( | 260 items.add(new JS.ExportDeclaration( |
| 260 js.call('const # = Object.create(null)', [libraryTemp]))); | 261 js.call('const # = Object.create(null)', [libraryTemp]))); |
| 261 | 262 |
| 262 // dart:_runtime has a magic module that holds extension method symbols. | 263 // dart:_runtime has a magic module that holds extension method symbols. |
| 263 // TODO(jmesserly): find a cleaner design for this. | 264 // TODO(jmesserly): find a cleaner design for this. |
| 264 if (_isDartRuntime(library)) { | 265 if (_isDartRuntime(library)) { |
| 265 items.add(new JS.ExportDeclaration(js | 266 items.add(new JS.ExportDeclaration(js |
| 266 .call('const # = Object.create(null)', [_extensionSymbolsModule]))); | 267 .call('const # = Object.create(null)', [_extensionSymbolsModule]))); |
| 267 } | 268 } |
| 268 } | 269 } |
| 269 | 270 |
| 270 // Collect all Element -> Node mappings, in case we need to forward declare | 271 // Collect all Element -> Node mappings, in case we need to forward declare |
| 271 // any nodes. | 272 // any nodes. |
| 272 var nodes = new HashMap<Element, AstNode>.identity(); | 273 var nodes = new HashMap<Element, AstNode>.identity(); |
| 273 var sdkBootstrappingFns = new List<FunctionElement>(); | 274 var sdkBootstrappingFns = new List<FunctionElement>(); |
| 274 for (var unit in compilationUnits) { | 275 for (var unit in compilationUnits) { |
| 275 if (_isDartRuntime(unit.element.library)) { | 276 if (_isDartRuntime(elementForCompilationUnit(unit).library)) { |
| 276 sdkBootstrappingFns.addAll(unit.element.functions); | 277 sdkBootstrappingFns.addAll(elementForCompilationUnit(unit).functions); |
| 277 } | 278 } |
| 278 _collectElements(unit, nodes); | 279 _collectElements(unit, nodes); |
| 279 } | 280 } |
| 280 _loader = new ElementLoader(nodes); | 281 _loader = new ElementLoader(nodes); |
| 281 if (compilationUnits.isNotEmpty) { | 282 if (compilationUnits.isNotEmpty) { |
| 282 _constants = new ConstFieldVisitor(context, | 283 _constants = new ConstFieldVisitor(context, |
| 283 dummySource: compilationUnits.first.element.source); | 284 dummySource: elementForCompilationUnit(compilationUnits.first).source)
; |
| 284 } | 285 } |
| 285 | 286 |
| 286 // Add implicit dart:core dependency so it is first. | 287 // Add implicit dart:core dependency so it is first. |
| 287 emitLibraryName(dartCoreLibrary); | 288 emitLibraryName(dartCoreLibrary); |
| 288 | 289 |
| 289 // Emit SDK bootstrapping functions first, if any. | 290 // Emit SDK bootstrapping functions first, if any. |
| 290 sdkBootstrappingFns.forEach(_emitDeclaration); | 291 sdkBootstrappingFns.forEach(_emitDeclaration); |
| 291 | 292 |
| 292 // Visit each compilation unit and emit its code. | 293 // Visit each compilation unit and emit its code. |
| 293 // | 294 // |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 | 722 |
| 722 // We export the JS type as if it was a Dart type. For example this allows | 723 // We export the JS type as if it was a Dart type. For example this allows |
| 723 // `dom.InputElement` to actually be HTMLInputElement. | 724 // `dom.InputElement` to actually be HTMLInputElement. |
| 724 // TODO(jmesserly): if we had the JS name on the Element, we could just | 725 // TODO(jmesserly): if we had the JS name on the Element, we could just |
| 725 // generate it correctly when we refer to it. | 726 // generate it correctly when we refer to it. |
| 726 return js.statement('# = #;', [_emitTopLevelName(e), jsTypeName]); | 727 return js.statement('# = #;', [_emitTopLevelName(e), jsTypeName]); |
| 727 } | 728 } |
| 728 | 729 |
| 729 @override | 730 @override |
| 730 JS.Statement visitClassDeclaration(ClassDeclaration node) { | 731 JS.Statement visitClassDeclaration(ClassDeclaration node) { |
| 731 var classElem = node.element; | 732 var classElem = elementForClassDeclaration(node); |
| 732 | 733 |
| 733 // If this class is annotated with `@JS`, then there is nothing to emit. | 734 // If this class is annotated with `@JS`, then there is nothing to emit. |
| 734 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; | 735 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; |
| 735 | 736 |
| 736 // If this is a JavaScript type, emit it now and then exit. | 737 // If this is a JavaScript type, emit it now and then exit. |
| 737 var jsTypeDef = _emitJsType(classElem); | 738 var jsTypeDef = _emitJsType(classElem); |
| 738 if (jsTypeDef != null) return jsTypeDef; | 739 if (jsTypeDef != null) return jsTypeDef; |
| 739 | 740 |
| 740 var ctors = <ConstructorDeclaration>[]; | 741 var ctors = <ConstructorDeclaration>[]; |
| 741 var fields = <FieldDeclaration>[]; | 742 var fields = <FieldDeclaration>[]; |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1103 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED | 1104 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED |
| 1104 /// (e.g. `class Foo { i: string; }`) | 1105 /// (e.g. `class Foo { i: string; }`) |
| 1105 JS.VariableDeclarationList _emitTypeScriptField(FieldDeclaration field) { | 1106 JS.VariableDeclarationList _emitTypeScriptField(FieldDeclaration field) { |
| 1106 return new JS.VariableDeclarationList( | 1107 return new JS.VariableDeclarationList( |
| 1107 field.isStatic ? 'static' : null, | 1108 field.isStatic ? 'static' : null, |
| 1108 field.fields.variables | 1109 field.fields.variables |
| 1109 .map((decl) => new JS.VariableInitialization( | 1110 .map((decl) => new JS.VariableInitialization( |
| 1110 new JS.Identifier( | 1111 new JS.Identifier( |
| 1111 // TODO(ochafik): use a refactored _emitMemberName instead. | 1112 // TODO(ochafik): use a refactored _emitMemberName instead. |
| 1112 decl.name.name, | 1113 decl.name.name, |
| 1113 type: emitTypeRef(decl.element.type)), | 1114 type: emitTypeRef(elementForVariableDeclaration(decl).type))
, |
| 1114 null)) | 1115 null)) |
| 1115 .toList(growable: false)); | 1116 .toList(growable: false)); |
| 1116 } | 1117 } |
| 1117 | 1118 |
| 1118 @override | 1119 @override |
| 1119 JS.Statement visitEnumDeclaration(EnumDeclaration node) { | 1120 JS.Statement visitEnumDeclaration(EnumDeclaration node) { |
| 1120 var element = node.element; | 1121 var element = elementForEnumDeclaration(node); |
| 1121 var type = element.type; | 1122 var type = element.type; |
| 1122 | 1123 |
| 1123 // Generate a class per section 13 of the spec. | 1124 // Generate a class per section 13 of the spec. |
| 1124 // TODO(vsm): Generate any accompanying metadata | 1125 // TODO(vsm): Generate any accompanying metadata |
| 1125 | 1126 |
| 1126 // Create constructor and initialize index | 1127 // Create constructor and initialize index |
| 1127 var constructor = new JS.Method(_propertyName('new'), | 1128 var constructor = new JS.Method(_propertyName('new'), |
| 1128 js.call('function(index) { this.index = index; }') as JS.Fun); | 1129 js.call('function(index) { this.index = index; }') as JS.Fun); |
| 1129 var fields = new List<FieldElement>.from( | 1130 var fields = new List<FieldElement>.from( |
| 1130 element.fields.where((f) => f.type == type)); | 1131 element.fields.where((f) => f.type == type)); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1281 } | 1282 } |
| 1282 return jsMethods; | 1283 return jsMethods; |
| 1283 } | 1284 } |
| 1284 | 1285 |
| 1285 List<JS.Method> _emitClassMethods( | 1286 List<JS.Method> _emitClassMethods( |
| 1286 ClassDeclaration node, | 1287 ClassDeclaration node, |
| 1287 List<ConstructorDeclaration> ctors, | 1288 List<ConstructorDeclaration> ctors, |
| 1288 List<FieldDeclaration> fields, | 1289 List<FieldDeclaration> fields, |
| 1289 List<ClassElement> superclasses, | 1290 List<ClassElement> superclasses, |
| 1290 Map<FieldElement, JS.TemporaryId> virtualFields) { | 1291 Map<FieldElement, JS.TemporaryId> virtualFields) { |
| 1291 var element = node.element; | 1292 var element = elementForClassDeclaration(node); |
| 1292 var type = element.type; | 1293 var type = element.type; |
| 1293 var isObject = type.isObject; | 1294 var isObject = type.isObject; |
| 1294 | 1295 |
| 1295 // Iff no constructor is specified for a class C, it implicitly has a | 1296 // Iff no constructor is specified for a class C, it implicitly has a |
| 1296 // default constructor `C() : super() {}`, unless C is class Object. | 1297 // default constructor `C() : super() {}`, unless C is class Object. |
| 1297 var jsMethods = <JS.Method>[]; | 1298 var jsMethods = <JS.Method>[]; |
| 1298 if (isObject) { | 1299 if (isObject) { |
| 1299 // Implements Dart constructor behavior. | 1300 // Implements Dart constructor behavior. |
| 1300 // | 1301 // |
| 1301 // Because of ES6 constructor restrictions (`this` is not available until | 1302 // Because of ES6 constructor restrictions (`this` is not available until |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1761 | 1762 |
| 1762 var tStaticMethods = <JS.Property>[]; | 1763 var tStaticMethods = <JS.Property>[]; |
| 1763 var tInstanceMethods = <JS.Property>[]; | 1764 var tInstanceMethods = <JS.Property>[]; |
| 1764 var tStaticGetters = <JS.Property>[]; | 1765 var tStaticGetters = <JS.Property>[]; |
| 1765 var tInstanceGetters = <JS.Property>[]; | 1766 var tInstanceGetters = <JS.Property>[]; |
| 1766 var tStaticSetters = <JS.Property>[]; | 1767 var tStaticSetters = <JS.Property>[]; |
| 1767 var tInstanceSetters = <JS.Property>[]; | 1768 var tInstanceSetters = <JS.Property>[]; |
| 1768 var sNames = <JS.Expression>[]; | 1769 var sNames = <JS.Expression>[]; |
| 1769 for (MethodDeclaration node in methods) { | 1770 for (MethodDeclaration node in methods) { |
| 1770 var name = node.name.name; | 1771 var name = node.name.name; |
| 1771 var element = node.element; | 1772 var element = elementForMethodDeclaration(node); |
| 1772 // TODO(vsm): Clean up all the nasty duplication. | 1773 // TODO(vsm): Clean up all the nasty duplication. |
| 1773 if (node.isAbstract) { | 1774 if (node.isAbstract) { |
| 1774 continue; | 1775 continue; |
| 1775 } | 1776 } |
| 1776 | 1777 |
| 1777 Function lookup; | 1778 Function lookup; |
| 1778 List<JS.Property> tMember; | 1779 List<JS.Property> tMember; |
| 1779 JS.Expression type; | 1780 JS.Expression type; |
| 1780 if (node.isGetter) { | 1781 if (node.isGetter) { |
| 1781 lookup = classElem.lookUpInheritedConcreteGetter; | 1782 lookup = classElem.lookUpInheritedConcreteGetter; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1816 var memberName = _declareMemberName(element.getter); | 1817 var memberName = _declareMemberName(element.getter); |
| 1817 var type = _emitAnnotatedType(element.type, node.metadata); | 1818 var type = _emitAnnotatedType(element.type, node.metadata); |
| 1818 var property = new JS.Property(memberName, type); | 1819 var property = new JS.Property(memberName, type); |
| 1819 (node.isStatic ? tStaticFields : tInstanceFields).add(property); | 1820 (node.isStatic ? tStaticFields : tInstanceFields).add(property); |
| 1820 } | 1821 } |
| 1821 } | 1822 } |
| 1822 | 1823 |
| 1823 var tCtors = <JS.Property>[]; | 1824 var tCtors = <JS.Property>[]; |
| 1824 for (ConstructorDeclaration node in ctors) { | 1825 for (ConstructorDeclaration node in ctors) { |
| 1825 var memberName = _constructorName(node.element); | 1826 var memberName = _constructorName(node.element); |
| 1826 var element = node.element; | 1827 var element = elementForConstructorDeclaration(node); |
| 1827 var type = _emitAnnotatedFunctionType(element.type, node.metadata, | 1828 var type = _emitAnnotatedFunctionType(element.type, node.metadata, |
| 1828 parameters: node.parameters.parameters, | 1829 parameters: node.parameters.parameters, |
| 1829 nameType: options.hoistSignatureTypes, | 1830 nameType: options.hoistSignatureTypes, |
| 1830 hoistType: options.hoistSignatureTypes, | 1831 hoistType: options.hoistSignatureTypes, |
| 1831 definite: true); | 1832 definite: true); |
| 1832 var property = new JS.Property(memberName, type); | 1833 var property = new JS.Property(memberName, type); |
| 1833 tCtors.add(property); | 1834 tCtors.add(property); |
| 1834 } | 1835 } |
| 1835 | 1836 |
| 1836 JS.Property build(String name, List<JS.Property> elements) { | 1837 JS.Property build(String name, List<JS.Property> elements) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1888 | 1889 |
| 1889 /// Ensure `dartx.` symbols we will use are present. | 1890 /// Ensure `dartx.` symbols we will use are present. |
| 1890 void _initExtensionSymbols( | 1891 void _initExtensionSymbols( |
| 1891 ClassElement classElem, | 1892 ClassElement classElem, |
| 1892 List<MethodDeclaration> methods, | 1893 List<MethodDeclaration> methods, |
| 1893 List<FieldDeclaration> fields, | 1894 List<FieldDeclaration> fields, |
| 1894 List<JS.Statement> body) { | 1895 List<JS.Statement> body) { |
| 1895 if (_extensionTypes.hasNativeSubtype(classElem.type)) { | 1896 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
| 1896 var dartxNames = <JS.Expression>[]; | 1897 var dartxNames = <JS.Expression>[]; |
| 1897 for (var m in methods) { | 1898 for (var m in methods) { |
| 1898 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1899 if (!m.isAbstract && !m.isStatic && elementForMethodDeclaration(m).isPub
lic) { |
| 1899 dartxNames.add(_declareMemberName(m.element, useExtension: false)); | 1900 dartxNames.add(_declareMemberName(m.element, useExtension: false)); |
| 1900 } | 1901 } |
| 1901 } | 1902 } |
| 1902 for (var fieldDecl in fields) { | 1903 for (var fieldDecl in fields) { |
| 1903 if (!fieldDecl.isStatic) { | 1904 if (!fieldDecl.isStatic) { |
| 1904 for (var field in fieldDecl.fields.variables) { | 1905 for (var field in fieldDecl.fields.variables) { |
| 1905 var e = field.element as FieldElement; | 1906 var e = field.element as FieldElement; |
| 1906 if (e.isPublic) { | 1907 if (e.isPublic) { |
| 1907 dartxNames.add(_declareMemberName(e.getter, useExtension: false)); | 1908 dartxNames.add(_declareMemberName(e.getter, useExtension: false)); |
| 1908 } | 1909 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1950 Map<FieldElement, JS.TemporaryId> virtualFields) { | 1951 Map<FieldElement, JS.TemporaryId> virtualFields) { |
| 1951 // If we don't have a method body, skip this. | 1952 // If we don't have a method body, skip this. |
| 1952 var superCall = _superConstructorCall(node.element); | 1953 var superCall = _superConstructorCall(node.element); |
| 1953 if (fields.isEmpty && superCall == null) return null; | 1954 if (fields.isEmpty && superCall == null) return null; |
| 1954 | 1955 |
| 1955 var initFields = _initializeFields(node, fields, virtualFields); | 1956 var initFields = _initializeFields(node, fields, virtualFields); |
| 1956 List<JS.Statement> body = [initFields]; | 1957 List<JS.Statement> body = [initFields]; |
| 1957 if (superCall != null) { | 1958 if (superCall != null) { |
| 1958 body.add(superCall); | 1959 body.add(superCall); |
| 1959 } | 1960 } |
| 1960 var name = _constructorName(node.element.unnamedConstructor); | 1961 var name = _constructorName(elementForClassDeclaration(node).unnamedConstruc
tor); |
| 1961 return annotate( | 1962 return annotate( |
| 1962 new JS.Method(name, js.call('function() { #; }', [body]) as JS.Fun), | 1963 new JS.Method(name, js.call('function() { #; }', [body]) as JS.Fun), |
| 1963 node, | 1964 node, |
| 1964 node.element); | 1965 node.element); |
| 1965 } | 1966 } |
| 1966 | 1967 |
| 1967 JS.Method _emitConstructor( | 1968 JS.Method _emitConstructor( |
| 1968 ConstructorDeclaration node, | 1969 ConstructorDeclaration node, |
| 1969 InterfaceType type, | 1970 InterfaceType type, |
| 1970 List<FieldDeclaration> fields, | 1971 List<FieldDeclaration> fields, |
| 1971 Map<FieldElement, JS.TemporaryId> virtualFields, | 1972 Map<FieldElement, JS.TemporaryId> virtualFields, |
| 1972 bool isObject) { | 1973 bool isObject) { |
| 1973 if (_externalOrNative(node)) return null; | 1974 if (_externalOrNative(node)) return null; |
| 1974 | 1975 |
| 1975 var name = _constructorName(node.element); | 1976 var name = _constructorName(node.element); |
| 1976 var returnType = emitTypeRef(node.element.enclosingElement.type); | 1977 var returnType = emitTypeRef(elementForConstructorDeclaration(node).enclosin
gElement.type); |
| 1977 | 1978 |
| 1978 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; | 1979 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; |
| 1979 var redirect = node.redirectedConstructor; | 1980 var redirect = node.redirectedConstructor; |
| 1980 if (redirect != null) { | 1981 if (redirect != null) { |
| 1981 var newKeyword = redirect.staticElement.isFactory ? '' : 'new'; | 1982 var newKeyword = staticElementForConstructorReference(redirect).isFactory
? '' : 'new'; |
| 1982 // Pass along all arguments verbatim, and let the callee handle them. | 1983 // Pass along all arguments verbatim, and let the callee handle them. |
| 1983 // TODO(jmesserly): we'll need something different once we have | 1984 // TODO(jmesserly): we'll need something different once we have |
| 1984 // rest/spread support, but this should work for now. | 1985 // rest/spread support, but this should work for now. |
| 1985 var params = | 1986 var params = |
| 1986 visitFormalParameterList(node.parameters, destructure: false); | 1987 visitFormalParameterList(node.parameters, destructure: false); |
| 1987 | 1988 |
| 1988 var fun = new JS.Fun( | 1989 var fun = new JS.Fun( |
| 1989 params, | 1990 params, |
| 1990 js.statement('{ return $newKeyword #(#); }', | 1991 js.statement('{ return $newKeyword #(#); }', |
| 1991 [_visit(redirect) as JS.Node, params]), | 1992 [_visit(redirect) as JS.Node, params]), |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2080 var jsSuper = _superConstructorCall(cls.element, superCall); | 2081 var jsSuper = _superConstructorCall(cls.element, superCall); |
| 2081 if (jsSuper != null) body.add(jsSuper); | 2082 if (jsSuper != null) body.add(jsSuper); |
| 2082 | 2083 |
| 2083 body.add(_visit(node.body)); | 2084 body.add(_visit(node.body)); |
| 2084 return new JS.Block(body)..sourceInformation = node; | 2085 return new JS.Block(body)..sourceInformation = node; |
| 2085 } | 2086 } |
| 2086 | 2087 |
| 2087 @override | 2088 @override |
| 2088 JS.Statement visitRedirectingConstructorInvocation( | 2089 JS.Statement visitRedirectingConstructorInvocation( |
| 2089 RedirectingConstructorInvocation node) { | 2090 RedirectingConstructorInvocation node) { |
| 2090 var ctor = node.staticElement; | 2091 var ctor = staticElementForConstructorReference(node); |
| 2091 var cls = ctor.enclosingElement; | 2092 var cls = ctor.enclosingElement; |
| 2092 // We can't dispatch to the constructor with `this.new` as that might hit a | 2093 // We can't dispatch to the constructor with `this.new` as that might hit a |
| 2093 // derived class constructor with the same name. | 2094 // derived class constructor with the same name. |
| 2094 return js.statement('#.prototype.#.call(this, #);', [ | 2095 return js.statement('#.prototype.#.call(this, #);', [ |
| 2095 new JS.Identifier(cls.name), | 2096 new JS.Identifier(cls.name), |
| 2096 _constructorName(ctor), | 2097 _constructorName(ctor), |
| 2097 _visit(node.argumentList) | 2098 _visit(node.argumentList) |
| 2098 ]); | 2099 ]); |
| 2099 } | 2100 } |
| 2100 | 2101 |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2257 _defaultParamValue(param), | 2258 _defaultParamValue(param), |
| 2258 ])); | 2259 ])); |
| 2259 } else if (param.kind == ParameterKind.POSITIONAL) { | 2260 } else if (param.kind == ParameterKind.POSITIONAL) { |
| 2260 body.add(js.statement('if (# === void 0) # = #;', | 2261 body.add(js.statement('if (# === void 0) # = #;', |
| 2261 [jsParam, jsParam, _defaultParamValue(param)])); | 2262 [jsParam, jsParam, _defaultParamValue(param)])); |
| 2262 } | 2263 } |
| 2263 } | 2264 } |
| 2264 | 2265 |
| 2265 // TODO(jmesserly): various problems here, see: | 2266 // TODO(jmesserly): various problems here, see: |
| 2266 // https://github.com/dart-lang/dev_compiler/issues/116 | 2267 // https://github.com/dart-lang/dev_compiler/issues/116 |
| 2267 var paramType = param.element.type; | 2268 var paramType = elementForFormalParameter(param).type; |
| 2268 if (node is MethodDeclaration && | 2269 if (node is MethodDeclaration && |
| 2269 (param.element.isCovariant || _unsoundCovariant(paramType, true)) && | 2270 (elementForFormalParameter(param).isCovariant || _unsoundCovariant(par
amType, true)) && |
| 2270 !_inWhitelistCode(node)) { | 2271 !_inWhitelistCode(node)) { |
| 2271 var castType = _emitType(paramType, | 2272 var castType = _emitType(paramType, |
| 2272 nameType: options.nameTypeTests || options.hoistTypeTests, | 2273 nameType: options.nameTypeTests || options.hoistTypeTests, |
| 2273 hoistType: options.hoistTypeTests); | 2274 hoistType: options.hoistTypeTests); |
| 2274 body.add(js.statement('#._check(#);', [castType, jsParam])); | 2275 body.add(js.statement('#._check(#);', [castType, jsParam])); |
| 2275 } | 2276 } |
| 2276 } | 2277 } |
| 2277 return body.isEmpty ? null : _statement(body); | 2278 return body.isEmpty ? null : _statement(body); |
| 2278 } | 2279 } |
| 2279 | 2280 |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2404 } | 2405 } |
| 2405 | 2406 |
| 2406 var body = <JS.Statement>[]; | 2407 var body = <JS.Statement>[]; |
| 2407 var fn = _emitFunction(node.functionExpression); | 2408 var fn = _emitFunction(node.functionExpression); |
| 2408 | 2409 |
| 2409 if (currentLibrary.source.isInSystemLibrary && | 2410 if (currentLibrary.source.isInSystemLibrary && |
| 2410 _isInlineJSFunction(node.functionExpression)) { | 2411 _isInlineJSFunction(node.functionExpression)) { |
| 2411 fn = _simplifyPassThroughArrowFunCallBody(fn); | 2412 fn = _simplifyPassThroughArrowFunCallBody(fn); |
| 2412 } | 2413 } |
| 2413 | 2414 |
| 2414 var element = node.element; | 2415 var element = elementForFunctionDeclaration(node); |
| 2415 var nameExpr = _emitTopLevelName(element); | 2416 var nameExpr = _emitTopLevelName(element); |
| 2416 body.add(annotate(js.statement('# = #', [nameExpr, fn]), node, element)); | 2417 body.add(annotate(js.statement('# = #', [nameExpr, fn]), node, element)); |
| 2417 if (!_isDartRuntime(element.library)) { | 2418 if (!_isDartRuntime(element.library)) { |
| 2418 body.add(_emitFunctionTagged(nameExpr, element.type, topLevel: true) | 2419 body.add(_emitFunctionTagged(nameExpr, element.type, topLevel: true) |
| 2419 .toStatement()); | 2420 .toStatement()); |
| 2420 } | 2421 } |
| 2421 | 2422 |
| 2422 return _statement(body); | 2423 return _statement(body); |
| 2423 } | 2424 } |
| 2424 | 2425 |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2672 JS.Statement declareFn; | 2673 JS.Statement declareFn; |
| 2673 if (JS.This.foundIn(fn)) { | 2674 if (JS.This.foundIn(fn)) { |
| 2674 declareFn = js.statement('const # = #.bind(this);', [name, fn]); | 2675 declareFn = js.statement('const # = #.bind(this);', [name, fn]); |
| 2675 } else { | 2676 } else { |
| 2676 declareFn = new JS.FunctionDeclaration(name, fn); | 2677 declareFn = new JS.FunctionDeclaration(name, fn); |
| 2677 } | 2678 } |
| 2678 declareFn = annotate(declareFn, node, node.functionDeclaration.element); | 2679 declareFn = annotate(declareFn, node, node.functionDeclaration.element); |
| 2679 | 2680 |
| 2680 return new JS.Block([ | 2681 return new JS.Block([ |
| 2681 declareFn, | 2682 declareFn, |
| 2682 _emitFunctionTagged(name, func.element.type).toStatement() | 2683 _emitFunctionTagged(name, elementForFunctionDeclaration(func).type).toStat
ement() |
| 2683 ]); | 2684 ]); |
| 2684 } | 2685 } |
| 2685 | 2686 |
| 2686 /// Emits a simple identifier, including handling an inferred generic | 2687 /// Emits a simple identifier, including handling an inferred generic |
| 2687 /// function instantiation. | 2688 /// function instantiation. |
| 2688 @override | 2689 @override |
| 2689 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { | 2690 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { |
| 2690 var typeArgs = _getTypeArgs(node.staticElement, node.staticType); | 2691 var typeArgs = _getTypeArgs(node.staticElement, node.staticType); |
| 2691 var simpleId = _emitSimpleIdentifier(node); | 2692 var simpleId = _emitSimpleIdentifier(node); |
| 2692 if (typeArgs == null) { | 2693 if (typeArgs == null) { |
| 2693 return simpleId; | 2694 return simpleId; |
| 2694 } | 2695 } |
| 2695 return _callHelper('gbind(#, #)', [simpleId, typeArgs]); | 2696 return _callHelper('gbind(#, #)', [simpleId, typeArgs]); |
| 2696 } | 2697 } |
| 2697 | 2698 |
| 2698 /// Emits a simple identifier, handling implicit `this` as well as | 2699 /// Emits a simple identifier, handling implicit `this` as well as |
| 2699 /// going through the qualified library name if necessary, but *not* handling | 2700 /// going through the qualified library name if necessary, but *not* handling |
| 2700 /// inferred generic function instantiation. | 2701 /// inferred generic function instantiation. |
| 2701 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { | 2702 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { |
| 2702 var accessor = node.staticElement; | 2703 var accessor = staticElementForIdentifier(node); |
| 2703 if (accessor == null) { | 2704 if (accessor == null) { |
| 2704 return js.commentExpression( | 2705 return js.commentExpression( |
| 2705 'Unimplemented unknown name', new JS.Identifier(node.name)); | 2706 'Unimplemented unknown name', new JS.Identifier(node.name)); |
| 2706 } | 2707 } |
| 2707 | 2708 |
| 2708 // Get the original declaring element. If we had a property accessor, this | 2709 // Get the original declaring element. If we had a property accessor, this |
| 2709 // indirects back to a (possibly synthetic) field. | 2710 // indirects back to a (possibly synthetic) field. |
| 2710 var element = accessor; | 2711 var element = accessor; |
| 2711 if (accessor is PropertyAccessorElement) element = accessor.variable; | 2712 if (accessor is PropertyAccessorElement) element = accessor.variable; |
| 2712 | 2713 |
| (...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3223 | 3224 |
| 3224 /// Emits assignment to a simple identifier. Handles all legal simple | 3225 /// Emits assignment to a simple identifier. Handles all legal simple |
| 3225 /// identifier assignment targets (local, top level library member, implicit | 3226 /// identifier assignment targets (local, top level library member, implicit |
| 3226 /// `this` or class, etc.) | 3227 /// `this` or class, etc.) |
| 3227 JS.Expression _emitSetSimpleIdentifier( | 3228 JS.Expression _emitSetSimpleIdentifier( |
| 3228 SimpleIdentifier node, Expression rhs) { | 3229 SimpleIdentifier node, Expression rhs) { |
| 3229 JS.Expression unimplemented() { | 3230 JS.Expression unimplemented() { |
| 3230 return _badAssignment("Unimplemented: unknown name '$node'", node, rhs); | 3231 return _badAssignment("Unimplemented: unknown name '$node'", node, rhs); |
| 3231 } | 3232 } |
| 3232 | 3233 |
| 3233 var accessor = node.staticElement; | 3234 var accessor = staticElementForIdentifier(node); |
| 3234 if (accessor == null) return unimplemented(); | 3235 if (accessor == null) return unimplemented(); |
| 3235 | 3236 |
| 3236 // Get the original declaring element. If we had a property accessor, this | 3237 // Get the original declaring element. If we had a property accessor, this |
| 3237 // indirects back to a (possibly synthetic) field. | 3238 // indirects back to a (possibly synthetic) field. |
| 3238 var element = accessor; | 3239 var element = accessor; |
| 3239 if (accessor is PropertyAccessorElement) element = accessor.variable; | 3240 if (accessor is PropertyAccessorElement) element = accessor.variable; |
| 3240 | 3241 |
| 3241 _declareBeforeUse(element); | 3242 _declareBeforeUse(element); |
| 3242 | 3243 |
| 3243 if (element is LocalVariableElement || element is ParameterElement) { | 3244 if (element is LocalVariableElement || element is ParameterElement) { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3385 } | 3386 } |
| 3386 | 3387 |
| 3387 var result = _emitForeignJS(node); | 3388 var result = _emitForeignJS(node); |
| 3388 if (result != null) return result; | 3389 if (result != null) return result; |
| 3389 | 3390 |
| 3390 var target = _getTarget(node); | 3391 var target = _getTarget(node); |
| 3391 if (target == null || isLibraryPrefix(target)) { | 3392 if (target == null || isLibraryPrefix(target)) { |
| 3392 return _emitFunctionCall(node); | 3393 return _emitFunctionCall(node); |
| 3393 } | 3394 } |
| 3394 if (node.methodName.name == 'call') { | 3395 if (node.methodName.name == 'call') { |
| 3395 var targetType = target.staticType; | 3396 var targetType = staticTypeForExpression(target); |
| 3396 if (targetType is FunctionType) { | 3397 if (targetType is FunctionType) { |
| 3397 // Call methods on function types should be handled as regular function | 3398 // Call methods on function types should be handled as regular function |
| 3398 // invocations. | 3399 // invocations. |
| 3399 return _emitFunctionCall(node, node.target); | 3400 return _emitFunctionCall(node, node.target); |
| 3400 } | 3401 } |
| 3401 if (targetType.isDartCoreFunction || targetType.isDynamic) { | 3402 if (targetType.isDartCoreFunction || targetType.isDynamic) { |
| 3402 // TODO(vsm): Can a call method take generic type parameters? | 3403 // TODO(vsm): Can a call method take generic type parameters? |
| 3403 return _emitDynamicInvoke(node, _visit(target), | 3404 return _emitDynamicInvoke(node, _visit(target), |
| 3404 _visit(node.argumentList) as List<JS.Expression>); | 3405 _visit(node.argumentList) as List<JS.Expression>); |
| 3405 } | 3406 } |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3860 | 3861 |
| 3861 @override | 3862 @override |
| 3862 visitVariableDeclaration(VariableDeclaration node) { | 3863 visitVariableDeclaration(VariableDeclaration node) { |
| 3863 if (node.element is PropertyInducingElement) { | 3864 if (node.element is PropertyInducingElement) { |
| 3864 // Static and instance fields are handled elsewhere. | 3865 // Static and instance fields are handled elsewhere. |
| 3865 assert(node.element is TopLevelVariableElement); | 3866 assert(node.element is TopLevelVariableElement); |
| 3866 return _emitTopLevelField(node); | 3867 return _emitTopLevelField(node); |
| 3867 } | 3868 } |
| 3868 | 3869 |
| 3869 var name = | 3870 var name = |
| 3870 new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type)); | 3871 new JS.Identifier(node.name.name, type: emitTypeRef(elementForVariableDe
claration(node).type)); |
| 3871 return new JS.VariableInitialization(name, _visitInitializer(node)); | 3872 return new JS.VariableInitialization(name, _visitInitializer(node)); |
| 3872 } | 3873 } |
| 3873 | 3874 |
| 3874 /// Try to emit a constant static field. | 3875 /// Try to emit a constant static field. |
| 3875 /// | 3876 /// |
| 3876 /// If the field's initializer does not cause side effects, and if all of | 3877 /// If the field's initializer does not cause side effects, and if all of |
| 3877 /// dependencies are safe to refer to while we are initializing the class, | 3878 /// dependencies are safe to refer to while we are initializing the class, |
| 3878 /// then we can initialize it eagerly: | 3879 /// then we can initialize it eagerly: |
| 3879 /// | 3880 /// |
| 3880 /// // Baz must be const constructor, and the name "Baz" must be defined | 3881 /// // Baz must be const constructor, and the name "Baz" must be defined |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4077 var args = _visit(argumentList) as List<JS.Expression>; | 4078 var args = _visit(argumentList) as List<JS.Expression>; |
| 4078 if (args.isEmpty) { | 4079 if (args.isEmpty) { |
| 4079 return js.call('{}'); | 4080 return js.call('{}'); |
| 4080 } | 4081 } |
| 4081 assert(args.single is JS.ObjectInitializer); | 4082 assert(args.single is JS.ObjectInitializer); |
| 4082 return args.single; | 4083 return args.single; |
| 4083 } | 4084 } |
| 4084 | 4085 |
| 4085 @override | 4086 @override |
| 4086 visitInstanceCreationExpression(InstanceCreationExpression node) { | 4087 visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 4087 var element = node.staticElement; | 4088 var element = staticElementForConstructorReference(node); |
| 4088 var constructor = node.constructorName; | 4089 var constructor = node.constructorName; |
| 4089 var name = constructor.name; | 4090 var name = constructor.name; |
| 4090 var type = constructor.type.type; | 4091 var type = constructor.type.type; |
| 4091 if (node.isConst && | 4092 if (node.isConst && |
| 4092 element?.name == 'fromEnvironment' && | 4093 element?.name == 'fromEnvironment' && |
| 4093 element.library.isDartCore) { | 4094 element.library.isDartCore) { |
| 4094 var value = node.accept(_constants.constantVisitor); | 4095 var value = node.accept(_constants.constantVisitor); |
| 4095 | 4096 |
| 4096 if (value == null || value.isNull) { | 4097 if (value == null || value.isNull) { |
| 4097 return new JS.LiteralNull(); | 4098 return new JS.LiteralNull(); |
| (...skipping 1668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5766 bool _isDeferredLoadLibrary(Expression target, SimpleIdentifier name) { | 5767 bool _isDeferredLoadLibrary(Expression target, SimpleIdentifier name) { |
| 5767 if (name.name != "loadLibrary") return false; | 5768 if (name.name != "loadLibrary") return false; |
| 5768 | 5769 |
| 5769 if (target is! SimpleIdentifier) return false; | 5770 if (target is! SimpleIdentifier) return false; |
| 5770 var targetIdentifier = target as SimpleIdentifier; | 5771 var targetIdentifier = target as SimpleIdentifier; |
| 5771 | 5772 |
| 5772 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5773 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5773 var prefix = targetIdentifier.staticElement as PrefixElement; | 5774 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5774 | 5775 |
| 5775 // The library the prefix is referring to must come from a deferred import. | 5776 // The library the prefix is referring to must come from a deferred import. |
| 5776 var containingLibrary = (target.root as CompilationUnit).element.library; | 5777 var containingLibrary = elementForCompilationUnit(target.root as CompilationUn
it).library; |
| 5777 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5778 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5778 return imports.length == 1 && imports[0].isDeferred; | 5779 return imports.length == 1 && imports[0].isDeferred; |
| 5779 } | 5780 } |
| OLD | NEW |