Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
| 6 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 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 return module; | 276 return module; |
| 277 } | 277 } |
| 278 } | 278 } |
| 279 | 279 |
| 280 List<String> _getJSName(Element e) { | 280 List<String> _getJSName(Element e) { |
| 281 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { | 281 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { |
| 282 return null; | 282 return null; |
| 283 } | 283 } |
| 284 | 284 |
| 285 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 285 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
| 286 var libraryPrefix = []; | 286 var libraryPrefix = <String>[]; |
| 287 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 287 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
| 288 libraryPrefix.addAll(libraryJSName.split('.')); | 288 libraryPrefix.addAll(libraryJSName.split('.')); |
| 289 } | 289 } |
| 290 | 290 |
| 291 var elementJSName; | 291 String elementJSName; |
| 292 if (findAnnotation(e, isPublicJSAnnotation) != null) { | 292 if (findAnnotation(e, isPublicJSAnnotation) != null) { |
| 293 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; | 293 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; |
| 294 } | 294 } |
| 295 if (e is TopLevelVariableElement && | 295 if (e is TopLevelVariableElement && |
| 296 e.getter != null && | 296 e.getter != null && |
| 297 (e.getter.isExternal || | 297 (e.getter.isExternal || |
| 298 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | 298 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { |
| 299 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | 299 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; |
| 300 } | 300 } |
| 301 if (elementJSName == null) return null; | 301 if (elementJSName == null) return null; |
| 302 | 302 |
| 303 var elementJSParts = []; | 303 var elementJSParts = <String>[]; |
| 304 if (elementJSName.isNotEmpty) { | 304 if (elementJSName.isNotEmpty) { |
| 305 elementJSParts.addAll(elementJSName.split('.')); | 305 elementJSParts.addAll(elementJSName.split('.')); |
| 306 } else { | 306 } else { |
| 307 elementJSParts.add(e.name); | 307 elementJSParts.add(e.name); |
| 308 } | 308 } |
| 309 | 309 |
| 310 return libraryPrefix..addAll(elementJSParts); | 310 return libraryPrefix..addAll(elementJSParts); |
| 311 } | 311 } |
| 312 | 312 |
| 313 JS.Expression _emitJSInterop(Element e) { | 313 JS.Expression _emitJSInterop(Element e) { |
| 314 var jsName = _getJSName(e); | 314 var jsName = _getJSName(e); |
| 315 if (jsName == null) return null; | 315 if (jsName == null) return null; |
| 316 var fullName = ['global']..addAll(jsName); | 316 var fullName = ['global']..addAll(jsName); |
| 317 var access = _runtimeLibVar; | 317 JS.Expression access = _runtimeLibVar; |
| 318 for (var part in fullName) { | 318 for (var part in fullName) { |
| 319 access = new JS.PropertyAccess(access, js.string(part)); | 319 access = new JS.PropertyAccess(access, js.string(part)); |
| 320 } | 320 } |
| 321 return access; | 321 return access; |
| 322 } | 322 } |
| 323 | 323 |
| 324 /// Flattens blocks in [items] to a single list. | 324 /// Flattens blocks in [items] to a single list. |
| 325 /// | 325 /// |
| 326 /// This will not flatten blocks that are marked as being scopes. | 326 /// This will not flatten blocks that are marked as being scopes. |
| 327 void _copyAndFlattenBlocks( | 327 void _copyAndFlattenBlocks( |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 685 | 685 |
| 686 JS.Expression className; | 686 JS.Expression className; |
| 687 if (classElem.typeParameters.isNotEmpty) { | 687 if (classElem.typeParameters.isNotEmpty) { |
| 688 // Generic classes will be defined inside a function that closes over the | 688 // Generic classes will be defined inside a function that closes over the |
| 689 // type parameter. So we can use their local variable name directly. | 689 // type parameter. So we can use their local variable name directly. |
| 690 className = new JS.Identifier(classElem.name); | 690 className = new JS.Identifier(classElem.name); |
| 691 } else { | 691 } else { |
| 692 className = _emitTopLevelName(classElem); | 692 className = _emitTopLevelName(classElem); |
| 693 } | 693 } |
| 694 | 694 |
| 695 var allFields = new List.from(fields)..addAll(staticFields); | 695 var allFields = fields.toList()..addAll(staticFields); |
| 696 var superclasses = getSuperclasses(classElem); | 696 var superclasses = getSuperclasses(classElem); |
| 697 var virtualFields = <FieldElement, JS.TemporaryId>{}; | 697 var virtualFields = <FieldElement, JS.TemporaryId>{}; |
| 698 var virtualFieldSymbols = <JS.Statement>[]; | 698 var virtualFieldSymbols = <JS.Statement>[]; |
| 699 var staticFieldOverrides = new HashSet<FieldElement>(); | 699 var staticFieldOverrides = new HashSet<FieldElement>(); |
| 700 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 700 _registerPropertyOverrides(classElem, className, superclasses, allFields, |
| 701 virtualFields, virtualFieldSymbols, staticFieldOverrides); | 701 virtualFields, virtualFieldSymbols, staticFieldOverrides); |
| 702 | 702 |
| 703 var classExpr = _emitClassExpression(classElem, | 703 var classExpr = _emitClassExpression(classElem, |
| 704 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 704 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
| 705 fields: allFields); | 705 fields: allFields); |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 935 /// conflicts. They will be installed as extension methods on the underlying | 935 /// conflicts. They will be installed as extension methods on the underlying |
| 936 /// native type. | 936 /// native type. |
| 937 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { | 937 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { |
| 938 // TODO(vsm): Can this by meta-programmed? | 938 // TODO(vsm): Can this by meta-programmed? |
| 939 // E.g., dart.nativeField(symbol, jsName) | 939 // E.g., dart.nativeField(symbol, jsName) |
| 940 // Alternatively, perhaps it could be meta-programmed directly in | 940 // Alternatively, perhaps it could be meta-programmed directly in |
| 941 // dart.registerExtensions? | 941 // dart.registerExtensions? |
| 942 var jsMethods = <JS.Method>[]; | 942 var jsMethods = <JS.Method>[]; |
| 943 if (!node.isStatic) { | 943 if (!node.isStatic) { |
| 944 for (var decl in node.fields.variables) { | 944 for (var decl in node.fields.variables) { |
| 945 var field = decl.element; | 945 var field = decl.element as FieldElement; |
| 946 var name = getAnnotationName(field, isJsName) ?? field.name; | 946 var name = getAnnotationName(field, isJsName) ?? field.name; |
| 947 // Generate getter | 947 // Generate getter |
| 948 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); | 948 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); |
| 949 var method = | 949 var method = |
| 950 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); | 950 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); |
| 951 jsMethods.add(method); | 951 jsMethods.add(method); |
| 952 | 952 |
| 953 // Generate setter | 953 // Generate setter |
| 954 if (!decl.isFinal) { | 954 if (!decl.isFinal) { |
| 955 var value = new JS.TemporaryId('value'); | 955 var value = new JS.TemporaryId('value'); |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1337 List<MethodDeclaration> methods, | 1337 List<MethodDeclaration> methods, |
| 1338 List<FieldDeclaration> fields, | 1338 List<FieldDeclaration> fields, |
| 1339 List<JS.Statement> body) { | 1339 List<JS.Statement> body) { |
| 1340 if (_extensionTypes.hasNativeSubtype(classElem.type)) { | 1340 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
| 1341 var dartxNames = <JS.Expression>[]; | 1341 var dartxNames = <JS.Expression>[]; |
| 1342 for (var m in methods) { | 1342 for (var m in methods) { |
| 1343 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1343 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
| 1344 dartxNames.add(_elementMemberName(m.element, useExtension: false)); | 1344 dartxNames.add(_elementMemberName(m.element, useExtension: false)); |
| 1345 } | 1345 } |
| 1346 } | 1346 } |
| 1347 for (var f in fields) { | 1347 for (var fieldDecl in fields) { |
| 1348 if (!f.isStatic) { | 1348 if (!fieldDecl.isStatic) { |
| 1349 for (var d in f.fields.variables) { | 1349 for (var field in fieldDecl.fields.variables) { |
| 1350 if (d.element.isPublic) { | 1350 var e = field.element as FieldElement; |
| 1351 dartxNames.add( | 1351 if (e.isPublic) { |
| 1352 _elementMemberName(d.element.getter, useExtension: false)); | 1352 dartxNames.add(_elementMemberName(e.getter, useExtension: false)); |
| 1353 } | 1353 } |
| 1354 } | 1354 } |
| 1355 } | 1355 } |
| 1356 } | 1356 } |
| 1357 if (dartxNames.isNotEmpty) { | 1357 if (dartxNames.isNotEmpty) { |
| 1358 body.add(js.statement('dart.defineExtensionNames(#)', | 1358 body.add(js.statement('dart.defineExtensionNames(#)', |
| 1359 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1359 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
| 1360 } | 1360 } |
| 1361 } | 1361 } |
| 1362 } | 1362 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1528 if (jsSuper != null) body.add(jsSuper); | 1528 if (jsSuper != null) body.add(jsSuper); |
| 1529 | 1529 |
| 1530 body.add(_visit(node.body)); | 1530 body.add(_visit(node.body)); |
| 1531 return new JS.Block(body)..sourceInformation = node; | 1531 return new JS.Block(body)..sourceInformation = node; |
| 1532 } | 1532 } |
| 1533 | 1533 |
| 1534 @override | 1534 @override |
| 1535 JS.Statement visitRedirectingConstructorInvocation( | 1535 JS.Statement visitRedirectingConstructorInvocation( |
| 1536 RedirectingConstructorInvocation node) { | 1536 RedirectingConstructorInvocation node) { |
| 1537 var ctor = node.staticElement; | 1537 var ctor = node.staticElement; |
| 1538 var cls = ctor.enclosingElement as ClassElement; | 1538 var cls = ctor.enclosingElement; |
| 1539 // We can't dispatch to the constructor with `this.new` as that might hit a | 1539 // We can't dispatch to the constructor with `this.new` as that might hit a |
| 1540 // derived class constructor with the same name. | 1540 // derived class constructor with the same name. |
| 1541 return js.statement('#.prototype.#.call(this, #);', [ | 1541 return js.statement('#.prototype.#.call(this, #);', [ |
| 1542 new JS.Identifier(cls.name), | 1542 new JS.Identifier(cls.name), |
| 1543 _constructorName(ctor), | 1543 _constructorName(ctor), |
| 1544 _visit(node.argumentList) | 1544 _visit(node.argumentList) |
| 1545 ]); | 1545 ]); |
| 1546 } | 1546 } |
| 1547 | 1547 |
| 1548 JS.Statement _superConstructorCall(ClassElement element, | 1548 JS.Statement _superConstructorCall(ClassElement element, |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1832 assert(node.parent is CompilationUnit); | 1832 assert(node.parent is CompilationUnit); |
| 1833 | 1833 |
| 1834 if (_externalOrNative(node)) return null; | 1834 if (_externalOrNative(node)) return null; |
| 1835 | 1835 |
| 1836 // If we have a getter/setter pair, they need to be defined together. | 1836 // If we have a getter/setter pair, they need to be defined together. |
| 1837 if (node.isGetter) { | 1837 if (node.isGetter) { |
| 1838 PropertyAccessorElement element = node.element; | 1838 PropertyAccessorElement element = node.element; |
| 1839 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1839 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| 1840 var setter = element.correspondingSetter; | 1840 var setter = element.correspondingSetter; |
| 1841 if (setter != null) { | 1841 if (setter != null) { |
| 1842 props.add(_loader.emitDeclaration(setter, _emitTopLevelProperty)); | 1842 props.add(_loader.emitDeclaration( |
| 1843 setter, (node) => _emitTopLevelProperty(node))); | |
|
Leaf
2016/05/26 17:53:37
Annoying. I guess alternatively emitDeclaration c
Jennifer Messerly
2016/05/26 18:11:48
yeah, that was my thought too. Seems like either w
| |
| 1843 } | 1844 } |
| 1844 return js.statement('dart.copyProperties(#, { # });', | 1845 return js.statement('dart.copyProperties(#, { # });', |
| 1845 [emitLibraryName(currentLibrary), props]); | 1846 [emitLibraryName(currentLibrary), props]); |
| 1846 } | 1847 } |
| 1847 if (node.isSetter) { | 1848 if (node.isSetter) { |
| 1848 PropertyAccessorElement element = node.element; | 1849 PropertyAccessorElement element = node.element; |
| 1849 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1850 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| 1850 var getter = element.correspondingGetter; | 1851 var getter = element.correspondingGetter; |
| 1851 if (getter != null) { | 1852 if (getter != null) { |
| 1852 props.add(_loader.emitDeclaration(getter, _emitTopLevelProperty)); | 1853 props.add(_loader.emitDeclaration( |
| 1854 getter, (node) => _emitTopLevelProperty(node))); | |
| 1853 } | 1855 } |
| 1854 return js.statement('dart.copyProperties(#, { # });', | 1856 return js.statement('dart.copyProperties(#, { # });', |
| 1855 [emitLibraryName(currentLibrary), props]); | 1857 [emitLibraryName(currentLibrary), props]); |
| 1856 } | 1858 } |
| 1857 | 1859 |
| 1858 var body = <JS.Statement>[]; | 1860 var body = <JS.Statement>[]; |
| 1859 var fn = _emitFunction(node.functionExpression); | 1861 var fn = _emitFunction(node.functionExpression); |
| 1860 | 1862 |
| 1861 if (currentLibrary.source.isInSystemLibrary && | 1863 if (currentLibrary.source.isInSystemLibrary && |
| 1862 _isInlineJSFunction(node.functionExpression)) { | 1864 _isInlineJSFunction(node.functionExpression)) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1967 @override | 1969 @override |
| 1968 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1970 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 1969 assert(node.parent is! FunctionDeclaration && | 1971 assert(node.parent is! FunctionDeclaration && |
| 1970 node.parent is! MethodDeclaration); | 1972 node.parent is! MethodDeclaration); |
| 1971 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), | 1973 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), |
| 1972 topLevel: _executesAtTopLevel(node)); | 1974 topLevel: _executesAtTopLevel(node)); |
| 1973 } | 1975 } |
| 1974 | 1976 |
| 1975 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { | 1977 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { |
| 1976 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); | 1978 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); |
| 1977 var body = f.body; | 1979 JS.Node body = f.body; |
| 1978 | 1980 |
| 1979 // Simplify `=> { return e; }` to `=> e` | 1981 // Simplify `=> { return e; }` to `=> e` |
| 1980 if (body is JS.Block) { | 1982 if (body is JS.Block) { |
| 1981 JS.Block block = body; | 1983 JS.Block block = body; |
| 1982 if (block.statements.length == 1) { | 1984 if (block.statements.length == 1) { |
| 1983 JS.Statement s = block.statements[0]; | 1985 JS.Statement s = block.statements[0]; |
| 1984 if (s is JS.Return) body = s.value; | 1986 if (s is JS.Return) body = s.value; |
| 1985 } | 1987 } |
| 1986 } | 1988 } |
| 1987 | 1989 |
| 1988 // Convert `function(...) { ... }` to `(...) => ...` | 1990 // Convert `function(...) { ... }` to `(...) => ...` |
| 1989 // This is for readability, but it also ensures correct `this` binding. | 1991 // This is for readability, but it also ensures correct `this` binding. |
| 1990 var fn = new JS.ArrowFun(f.params, body, | 1992 var fn = new JS.ArrowFun(f.params, body, |
| 1991 typeParams: f.typeParams, returnType: f.returnType); | 1993 typeParams: f.typeParams, returnType: f.returnType); |
| 1992 | 1994 |
| 1993 return annotate(_makeGenericFunction(fn), node); | 1995 return annotate(_makeGenericArrowFun(fn), node); |
| 1994 } | 1996 } |
| 1995 | 1997 |
| 1996 JS.FunctionExpression/*=T*/ _makeGenericFunction | 1998 JS.ArrowFun _makeGenericArrowFun(JS.ArrowFun fn) { |
| 1997 /*<T extends JS.FunctionExpression>*/(JS.FunctionExpression/*=T*/ fn) { | 1999 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
| 2000 return new JS.ArrowFun(fn.typeParams, fn); | |
| 2001 } | |
| 2002 | |
| 2003 JS.Fun _makeGenericFunction(JS.Fun fn) { | |
| 1998 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; | 2004 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
| 1999 | 2005 |
| 2000 // TODO(jmesserly): we could make these default to `dynamic`. | 2006 // TODO(jmesserly): we could make these default to `dynamic`. |
| 2001 var typeParams = fn.typeParams; | |
| 2002 if (fn is JS.ArrowFun) { | |
| 2003 return new JS.ArrowFun(typeParams, fn); | |
| 2004 } | |
| 2005 var f = fn as JS.Fun; | |
| 2006 return new JS.Fun( | 2007 return new JS.Fun( |
| 2007 typeParams, | 2008 fn.typeParams, |
| 2008 new JS.Block([ | 2009 new JS.Block([ |
| 2009 // Convert the function to an => function, to ensure `this` binding. | 2010 // Convert the function to an => function, to ensure `this` binding. |
| 2010 new JS.Return(new JS.ArrowFun(f.params, f.body, | 2011 new JS.Return(new JS.ArrowFun(fn.params, fn.body, |
| 2011 typeParams: f.typeParams, returnType: f.returnType)) | 2012 typeParams: fn.typeParams, returnType: fn.returnType)) |
| 2012 ])); | 2013 ])); |
| 2013 } | 2014 } |
| 2014 | 2015 |
| 2015 /// Emits a non-arrow FunctionExpression node. | 2016 /// Emits a non-arrow FunctionExpression node. |
| 2016 /// | 2017 /// |
| 2017 /// This should be used for all places in Dart's AST where FunctionExpression | 2018 /// This should be used for all places in Dart's AST where FunctionExpression |
| 2018 /// appears but the function is not actually in an Expression context, such | 2019 /// appears but the function is not actually in an Expression context, such |
| 2019 /// as methods, properties, and top-level functions. | 2020 /// as methods, properties, and top-level functions. |
| 2020 /// | 2021 /// |
| 2021 /// Contrast with [visitFunctionExpression]. | 2022 /// Contrast with [visitFunctionExpression]. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2075 // In the body of a `sync*` and `async`, `yield`/`await` are both generated | 2076 // In the body of a `sync*` and `async`, `yield`/`await` are both generated |
| 2076 // simply as `yield`. | 2077 // simply as `yield`. |
| 2077 // | 2078 // |
| 2078 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` | 2079 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` |
| 2079 // argument to the generator, which is used for passing values to the | 2080 // argument to the generator, which is used for passing values to the |
| 2080 // _AsyncStarStreamController implementation type. | 2081 // _AsyncStarStreamController implementation type. |
| 2081 // `yield` is specially generated inside `async*`, see visitYieldStatement. | 2082 // `yield` is specially generated inside `async*`, see visitYieldStatement. |
| 2082 // `await` is generated as `yield`. | 2083 // `await` is generated as `yield`. |
| 2083 // runtime/_generators.js has an example of what the code is generated as. | 2084 // runtime/_generators.js has an example of what the code is generated as. |
| 2084 var savedController = _asyncStarController; | 2085 var savedController = _asyncStarController; |
| 2085 List jsParams = visitFormalParameterList(parameters); | 2086 var jsParams = visitFormalParameterList(parameters); |
| 2086 if (kind == 'asyncStar') { | 2087 if (kind == 'asyncStar') { |
| 2087 _asyncStarController = new JS.TemporaryId('stream'); | 2088 _asyncStarController = new JS.TemporaryId('stream'); |
| 2088 jsParams.insert(0, _asyncStarController); | 2089 jsParams.insert(0, _asyncStarController); |
| 2089 } else { | 2090 } else { |
| 2090 _asyncStarController = null; | 2091 _asyncStarController = null; |
| 2091 } | 2092 } |
| 2092 var savedSuperAllowed = _superAllowed; | 2093 var savedSuperAllowed = _superAllowed; |
| 2093 _superAllowed = false; | 2094 _superAllowed = false; |
| 2094 // Visit the body with our async* controller set. | 2095 // Visit the body with our async* controller set. |
| 2095 var jsBody = _visit(body); | 2096 var jsBody = _visit(body); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2269 List<DartType> types, List<FormalParameter> parameters, | 2270 List<DartType> types, List<FormalParameter> parameters, |
| 2270 {bool nameType: true, bool hoistType: true}) { | 2271 {bool nameType: true, bool hoistType: true}) { |
| 2271 var result = <JS.Expression>[]; | 2272 var result = <JS.Expression>[]; |
| 2272 for (int i = 0; i < types.length; ++i) { | 2273 for (int i = 0; i < types.length; ++i) { |
| 2273 var metadata = | 2274 var metadata = |
| 2274 parameters != null ? _parameterMetadata(parameters[i]) : []; | 2275 parameters != null ? _parameterMetadata(parameters[i]) : []; |
| 2275 var typeName = | 2276 var typeName = |
| 2276 _emitType(types[i], nameType: nameType, hoistType: hoistType); | 2277 _emitType(types[i], nameType: nameType, hoistType: hoistType); |
| 2277 var value = typeName; | 2278 var value = typeName; |
| 2278 if (options.emitMetadata && metadata.isNotEmpty) { | 2279 if (options.emitMetadata && metadata.isNotEmpty) { |
| 2279 metadata = metadata.map(_instantiateAnnotation).toList(); | 2280 value = new JS.ArrayInitializer( |
| 2280 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); | 2281 [typeName]..addAll(metadata.map(_instantiateAnnotation))); |
| 2281 } | 2282 } |
| 2282 result.add(value); | 2283 result.add(value); |
| 2283 } | 2284 } |
| 2284 return new JS.ArrayInitializer(result); | 2285 return new JS.ArrayInitializer(result); |
| 2285 } | 2286 } |
| 2286 | 2287 |
| 2287 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 2288 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
| 2288 var properties = <JS.Property>[]; | 2289 var properties = <JS.Property>[]; |
| 2289 types.forEach((name, type) { | 2290 types.forEach((name, type) { |
| 2290 var key = _propertyName(name); | 2291 var key = _propertyName(name); |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2580 | 2581 |
| 2581 var target = _getTarget(node); | 2582 var target = _getTarget(node); |
| 2582 if (target == null || isLibraryPrefix(target)) { | 2583 if (target == null || isLibraryPrefix(target)) { |
| 2583 return _emitFunctionCall(node); | 2584 return _emitFunctionCall(node); |
| 2584 } | 2585 } |
| 2585 | 2586 |
| 2586 return _emitMethodCall(target, node); | 2587 return _emitMethodCall(target, node); |
| 2587 } | 2588 } |
| 2588 | 2589 |
| 2589 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { | 2590 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { |
| 2590 List<JS.Expression> args = _visit(node.argumentList); | 2591 var args = _visit(node.argumentList) as List<JS.Expression>; |
| 2591 var typeArgs = _emitInvokeTypeArguments(node); | 2592 var typeArgs = _emitInvokeTypeArguments(node); |
| 2592 | 2593 |
| 2593 if (target is SuperExpression && !_superAllowed) { | 2594 if (target is SuperExpression && !_superAllowed) { |
| 2594 return _emitSuperHelperCall(typeArgs, args, target, node); | 2595 return _emitSuperHelperCall(typeArgs, args, target, node); |
| 2595 } | 2596 } |
| 2596 | 2597 |
| 2597 return _emitMethodCallInternal(target, node, args, typeArgs); | 2598 return _emitMethodCallInternal(target, node, args, typeArgs); |
| 2598 } | 2599 } |
| 2599 | 2600 |
| 2600 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, | 2601 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2662 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | 2663 jsTarget = new JS.PropertyAccess(jsTarget, memberName); |
| 2663 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 2664 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
| 2664 | 2665 |
| 2665 return new JS.Call(jsTarget, args); | 2666 return new JS.Call(jsTarget, args); |
| 2666 } | 2667 } |
| 2667 | 2668 |
| 2668 /// Emits a function call, to a top-level function, local function, or | 2669 /// Emits a function call, to a top-level function, local function, or |
| 2669 /// an expression. | 2670 /// an expression. |
| 2670 JS.Expression _emitFunctionCall(InvocationExpression node) { | 2671 JS.Expression _emitFunctionCall(InvocationExpression node) { |
| 2671 var fn = _visit(node.function); | 2672 var fn = _visit(node.function); |
| 2672 var args = _visit(node.argumentList); | 2673 var args = _visit(node.argumentList) as List<JS.Expression>; |
| 2673 if (DynamicInvoke.get(node.function)) { | 2674 if (DynamicInvoke.get(node.function)) { |
| 2674 var typeArgs = _emitInvokeTypeArguments(node); | 2675 var typeArgs = _emitInvokeTypeArguments(node); |
| 2675 if (typeArgs != null) { | 2676 if (typeArgs != null) { |
| 2676 return js.call('dart.dgcall(#, #, #)', | 2677 return js.call('dart.dgcall(#, #, #)', |
| 2677 [fn, new JS.ArrayInitializer(typeArgs), args]); | 2678 [fn, new JS.ArrayInitializer(typeArgs), args]); |
| 2678 } else { | 2679 } else { |
| 2679 return js.call('dart.dcall(#, #)', [fn, args]); | 2680 return js.call('dart.dcall(#, #)', [fn, args]); |
| 2680 } | 2681 } |
| 2681 } else { | 2682 } else { |
| 2682 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); | 2683 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2739 return f.typeArguments.skip(g.typeArguments.length); | 2740 return f.typeArguments.skip(g.typeArguments.length); |
| 2740 } | 2741 } |
| 2741 | 2742 |
| 2742 /// Emits code for the `JS(...)` macro. | 2743 /// Emits code for the `JS(...)` macro. |
| 2743 _emitForeignJS(MethodInvocation node) { | 2744 _emitForeignJS(MethodInvocation node) { |
| 2744 var e = node.methodName.staticElement; | 2745 var e = node.methodName.staticElement; |
| 2745 if (isInlineJS(e)) { | 2746 if (isInlineJS(e)) { |
| 2746 var args = node.argumentList.arguments; | 2747 var args = node.argumentList.arguments; |
| 2747 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` | 2748 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` |
| 2748 var code = args[1]; | 2749 var code = args[1]; |
| 2749 var templateArgs; | 2750 List<AstNode> templateArgs; |
| 2750 var source; | 2751 var source; |
| 2751 if (code is StringInterpolation) { | 2752 if (code is StringInterpolation) { |
| 2752 if (args.length > 2) { | 2753 if (args.length > 2) { |
| 2753 throw new ArgumentError( | 2754 throw new ArgumentError( |
| 2754 "Can't mix template args and string interpolation in JS calls."); | 2755 "Can't mix template args and string interpolation in JS calls."); |
| 2755 } | 2756 } |
| 2756 templateArgs = <Expression>[]; | 2757 templateArgs = <Expression>[]; |
| 2757 source = code.elements.map((element) { | 2758 source = code.elements.map((element) { |
| 2758 if (element is InterpolationExpression) { | 2759 if (element is InterpolationExpression) { |
| 2759 templateArgs.add(element.expression); | 2760 templateArgs.add(element.expression); |
| 2760 return '#'; | 2761 return '#'; |
| 2761 } else { | 2762 } else { |
| 2762 return (element as InterpolationString).value; | 2763 return (element as InterpolationString).value; |
| 2763 } | 2764 } |
| 2764 }).join(); | 2765 }).join(); |
| 2765 } else { | 2766 } else { |
| 2766 templateArgs = args.skip(2); | 2767 templateArgs = args.skip(2).toList(); |
| 2767 source = (code as StringLiteral).stringValue; | 2768 source = (code as StringLiteral).stringValue; |
| 2768 } | 2769 } |
| 2769 | 2770 |
| 2770 // TODO(rnystrom): The JS() calls are almost never nested, and probably | 2771 // TODO(rnystrom): The JS() calls are almost never nested, and probably |
| 2771 // really shouldn't be, but there are at least a couple of calls in the | 2772 // really shouldn't be, but there are at least a couple of calls in the |
| 2772 // HTML library where an argument to JS() is itself a JS() call. If those | 2773 // HTML library where an argument to JS() is itself a JS() call. If those |
| 2773 // go away, this can just assert(!_isInForeignJS). | 2774 // go away, this can just assert(!_isInForeignJS). |
| 2774 // Inside JS(), type names evaluate to the raw runtime type, not the | 2775 // Inside JS(), type names evaluate to the raw runtime type, not the |
| 2775 // wrapped Type object. | 2776 // wrapped Type object. |
| 2776 var wasInForeignJS = _isInForeignJS; | 2777 var wasInForeignJS = _isInForeignJS; |
| (...skipping 1253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4030 // await iter.cancel(); | 4031 // await iter.cancel(); |
| 4031 // } | 4032 // } |
| 4032 // | 4033 // |
| 4033 // Like the Dart VM, we call cancel() always, as it's safe to call if the | 4034 // Like the Dart VM, we call cancel() always, as it's safe to call if the |
| 4034 // stream has already been cancelled. | 4035 // stream has already been cancelled. |
| 4035 // | 4036 // |
| 4036 // TODO(jmesserly): we may want a helper if these become common. For now the | 4037 // TODO(jmesserly): we may want a helper if these become common. For now the |
| 4037 // full desugaring seems okay. | 4038 // full desugaring seems okay. |
| 4038 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); | 4039 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); |
| 4039 var createStreamIter = _emitInstanceCreationExpression( | 4040 var createStreamIter = _emitInstanceCreationExpression( |
| 4040 streamIterator.element.unnamedConstructor, | 4041 (streamIterator.element as ClassElement).unnamedConstructor, |
| 4041 streamIterator, | 4042 streamIterator, |
| 4042 null, | 4043 null, |
| 4043 AstBuilder.argumentList([node.iterable]), | 4044 AstBuilder.argumentList([node.iterable]), |
| 4044 false); | 4045 false); |
| 4045 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); | 4046 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); |
| 4046 | 4047 |
| 4047 var init = _visit(node.identifier); | 4048 var init = _visit(node.identifier); |
| 4048 if (init == null) { | 4049 if (init == null) { |
| 4049 init = js | 4050 init = js |
| 4050 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); | 4051 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4326 _visit(AstNode node) { | 4327 _visit(AstNode node) { |
| 4327 if (node == null) return null; | 4328 if (node == null) return null; |
| 4328 var result = node.accept(this); | 4329 var result = node.accept(this); |
| 4329 if (result is JS.Node) result = annotate(result, node); | 4330 if (result is JS.Node) result = annotate(result, node); |
| 4330 return result; | 4331 return result; |
| 4331 } | 4332 } |
| 4332 | 4333 |
| 4333 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { | 4334 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { |
| 4334 if (nodes == null) return null; | 4335 if (nodes == null) return null; |
| 4335 var result = /*<T>*/ []; | 4336 var result = /*<T>*/ []; |
| 4336 for (var node in nodes) result.add(_visit(node)); | 4337 for (var node in nodes) result.add(_visit(node) as dynamic/*=T*/); |
| 4337 return result; | 4338 return result; |
| 4338 } | 4339 } |
| 4339 | 4340 |
| 4340 /// Visits a list of expressions, creating a comma expression if needed in JS. | 4341 /// Visits a list of expressions, creating a comma expression if needed in JS. |
| 4341 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { | 4342 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { |
| 4342 if (nodes == null || nodes.isEmpty) return null; | 4343 if (nodes == null || nodes.isEmpty) return null; |
| 4343 return new JS.Expression.binary( | 4344 return new JS.Expression.binary( |
| 4344 _visitList(nodes) as List<JS.Expression>, operator); | 4345 _visitList(nodes) as List<JS.Expression>, operator); |
| 4345 } | 4346 } |
| 4346 | 4347 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4459 // conflict. We could use practically any character for this. | 4460 // conflict. We could use practically any character for this. |
| 4460 name = '+$name'; | 4461 name = '+$name'; |
| 4461 } | 4462 } |
| 4462 | 4463 |
| 4463 var result = _propertyName(name); | 4464 var result = _propertyName(name); |
| 4464 | 4465 |
| 4465 if (useExtension == null) { | 4466 if (useExtension == null) { |
| 4466 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 4467 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
| 4467 var baseType = type; | 4468 var baseType = type; |
| 4468 while (baseType is TypeParameterType) { | 4469 while (baseType is TypeParameterType) { |
| 4469 baseType = baseType.element.bound; | 4470 baseType = (baseType.element as TypeParameterElement).bound; |
| 4470 } | 4471 } |
| 4471 useExtension = baseType != null && | 4472 useExtension = baseType != null && |
| 4472 _extensionTypes.hasNativeSubtype(baseType) && | 4473 _extensionTypes.hasNativeSubtype(baseType) && |
| 4473 !isObjectMember(name); | 4474 !isObjectMember(name); |
| 4474 } | 4475 } |
| 4475 | 4476 |
| 4476 return useExtension ? js.call('dartx.#', result) : result; | 4477 return useExtension ? js.call('dartx.#', result) : result; |
| 4477 } | 4478 } |
| 4478 | 4479 |
| 4479 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { | 4480 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 4499 return _libraries[library] ?? | 4500 return _libraries[library] ?? |
| 4500 _imports.putIfAbsent(library, | 4501 _imports.putIfAbsent(library, |
| 4501 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); | 4502 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); |
| 4502 } | 4503 } |
| 4503 | 4504 |
| 4504 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( | 4505 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( |
| 4505 JS.Node/*=T*/ node, AstNode original, | 4506 JS.Node/*=T*/ node, AstNode original, |
| 4506 [Element element]) { | 4507 [Element element]) { |
| 4507 if (options.closure && element != null) { | 4508 if (options.closure && element != null) { |
| 4508 node = node.withClosureAnnotation(closureAnnotationFor( | 4509 node = node.withClosureAnnotation(closureAnnotationFor( |
| 4509 node, original, element, namedArgumentTemp.name)); | 4510 node, original, element, namedArgumentTemp.name)) as dynamic/*=T*/; |
| 4510 } | 4511 } |
| 4511 return node..sourceInformation = original; | 4512 return node..sourceInformation = original; |
| 4512 } | 4513 } |
| 4513 | 4514 |
| 4514 /// Returns true if this is any kind of object represented by `Number` in JS. | 4515 /// Returns true if this is any kind of object represented by `Number` in JS. |
| 4515 /// | 4516 /// |
| 4516 /// In practice, this is 4 types: num, int, double, and JSNumber. | 4517 /// In practice, this is 4 types: num, int, double, and JSNumber. |
| 4517 /// | 4518 /// |
| 4518 /// JSNumber is the type that actually "implements" all numbers, hence it's | 4519 /// JSNumber is the type that actually "implements" all numbers, hence it's |
| 4519 /// a subtype of int and double (and num). It's in our "dart:_interceptors". | 4520 /// 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... | |
| 4627 } | 4628 } |
| 4628 | 4629 |
| 4629 bool isLibraryPrefix(Expression node) => | 4630 bool isLibraryPrefix(Expression node) => |
| 4630 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4631 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4631 | 4632 |
| 4632 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4633 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4633 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4634 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4634 | 4635 |
| 4635 bool _isDartRuntime(LibraryElement l) => | 4636 bool _isDartRuntime(LibraryElement l) => |
| 4636 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4637 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |