| 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 library dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
| 6 | 6 |
| 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 final _privateNames = new HashMap<String, JS.TemporaryId>(); | 87 final _privateNames = new HashMap<String, JS.TemporaryId>(); |
| 88 final _moduleItems = <JS.Statement>[]; | 88 final _moduleItems = <JS.Statement>[]; |
| 89 final _temps = new HashMap<Element, JS.TemporaryId>(); | 89 final _temps = new HashMap<Element, JS.TemporaryId>(); |
| 90 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); | 90 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); |
| 91 | 91 |
| 92 /// The name for the library's exports inside itself. | 92 /// The name for the library's exports inside itself. |
| 93 /// `exports` was chosen as the most similar to ES module patterns. | 93 /// `exports` was chosen as the most similar to ES module patterns. |
| 94 final _dartxVar = new JS.Identifier('dartx'); | 94 final _dartxVar = new JS.Identifier('dartx'); |
| 95 final _exportsVar = new JS.TemporaryId('exports'); | 95 final _exportsVar = new JS.TemporaryId('exports'); |
| 96 final _runtimeLibVar = new JS.Identifier('dart'); | 96 final _runtimeLibVar = new JS.Identifier('dart'); |
| 97 final _utilsLibVar = new JS.TemporaryId('utils'); |
| 98 final _classesLibVar = new JS.TemporaryId('classes'); |
| 99 final _rttiLibVar = new JS.TemporaryId('rtti'); |
| 97 final _namedArgTemp = new JS.TemporaryId('opts'); | 100 final _namedArgTemp = new JS.TemporaryId('opts'); |
| 98 | 101 |
| 99 final TypeProvider _types; | 102 final TypeProvider _types; |
| 100 | 103 |
| 101 ConstFieldVisitor _constField; | 104 ConstFieldVisitor _constField; |
| 102 | 105 |
| 103 ModuleItemLoadOrder _loader; | 106 ModuleItemLoadOrder _loader; |
| 104 | 107 |
| 105 /// _interceptors.JSArray<E>, used for List literals. | 108 /// _interceptors.JSArray<E>, used for List literals. |
| 106 ClassElement _jsArray; | 109 ClassElement _jsArray; |
| 107 | 110 |
| 108 /// The default value of the module object. See [visitLibraryDirective]. | 111 /// The default value of the module object. See [visitLibraryDirective]. |
| 109 String _jsModuleValue; | 112 String _jsModuleValue; |
| 110 | 113 |
| 111 bool _isDartUtils; | 114 bool _isDartRuntime; |
| 112 | 115 |
| 113 Map<String, DartType> _objectMembers; | 116 Map<String, DartType> _objectMembers; |
| 114 | 117 |
| 115 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, | 118 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, |
| 116 this._extensionTypes, this._fieldsNeedingStorage) | 119 this._extensionTypes, this._fieldsNeedingStorage) |
| 117 : compiler = compiler, | 120 : compiler = compiler, |
| 118 options = compiler.options.codegenOptions, | 121 options = compiler.options.codegenOptions, |
| 119 _types = compiler.context.typeProvider { | 122 _types = compiler.context.typeProvider { |
| 120 _loader = new ModuleItemLoadOrder(_emitModuleItem); | 123 _loader = new ModuleItemLoadOrder(_emitModuleItem); |
| 121 | 124 |
| 122 var context = compiler.context; | 125 var context = compiler.context; |
| 123 var src = context.sourceFactory.forUri('dart:_interceptors'); | 126 var src = context.sourceFactory.forUri('dart:_interceptors'); |
| 124 var interceptors = context.computeLibraryElement(src); | 127 var interceptors = context.computeLibraryElement(src); |
| 125 _jsArray = interceptors.getType('JSArray'); | 128 _jsArray = interceptors.getType('JSArray'); |
| 126 _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils'; | 129 |
| 130 _isDartRuntime = _runtimeLibUris.contains(_getLibUri(currentLibrary)); |
| 127 | 131 |
| 128 _objectMembers = getObjectMemberMap(types); | 132 _objectMembers = getObjectMemberMap(types); |
| 129 } | 133 } |
| 134 String _getLibUri(LibraryElement lib) => lib.source.uri.toString(); |
| 135 |
| 136 static final _runtimeLibUris = new Set<String>.from([ |
| 137 'dart:_utils', |
| 138 'dart:_runtime', |
| 139 'dart:_operations', |
| 140 'dart:_errors', |
| 141 'dart:_classes', |
| 142 'dart:_generators', |
| 143 'dart:_operations', |
| 144 'dart:_types', |
| 145 'dart:_rtti' |
| 146 ]); |
| 130 | 147 |
| 131 TypeProvider get types => rules.provider; | 148 TypeProvider get types => rules.provider; |
| 132 | 149 |
| 133 JS.Program emitLibrary(LibraryUnit library) { | 150 JS.Program emitLibrary(LibraryUnit library) { |
| 134 // Modify the AST to make coercions explicit. | 151 // Modify the AST to make coercions explicit. |
| 135 new CoercionReifier(library, rules).reify(); | 152 new CoercionReifier(library, rules).reify(); |
| 136 | 153 |
| 137 // Build the public namespace for this library. This allows us to do | 154 // Build the public namespace for this library. This allows us to do |
| 138 // constant time lookups (contrast with `Element.getChild(name)`). | 155 // constant time lookups (contrast with `Element.getChild(name)`). |
| 139 if (currentLibrary.publicNamespace == null) { | 156 if (currentLibrary.publicNamespace == null) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 // TODO(jmesserly): make these immutable in JS? | 206 // TODO(jmesserly): make these immutable in JS? |
| 190 for (var name in _exports) { | 207 for (var name in _exports) { |
| 191 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); | 208 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); |
| 192 } | 209 } |
| 193 | 210 |
| 194 var jsPath = compiler.getModuleName(currentLibrary.source.uri); | 211 var jsPath = compiler.getModuleName(currentLibrary.source.uri); |
| 195 | 212 |
| 196 // TODO(jmesserly): it would be great to run the renamer on the body, | 213 // TODO(jmesserly): it would be great to run the renamer on the body, |
| 197 // then figure out if we really need each of these parameters. | 214 // then figure out if we really need each of these parameters. |
| 198 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 | 215 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 |
| 199 var params = [_exportsVar, _runtimeLibVar]; | 216 var params = [_exportsVar]; |
| 200 var processImport = | 217 var lazyParams = []; |
| 201 (LibraryElement library, JS.TemporaryId temp, List list) { | |
| 202 params.add(temp); | |
| 203 list.add(js.string(compiler.getModuleName(library.source.uri), "'")); | |
| 204 }; | |
| 205 | 218 |
| 206 var needsDartRuntime = !_isDartUtils; | 219 var libUri = _getLibUri(currentLibrary); |
| 207 | 220 |
| 208 var imports = <JS.Expression>[]; | 221 var imports = <JS.Expression>[]; |
| 222 var lazyImports = <JS.Expression>[]; |
| 209 var moduleStatements = <JS.Statement>[]; | 223 var moduleStatements = <JS.Statement>[]; |
| 210 if (needsDartRuntime) { | 224 |
| 211 imports.add(js.string('dart/_runtime')); | 225 addImport(String name, JS.Expression libVar, {bool eager: true}) { |
| 226 (eager ? imports : lazyImports).add(js.string(name, "'")); |
| 227 (eager ? params : lazyParams).add(libVar); |
| 228 } |
| 229 |
| 230 if (!_isDartRuntime) { |
| 231 addImport('dart/_runtime', _runtimeLibVar); |
| 212 | 232 |
| 213 var dartxImport = | 233 var dartxImport = |
| 214 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); | 234 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); |
| 215 moduleStatements.add(dartxImport); | 235 moduleStatements.add(dartxImport); |
| 236 } else { |
| 237 if (libUri == 'dart:_generators') { |
| 238 addImport('dart/_classes', _classesLibVar); |
| 239 } |
| 216 } | 240 } |
| 217 moduleStatements.addAll(_moduleItems); | 241 moduleStatements.addAll(_moduleItems); |
| 218 | 242 |
| 219 _imports.forEach((library, temp) { | 243 bool shouldImportEagerly(lib) { |
| 220 if (_loader.libraryIsLoaded(library)) { | 244 var otherLibUri = _getLibUri(lib); |
| 221 processImport(library, temp, imports); | 245 if (otherLibUri == 'dart:_utils') return true; |
| 222 } | 246 if (libUri == 'dart:_types' && otherLibUri == 'dart:_rtti') return true; |
| 247 if (libUri == 'dart:_runtime') return otherLibUri != 'dart:_js_helper'; |
| 248 return !_isDartRuntime && _loader.libraryIsLoaded(lib); |
| 249 } |
| 250 |
| 251 var importsEagerness = new Map<LibraryElement, bool>.fromIterable( |
| 252 _imports.keys, value: shouldImportEagerly); |
| 253 |
| 254 _imports.forEach((LibraryElement lib, JS.TemporaryId temp) { |
| 255 bool eager = importsEagerness[lib]; |
| 256 addImport(compiler.getModuleName(lib.source.uri), temp, eager: eager); |
| 223 }); | 257 }); |
| 224 | 258 |
| 225 var lazyImports = <JS.Expression>[]; | 259 params.addAll(lazyParams); |
| 226 _imports.forEach((library, temp) { | |
| 227 if (!_loader.libraryIsLoaded(library)) { | |
| 228 processImport(library, temp, lazyImports); | |
| 229 } | |
| 230 }); | |
| 231 | 260 |
| 232 var module = | 261 var module = |
| 233 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]); | 262 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]); |
| 234 | 263 |
| 235 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [ | 264 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [ |
| 236 js.string(jsPath, "'"), | 265 js.string(jsPath, "'"), |
| 237 _jsModuleValue ?? new JS.LiteralNull(), | 266 _jsModuleValue ?? new JS.LiteralNull(), |
| 238 js.commentExpression( | 267 js.commentExpression( |
| 239 "Imports", new JS.ArrayInitializer(imports, multiline: true)), | 268 "Imports", new JS.ArrayInitializer(imports, multiline: true)), |
| 240 js.commentExpression("Lazy imports", | 269 js.commentExpression("Lazy imports", |
| (...skipping 16 matching lines...) Expand all Loading... |
| 257 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems); | 286 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems); |
| 258 | 287 |
| 259 var code = _visit(node); | 288 var code = _visit(node); |
| 260 if (code != null) _moduleItems.add(code); | 289 if (code != null) _moduleItems.add(code); |
| 261 } | 290 } |
| 262 | 291 |
| 263 @override | 292 @override |
| 264 void visitLibraryDirective(LibraryDirective node) { | 293 void visitLibraryDirective(LibraryDirective node) { |
| 265 assert(_jsModuleValue == null); | 294 assert(_jsModuleValue == null); |
| 266 | 295 |
| 267 var jsName = findAnnotation(node.element, isJSAnnotation); | 296 _jsModuleValue = _getJsName(node.element); |
| 268 _jsModuleValue = | 297 } |
| 269 getConstantField(jsName, 'name', types.stringType)?.toStringValue(); | 298 |
| 299 String _getJsName(Element e) { |
| 300 var jsName = findAnnotation(e, isJSAnnotation); |
| 301 return getConstantField(jsName, 'name', types.stringType)?.toStringValue(); |
| 270 } | 302 } |
| 271 | 303 |
| 272 @override | 304 @override |
| 273 void visitImportDirective(ImportDirective node) { | 305 void visitImportDirective(ImportDirective node) { |
| 274 // Nothing to do yet, but we'll want to convert this to an ES6 import once | 306 // Nothing to do yet, but we'll want to convert this to an ES6 import once |
| 275 // we have support for modules. | 307 // we have support for modules. |
| 276 } | 308 } |
| 277 | 309 |
| 278 @override void visitPartDirective(PartDirective node) {} | 310 @override void visitPartDirective(PartDirective node) {} |
| 279 @override void visitPartOfDirective(PartOfDirective node) {} | 311 @override void visitPartOfDirective(PartOfDirective node) {} |
| 280 | 312 |
| 281 @override | 313 @override |
| 282 void visitExportDirective(ExportDirective node) { | 314 void visitExportDirective(ExportDirective node) { |
| 283 var exportName = _libraryName(node.uriElement); | 315 var exportName = _libraryName(node.uriElement); |
| 284 | 316 |
| 285 var currentLibNames = currentLibrary.publicNamespace.definedNames; | 317 var currentLibNames = currentLibrary.publicNamespace.definedNames; |
| 286 | 318 |
| 287 var args = [_exportsVar, exportName]; | 319 var args = [_exportsVar, exportName]; |
| 288 if (node.combinators.isNotEmpty) { | 320 if (node.combinators.isNotEmpty) { |
| 289 var shownNames = <JS.Expression>[]; | 321 var shownNames = <JS.Expression>[]; |
| 290 var hiddenNames = <JS.Expression>[]; | 322 var hiddenNames = <JS.Expression>[]; |
| 291 | 323 |
| 292 var show = node.combinators.firstWhere((c) => c is ShowCombinator, | 324 var show = node.combinators.firstWhere((c) => c is ShowCombinator, |
| 293 orElse: () => null) as ShowCombinator; | 325 orElse: () => null) as ShowCombinator; |
| 294 var hide = node.combinators.firstWhere((c) => c is HideCombinator, | 326 var hide = node.combinators.firstWhere((c) => c is HideCombinator, |
| 295 orElse: () => null) as HideCombinator; | 327 orElse: () => null) as HideCombinator; |
| 296 if (show != null) { | 328 if (show != null) { |
| 329 var singleName = _getJsName(node.element); |
| 330 if (singleName != null && show.shownNames.length != 1) { |
| 331 throw new StateError('Cannot set js name on more than one name'); |
| 332 } |
| 297 shownNames.addAll(show.shownNames | 333 shownNames.addAll(show.shownNames |
| 298 .map((i) => i.name) | 334 .map((i) => singleName ?? i.name) |
| 299 .where((s) => !currentLibNames.containsKey(s)) | 335 .where((s) => !currentLibNames.containsKey(s)) |
| 300 .map((s) => js.string(s, "'"))); | 336 .map((s) => js.string(s, "'"))); |
| 301 } | 337 } |
| 302 if (hide != null) { | 338 if (hide != null) { |
| 303 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); | 339 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); |
| 304 } | 340 } |
| 305 args.add(new JS.ArrayInitializer(shownNames)); | 341 args.add(new JS.ArrayInitializer(shownNames)); |
| 306 args.add(new JS.ArrayInitializer(hiddenNames)); | 342 args.add(new JS.ArrayInitializer(hiddenNames)); |
| 307 } | 343 } |
| 308 _moduleItems.add(js.statement('dart.export_(#);', [args])); | 344 |
| 345 // When we compile _runtime.js, we need to source export_ from _utils.js: |
| 346 _moduleItems.add(js.statement('#.export(#);', |
| 347 [_isDartRuntime ? _utilsLibVar : _runtimeLibVar, args])); |
| 309 } | 348 } |
| 310 | 349 |
| 311 JS.Identifier _initSymbol(JS.Identifier id) { | 350 JS.Identifier _initSymbol(JS.Identifier id) { |
| 312 var s = | 351 var s = |
| 313 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); | 352 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); |
| 314 _moduleItems.add(s); | 353 _moduleItems.add(s); |
| 315 return id; | 354 return id; |
| 316 } | 355 } |
| 317 | 356 |
| 318 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, | 357 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); | 611 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); |
| 573 } | 612 } |
| 574 return body; | 613 return body; |
| 575 } | 614 } |
| 576 | 615 |
| 577 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { | 616 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { |
| 578 var name = type.name; | 617 var name = type.name; |
| 579 var genericName = '$name\$'; | 618 var genericName = '$name\$'; |
| 580 var typeParams = type.typeParameters.map((p) => p.name); | 619 var typeParams = type.typeParameters.map((p) => p.name); |
| 581 if (isPublic(name)) _exports.add(genericName); | 620 if (isPublic(name)) _exports.add(genericName); |
| 582 return js.statement('const # = dart.generic(function(#) { #; return #; });', | 621 |
| 583 [genericName, typeParams, body, name]); | 622 return js.statement('const # = #(function(#) { #; return #; });', |
| 623 [genericName, _dartGeneric, typeParams, body, name]); |
| 584 } | 624 } |
| 585 | 625 |
| 626 get _dartGeneric => |
| 627 js.call('#.generic', [_isDartRuntime ? _classesLibVar : _runtimeLibVar]); |
| 628 |
| 586 final _hasDeferredSupertype = new HashSet<ClassElement>(); | 629 final _hasDeferredSupertype = new HashSet<ClassElement>(); |
| 587 | 630 |
| 588 bool _deferIfNeeded(DartType type, ClassElement current) { | 631 bool _deferIfNeeded(DartType type, ClassElement current) { |
| 589 if (type is ParameterizedType) { | 632 if (type is ParameterizedType) { |
| 590 var typeArguments = type.typeArguments; | 633 var typeArguments = type.typeArguments; |
| 591 for (var typeArg in typeArguments) { | 634 for (var typeArg in typeArguments) { |
| 592 var typeElement = typeArg.element; | 635 var typeElement = typeArg.element; |
| 593 // FIXME(vsm): This does not track mutual recursive dependences. | 636 // FIXME(vsm): This does not track mutual recursive dependences. |
| 594 if (current == typeElement || _deferIfNeeded(typeArg, current)) { | 637 if (current == typeElement || _deferIfNeeded(typeArg, current)) { |
| 595 return true; | 638 return true; |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 if (!tStatics.isEmpty) { | 868 if (!tStatics.isEmpty) { |
| 826 assert(!sNames.isEmpty); | 869 assert(!sNames.isEmpty); |
| 827 var aNames = new JS.Property( | 870 var aNames = new JS.Property( |
| 828 _propertyName('names'), new JS.ArrayInitializer(sNames)); | 871 _propertyName('names'), new JS.ArrayInitializer(sNames)); |
| 829 sigFields.add(build('statics', tStatics)); | 872 sigFields.add(build('statics', tStatics)); |
| 830 sigFields.add(aNames); | 873 sigFields.add(aNames); |
| 831 } | 874 } |
| 832 if (!sigFields.isEmpty || extensions.isNotEmpty) { | 875 if (!sigFields.isEmpty || extensions.isNotEmpty) { |
| 833 var sig = new JS.ObjectInitializer(sigFields); | 876 var sig = new JS.ObjectInitializer(sigFields); |
| 834 var classExpr = new JS.Identifier(name); | 877 var classExpr = new JS.Identifier(name); |
| 835 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig])); | 878 body.add(js.statement('#(#, #);', [_dartSetSignature, classExpr, sig])); |
| 836 } | 879 } |
| 837 } | 880 } |
| 838 | 881 |
| 839 // If a concrete class implements one of our extensions, we might need to | 882 // If a concrete class implements one of our extensions, we might need to |
| 840 // add forwarders. | 883 // add forwarders. |
| 841 if (extensions.isNotEmpty) { | 884 if (extensions.isNotEmpty) { |
| 842 var methodNames = <JS.Expression>[]; | 885 var methodNames = <JS.Expression>[]; |
| 843 for (var e in extensions) { | 886 for (var e in extensions) { |
| 844 methodNames.add(_elementMemberName(e)); | 887 methodNames.add(_elementMemberName(e)); |
| 845 } | 888 } |
| 846 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ | 889 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ |
| 847 name, | 890 name, |
| 848 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) | 891 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) |
| 849 ])); | 892 ])); |
| 850 } | 893 } |
| 851 | 894 |
| 852 // TODO(vsm): Make this optional per #268. | 895 // TODO(vsm): Make this optional per #268. |
| 853 // Metadata | 896 // Metadata |
| 854 if (metadata.isNotEmpty) { | 897 if (metadata.isNotEmpty) { |
| 855 body.add(js.statement('#[dart.metadata] = () => #;', [ | 898 body.add(js.statement('#[dart.metadata] = () => #;', [ |
| 856 name, | 899 name, |
| 857 new JS.ArrayInitializer( | 900 new JS.ArrayInitializer( |
| 858 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation))) | 901 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation))) |
| 859 ])); | 902 ])); |
| 860 } | 903 } |
| 861 | 904 |
| 862 return _statement(body); | 905 return _statement(body); |
| 863 } | 906 } |
| 864 | 907 |
| 908 get _dartSetSignature => |
| 909 js.call('#.setSignature', [_isDartRuntime ? _classesLibVar : _runtimeLibVa
r]); |
| 910 |
| 865 List<ExecutableElement> _extensionsToImplement(ClassElement element) { | 911 List<ExecutableElement> _extensionsToImplement(ClassElement element) { |
| 866 var members = <ExecutableElement>[]; | 912 var members = <ExecutableElement>[]; |
| 867 if (_extensionTypes.contains(element)) return members; | 913 if (_extensionTypes.contains(element)) return members; |
| 868 | 914 |
| 869 // Collect all extension types we implement. | 915 // Collect all extension types we implement. |
| 870 var type = element.type; | 916 var type = element.type; |
| 871 var types = new Set<ClassElement>(); | 917 var types = new Set<ClassElement>(); |
| 872 _collectExtensions(type, types); | 918 _collectExtensions(type, types); |
| 873 if (types.isEmpty) return members; | 919 if (types.isEmpty) return members; |
| 874 | 920 |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 | 1341 |
| 1296 if (node.isGetter || node.isSetter) { | 1342 if (node.isGetter || node.isSetter) { |
| 1297 // Add these later so we can use getter/setter syntax. | 1343 // Add these later so we can use getter/setter syntax. |
| 1298 _properties.add(node); | 1344 _properties.add(node); |
| 1299 return null; | 1345 return null; |
| 1300 } | 1346 } |
| 1301 | 1347 |
| 1302 var body = <JS.Statement>[]; | 1348 var body = <JS.Statement>[]; |
| 1303 _flushLibraryProperties(body); | 1349 _flushLibraryProperties(body); |
| 1304 | 1350 |
| 1305 var name = node.name.name; | 1351 var name = _getJsName(node.element) ?? node.name.name; |
| 1306 | 1352 |
| 1307 var fn = _visit(node.functionExpression); | 1353 var fn = _visit(node.functionExpression); |
| 1308 bool needsTagging = true; | 1354 bool needsTagging = !_isDartRuntime; |
| 1309 | 1355 |
| 1310 if (currentLibrary.source.isInSystemLibrary && | 1356 if (currentLibrary.source.isInSystemLibrary && |
| 1311 _isInlineJSFunction(node.functionExpression)) { | 1357 _isInlineJSFunction(node.functionExpression)) { |
| 1312 fn = _simplifyPassThroughArrowFunCallBody(fn); | 1358 fn = _simplifyPassThroughArrowFunCallBody(fn); |
| 1313 needsTagging = !_isDartUtils; | |
| 1314 } | 1359 } |
| 1315 | 1360 |
| 1316 var id = new JS.Identifier(name); | 1361 var id = new JS.Identifier(name); |
| 1317 body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element)); | 1362 body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element)); |
| 1318 if (needsTagging) { | 1363 if (needsTagging) { |
| 1319 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) | 1364 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) |
| 1320 .toStatement()); | 1365 .toStatement()); |
| 1321 } | 1366 } |
| 1322 | 1367 |
| 1323 if (isPublic(name)) _addExport(name); | 1368 if (isPublic(name)) _addExport(name); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1399 JS.Expression _emitFunctionTagged(JS.Expression clos, DartType type, | 1444 JS.Expression _emitFunctionTagged(JS.Expression clos, DartType type, |
| 1400 {topLevel: false}) { | 1445 {topLevel: false}) { |
| 1401 var name = type.name; | 1446 var name = type.name; |
| 1402 var lazy = topLevel && !_typeIsLoaded(type); | 1447 var lazy = topLevel && !_typeIsLoaded(type); |
| 1403 | 1448 |
| 1404 if (type is FunctionType && (name == '' || name == null)) { | 1449 if (type is FunctionType && (name == '' || name == null)) { |
| 1405 if (type.returnType.isDynamic && | 1450 if (type.returnType.isDynamic && |
| 1406 type.optionalParameterTypes.isEmpty && | 1451 type.optionalParameterTypes.isEmpty && |
| 1407 type.namedParameterTypes.isEmpty && | 1452 type.namedParameterTypes.isEmpty && |
| 1408 type.normalParameterTypes.every((t) => t.isDynamic)) { | 1453 type.normalParameterTypes.every((t) => t.isDynamic)) { |
| 1409 return js.call('dart.fn(#)', [clos]); | 1454 return js.call('#(#)', [_dartFn, clos]); |
| 1410 } | 1455 } |
| 1411 if (lazy) { | 1456 if (lazy) { |
| 1412 return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]); | 1457 return js.call('#(#, () => #)', [_dartFn, clos, _emitFunctionRTTI(type)]
); |
| 1413 } | 1458 } |
| 1414 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); | 1459 return js.call('#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]); |
| 1415 } | 1460 } |
| 1416 throw 'Function has non function type: $type'; | 1461 throw 'Function has non function type: $type'; |
| 1417 } | 1462 } |
| 1418 | 1463 |
| 1464 get _dartFn => js.call('#.fn', _isDartRuntime ? _rttiLibVar : _runtimeLibVar); |
| 1465 |
| 1419 @override | 1466 @override |
| 1420 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1467 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 1421 var params = _visit(node.parameters) as List<JS.Parameter>; | 1468 var params = _visit(node.parameters) as List<JS.Parameter>; |
| 1422 if (params == null) params = <JS.Parameter>[]; | 1469 if (params == null) params = <JS.Parameter>[]; |
| 1423 | 1470 |
| 1424 var parent = node.parent; | 1471 var parent = node.parent; |
| 1425 var inStmt = parent.parent is FunctionDeclarationStatement; | 1472 var inStmt = parent.parent is FunctionDeclarationStatement; |
| 1426 if (parent is FunctionDeclaration) { | 1473 if (parent is FunctionDeclaration) { |
| 1427 return _emitFunctionBody(params, node.body); | 1474 return _emitFunctionBody(params, node.body); |
| 1428 } else { | 1475 } else { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1559 'Unimplemented unknown name', new JS.Identifier(node.name)); | 1606 'Unimplemented unknown name', new JS.Identifier(node.name)); |
| 1560 } | 1607 } |
| 1561 | 1608 |
| 1562 // Get the original declaring element. If we had a property accessor, this | 1609 // Get the original declaring element. If we had a property accessor, this |
| 1563 // indirects back to a (possibly synthetic) field. | 1610 // indirects back to a (possibly synthetic) field. |
| 1564 var element = accessor; | 1611 var element = accessor; |
| 1565 if (accessor is PropertyAccessorElement) element = accessor.variable; | 1612 if (accessor is PropertyAccessorElement) element = accessor.variable; |
| 1566 | 1613 |
| 1567 _loader.declareBeforeUse(element); | 1614 _loader.declareBeforeUse(element); |
| 1568 | 1615 |
| 1569 var name = element.name; | 1616 var name = _getJsName(element) ?? element.name; |
| 1570 | 1617 |
| 1571 // type literal | 1618 // type literal |
| 1572 if (element is ClassElement || | 1619 if (element is ClassElement || |
| 1573 element is DynamicElementImpl || | 1620 element is DynamicElementImpl || |
| 1574 element is FunctionTypeAliasElement) { | 1621 element is FunctionTypeAliasElement) { |
| 1575 return _emitTypeName( | 1622 return _emitTypeName( |
| 1576 fillDynamicTypeArgs((element as dynamic).type, types)); | 1623 fillDynamicTypeArgs((element as dynamic).type, types)); |
| 1577 } | 1624 } |
| 1578 | 1625 |
| 1579 // library member | 1626 // library member |
| 1580 if (element.enclosingElement is CompilationUnitElement) { | 1627 if (element.enclosingElement is CompilationUnitElement) { |
| 1581 return _maybeQualifiedName(element); | 1628 return _maybeQualifiedName(element, name); |
| 1582 } | 1629 } |
| 1583 | 1630 |
| 1584 // Unqualified class member. This could mean implicit-this, or implicit | 1631 // Unqualified class member. This could mean implicit-this, or implicit |
| 1585 // call to a static from the same class. | 1632 // call to a static from the same class. |
| 1586 if (element is ClassMemberElement && element is! ConstructorElement) { | 1633 if (element is ClassMemberElement && element is! ConstructorElement) { |
| 1587 bool isStatic = element.isStatic; | 1634 bool isStatic = element.isStatic; |
| 1588 var type = element.enclosingElement.type; | 1635 var type = element.enclosingElement.type; |
| 1589 var member = _emitMemberName(name, isStatic: isStatic, type: type); | 1636 var member = _emitMemberName(name, isStatic: isStatic, type: type); |
| 1590 | 1637 |
| 1591 // For static methods, we add the raw type name, without generics or | 1638 // For static methods, we add the raw type name, without generics or |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1874 var stmts = _visitList(node.block.statements) as List<JS.Statement>; | 1921 var stmts = _visitList(node.block.statements) as List<JS.Statement>; |
| 1875 if (initArgs != null) stmts.insert(0, initArgs); | 1922 if (initArgs != null) stmts.insert(0, initArgs); |
| 1876 return new JS.Block(stmts); | 1923 return new JS.Block(stmts); |
| 1877 } | 1924 } |
| 1878 | 1925 |
| 1879 @override | 1926 @override |
| 1880 JS.Block visitBlock(Block node) => | 1927 JS.Block visitBlock(Block node) => |
| 1881 new JS.Block(_visitList(node.statements) as List<JS.Statement>, | 1928 new JS.Block(_visitList(node.statements) as List<JS.Statement>, |
| 1882 isScope: true); | 1929 isScope: true); |
| 1883 | 1930 |
| 1931 /// Return the type constructor `_foolib.Bar$` given `Bar` from lib `_foolib`. |
| 1932 JS.Expression _emitGenericTypeConstructor(Expression typeExpression) { |
| 1933 var ref = _visit(typeExpression); |
| 1934 if (ref is JS.PropertyAccess) { |
| 1935 var name = (ref.selector as JS.LiteralString).valueWithoutQuotes; |
| 1936 return new JS.PropertyAccess( |
| 1937 ref.receiver, new JS.LiteralString("'$name\$'")); |
| 1938 } else if (ref is JS.MaybeQualifiedId) { |
| 1939 var name = (ref.name as JS.Identifier).name; |
| 1940 return new JS.PropertyAccess( |
| 1941 ref.qualifier, new JS.Identifier('$name\$')); |
| 1942 } else { |
| 1943 throw new ArgumentError('Invalid type ref: $ref (${ref?.runtimeType})'); |
| 1944 } |
| 1945 } |
| 1946 |
| 1884 @override | 1947 @override |
| 1885 visitMethodInvocation(MethodInvocation node) { | 1948 visitMethodInvocation(MethodInvocation node) { |
| 1886 if (node.operator != null && node.operator.lexeme == '?.') { | 1949 if (node.operator != null && node.operator.lexeme == '?.') { |
| 1887 return _emitNullSafe(node); | 1950 return _emitNullSafe(node); |
| 1888 } | 1951 } |
| 1952 if (isGenericTypeConstructorInvocation(node)) { |
| 1953 return _emitGenericTypeConstructor(node.argumentList.arguments.single); |
| 1954 } |
| 1889 | 1955 |
| 1890 var target = _getTarget(node); | 1956 var target = _getTarget(node); |
| 1891 var result = _emitForeignJS(node); | 1957 var result = _emitForeignJS(node); |
| 1892 if (result != null) return result; | 1958 if (result != null) return result; |
| 1893 | 1959 |
| 1894 String code; | 1960 String code; |
| 1895 if (target == null || isLibraryPrefix(target)) { | 1961 if (target == null || isLibraryPrefix(target)) { |
| 1896 if (DynamicInvoke.get(node.methodName)) { | 1962 if (DynamicInvoke.get(node.methodName)) { |
| 1897 code = 'dart.$DCALL(#, #)'; | 1963 code = 'dart.$DCALL(#, #)'; |
| 1898 } else { | 1964 } else { |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2204 } else { | 2270 } else { |
| 2205 jsInit = _visitInitializer(field); | 2271 jsInit = _visitInitializer(field); |
| 2206 eagerInit = false; | 2272 eagerInit = false; |
| 2207 } | 2273 } |
| 2208 | 2274 |
| 2209 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile | 2275 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile |
| 2210 // runtime helpers. | 2276 // runtime helpers. |
| 2211 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); | 2277 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); |
| 2212 if (isJSTopLevel) eagerInit = true; | 2278 if (isJSTopLevel) eagerInit = true; |
| 2213 | 2279 |
| 2214 var fieldName = field.name.name; | 2280 var fieldName = _getJsName(element) ?? field.name.name; |
| 2281 |
| 2215 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || | 2282 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || |
| 2216 isJSTopLevel) { | 2283 isJSTopLevel) { |
| 2217 // constant fields don't change, so we can generate them as `let` | 2284 // constant fields don't change, so we can generate them as `let` |
| 2218 // but add them to the module's exports. However, make sure we generate | 2285 // but add them to the module's exports. However, make sure we generate |
| 2219 // anything they depend on first. | 2286 // anything they depend on first. |
| 2220 | 2287 |
| 2221 if (isPublic(fieldName)) _addExport(fieldName); | 2288 if (isPublic(fieldName)) _addExport(fieldName); |
| 2222 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; | 2289 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; |
| 2223 return annotateVariable( | 2290 return annotateVariable( |
| 2224 js.statement( | 2291 js.statement( |
| (...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2840 } | 2907 } |
| 2841 | 2908 |
| 2842 String code; | 2909 String code; |
| 2843 if (member != null && member is MethodElement && !isStatic) { | 2910 if (member != null && member is MethodElement && !isStatic) { |
| 2844 // Tear-off methods: explicitly bind it. | 2911 // Tear-off methods: explicitly bind it. |
| 2845 if (target is SuperExpression) { | 2912 if (target is SuperExpression) { |
| 2846 return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]); | 2913 return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]); |
| 2847 } else if (_requiresStaticDispatch(target, memberId.name)) { | 2914 } else if (_requiresStaticDispatch(target, memberId.name)) { |
| 2848 var type = member.type; | 2915 var type = member.type; |
| 2849 var clos = js.call('dart.#.bind(#)', [name, _visit(target)]); | 2916 var clos = js.call('dart.#.bind(#)', [name, _visit(target)]); |
| 2850 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); | 2917 return js.call('#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)])
; |
| 2851 } | 2918 } |
| 2852 code = 'dart.bind(#, #)'; | 2919 code = 'dart.bind(#, #)'; |
| 2853 } else if (_requiresStaticDispatch(target, memberId.name)) { | 2920 } else if (_requiresStaticDispatch(target, memberId.name)) { |
| 2854 return js.call('dart.#(#)', [name, _visit(target)]); | 2921 return js.call('dart.#(#)', [name, _visit(target)]); |
| 2855 } else { | 2922 } else { |
| 2856 code = '#.#'; | 2923 code = '#.#'; |
| 2857 } | 2924 } |
| 2858 | 2925 |
| 2859 return js.call(code, [_visit(target), name]); | 2926 return js.call(code, [_visit(target), name]); |
| 2860 } | 2927 } |
| (...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3409 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 3476 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 3410 | 3477 |
| 3411 FunctionBody _functionBody(node) => | 3478 FunctionBody _functionBody(node) => |
| 3412 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 3479 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| 3413 | 3480 |
| 3414 /// Choose a canonical name from the library element. | 3481 /// Choose a canonical name from the library element. |
| 3415 /// This never uses the library's name (the identifier in the `library` | 3482 /// This never uses the library's name (the identifier in the `library` |
| 3416 /// declaration) as it doesn't have any meaningful rules enforced. | 3483 /// declaration) as it doesn't have any meaningful rules enforced. |
| 3417 JS.Identifier _libraryName(LibraryElement library) { | 3484 JS.Identifier _libraryName(LibraryElement library) { |
| 3418 if (library == currentLibrary) return _exportsVar; | 3485 if (library == currentLibrary) return _exportsVar; |
| 3419 return _imports.putIfAbsent( | 3486 return _imports.putIfAbsent(library, () { |
| 3420 library, () => new JS.TemporaryId(jsLibraryName(library))); | 3487 var name = library.name; |
| 3488 if (name == 'dart._utils') return _utilsLibVar; |
| 3489 else if (name == 'dart._classes') return _classesLibVar; |
| 3490 else if (name == 'dart._rtti') return _rttiLibVar; |
| 3491 else return new JS.TemporaryId(jsLibraryName(library)); |
| 3492 }); |
| 3421 } | 3493 } |
| 3422 | 3494 |
| 3423 DartType getStaticType(Expression e) => rules.getStaticType(e); | 3495 DartType getStaticType(Expression e) => rules.getStaticType(e); |
| 3424 | 3496 |
| 3425 @override | 3497 @override |
| 3426 String getQualifiedName(TypeDefiningElement type) { | 3498 String getQualifiedName(TypeDefiningElement type) { |
| 3427 JS.TemporaryId id = _imports[type.library]; | 3499 JS.TemporaryId id = _imports[type.library]; |
| 3428 return id == null ? type.name : '${id.name}.${type.name}'; | 3500 return id == null ? type.name : '${id.name}.${type.name}'; |
| 3429 } | 3501 } |
| 3430 | 3502 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3521 | 3593 |
| 3522 /// A special kind of element created by the compiler, signifying a temporary | 3594 /// A special kind of element created by the compiler, signifying a temporary |
| 3523 /// variable. These objects use instance equality, and should be shared | 3595 /// variable. These objects use instance equality, and should be shared |
| 3524 /// everywhere in the tree where they are treated as the same variable. | 3596 /// everywhere in the tree where they are treated as the same variable. |
| 3525 class TemporaryVariableElement extends LocalVariableElementImpl { | 3597 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3526 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3598 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3527 | 3599 |
| 3528 int get hashCode => identityHashCode(this); | 3600 int get hashCode => identityHashCode(this); |
| 3529 bool operator ==(Object other) => identical(this, other); | 3601 bool operator ==(Object other) => identical(this, other); |
| 3530 } | 3602 } |
| OLD | NEW |