| 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 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
| 7 | 7 |
| 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 return module; | 278 return module; |
| 279 } | 279 } |
| 280 } | 280 } |
| 281 | 281 |
| 282 List<String> _getJSName(Element e) { | 282 List<String> _getJSName(Element e) { |
| 283 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { | 283 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { |
| 284 return null; | 284 return null; |
| 285 } | 285 } |
| 286 | 286 |
| 287 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 287 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
| 288 var libraryPrefix = []; | 288 var libraryPrefix = <String>[]; |
| 289 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 289 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
| 290 libraryPrefix.addAll(libraryJSName.split('.')); | 290 libraryPrefix.addAll(libraryJSName.split('.')); |
| 291 } | 291 } |
| 292 | 292 |
| 293 var elementJSName; | 293 String elementJSName; |
| 294 if (findAnnotation(e, isPublicJSAnnotation) != null) { | 294 if (findAnnotation(e, isPublicJSAnnotation) != null) { |
| 295 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; | 295 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; |
| 296 } | 296 } |
| 297 if (e is TopLevelVariableElement && | 297 if (e is TopLevelVariableElement && |
| 298 e.getter != null && | 298 e.getter != null && |
| 299 (e.getter.isExternal || | 299 (e.getter.isExternal || |
| 300 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | 300 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { |
| 301 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | 301 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; |
| 302 } | 302 } |
| 303 if (elementJSName == null) return null; | 303 if (elementJSName == null) return null; |
| 304 | 304 |
| 305 var elementJSParts = []; | 305 var elementJSParts = <String>[]; |
| 306 if (elementJSName.isNotEmpty) { | 306 if (elementJSName.isNotEmpty) { |
| 307 elementJSParts.addAll(elementJSName.split('.')); | 307 elementJSParts.addAll(elementJSName.split('.')); |
| 308 } else { | 308 } else { |
| 309 elementJSParts.add(e.name); | 309 elementJSParts.add(e.name); |
| 310 } | 310 } |
| 311 | 311 |
| 312 return libraryPrefix..addAll(elementJSParts); | 312 return libraryPrefix..addAll(elementJSParts); |
| 313 } | 313 } |
| 314 | 314 |
| 315 JS.Expression _emitJSInterop(Element e) { | 315 JS.Expression _emitJSInterop(Element e) { |
| 316 var jsName = _getJSName(e); | 316 var jsName = _getJSName(e); |
| 317 if (jsName == null) return null; | 317 if (jsName == null) return null; |
| 318 var fullName = ['global']..addAll(jsName); | 318 var fullName = ['global']..addAll(jsName); |
| 319 var access = _runtimeLibVar; | 319 JS.Expression access = _runtimeLibVar; |
| 320 for (var part in fullName) { | 320 for (var part in fullName) { |
| 321 access = new JS.PropertyAccess(access, js.string(part)); | 321 access = new JS.PropertyAccess(access, js.string(part)); |
| 322 } | 322 } |
| 323 return access; | 323 return access; |
| 324 } | 324 } |
| 325 | 325 |
| 326 /// Flattens blocks in [items] to a single list. | 326 /// Flattens blocks in [items] to a single list. |
| 327 /// | 327 /// |
| 328 /// This will not flatten blocks that are marked as being scopes. | 328 /// This will not flatten blocks that are marked as being scopes. |
| 329 void _copyAndFlattenBlocks( | 329 void _copyAndFlattenBlocks( |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 | 692 |
| 693 JS.Expression className; | 693 JS.Expression className; |
| 694 if (classElem.typeParameters.isNotEmpty) { | 694 if (classElem.typeParameters.isNotEmpty) { |
| 695 // Generic classes will be defined inside a function that closes over the | 695 // Generic classes will be defined inside a function that closes over the |
| 696 // type parameter. So we can use their local variable name directly. | 696 // type parameter. So we can use their local variable name directly. |
| 697 className = new JS.Identifier(classElem.name); | 697 className = new JS.Identifier(classElem.name); |
| 698 } else { | 698 } else { |
| 699 className = _emitTopLevelName(classElem); | 699 className = _emitTopLevelName(classElem); |
| 700 } | 700 } |
| 701 | 701 |
| 702 var allFields = new List.from(fields)..addAll(staticFields); | 702 var allFields = fields.toList()..addAll(staticFields); |
| 703 var superclasses = getSuperclasses(classElem); | 703 var superclasses = getSuperclasses(classElem); |
| 704 var virtualFields = <FieldElement, JS.TemporaryId>{}; | 704 var virtualFields = <FieldElement, JS.TemporaryId>{}; |
| 705 var virtualFieldSymbols = <JS.Statement>[]; | 705 var virtualFieldSymbols = <JS.Statement>[]; |
| 706 var staticFieldOverrides = new HashSet<FieldElement>(); | 706 var staticFieldOverrides = new HashSet<FieldElement>(); |
| 707 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 707 _registerPropertyOverrides(classElem, className, superclasses, allFields, |
| 708 virtualFields, virtualFieldSymbols, staticFieldOverrides); | 708 virtualFields, virtualFieldSymbols, staticFieldOverrides); |
| 709 | 709 |
| 710 var classExpr = _emitClassExpression(classElem, | 710 var classExpr = _emitClassExpression(classElem, |
| 711 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 711 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
| 712 fields: allFields); | 712 fields: allFields); |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 942 /// conflicts. They will be installed as extension methods on the underlying | 942 /// conflicts. They will be installed as extension methods on the underlying |
| 943 /// native type. | 943 /// native type. |
| 944 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { | 944 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { |
| 945 // TODO(vsm): Can this by meta-programmed? | 945 // TODO(vsm): Can this by meta-programmed? |
| 946 // E.g., dart.nativeField(symbol, jsName) | 946 // E.g., dart.nativeField(symbol, jsName) |
| 947 // Alternatively, perhaps it could be meta-programmed directly in | 947 // Alternatively, perhaps it could be meta-programmed directly in |
| 948 // dart.registerExtensions? | 948 // dart.registerExtensions? |
| 949 var jsMethods = <JS.Method>[]; | 949 var jsMethods = <JS.Method>[]; |
| 950 if (!node.isStatic) { | 950 if (!node.isStatic) { |
| 951 for (var decl in node.fields.variables) { | 951 for (var decl in node.fields.variables) { |
| 952 var field = decl.element; | 952 var field = decl.element as FieldElement; |
| 953 var name = getAnnotationName(field, isJsName) ?? field.name; | 953 var name = getAnnotationName(field, isJsName) ?? field.name; |
| 954 // Generate getter | 954 // Generate getter |
| 955 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); | 955 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); |
| 956 var method = | 956 var method = |
| 957 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); | 957 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); |
| 958 jsMethods.add(method); | 958 jsMethods.add(method); |
| 959 | 959 |
| 960 // Generate setter | 960 // Generate setter |
| 961 if (!decl.isFinal) { | 961 if (!decl.isFinal) { |
| 962 var value = new JS.TemporaryId('value'); | 962 var value = new JS.TemporaryId('value'); |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 List<MethodDeclaration> methods, | 1344 List<MethodDeclaration> methods, |
| 1345 List<FieldDeclaration> fields, | 1345 List<FieldDeclaration> fields, |
| 1346 List<JS.Statement> body) { | 1346 List<JS.Statement> body) { |
| 1347 if (_extensionTypes.hasNativeSubtype(classElem.type)) { | 1347 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
| 1348 var dartxNames = <JS.Expression>[]; | 1348 var dartxNames = <JS.Expression>[]; |
| 1349 for (var m in methods) { | 1349 for (var m in methods) { |
| 1350 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1350 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
| 1351 dartxNames.add(_elementMemberName(m.element, useExtension: false)); | 1351 dartxNames.add(_elementMemberName(m.element, useExtension: false)); |
| 1352 } | 1352 } |
| 1353 } | 1353 } |
| 1354 for (var f in fields) { | 1354 for (var fieldDecl in fields) { |
| 1355 if (!f.isStatic) { | 1355 if (!fieldDecl.isStatic) { |
| 1356 for (var d in f.fields.variables) { | 1356 for (var field in fieldDecl.fields.variables) { |
| 1357 if (d.element.isPublic) { | 1357 var e = field.element as FieldElement; |
| 1358 dartxNames.add( | 1358 if (e.isPublic) { |
| 1359 _elementMemberName(d.element.getter, useExtension: false)); | 1359 dartxNames.add(_elementMemberName(e.getter, useExtension: false)); |
| 1360 } | 1360 } |
| 1361 } | 1361 } |
| 1362 } | 1362 } |
| 1363 } | 1363 } |
| 1364 if (dartxNames.isNotEmpty) { | 1364 if (dartxNames.isNotEmpty) { |
| 1365 body.add(js.statement('dart.defineExtensionNames(#)', | 1365 body.add(js.statement('dart.defineExtensionNames(#)', |
| 1366 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1366 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
| 1367 } | 1367 } |
| 1368 } | 1368 } |
| 1369 } | 1369 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1535 if (jsSuper != null) body.add(jsSuper); | 1535 if (jsSuper != null) body.add(jsSuper); |
| 1536 | 1536 |
| 1537 body.add(_visit(node.body)); | 1537 body.add(_visit(node.body)); |
| 1538 return new JS.Block(body)..sourceInformation = node; | 1538 return new JS.Block(body)..sourceInformation = node; |
| 1539 } | 1539 } |
| 1540 | 1540 |
| 1541 @override | 1541 @override |
| 1542 JS.Statement visitRedirectingConstructorInvocation( | 1542 JS.Statement visitRedirectingConstructorInvocation( |
| 1543 RedirectingConstructorInvocation node) { | 1543 RedirectingConstructorInvocation node) { |
| 1544 var ctor = node.staticElement; | 1544 var ctor = node.staticElement; |
| 1545 var cls = ctor.enclosingElement as ClassElement; | 1545 var cls = ctor.enclosingElement; |
| 1546 // We can't dispatch to the constructor with `this.new` as that might hit a | 1546 // We can't dispatch to the constructor with `this.new` as that might hit a |
| 1547 // derived class constructor with the same name. | 1547 // derived class constructor with the same name. |
| 1548 return js.statement('#.prototype.#.call(this, #);', [ | 1548 return js.statement('#.prototype.#.call(this, #);', [ |
| 1549 new JS.Identifier(cls.name), | 1549 new JS.Identifier(cls.name), |
| 1550 _constructorName(ctor), | 1550 _constructorName(ctor), |
| 1551 _visit(node.argumentList) | 1551 _visit(node.argumentList) |
| 1552 ]); | 1552 ]); |
| 1553 } | 1553 } |
| 1554 | 1554 |
| 1555 JS.Statement _superConstructorCall(ClassElement element, | 1555 JS.Statement _superConstructorCall(ClassElement element, |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1841 assert(node.parent is CompilationUnit); | 1841 assert(node.parent is CompilationUnit); |
| 1842 | 1842 |
| 1843 if (_externalOrNative(node)) return null; | 1843 if (_externalOrNative(node)) return null; |
| 1844 | 1844 |
| 1845 // If we have a getter/setter pair, they need to be defined together. | 1845 // If we have a getter/setter pair, they need to be defined together. |
| 1846 if (node.isGetter) { | 1846 if (node.isGetter) { |
| 1847 PropertyAccessorElement element = node.element; | 1847 PropertyAccessorElement element = node.element; |
| 1848 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1848 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| 1849 var setter = element.correspondingSetter; | 1849 var setter = element.correspondingSetter; |
| 1850 if (setter != null) { | 1850 if (setter != null) { |
| 1851 props.add(_loader.emitDeclaration(setter, _emitTopLevelProperty)); | 1851 props.add(_loader.emitDeclaration( |
| 1852 setter, (node) => _emitTopLevelProperty(node))); |
| 1852 } | 1853 } |
| 1853 return js.statement('dart.copyProperties(#, { # });', | 1854 return js.statement('dart.copyProperties(#, { # });', |
| 1854 [emitLibraryName(currentLibrary), props]); | 1855 [emitLibraryName(currentLibrary), props]); |
| 1855 } | 1856 } |
| 1856 if (node.isSetter) { | 1857 if (node.isSetter) { |
| 1857 PropertyAccessorElement element = node.element; | 1858 PropertyAccessorElement element = node.element; |
| 1858 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1859 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| 1859 var getter = element.correspondingGetter; | 1860 var getter = element.correspondingGetter; |
| 1860 if (getter != null) { | 1861 if (getter != null) { |
| 1861 props.add(_loader.emitDeclaration(getter, _emitTopLevelProperty)); | 1862 props.add(_loader.emitDeclaration( |
| 1863 getter, (node) => _emitTopLevelProperty(node))); |
| 1862 } | 1864 } |
| 1863 return js.statement('dart.copyProperties(#, { # });', | 1865 return js.statement('dart.copyProperties(#, { # });', |
| 1864 [emitLibraryName(currentLibrary), props]); | 1866 [emitLibraryName(currentLibrary), props]); |
| 1865 } | 1867 } |
| 1866 | 1868 |
| 1867 var body = <JS.Statement>[]; | 1869 var body = <JS.Statement>[]; |
| 1868 var fn = _emitFunction(node.functionExpression); | 1870 var fn = _emitFunction(node.functionExpression); |
| 1869 | 1871 |
| 1870 if (currentLibrary.source.isInSystemLibrary && | 1872 if (currentLibrary.source.isInSystemLibrary && |
| 1871 _isInlineJSFunction(node.functionExpression)) { | 1873 _isInlineJSFunction(node.functionExpression)) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1976 @override | 1978 @override |
| 1977 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1979 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 1978 assert(node.parent is! FunctionDeclaration && | 1980 assert(node.parent is! FunctionDeclaration && |
| 1979 node.parent is! MethodDeclaration); | 1981 node.parent is! MethodDeclaration); |
| 1980 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), | 1982 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), |
| 1981 topLevel: _executesAtTopLevel(node)); | 1983 topLevel: _executesAtTopLevel(node)); |
| 1982 } | 1984 } |
| 1983 | 1985 |
| 1984 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { | 1986 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { |
| 1985 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); | 1987 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); |
| 1986 var body = f.body; | 1988 JS.Node body = f.body; |
| 1987 | 1989 |
| 1988 // Simplify `=> { return e; }` to `=> e` | 1990 // Simplify `=> { return e; }` to `=> e` |
| 1989 if (body is JS.Block) { | 1991 if (body is JS.Block) { |
| 1990 JS.Block block = body; | 1992 JS.Block block = body; |
| 1991 if (block.statements.length == 1) { | 1993 if (block.statements.length == 1) { |
| 1992 JS.Statement s = block.statements[0]; | 1994 JS.Statement s = block.statements[0]; |
| 1993 if (s is JS.Return) body = s.value; | 1995 if (s is JS.Return) body = s.value; |
| 1994 } | 1996 } |
| 1995 } | 1997 } |
| 1996 | 1998 |
| 1997 // Convert `function(...) { ... }` to `(...) => ...` | 1999 // Convert `function(...) { ... }` to `(...) => ...` |
| 1998 // This is for readability, but it also ensures correct `this` binding. | 2000 // This is for readability, but it also ensures correct `this` binding. |
| 1999 var fn = new JS.ArrowFun(f.params, body, | 2001 var fn = new JS.ArrowFun(f.params, body, |
| 2000 typeParams: f.typeParams, returnType: f.returnType); | 2002 typeParams: f.typeParams, returnType: f.returnType); |
| 2001 | 2003 |
| 2002 return annotate(_makeGenericFunction(fn), node); | 2004 return annotate(_makeGenericArrowFun(fn), node); |
| 2003 } | 2005 } |
| 2004 | 2006 |
| 2005 JS.FunctionExpression/*=T*/ _makeGenericFunction | 2007 JS.ArrowFun _makeGenericArrowFun(JS.ArrowFun fn) { |
| 2006 /*<T extends JS.FunctionExpression>*/(JS.FunctionExpression/*=T*/ fn) { | 2008 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
| 2009 return new JS.ArrowFun(fn.typeParams, fn); |
| 2010 } |
| 2011 |
| 2012 JS.Fun _makeGenericFunction(JS.Fun fn) { |
| 2007 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; | 2013 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
| 2008 | 2014 |
| 2009 // TODO(jmesserly): we could make these default to `dynamic`. | 2015 // TODO(jmesserly): we could make these default to `dynamic`. |
| 2010 var typeParams = fn.typeParams; | |
| 2011 if (fn is JS.ArrowFun) { | |
| 2012 return new JS.ArrowFun(typeParams, fn); | |
| 2013 } | |
| 2014 var f = fn as JS.Fun; | |
| 2015 return new JS.Fun( | 2016 return new JS.Fun( |
| 2016 typeParams, | 2017 fn.typeParams, |
| 2017 new JS.Block([ | 2018 new JS.Block([ |
| 2018 // Convert the function to an => function, to ensure `this` binding. | 2019 // Convert the function to an => function, to ensure `this` binding. |
| 2019 new JS.Return(new JS.ArrowFun(f.params, f.body, | 2020 new JS.Return(new JS.ArrowFun(fn.params, fn.body, |
| 2020 typeParams: f.typeParams, returnType: f.returnType)) | 2021 typeParams: fn.typeParams, returnType: fn.returnType)) |
| 2021 ])); | 2022 ])); |
| 2022 } | 2023 } |
| 2023 | 2024 |
| 2024 /// Emits a non-arrow FunctionExpression node. | 2025 /// Emits a non-arrow FunctionExpression node. |
| 2025 /// | 2026 /// |
| 2026 /// This should be used for all places in Dart's AST where FunctionExpression | 2027 /// This should be used for all places in Dart's AST where FunctionExpression |
| 2027 /// appears but the function is not actually in an Expression context, such | 2028 /// appears but the function is not actually in an Expression context, such |
| 2028 /// as methods, properties, and top-level functions. | 2029 /// as methods, properties, and top-level functions. |
| 2029 /// | 2030 /// |
| 2030 /// Contrast with [visitFunctionExpression]. | 2031 /// Contrast with [visitFunctionExpression]. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2084 // In the body of a `sync*` and `async`, `yield`/`await` are both generated | 2085 // In the body of a `sync*` and `async`, `yield`/`await` are both generated |
| 2085 // simply as `yield`. | 2086 // simply as `yield`. |
| 2086 // | 2087 // |
| 2087 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` | 2088 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` |
| 2088 // argument to the generator, which is used for passing values to the | 2089 // argument to the generator, which is used for passing values to the |
| 2089 // _AsyncStarStreamController implementation type. | 2090 // _AsyncStarStreamController implementation type. |
| 2090 // `yield` is specially generated inside `async*`, see visitYieldStatement. | 2091 // `yield` is specially generated inside `async*`, see visitYieldStatement. |
| 2091 // `await` is generated as `yield`. | 2092 // `await` is generated as `yield`. |
| 2092 // runtime/_generators.js has an example of what the code is generated as. | 2093 // runtime/_generators.js has an example of what the code is generated as. |
| 2093 var savedController = _asyncStarController; | 2094 var savedController = _asyncStarController; |
| 2094 List jsParams = visitFormalParameterList(parameters); | 2095 var jsParams = visitFormalParameterList(parameters); |
| 2095 if (kind == 'asyncStar') { | 2096 if (kind == 'asyncStar') { |
| 2096 _asyncStarController = new JS.TemporaryId('stream'); | 2097 _asyncStarController = new JS.TemporaryId('stream'); |
| 2097 jsParams.insert(0, _asyncStarController); | 2098 jsParams.insert(0, _asyncStarController); |
| 2098 } else { | 2099 } else { |
| 2099 _asyncStarController = null; | 2100 _asyncStarController = null; |
| 2100 } | 2101 } |
| 2101 var savedSuperAllowed = _superAllowed; | 2102 var savedSuperAllowed = _superAllowed; |
| 2102 _superAllowed = false; | 2103 _superAllowed = false; |
| 2103 // Visit the body with our async* controller set. | 2104 // Visit the body with our async* controller set. |
| 2104 var jsBody = _visit(body); | 2105 var jsBody = _visit(body); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2278 List<DartType> types, List<FormalParameter> parameters, | 2279 List<DartType> types, List<FormalParameter> parameters, |
| 2279 {bool nameType: true, bool hoistType: true}) { | 2280 {bool nameType: true, bool hoistType: true}) { |
| 2280 var result = <JS.Expression>[]; | 2281 var result = <JS.Expression>[]; |
| 2281 for (int i = 0; i < types.length; ++i) { | 2282 for (int i = 0; i < types.length; ++i) { |
| 2282 var metadata = | 2283 var metadata = |
| 2283 parameters != null ? _parameterMetadata(parameters[i]) : []; | 2284 parameters != null ? _parameterMetadata(parameters[i]) : []; |
| 2284 var typeName = | 2285 var typeName = |
| 2285 _emitType(types[i], nameType: nameType, hoistType: hoistType); | 2286 _emitType(types[i], nameType: nameType, hoistType: hoistType); |
| 2286 var value = typeName; | 2287 var value = typeName; |
| 2287 if (options.emitMetadata && metadata.isNotEmpty) { | 2288 if (options.emitMetadata && metadata.isNotEmpty) { |
| 2288 metadata = metadata.map(_instantiateAnnotation).toList(); | 2289 value = new JS.ArrayInitializer( |
| 2289 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); | 2290 [typeName]..addAll(metadata.map(_instantiateAnnotation))); |
| 2290 } | 2291 } |
| 2291 result.add(value); | 2292 result.add(value); |
| 2292 } | 2293 } |
| 2293 return new JS.ArrayInitializer(result); | 2294 return new JS.ArrayInitializer(result); |
| 2294 } | 2295 } |
| 2295 | 2296 |
| 2296 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 2297 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
| 2297 var properties = <JS.Property>[]; | 2298 var properties = <JS.Property>[]; |
| 2298 types.forEach((name, type) { | 2299 types.forEach((name, type) { |
| 2299 var key = _propertyName(name); | 2300 var key = _propertyName(name); |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 | 2593 |
| 2593 var target = _getTarget(node); | 2594 var target = _getTarget(node); |
| 2594 if (target == null || isLibraryPrefix(target)) { | 2595 if (target == null || isLibraryPrefix(target)) { |
| 2595 return _emitFunctionCall(node); | 2596 return _emitFunctionCall(node); |
| 2596 } | 2597 } |
| 2597 | 2598 |
| 2598 return _emitMethodCall(target, node); | 2599 return _emitMethodCall(target, node); |
| 2599 } | 2600 } |
| 2600 | 2601 |
| 2601 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { | 2602 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { |
| 2602 List<JS.Expression> args = _visit(node.argumentList); | 2603 var args = _visit(node.argumentList) as List<JS.Expression>; |
| 2603 var typeArgs = _emitInvokeTypeArguments(node); | 2604 var typeArgs = _emitInvokeTypeArguments(node); |
| 2604 | 2605 |
| 2605 if (target is SuperExpression && !_superAllowed) { | 2606 if (target is SuperExpression && !_superAllowed) { |
| 2606 return _emitSuperHelperCall(typeArgs, args, target, node); | 2607 return _emitSuperHelperCall(typeArgs, args, target, node); |
| 2607 } | 2608 } |
| 2608 | 2609 |
| 2609 return _emitMethodCallInternal(target, node, args, typeArgs); | 2610 return _emitMethodCallInternal(target, node, args, typeArgs); |
| 2610 } | 2611 } |
| 2611 | 2612 |
| 2612 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, | 2613 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2679 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | 2680 jsTarget = new JS.PropertyAccess(jsTarget, memberName); |
| 2680 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 2681 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
| 2681 | 2682 |
| 2682 return new JS.Call(jsTarget, args); | 2683 return new JS.Call(jsTarget, args); |
| 2683 } | 2684 } |
| 2684 | 2685 |
| 2685 /// Emits a function call, to a top-level function, local function, or | 2686 /// Emits a function call, to a top-level function, local function, or |
| 2686 /// an expression. | 2687 /// an expression. |
| 2687 JS.Expression _emitFunctionCall(InvocationExpression node) { | 2688 JS.Expression _emitFunctionCall(InvocationExpression node) { |
| 2688 var fn = _visit(node.function); | 2689 var fn = _visit(node.function); |
| 2689 var args = _visit(node.argumentList); | 2690 var args = _visit(node.argumentList) as List<JS.Expression>; |
| 2690 if (DynamicInvoke.get(node.function)) { | 2691 if (DynamicInvoke.get(node.function)) { |
| 2691 var typeArgs = _emitInvokeTypeArguments(node); | 2692 var typeArgs = _emitInvokeTypeArguments(node); |
| 2692 if (typeArgs != null) { | 2693 if (typeArgs != null) { |
| 2693 return js.call('dart.dgcall(#, #, #)', | 2694 return js.call('dart.dgcall(#, #, #)', |
| 2694 [fn, new JS.ArrayInitializer(typeArgs), args]); | 2695 [fn, new JS.ArrayInitializer(typeArgs), args]); |
| 2695 } else { | 2696 } else { |
| 2696 if (_inAngularTemplate) { | 2697 if (_inAngularTemplate) { |
| 2697 return new JS.Call(fn, args); | 2698 return new JS.Call(fn, args); |
| 2698 } | 2699 } |
| 2699 return js.call('dart.dcall(#, #)', [fn, args]); | 2700 return js.call('dart.dcall(#, #)', [fn, args]); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2759 return f.typeArguments.skip(g.typeArguments.length); | 2760 return f.typeArguments.skip(g.typeArguments.length); |
| 2760 } | 2761 } |
| 2761 | 2762 |
| 2762 /// Emits code for the `JS(...)` macro. | 2763 /// Emits code for the `JS(...)` macro. |
| 2763 _emitForeignJS(MethodInvocation node) { | 2764 _emitForeignJS(MethodInvocation node) { |
| 2764 var e = node.methodName.staticElement; | 2765 var e = node.methodName.staticElement; |
| 2765 if (isInlineJS(e)) { | 2766 if (isInlineJS(e)) { |
| 2766 var args = node.argumentList.arguments; | 2767 var args = node.argumentList.arguments; |
| 2767 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` | 2768 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` |
| 2768 var code = args[1]; | 2769 var code = args[1]; |
| 2769 var templateArgs; | 2770 List<AstNode> templateArgs; |
| 2770 var source; | 2771 var source; |
| 2771 if (code is StringInterpolation) { | 2772 if (code is StringInterpolation) { |
| 2772 if (args.length > 2) { | 2773 if (args.length > 2) { |
| 2773 throw new ArgumentError( | 2774 throw new ArgumentError( |
| 2774 "Can't mix template args and string interpolation in JS calls."); | 2775 "Can't mix template args and string interpolation in JS calls."); |
| 2775 } | 2776 } |
| 2776 templateArgs = <Expression>[]; | 2777 templateArgs = <Expression>[]; |
| 2777 source = code.elements.map((element) { | 2778 source = code.elements.map((element) { |
| 2778 if (element is InterpolationExpression) { | 2779 if (element is InterpolationExpression) { |
| 2779 templateArgs.add(element.expression); | 2780 templateArgs.add(element.expression); |
| 2780 return '#'; | 2781 return '#'; |
| 2781 } else { | 2782 } else { |
| 2782 return (element as InterpolationString).value; | 2783 return (element as InterpolationString).value; |
| 2783 } | 2784 } |
| 2784 }).join(); | 2785 }).join(); |
| 2785 } else { | 2786 } else { |
| 2786 templateArgs = args.skip(2); | 2787 templateArgs = args.skip(2).toList(); |
| 2787 source = (code as StringLiteral).stringValue; | 2788 source = (code as StringLiteral).stringValue; |
| 2788 } | 2789 } |
| 2789 | 2790 |
| 2790 // TODO(rnystrom): The JS() calls are almost never nested, and probably | 2791 // TODO(rnystrom): The JS() calls are almost never nested, and probably |
| 2791 // really shouldn't be, but there are at least a couple of calls in the | 2792 // really shouldn't be, but there are at least a couple of calls in the |
| 2792 // HTML library where an argument to JS() is itself a JS() call. If those | 2793 // HTML library where an argument to JS() is itself a JS() call. If those |
| 2793 // go away, this can just assert(!_isInForeignJS). | 2794 // go away, this can just assert(!_isInForeignJS). |
| 2794 // Inside JS(), type names evaluate to the raw runtime type, not the | 2795 // Inside JS(), type names evaluate to the raw runtime type, not the |
| 2795 // wrapped Type object. | 2796 // wrapped Type object. |
| 2796 var wasInForeignJS = _isInForeignJS; | 2797 var wasInForeignJS = _isInForeignJS; |
| (...skipping 1261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4058 // await iter.cancel(); | 4059 // await iter.cancel(); |
| 4059 // } | 4060 // } |
| 4060 // | 4061 // |
| 4061 // Like the Dart VM, we call cancel() always, as it's safe to call if the | 4062 // Like the Dart VM, we call cancel() always, as it's safe to call if the |
| 4062 // stream has already been cancelled. | 4063 // stream has already been cancelled. |
| 4063 // | 4064 // |
| 4064 // TODO(jmesserly): we may want a helper if these become common. For now the | 4065 // TODO(jmesserly): we may want a helper if these become common. For now the |
| 4065 // full desugaring seems okay. | 4066 // full desugaring seems okay. |
| 4066 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); | 4067 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); |
| 4067 var createStreamIter = _emitInstanceCreationExpression( | 4068 var createStreamIter = _emitInstanceCreationExpression( |
| 4068 streamIterator.element.unnamedConstructor, | 4069 (streamIterator.element as ClassElement).unnamedConstructor, |
| 4069 streamIterator, | 4070 streamIterator, |
| 4070 null, | 4071 null, |
| 4071 AstBuilder.argumentList([node.iterable]), | 4072 AstBuilder.argumentList([node.iterable]), |
| 4072 false); | 4073 false); |
| 4073 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); | 4074 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); |
| 4074 | 4075 |
| 4075 var init = _visit(node.identifier); | 4076 var init = _visit(node.identifier); |
| 4076 if (init == null) { | 4077 if (init == null) { |
| 4077 init = js | 4078 init = js |
| 4078 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); | 4079 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4359 _visit(AstNode node) { | 4360 _visit(AstNode node) { |
| 4360 if (node == null) return null; | 4361 if (node == null) return null; |
| 4361 var result = node.accept(this); | 4362 var result = node.accept(this); |
| 4362 if (result is JS.Node) result = annotate(result, node); | 4363 if (result is JS.Node) result = annotate(result, node); |
| 4363 return result; | 4364 return result; |
| 4364 } | 4365 } |
| 4365 | 4366 |
| 4366 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { | 4367 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { |
| 4367 if (nodes == null) return null; | 4368 if (nodes == null) return null; |
| 4368 var result = /*<T>*/ []; | 4369 var result = /*<T>*/ []; |
| 4369 for (var node in nodes) result.add(_visit(node)); | 4370 for (var node in nodes) result.add(_visit(node) as dynamic/*=T*/); |
| 4370 return result; | 4371 return result; |
| 4371 } | 4372 } |
| 4372 | 4373 |
| 4373 /// Visits a list of expressions, creating a comma expression if needed in JS. | 4374 /// Visits a list of expressions, creating a comma expression if needed in JS. |
| 4374 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { | 4375 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { |
| 4375 if (nodes == null || nodes.isEmpty) return null; | 4376 if (nodes == null || nodes.isEmpty) return null; |
| 4376 return new JS.Expression.binary( | 4377 return new JS.Expression.binary( |
| 4377 _visitList(nodes) as List<JS.Expression>, operator); | 4378 _visitList(nodes) as List<JS.Expression>, operator); |
| 4378 } | 4379 } |
| 4379 | 4380 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4492 // conflict. We could use practically any character for this. | 4493 // conflict. We could use practically any character for this. |
| 4493 name = '+$name'; | 4494 name = '+$name'; |
| 4494 } | 4495 } |
| 4495 | 4496 |
| 4496 var result = _propertyName(name); | 4497 var result = _propertyName(name); |
| 4497 | 4498 |
| 4498 if (useExtension == null) { | 4499 if (useExtension == null) { |
| 4499 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 4500 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
| 4500 var baseType = type; | 4501 var baseType = type; |
| 4501 while (baseType is TypeParameterType) { | 4502 while (baseType is TypeParameterType) { |
| 4502 baseType = baseType.element.bound; | 4503 baseType = (baseType.element as TypeParameterElement).bound; |
| 4503 } | 4504 } |
| 4504 useExtension = baseType != null && | 4505 useExtension = baseType != null && |
| 4505 _extensionTypes.hasNativeSubtype(baseType) && | 4506 _extensionTypes.hasNativeSubtype(baseType) && |
| 4506 !isObjectMember(name); | 4507 !isObjectMember(name); |
| 4507 } | 4508 } |
| 4508 | 4509 |
| 4509 return useExtension ? js.call('dartx.#', result) : result; | 4510 return useExtension ? js.call('dartx.#', result) : result; |
| 4510 } | 4511 } |
| 4511 | 4512 |
| 4512 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { | 4513 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 4532 return _libraries[library] ?? | 4533 return _libraries[library] ?? |
| 4533 _imports.putIfAbsent(library, | 4534 _imports.putIfAbsent(library, |
| 4534 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); | 4535 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); |
| 4535 } | 4536 } |
| 4536 | 4537 |
| 4537 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( | 4538 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( |
| 4538 JS.Node/*=T*/ node, AstNode original, | 4539 JS.Node/*=T*/ node, AstNode original, |
| 4539 [Element element]) { | 4540 [Element element]) { |
| 4540 if (options.closure && element != null) { | 4541 if (options.closure && element != null) { |
| 4541 node = node.withClosureAnnotation(closureAnnotationFor( | 4542 node = node.withClosureAnnotation(closureAnnotationFor( |
| 4542 node, original, element, namedArgumentTemp.name)); | 4543 node, original, element, namedArgumentTemp.name)) as dynamic/*=T*/; |
| 4543 } | 4544 } |
| 4544 return node..sourceInformation = original; | 4545 return node..sourceInformation = original; |
| 4545 } | 4546 } |
| 4546 | 4547 |
| 4547 /// Returns true if this is any kind of object represented by `Number` in JS. | 4548 /// Returns true if this is any kind of object represented by `Number` in JS. |
| 4548 /// | 4549 /// |
| 4549 /// In practice, this is 4 types: num, int, double, and JSNumber. | 4550 /// In practice, this is 4 types: num, int, double, and JSNumber. |
| 4550 /// | 4551 /// |
| 4551 /// JSNumber is the type that actually "implements" all numbers, hence it's | 4552 /// JSNumber is the type that actually "implements" all numbers, hence it's |
| 4552 /// a subtype of int and double (and num). It's in our "dart:_interceptors". | 4553 /// a subtype of int and double (and num). It's in our "dart:_interceptors". |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4660 } | 4661 } |
| 4661 | 4662 |
| 4662 bool isLibraryPrefix(Expression node) => | 4663 bool isLibraryPrefix(Expression node) => |
| 4663 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4664 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4664 | 4665 |
| 4665 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4666 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4666 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4667 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4667 | 4668 |
| 4668 bool _isDartRuntime(LibraryElement l) => | 4669 bool _isDartRuntime(LibraryElement l) => |
| 4669 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4670 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |