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 | 2 |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
| 7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 import 'package:analyzer/src/generated/type_system.dart' | 24 import 'package:analyzer/src/generated/type_system.dart' |
| 25 show StrongTypeSystemImpl; | 25 show StrongTypeSystemImpl; |
| 26 import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit; | 26 import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit; |
| 27 import 'package:analyzer/src/summary/link.dart' as summary_link; | 27 import 'package:analyzer/src/summary/link.dart' as summary_link; |
| 28 import 'package:analyzer/src/summary/package_bundle_reader.dart'; | 28 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| 29 import 'package:analyzer/src/summary/summarize_ast.dart' | 29 import 'package:analyzer/src/summary/summarize_ast.dart' |
| 30 show serializeAstUnlinked; | 30 show serializeAstUnlinked; |
| 31 import 'package:analyzer/src/summary/summarize_elements.dart' | 31 import 'package:analyzer/src/summary/summarize_elements.dart' |
| 32 show PackageBundleAssembler; | 32 show PackageBundleAssembler; |
| 33 import 'package:analyzer/src/summary/summary_sdk.dart'; | 33 import 'package:analyzer/src/summary/summary_sdk.dart'; |
| 34 import 'package:analyzer/src/task/strong/ast_properties.dart' | 34 import 'package:analyzer/src/task/strong/ast_properties.dart'; |
| 35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast; | |
| 36 import 'package:path/path.dart' show isWithin, relative, separator; | 35 import 'package:path/path.dart' show isWithin, relative, separator; |
| 37 | 36 |
| 38 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 37 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
| 39 import '../js_ast/js_ast.dart' as JS; | 38 import '../js_ast/js_ast.dart' as JS; |
| 40 import '../js_ast/js_ast.dart' show js; | 39 import '../js_ast/js_ast.dart' show js; |
| 41 import 'ast_builder.dart' show AstBuilder; | 40 import 'ast_builder.dart' show AstBuilder; |
| 42 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; | 41 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; |
| 43 import 'element_helpers.dart'; | 42 import 'element_helpers.dart'; |
| 44 import 'extension_types.dart' show ExtensionTypeSet; | 43 import 'extension_types.dart' show ExtensionTypeSet; |
| 45 import 'js_interop.dart'; | 44 import 'js_interop.dart'; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 188 bool _isInForeignJS = false; | 187 bool _isInForeignJS = false; |
| 189 | 188 |
| 190 /// Information about virtual and overridden fields/getters/setters in the | 189 /// Information about virtual and overridden fields/getters/setters in the |
| 191 /// class we're currently compiling, or `null` if we aren't compiling a class. | 190 /// class we're currently compiling, or `null` if we aren't compiling a class. |
| 192 ClassPropertyModel _classProperties; | 191 ClassPropertyModel _classProperties; |
| 193 | 192 |
| 194 /// Information about virtual fields for all libraries in the current build | 193 /// Information about virtual fields for all libraries in the current build |
| 195 /// unit. | 194 /// unit. |
| 196 final virtualFields = new VirtualFieldModel(); | 195 final virtualFields = new VirtualFieldModel(); |
| 197 | 196 |
| 197 final _usedCovariantPrivateMembers = new HashSet<ExecutableElement>(); | |
| 198 | |
| 198 CodeGenerator( | 199 CodeGenerator( |
| 199 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) | 200 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) |
| 200 : context = c, | 201 : context = c, |
| 201 rules = new StrongTypeSystemImpl(c.typeProvider), | 202 rules = new StrongTypeSystemImpl(c.typeProvider), |
| 202 types = c.typeProvider, | 203 types = c.typeProvider, |
| 203 _asyncStreamIterator = | 204 _asyncStreamIterator = |
| 204 _getLibrary(c, 'dart:async').getType('StreamIterator').type, | 205 _getLibrary(c, 'dart:async').getType('StreamIterator').type, |
| 205 _coreIdentical = | 206 _coreIdentical = |
| 206 _getLibrary(c, 'dart:core').publicNamespace.get('identical'), | 207 _getLibrary(c, 'dart:core').publicNamespace.get('identical'), |
| 207 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), | 208 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 282 // Preserve only API-level information in the summary. | 283 // Preserve only API-level information in the summary. |
| 283 bundle.flushInformative(); | 284 bundle.flushInformative(); |
| 284 return bundle.toBuffer(); | 285 return bundle.toBuffer(); |
| 285 } | 286 } |
| 286 | 287 |
| 287 JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) { | 288 JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) { |
| 288 if (_moduleItems.isNotEmpty) { | 289 if (_moduleItems.isNotEmpty) { |
| 289 throw new StateError('Can only call emitModule once.'); | 290 throw new StateError('Can only call emitModule once.'); |
| 290 } | 291 } |
| 291 | 292 |
| 293 for (var unit in compilationUnits) { | |
| 294 _usedCovariantPrivateMembers.addAll(getCovariantPrivateMembers(unit)); | |
| 295 } | |
| 296 | |
| 292 // Transform the AST to make coercions explicit. | 297 // Transform the AST to make coercions explicit. |
| 293 compilationUnits = CoercionReifier.reify(compilationUnits); | 298 compilationUnits = CoercionReifier.reify(compilationUnits); |
| 294 | 299 |
| 295 if (compilationUnits.any((u) => isSdkInternalRuntime( | 300 if (compilationUnits.any((u) => isSdkInternalRuntime( |
| 296 resolutionMap.elementDeclaredByCompilationUnit(u).library))) { | 301 resolutionMap.elementDeclaredByCompilationUnit(u).library))) { |
| 297 // Don't allow these to be renamed when we're building the SDK. | 302 // Don't allow these to be renamed when we're building the SDK. |
| 298 // There is JS code in dart:* that depends on their names. | 303 // There is JS code in dart:* that depends on their names. |
| 299 _runtimeModule = new JS.Identifier('dart'); | 304 _runtimeModule = new JS.Identifier('dart'); |
| 300 _extensionSymbolsModule = new JS.Identifier('dartx'); | 305 _extensionSymbolsModule = new JS.Identifier('dartx'); |
| 301 } else { | 306 } else { |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 692 _moduleItems.add(js.statement( | 697 _moduleItems.add(js.statement( |
| 693 '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name])); | 698 '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name])); |
| 694 } | 699 } |
| 695 } | 700 } |
| 696 | 701 |
| 697 @override | 702 @override |
| 698 visitAsExpression(AsExpression node) { | 703 visitAsExpression(AsExpression node) { |
| 699 Expression fromExpr = node.expression; | 704 Expression fromExpr = node.expression; |
| 700 var from = getStaticType(fromExpr); | 705 var from = getStaticType(fromExpr); |
| 701 var to = node.type.type; | 706 var to = node.type.type; |
| 702 | |
| 703 JS.Expression jsFrom = _visit(fromExpr); | 707 JS.Expression jsFrom = _visit(fromExpr); |
| 704 | 708 |
| 705 // Skip the cast if it's not needed. | 709 // If the check was put here by static analysis to ensure soundness, we |
| 706 if (rules.isSubtypeOf(from, to)) return jsFrom; | 710 // can't skip it. This happens because of unsound covariant generics: |
| 711 // | |
| 712 // typedef F<T>(T t); | |
| 713 // class C<T> { | |
| 714 // F<T> f; | |
| 715 // add(T t) { | |
| 716 // // required check `t as T` | |
| 717 // } | |
| 718 // } | |
| 719 // main() { | |
| 720 // C<Object> c = new C<int>()..f = (int x) => x.isEven; | |
| 721 // c.f('hi'); // required check `c.f as F<Object>` | |
| 722 // c.add('hi); | |
| 723 // } | |
| 724 // | |
| 725 // NOTE: due to implementation details, we do not currently reify the the | |
| 726 // `C<T>.add` check in CoercionReifier, so it does not reach this point; | |
| 727 // rather we check for it explicitly when emitting methods and fields. | |
| 728 // However we do reify the `c.f` check, so we must not eliminate it. | |
| 729 var isRequiredForSoundness = CoercionReifier.isRequiredForSoundness(node); | |
| 730 if (!isRequiredForSoundness && rules.isSubtypeOf(from, to)) return jsFrom; | |
|
vsm
2017/07/06 15:43:02
thanks! The rename is nice too.
| |
| 707 | 731 |
| 708 // All Dart number types map to a JS double. | 732 // All Dart number types map to a JS double. |
| 709 if (typeRep.isNumber(from) && typeRep.isNumber(to)) { | 733 if (typeRep.isNumber(from) && typeRep.isNumber(to)) { |
| 710 // Make sure to check when converting to int. | 734 // Make sure to check when converting to int. |
| 711 if (from != types.intType && to == types.intType) { | 735 if (from != types.intType && to == types.intType) { |
| 712 // TODO(jmesserly): fuse this with notNull check. | 736 // TODO(jmesserly): fuse this with notNull check. |
| 737 // TODO(jmesserly): this does not correctly distinguish user casts from | |
| 738 // required-for-soundness casts. | |
| 713 return _callHelper('asInt(#)', jsFrom); | 739 return _callHelper('asInt(#)', jsFrom); |
| 714 } | 740 } |
| 715 | 741 |
| 716 // A no-op in JavaScript. | 742 // A no-op in JavaScript. |
| 717 return jsFrom; | 743 return jsFrom; |
| 718 } | 744 } |
| 719 | 745 |
| 720 var type = _emitType(to, | 746 var code = isRequiredForSoundness ? '#._check(#)' : '#.as(#)'; |
| 721 nameType: options.nameTypeTests || options.hoistTypeTests, | 747 return js.call(code, [_emitType(to), jsFrom]); |
| 722 hoistType: options.hoistTypeTests); | |
| 723 if (CoercionReifier.isImplicitCast(node)) { | |
| 724 return js.call('#._check(#)', [type, jsFrom]); | |
| 725 } else { | |
| 726 return js.call('#.as(#)', [type, jsFrom]); | |
| 727 } | |
| 728 } | 748 } |
| 729 | 749 |
| 730 @override | 750 @override |
| 731 visitIsExpression(IsExpression node) { | 751 visitIsExpression(IsExpression node) { |
| 732 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. | 752 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. |
| 733 JS.Expression result; | 753 JS.Expression result; |
| 734 var type = node.type.type; | 754 var type = node.type.type; |
| 735 var lhs = _visit(node.expression); | 755 var lhs = _visit(node.expression); |
| 736 var typeofName = _jsTypeofName(type); | 756 var typeofName = _jsTypeofName(type); |
| 737 // Inline primitives other than int (which requires a Math.floor check). | 757 // Inline primitives other than int (which requires a Math.floor check). |
| 738 if (typeofName != null && type != types.intType) { | 758 if (typeofName != null && type != types.intType) { |
| 739 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); | 759 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); |
| 740 } else { | 760 } else { |
| 741 // Always go through a runtime helper, because implicit interfaces. | 761 // Always go through a runtime helper, because implicit interfaces. |
| 742 | 762 |
| 743 var castType = _emitType(type, | 763 var castType = _emitType(type); |
| 744 nameType: options.nameTypeTests || options.hoistTypeTests, | |
| 745 hoistType: options.hoistTypeTests); | |
| 746 | 764 |
| 747 result = js.call('#.is(#)', [castType, lhs]); | 765 result = js.call('#.is(#)', [castType, lhs]); |
| 748 } | 766 } |
| 749 | 767 |
| 750 if (node.notOperator != null) { | 768 if (node.notOperator != null) { |
| 751 return js.call('!#', result); | 769 return js.call('!#', result); |
| 752 } | 770 } |
| 753 return result; | 771 return result; |
| 754 } | 772 } |
| 755 | 773 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 813 ClassElement classElem = node.element; | 831 ClassElement classElem = node.element; |
| 814 var supertype = classElem.supertype; | 832 var supertype = classElem.supertype; |
| 815 | 833 |
| 816 var typeFormals = classElem.typeParameters; | 834 var typeFormals = classElem.typeParameters; |
| 817 var isGeneric = typeFormals.isNotEmpty; | 835 var isGeneric = typeFormals.isNotEmpty; |
| 818 | 836 |
| 819 // Special case where supertype is Object, and we mixin a single class. | 837 // Special case where supertype is Object, and we mixin a single class. |
| 820 // The resulting 'class' is a mixable class in this case. | 838 // The resulting 'class' is a mixable class in this case. |
| 821 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; | 839 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; |
| 822 | 840 |
| 841 // TODO(jmesserly): what do we do if the mixin alias has implied superclass | |
| 842 // covariance checks (due to new interfaces)? We can't add them without | |
| 843 // messing up the inheritance chain and breaking the ability of the mixin | |
| 844 // alias to be mixed in elsewhere. We're going to need something special, | |
| 845 // like adding these checks when we copy in the methods. | |
| 846 var jsMethods = <JS.Method>[]; | |
| 847 _emitSuperclassCovarianceChecks(node, jsMethods); | |
| 823 var classExpr = isMixinAlias | 848 var classExpr = isMixinAlias |
| 824 ? _emitClassHeritage(classElem) | 849 ? _emitClassHeritage(classElem) |
| 825 : _emitClassExpression(classElem, []); | 850 : _emitClassExpression(classElem, jsMethods); |
| 826 var className = isGeneric | 851 var className = isGeneric |
| 827 ? new JS.Identifier(classElem.name) | 852 ? new JS.Identifier(classElem.name) |
| 828 : _emitTopLevelName(classElem); | 853 : _emitTopLevelName(classElem); |
| 829 var block = <JS.Statement>[]; | 854 var block = <JS.Statement>[]; |
| 830 | 855 |
| 831 if (isGeneric) { | 856 if (isGeneric) { |
| 832 if (isMixinAlias) { | 857 if (isMixinAlias) { |
| 833 block.add(js.statement('const # = #;', [className, classExpr])); | 858 block.add(js.statement('const # = #;', [className, classExpr])); |
| 834 } else { | 859 } else { |
| 835 block.add(new JS.ClassDeclaration(classExpr)); | 860 block.add(new JS.ClassDeclaration(classExpr)); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 JS.Expression className; | 924 JS.Expression className; |
| 900 if (classElem.typeParameters.isNotEmpty) { | 925 if (classElem.typeParameters.isNotEmpty) { |
| 901 // Generic classes will be defined inside a function that closes over the | 926 // Generic classes will be defined inside a function that closes over the |
| 902 // type parameter. So we can use their local variable name directly. | 927 // type parameter. So we can use their local variable name directly. |
| 903 className = new JS.Identifier(classElem.name); | 928 className = new JS.Identifier(classElem.name); |
| 904 } else { | 929 } else { |
| 905 className = _emitTopLevelName(classElem); | 930 className = _emitTopLevelName(classElem); |
| 906 } | 931 } |
| 907 | 932 |
| 908 var savedClassProperties = _classProperties; | 933 var savedClassProperties = _classProperties; |
| 909 _classProperties = | 934 _classProperties = new ClassPropertyModel.build( |
| 910 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); | 935 _extensionTypes, |
| 936 virtualFields, | |
| 937 classElem, | |
| 938 getClassCovariantParameters(node), | |
| 939 _usedCovariantPrivateMembers); | |
| 911 | 940 |
| 912 var jsCtors = _defineConstructors(classElem, className, fields, ctors); | 941 var jsCtors = _defineConstructors(classElem, className, fields, ctors); |
| 913 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), | 942 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), |
| 914 fields: allFields); | 943 fields: allFields); |
| 915 | 944 |
| 916 var body = <JS.Statement>[]; | 945 var body = <JS.Statement>[]; |
| 917 _initExtensionSymbols(classElem, methods, fields, body); | 946 _initExtensionSymbols(classElem, methods, fields, body); |
| 918 _emitSuperHelperSymbols(body); | 947 _emitSuperHelperSymbols(body); |
| 919 | 948 |
| 920 // Emit the class, e.g. `core.Object = class Object { ... }` | 949 // Emit the class, e.g. `core.Object = class Object { ... }` |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1436 // (We could do this same optimization for any interface with an `iterator` | 1465 // (We could do this same optimization for any interface with an `iterator` |
| 1437 // method, but that's more expensive to check for, so it doesn't seem worth | 1466 // method, but that's more expensive to check for, so it doesn't seem worth |
| 1438 // it. The above case for an explicit `iterator` method will catch those.) | 1467 // it. The above case for an explicit `iterator` method will catch those.) |
| 1439 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 1468 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
| 1440 jsMethods.add(_emitIterable(type)); | 1469 jsMethods.add(_emitIterable(type)); |
| 1441 } | 1470 } |
| 1442 | 1471 |
| 1443 // Add all of the super helper methods | 1472 // Add all of the super helper methods |
| 1444 jsMethods.addAll(_superHelpers.values); | 1473 jsMethods.addAll(_superHelpers.values); |
| 1445 | 1474 |
| 1475 _emitSuperclassCovarianceChecks(node, jsMethods); | |
| 1446 return jsMethods.where((m) => m != null).toList(growable: false); | 1476 return jsMethods.where((m) => m != null).toList(growable: false); |
| 1447 } | 1477 } |
| 1448 | 1478 |
| 1479 void _emitSuperclassCovarianceChecks( | |
| 1480 Declaration node, List<JS.Method> methods) { | |
| 1481 var covariantParams = getSuperclassCovariantParameters(node); | |
| 1482 if (covariantParams == null) return; | |
| 1483 | |
| 1484 for (var member in covariantParams.map((p) => p.enclosingElement).toSet()) { | |
| 1485 var name = _declareMemberName(member); | |
| 1486 if (member is PropertyAccessorElement) { | |
| 1487 var param = member.parameters[0]; | |
| 1488 assert(covariantParams.contains(param)); | |
| 1489 methods.add(new JS.Method( | |
| 1490 name, | |
| 1491 js.call('function(x) { return super.#(#._check(x)); }', | |
| 1492 [name, _emitType(param.type)]), | |
| 1493 isSetter: true)); | |
| 1494 methods.add(new JS.Method( | |
| 1495 name, js.call('function() { return super.#; }', [name]), | |
| 1496 isGetter: true)); | |
| 1497 } else if (member is MethodElement) { | |
| 1498 var type = member.type; | |
| 1499 | |
| 1500 var body = <JS.Statement>[]; | |
| 1501 var typeFormals = _emitTypeFormals(type.typeFormals); | |
| 1502 if (type.typeFormals.any(covariantParams.contains)) { | |
| 1503 body.add(js.statement( | |
| 1504 '#.checkBounds([#]);', [_emitType(type), typeFormals])); | |
| 1505 } | |
| 1506 | |
| 1507 var jsParams = <JS.Parameter>[]; | |
| 1508 bool foundNamedParams = false; | |
| 1509 for (var param in member.parameters) { | |
| 1510 JS.Parameter jsParam; | |
| 1511 if (param.kind == ParameterKind.NAMED) { | |
| 1512 foundNamedParams = true; | |
| 1513 if (covariantParams.contains(param)) { | |
| 1514 var name = _propertyName(param.name); | |
| 1515 body.add(js.statement('if (# in #) #._check(#.#);', [ | |
| 1516 name, | |
| 1517 namedArgumentTemp, | |
| 1518 _emitType(param.type), | |
| 1519 namedArgumentTemp, | |
| 1520 name | |
| 1521 ])); | |
| 1522 } | |
| 1523 } else { | |
| 1524 jsParam = _emitParameter(param); | |
| 1525 jsParams.add(jsParam); | |
| 1526 if (covariantParams.contains(param)) { | |
| 1527 if (param.kind == ParameterKind.POSITIONAL) { | |
| 1528 body.add(js.statement('if (# !== void 0) #._check(#);', | |
| 1529 [jsParam, _emitType(param.type), jsParam])); | |
| 1530 } else { | |
| 1531 body.add(js.statement( | |
| 1532 '#._check(#);', [_emitType(param.type), jsParam])); | |
| 1533 } | |
| 1534 } | |
| 1535 } | |
| 1536 } | |
| 1537 | |
| 1538 if (foundNamedParams) jsParams.add(namedArgumentTemp); | |
| 1539 | |
| 1540 if (typeFormals.isEmpty) { | |
| 1541 body.add(js.statement('return super.#(#);', [name, jsParams])); | |
| 1542 } else { | |
| 1543 body.add(js.statement( | |
| 1544 'return super.#(#)(#);', [name, typeFormals, jsParams])); | |
| 1545 } | |
| 1546 var fn = new JS.Fun(jsParams, new JS.Block(body), | |
| 1547 typeParams: typeFormals, returnType: emitTypeRef(type.returnType)); | |
| 1548 methods.add(new JS.Method(name, _makeGenericFunction(fn))); | |
| 1549 } else { | |
| 1550 throw new StateError( | |
| 1551 'unable to generate a covariant check for element: `$member` ' | |
| 1552 '(${member.runtimeType})'); | |
| 1553 } | |
| 1554 } | |
| 1555 } | |
| 1556 | |
| 1449 /// Emits a Dart factory constructor to a JS static method. | 1557 /// Emits a Dart factory constructor to a JS static method. |
| 1450 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { | 1558 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { |
| 1451 var element = node.element; | 1559 var element = node.element; |
| 1452 var returnType = emitTypeRef(element.returnType); | 1560 var returnType = emitTypeRef(element.returnType); |
| 1453 var name = _constructorName(element); | 1561 var name = _constructorName(element); |
| 1454 JS.Fun fun; | 1562 JS.Fun fun; |
| 1455 | 1563 |
| 1456 var redirect = node.redirectedConstructor; | 1564 var redirect = node.redirectedConstructor; |
| 1457 if (redirect != null) { | 1565 if (redirect != null) { |
| 1458 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; | 1566 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1579 if (!mocks.containsKey(element.name)) { | 1687 if (!mocks.containsKey(element.name)) { |
| 1580 var getter = js.call('function() { return this[#]; }', [virtualField]); | 1688 var getter = js.call('function() { return this[#]; }', [virtualField]); |
| 1581 result.add(new JS.Method(name, getter, isGetter: true)); | 1689 result.add(new JS.Method(name, getter, isGetter: true)); |
| 1582 } | 1690 } |
| 1583 | 1691 |
| 1584 if (!mocks.containsKey(element.name + '=')) { | 1692 if (!mocks.containsKey(element.name + '=')) { |
| 1585 var args = field.isFinal | 1693 var args = field.isFinal |
| 1586 ? [new JS.Super(), name] | 1694 ? [new JS.Super(), name] |
| 1587 : [new JS.This(), virtualField]; | 1695 : [new JS.This(), virtualField]; |
| 1588 | 1696 |
| 1589 result.add(new JS.Method( | 1697 String jsCode; |
| 1590 name, js.call('function(value) { #[#] = value; }', args), | 1698 var setter = element.setter; |
| 1591 isSetter: true)); | 1699 var covariantParams = _classProperties.covariantParameters; |
| 1700 if (setter != null && | |
| 1701 covariantParams != null && | |
| 1702 covariantParams.contains(setter.parameters[0])) { | |
| 1703 args.add(_emitType(setter.parameters[0].type)); | |
| 1704 jsCode = 'function(value) { #[#] = #._check(value); }'; | |
| 1705 } else { | |
| 1706 jsCode = 'function(value) { #[#] = value; }'; | |
| 1707 } | |
| 1708 | |
| 1709 result.add(new JS.Method(name, js.call(jsCode, args), isSetter: true)); | |
| 1592 } | 1710 } |
| 1593 | 1711 |
| 1594 return result; | 1712 return result; |
| 1595 } | 1713 } |
| 1596 | 1714 |
| 1597 /// Emit a getter or setter that simply forwards to the superclass getter or | 1715 /// Emit a getter or setter that simply forwards to the superclass getter or |
| 1598 /// setter. This is needed because in ES6, if you only override a getter | 1716 /// setter. This is needed because in ES6, if you only override a getter |
| 1599 /// (alternatively, a setter), then there is an implicit override of the | 1717 /// (alternatively, a setter), then there is an implicit override of the |
| 1600 /// setter (alternatively, the getter) that does nothing. | 1718 /// setter (alternatively, the getter) that does nothing. |
| 1601 JS.Method _emitSuperAccessorWrapper( | 1719 JS.Method _emitSuperAccessorWrapper( |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1943 // overriding has a different reified type from ourselves, we must | 2061 // overriding has a different reified type from ourselves, we must |
| 1944 // emit a signature on this class. Otherwise we will inherit the | 2062 // emit a signature on this class. Otherwise we will inherit the |
| 1945 // signature from the superclass. | 2063 // signature from the superclass. |
| 1946 var needsSignature = getOverride(name, currentLibrary) == null || | 2064 var needsSignature = getOverride(name, currentLibrary) == null || |
| 1947 elementToType( | 2065 elementToType( |
| 1948 lookup(name, library: currentLibrary, thisType: false)) != | 2066 lookup(name, library: currentLibrary, thisType: false)) != |
| 1949 reifiedType; | 2067 reifiedType; |
| 1950 | 2068 |
| 1951 var type = _emitAnnotatedFunctionType(reifiedType, node.metadata, | 2069 var type = _emitAnnotatedFunctionType(reifiedType, node.metadata, |
| 1952 parameters: node.parameters?.parameters, | 2070 parameters: node.parameters?.parameters, |
| 1953 nameType: options.hoistSignatureTypes, | 2071 nameType: false, |
| 1954 hoistType: options.hoistSignatureTypes, | |
| 1955 definite: true); | 2072 definite: true); |
| 1956 | 2073 |
| 1957 if (needsSignature) { | 2074 if (needsSignature) { |
| 1958 var memberName = _declareMemberName(element); | 2075 var memberName = _declareMemberName(element); |
| 1959 var property = new JS.Property(memberName, type); | 2076 var property = new JS.Property(memberName, type); |
| 1960 tMember.add(property); | 2077 tMember.add(property); |
| 1961 // We record the names of static methods separately so we can | 2078 // We record the names of static methods separately so we can |
| 1962 // attach metadata to them individually. | 2079 // attach metadata to them individually. |
| 1963 // TODO(leafp): Revisit this. | 2080 // TODO(leafp): Revisit this. |
| 1964 if (node.isStatic && !node.isGetter && !node.isSetter) { | 2081 if (node.isStatic && !node.isGetter && !node.isSetter) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1985 } | 2102 } |
| 1986 } | 2103 } |
| 1987 | 2104 |
| 1988 var tCtors = <JS.Property>[]; | 2105 var tCtors = <JS.Property>[]; |
| 1989 if (options.emitMetadata) { | 2106 if (options.emitMetadata) { |
| 1990 for (ConstructorDeclaration node in ctors) { | 2107 for (ConstructorDeclaration node in ctors) { |
| 1991 var element = node.element; | 2108 var element = node.element; |
| 1992 var memberName = _constructorName(element); | 2109 var memberName = _constructorName(element); |
| 1993 var type = _emitAnnotatedFunctionType(element.type, node.metadata, | 2110 var type = _emitAnnotatedFunctionType(element.type, node.metadata, |
| 1994 parameters: node.parameters.parameters, | 2111 parameters: node.parameters.parameters, |
| 1995 nameType: options.hoistSignatureTypes, | 2112 nameType: false, |
| 1996 hoistType: options.hoistSignatureTypes, | |
| 1997 definite: true); | 2113 definite: true); |
| 1998 var property = new JS.Property(memberName, type); | 2114 var property = new JS.Property(memberName, type); |
| 1999 tCtors.add(property); | 2115 tCtors.add(property); |
| 2000 } | 2116 } |
| 2001 } | 2117 } |
| 2002 var sigFields = <JS.Property>[]; | 2118 var sigFields = <JS.Property>[]; |
| 2003 _buildSignatureField(sigFields, 'constructors', tCtors); | 2119 _buildSignatureField(sigFields, 'constructors', tCtors); |
| 2004 _buildSignatureField(sigFields, 'fields', tInstanceFields); | 2120 _buildSignatureField(sigFields, 'fields', tInstanceFields); |
| 2005 _buildSignatureField(sigFields, 'getters', tInstanceGetters); | 2121 _buildSignatureField(sigFields, 'getters', tInstanceGetters); |
| 2006 _buildSignatureField(sigFields, 'setters', tInstanceSetters); | 2122 _buildSignatureField(sigFields, 'setters', tInstanceSetters); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2287 /// Emits argument initializers, which handles optional/named args, as well | 2403 /// Emits argument initializers, which handles optional/named args, as well |
| 2288 /// as generic type checks needed due to our covariance. | 2404 /// as generic type checks needed due to our covariance. |
| 2289 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { | 2405 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { |
| 2290 // Constructor argument initializers are emitted earlier in the code, rather | 2406 // Constructor argument initializers are emitted earlier in the code, rather |
| 2291 // than always when we visit the function body, so we control it explicitly. | 2407 // than always when we visit the function body, so we control it explicitly. |
| 2292 if (node is ConstructorDeclaration != constructor) return null; | 2408 if (node is ConstructorDeclaration != constructor) return null; |
| 2293 | 2409 |
| 2294 var parameters = _parametersOf(node); | 2410 var parameters = _parametersOf(node); |
| 2295 if (parameters == null) return null; | 2411 if (parameters == null) return null; |
| 2296 | 2412 |
| 2413 var covariantParams = _classProperties?.covariantParameters; | |
| 2414 | |
| 2297 var body = <JS.Statement>[]; | 2415 var body = <JS.Statement>[]; |
| 2298 for (var param in parameters.parameters) { | 2416 for (var param in parameters.parameters) { |
| 2299 var jsParam = _emitSimpleIdentifier(param.identifier); | 2417 var jsParam = _emitSimpleIdentifier(param.identifier); |
| 2300 | 2418 |
| 2301 if (!options.destructureNamedParams) { | 2419 if (!options.destructureNamedParams) { |
| 2302 if (param.kind == ParameterKind.NAMED) { | 2420 if (param.kind == ParameterKind.NAMED) { |
| 2303 // Parameters will be passed using their real names, not the (possibly | 2421 // Parameters will be passed using their real names, not the (possibly |
| 2304 // renamed) local variable. | 2422 // renamed) local variable. |
| 2305 var paramName = js.string(param.identifier.name, "'"); | 2423 var paramName = js.string(param.identifier.name, "'"); |
| 2306 | 2424 |
| 2307 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. | 2425 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. |
| 2308 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 2426 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
| 2309 jsParam, | 2427 jsParam, |
| 2310 namedArgumentTemp, | 2428 namedArgumentTemp, |
| 2311 paramName, | 2429 paramName, |
| 2312 namedArgumentTemp, | 2430 namedArgumentTemp, |
| 2313 namedArgumentTemp, | 2431 namedArgumentTemp, |
| 2314 paramName, | 2432 paramName, |
| 2315 _defaultParamValue(param), | 2433 _defaultParamValue(param), |
| 2316 ])); | 2434 ])); |
| 2317 } else if (param.kind == ParameterKind.POSITIONAL) { | 2435 } else if (param.kind == ParameterKind.POSITIONAL) { |
| 2318 body.add(js.statement('if (# === void 0) # = #;', | 2436 body.add(js.statement('if (# === void 0) # = #;', |
| 2319 [jsParam, jsParam, _defaultParamValue(param)])); | 2437 [jsParam, jsParam, _defaultParamValue(param)])); |
| 2320 } | 2438 } |
| 2321 } | 2439 } |
| 2322 | 2440 |
| 2323 // TODO(jmesserly): various problems here, see: | 2441 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); |
| 2324 // https://github.com/dart-lang/sdk/issues/27259 | 2442 if (paramElement.isCovariant || |
| 2325 var paramType = | 2443 covariantParams != null && covariantParams.contains(paramElement)) { |
| 2326 resolutionMap.elementDeclaredByFormalParameter(param).type; | 2444 var castType = _emitType(paramElement.type); |
| 2327 if (node is MethodDeclaration && | |
| 2328 (resolutionMap.elementDeclaredByFormalParameter(param).isCovariant || | |
| 2329 _unsoundCovariant(paramType, true))) { | |
| 2330 var castType = _emitType(paramType, | |
| 2331 nameType: options.nameTypeTests || options.hoistTypeTests, | |
| 2332 hoistType: options.hoistTypeTests); | |
| 2333 body.add(js.statement('#._check(#);', [castType, jsParam])); | 2445 body.add(js.statement('#._check(#);', [castType, jsParam])); |
| 2334 } | 2446 } |
| 2335 } | 2447 } |
| 2336 return body.isEmpty ? null : _statement(body); | 2448 return body.isEmpty ? null : _statement(body); |
| 2337 } | 2449 } |
| 2338 | 2450 |
| 2339 /// Given a type [t], return whether or not t is unsoundly covariant. | |
| 2340 /// If [contravariant] is true, then t appears in a contravariant | |
| 2341 /// position. | |
| 2342 bool _unsoundCovariant(DartType t, bool contravariant) { | |
| 2343 if (t is TypeParameterType) { | |
| 2344 return contravariant && t.element.enclosingElement is ClassElement; | |
| 2345 } | |
| 2346 if (t is FunctionType) { | |
| 2347 if (_unsoundCovariant(t.returnType, contravariant)) return true; | |
| 2348 return t.parameters.any((p) => _unsoundCovariant(p.type, !contravariant)); | |
| 2349 } | |
| 2350 if (t is ParameterizedType) { | |
| 2351 return t.typeArguments.any((t) => _unsoundCovariant(t, contravariant)); | |
| 2352 } | |
| 2353 return false; | |
| 2354 } | |
| 2355 | |
| 2356 JS.Expression _defaultParamValue(FormalParameter param) { | 2451 JS.Expression _defaultParamValue(FormalParameter param) { |
| 2357 if (param is DefaultFormalParameter && param.defaultValue != null) { | 2452 if (param is DefaultFormalParameter && param.defaultValue != null) { |
| 2358 return _visit(param.defaultValue); | 2453 return _visit(param.defaultValue); |
| 2359 } else { | 2454 } else { |
| 2360 return new JS.LiteralNull(); | 2455 return new JS.LiteralNull(); |
| 2361 } | 2456 } |
| 2362 } | 2457 } |
| 2363 | 2458 |
| 2364 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { | 2459 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { |
| 2365 String name = | 2460 String name = |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2616 FunctionType type = element.type; | 2711 FunctionType type = element.type; |
| 2617 | 2712 |
| 2618 // normal function (sync), vs (sync*, async, async*) | 2713 // normal function (sync), vs (sync*, async, async*) |
| 2619 var stdFn = !(element.isAsynchronous || element.isGenerator); | 2714 var stdFn = !(element.isAsynchronous || element.isGenerator); |
| 2620 var formals = _emitFormalParameterList(parameters, destructure: stdFn); | 2715 var formals = _emitFormalParameterList(parameters, destructure: stdFn); |
| 2621 JS.Block code = stdFn | 2716 JS.Block code = stdFn |
| 2622 ? _visit(body) | 2717 ? _visit(body) |
| 2623 : new JS.Block( | 2718 : new JS.Block( |
| 2624 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); | 2719 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); |
| 2625 var typeFormals = _emitTypeFormals(type.typeFormals); | 2720 var typeFormals = _emitTypeFormals(type.typeFormals); |
| 2721 | |
| 2626 var returnType = emitTypeRef(type.returnType); | 2722 var returnType = emitTypeRef(type.returnType); |
| 2627 if (type.typeFormals.isNotEmpty) { | 2723 if (type.typeFormals.isNotEmpty) { |
| 2628 code = new JS.Block( | 2724 var block = <JS.Statement>[ |
| 2629 [new JS.Block(_typeTable.discharge(type.typeFormals)), code]); | 2725 new JS.Block(_typeTable.discharge(type.typeFormals)) |
| 2726 ]; | |
| 2727 | |
| 2728 var covariantParams = _classProperties?.covariantParameters; | |
| 2729 if (covariantParams != null && | |
| 2730 type.typeFormals.any(covariantParams.contains)) { | |
| 2731 block.add(js.statement('#.checkBounds(#);', | |
| 2732 [_emitType(type), new JS.ArrayInitializer(typeFormals)])); | |
| 2733 } | |
| 2734 | |
| 2735 code = new JS.Block(block..add(code)); | |
| 2630 } | 2736 } |
| 2631 | 2737 |
| 2632 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { | 2738 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { |
| 2633 // []= methods need to return the value. We could also address this at | 2739 // []= methods need to return the value. We could also address this at |
| 2634 // call sites, but it's cleaner to instead transform the operator method. | 2740 // call sites, but it's cleaner to instead transform the operator method. |
| 2635 code = _alwaysReturnLastParameter(code, formals.last); | 2741 code = _alwaysReturnLastParameter(code, formals.last); |
| 2636 } | 2742 } |
| 2637 | 2743 |
| 2638 if (body is BlockFunctionBody) { | 2744 if (body is BlockFunctionBody) { |
| 2639 var params = element.parameters.map((e) => e.name).toSet(); | 2745 var params = element.parameters.map((e) => e.name).toSet(); |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2886 JS.Expression _emitAnnotatedResult( | 2992 JS.Expression _emitAnnotatedResult( |
| 2887 JS.Expression result, List<Annotation> metadata) { | 2993 JS.Expression result, List<Annotation> metadata) { |
| 2888 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { | 2994 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { |
| 2889 result = new JS.ArrayInitializer( | 2995 result = new JS.ArrayInitializer( |
| 2890 [result]..addAll(metadata.map(_instantiateAnnotation))); | 2996 [result]..addAll(metadata.map(_instantiateAnnotation))); |
| 2891 } | 2997 } |
| 2892 return result; | 2998 return result; |
| 2893 } | 2999 } |
| 2894 | 3000 |
| 2895 JS.Expression _emitAnnotatedType(DartType type, List<Annotation> metadata, | 3001 JS.Expression _emitAnnotatedType(DartType type, List<Annotation> metadata, |
| 2896 {bool nameType: true, bool hoistType: true}) { | 3002 {bool nameType: true}) { |
| 2897 metadata ??= []; | 3003 metadata ??= []; |
| 2898 var typeName = _emitType(type, nameType: nameType, hoistType: hoistType); | 3004 var typeName = _emitType(type, nameType: nameType); |
| 2899 return _emitAnnotatedResult(typeName, metadata); | 3005 return _emitAnnotatedResult(typeName, metadata); |
| 2900 } | 3006 } |
| 2901 | 3007 |
| 2902 JS.Expression _emitFieldSignature(DartType type, | 3008 JS.Expression _emitFieldSignature(DartType type, |
| 2903 {List<Annotation> metadata, bool isFinal: true}) { | 3009 {List<Annotation> metadata, bool isFinal: true}) { |
| 2904 var args = [_emitType(type)]; | 3010 var args = [_emitType(type)]; |
| 2905 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { | 3011 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { |
| 2906 args.add(new JS.ArrayInitializer( | 3012 args.add(new JS.ArrayInitializer( |
| 2907 metadata.map(_instantiateAnnotation).toList())); | 3013 metadata.map(_instantiateAnnotation).toList())); |
| 2908 } | 3014 } |
| 2909 return _callHelper(isFinal ? 'finalFieldType(#)' : 'fieldType(#)', [args]); | 3015 return _callHelper(isFinal ? 'finalFieldType(#)' : 'fieldType(#)', [args]); |
| 2910 } | 3016 } |
| 2911 | 3017 |
| 2912 JS.ArrayInitializer _emitTypeNames( | 3018 JS.ArrayInitializer _emitTypeNames( |
| 2913 List<DartType> types, List<FormalParameter> parameters, | 3019 List<DartType> types, List<FormalParameter> parameters, |
| 2914 {bool nameType: true, bool hoistType: true}) { | 3020 {bool nameType: true}) { |
| 2915 var result = <JS.Expression>[]; | 3021 var result = <JS.Expression>[]; |
| 2916 for (int i = 0; i < types.length; ++i) { | 3022 for (int i = 0; i < types.length; ++i) { |
| 2917 var metadata = parameters != null | 3023 var metadata = parameters != null |
| 2918 ? _parameterMetadata(parameters[i]) | 3024 ? _parameterMetadata(parameters[i]) |
| 2919 : <Annotation>[]; | 3025 : <Annotation>[]; |
| 2920 result.add(_emitAnnotatedType(types[i], metadata)); | 3026 result.add(_emitAnnotatedType(types[i], metadata)); |
| 2921 } | 3027 } |
| 2922 return new JS.ArrayInitializer(result); | 3028 return new JS.ArrayInitializer(result); |
| 2923 } | 3029 } |
| 2924 | 3030 |
| 2925 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 3031 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
| 2926 var properties = <JS.Property>[]; | 3032 var properties = <JS.Property>[]; |
| 2927 types.forEach((name, type) { | 3033 types.forEach((name, type) { |
| 2928 var key = _propertyName(name); | 3034 var key = _propertyName(name); |
| 2929 var value = _emitType(type); | 3035 var value = _emitType(type); |
| 2930 properties.add(new JS.Property(key, value)); | 3036 properties.add(new JS.Property(key, value)); |
| 2931 }); | 3037 }); |
| 2932 return new JS.ObjectInitializer(properties); | 3038 return new JS.ObjectInitializer(properties); |
| 2933 } | 3039 } |
| 2934 | 3040 |
| 2935 /// Emit the pieces of a function type, as an array of return type, | 3041 /// Emit the pieces of a function type, as an array of return type, |
| 2936 /// regular args, and optional/named args. | 3042 /// regular args, and optional/named args. |
| 2937 JS.Expression _emitFunctionType(FunctionType type, | 3043 JS.Expression _emitFunctionType(FunctionType type, |
| 2938 {List<FormalParameter> parameters, | 3044 {List<FormalParameter> parameters, |
| 2939 bool lowerTypedef: false, | 3045 bool lowerTypedef: false, |
| 2940 bool nameType: true, | 3046 bool nameType: true, |
| 2941 bool hoistType: true, | |
| 2942 definite: false}) { | 3047 definite: false}) { |
| 2943 var parameterTypes = type.normalParameterTypes; | 3048 var parameterTypes = type.normalParameterTypes; |
| 2944 var optionalTypes = type.optionalParameterTypes; | 3049 var optionalTypes = type.optionalParameterTypes; |
| 2945 var namedTypes = type.namedParameterTypes; | 3050 var namedTypes = type.namedParameterTypes; |
| 2946 var rt = | 3051 var rt = _emitType(type.returnType, nameType: nameType); |
| 2947 _emitType(type.returnType, nameType: nameType, hoistType: hoistType); | |
| 2948 | 3052 |
| 2949 var ra = _emitTypeNames(parameterTypes, parameters, | 3053 var ra = _emitTypeNames(parameterTypes, parameters, nameType: nameType); |
| 2950 nameType: nameType, hoistType: hoistType); | |
| 2951 | 3054 |
| 2952 List<JS.Expression> typeParts; | 3055 List<JS.Expression> typeParts; |
| 2953 if (namedTypes.isNotEmpty) { | 3056 if (namedTypes.isNotEmpty) { |
| 2954 assert(optionalTypes.isEmpty); | 3057 assert(optionalTypes.isEmpty); |
| 2955 // TODO(vsm): Pass in annotations here as well. | 3058 // TODO(vsm): Pass in annotations here as well. |
| 2956 var na = _emitTypeProperties(namedTypes); | 3059 var na = _emitTypeProperties(namedTypes); |
| 2957 typeParts = [rt, ra, na]; | 3060 typeParts = [rt, ra, na]; |
| 2958 } else if (optionalTypes.isNotEmpty) { | 3061 } else if (optionalTypes.isNotEmpty) { |
| 2959 assert(namedTypes.isEmpty); | 3062 assert(namedTypes.isEmpty); |
| 2960 var oa = _emitTypeNames( | 3063 var oa = _emitTypeNames( |
| 2961 optionalTypes, parameters?.sublist(parameterTypes.length), | 3064 optionalTypes, parameters?.sublist(parameterTypes.length), |
| 2962 nameType: nameType, hoistType: hoistType); | 3065 nameType: nameType); |
| 2963 typeParts = [rt, ra, oa]; | 3066 typeParts = [rt, ra, oa]; |
| 2964 } else { | 3067 } else { |
| 2965 typeParts = [rt, ra]; | 3068 typeParts = [rt, ra]; |
| 2966 } | 3069 } |
| 2967 | 3070 |
| 2968 JS.Expression fullType; | 3071 JS.Expression fullType; |
| 2969 var typeFormals = type.typeFormals; | 3072 var typeFormals = type.typeFormals; |
| 2970 String helperCall; | 3073 String helperCall; |
| 2971 if (typeFormals.isNotEmpty) { | 3074 if (typeFormals.isNotEmpty) { |
| 2972 var tf = _emitTypeFormals(typeFormals); | 3075 var tf = _emitTypeFormals(typeFormals); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 2985 // If any explicit bounds were passed, emit them. | 3088 // If any explicit bounds were passed, emit them. |
| 2986 if (typeFormals.any((t) => t.bound != null)) { | 3089 if (typeFormals.any((t) => t.bound != null)) { |
| 2987 var bounds = typeFormals.map((t) => _emitType(t.type.bound)).toList(); | 3090 var bounds = typeFormals.map((t) => _emitType(t.type.bound)).toList(); |
| 2988 typeParts.add(addTypeFormalsAsParameters(bounds)); | 3091 typeParts.add(addTypeFormalsAsParameters(bounds)); |
| 2989 } | 3092 } |
| 2990 } else { | 3093 } else { |
| 2991 helperCall = definite ? 'fnType(#)' : 'fnTypeFuzzy(#)'; | 3094 helperCall = definite ? 'fnType(#)' : 'fnTypeFuzzy(#)'; |
| 2992 } | 3095 } |
| 2993 fullType = _callHelper(helperCall, [typeParts]); | 3096 fullType = _callHelper(helperCall, [typeParts]); |
| 2994 if (!nameType) return fullType; | 3097 if (!nameType) return fullType; |
| 2995 return _typeTable.nameType(type, fullType, | 3098 return _typeTable.nameType(type, fullType, definite: definite); |
| 2996 hoistType: hoistType, definite: definite); | |
| 2997 } | 3099 } |
| 2998 | 3100 |
| 2999 JS.Expression _emitAnnotatedFunctionType( | 3101 JS.Expression _emitAnnotatedFunctionType( |
| 3000 FunctionType type, List<Annotation> metadata, | 3102 FunctionType type, List<Annotation> metadata, |
| 3001 {List<FormalParameter> parameters, | 3103 {List<FormalParameter> parameters, |
| 3002 bool lowerTypedef: false, | 3104 bool lowerTypedef: false, |
| 3003 bool nameType: true, | 3105 bool nameType: true, |
| 3004 bool hoistType: true, | |
| 3005 bool definite: false}) { | 3106 bool definite: false}) { |
| 3006 var result = _emitFunctionType(type, | 3107 var result = _emitFunctionType(type, |
| 3007 parameters: parameters, | 3108 parameters: parameters, |
| 3008 lowerTypedef: lowerTypedef, | 3109 lowerTypedef: lowerTypedef, |
| 3009 nameType: nameType, | 3110 nameType: nameType, |
| 3010 hoistType: hoistType, | |
| 3011 definite: definite); | 3111 definite: definite); |
| 3012 return _emitAnnotatedResult(result, metadata); | 3112 return _emitAnnotatedResult(result, metadata); |
| 3013 } | 3113 } |
| 3014 | 3114 |
| 3015 /// Emits an expression that lets you access statics on a [type] from code. | 3115 /// Emits an expression that lets you access statics on a [type] from code. |
| 3016 /// | 3116 /// |
| 3017 /// If [nameType] is true, then the type will be named. In addition, | 3117 /// If [nameType] is true, then the type will be named. In addition, |
| 3018 /// if [hoistType] is true, then the named type will be hoisted. | 3118 /// if [hoistType] is true, then the named type will be hoisted. |
| 3019 JS.Expression _emitConstructorAccess(DartType type, | 3119 JS.Expression _emitConstructorAccess(DartType type, {bool nameType: true}) { |
| 3020 {bool nameType: true, bool hoistType: true}) { | 3120 return _emitJSInterop(type.element) ?? _emitType(type, nameType: nameType); |
| 3021 return _emitJSInterop(type.element) ?? | |
| 3022 _emitType(type, nameType: nameType, hoistType: hoistType); | |
| 3023 } | 3121 } |
| 3024 | 3122 |
| 3025 /// Emits an expression that lets you access statics on a [type] from code. | 3123 /// Emits an expression that lets you access statics on a [type] from code. |
| 3026 JS.Expression _emitStaticAccess(DartType type) { | 3124 JS.Expression _emitStaticAccess(DartType type) { |
| 3027 // Make sure we aren't attempting to emit a static access path to a type | 3125 // Make sure we aren't attempting to emit a static access path to a type |
| 3028 // that does not have a valid static access path. | 3126 // that does not have a valid static access path. |
| 3029 assert(!type.isVoid && | 3127 assert(!type.isVoid && |
| 3030 !type.isDynamic && | 3128 !type.isDynamic && |
| 3031 !type.isBottom && | 3129 !type.isBottom && |
| 3032 type is! TypeParameterType); | 3130 type is! TypeParameterType); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 3056 /// If [subClass] is set, then we are setting the base class for the given | 3154 /// If [subClass] is set, then we are setting the base class for the given |
| 3057 /// class and should emit the given [className], which will already be | 3155 /// class and should emit the given [className], which will already be |
| 3058 /// defined. | 3156 /// defined. |
| 3059 /// | 3157 /// |
| 3060 /// If [nameType] is true, then the type will be named. In addition, | 3158 /// If [nameType] is true, then the type will be named. In addition, |
| 3061 /// if [hoistType] is true, then the named type will be hoisted. | 3159 /// if [hoistType] is true, then the named type will be hoisted. |
| 3062 JS.Expression _emitType(DartType type, | 3160 JS.Expression _emitType(DartType type, |
| 3063 {bool lowerTypedef: false, | 3161 {bool lowerTypedef: false, |
| 3064 bool lowerGeneric: false, | 3162 bool lowerGeneric: false, |
| 3065 bool nameType: true, | 3163 bool nameType: true, |
| 3066 bool hoistType: true, | |
| 3067 ClassElement subClass, | 3164 ClassElement subClass, |
| 3068 JS.Expression className}) { | 3165 JS.Expression className}) { |
| 3069 // The void and dynamic types are not defined in core. | 3166 // The void and dynamic types are not defined in core. |
| 3070 if (type.isVoid) { | 3167 if (type.isVoid) { |
| 3071 return _callHelper('void'); | 3168 return _callHelper('void'); |
| 3072 } else if (type.isDynamic) { | 3169 } else if (type.isDynamic) { |
| 3073 return _callHelper('dynamic'); | 3170 return _callHelper('dynamic'); |
| 3074 } else if (type.isBottom) { | 3171 } else if (type.isBottom) { |
| 3075 return _callHelper('bottom'); | 3172 return _callHelper('bottom'); |
| 3076 } | 3173 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 3106 | 3203 |
| 3107 // TODO(jmesserly): like constants, should we hoist function types out of | 3204 // TODO(jmesserly): like constants, should we hoist function types out of |
| 3108 // methods? Similar issue with generic types. For all of these, we may want | 3205 // methods? Similar issue with generic types. For all of these, we may want |
| 3109 // to canonicalize them too, at least when inside the same library. | 3206 // to canonicalize them too, at least when inside the same library. |
| 3110 var name = type.name; | 3207 var name = type.name; |
| 3111 if (name == '' || name == null || lowerTypedef) { | 3208 if (name == '' || name == null || lowerTypedef) { |
| 3112 // TODO(jmesserly): should we change how typedefs work? They currently | 3209 // TODO(jmesserly): should we change how typedefs work? They currently |
| 3113 // go through use similar logic as generic classes. This makes them | 3210 // go through use similar logic as generic classes. This makes them |
| 3114 // different from universal function types. | 3211 // different from universal function types. |
| 3115 return _emitFunctionType(type as FunctionType, | 3212 return _emitFunctionType(type as FunctionType, |
| 3116 lowerTypedef: lowerTypedef, nameType: nameType, hoistType: hoistType); | 3213 lowerTypedef: lowerTypedef, nameType: nameType); |
| 3117 } | 3214 } |
| 3118 | 3215 |
| 3119 if (type is TypeParameterType) { | 3216 if (type is TypeParameterType) { |
| 3120 _typeParamInConst?.add(type); | 3217 _typeParamInConst?.add(type); |
| 3121 return new JS.Identifier(name); | 3218 return new JS.Identifier(name); |
| 3122 } | 3219 } |
| 3123 | 3220 |
| 3124 if (type == subClass?.type) return className; | 3221 if (type == subClass?.type) return className; |
| 3125 | 3222 |
| 3126 if (type is ParameterizedType) { | 3223 if (type is ParameterizedType) { |
| 3127 var args = type.typeArguments; | 3224 var args = type.typeArguments; |
| 3128 Iterable jsArgs = null; | 3225 Iterable jsArgs = null; |
| 3129 if (args.any((a) => !a.isDynamic)) { | 3226 if (args.any((a) => !a.isDynamic)) { |
| 3130 jsArgs = args.map((x) => _emitType(x, | 3227 jsArgs = args.map((x) => _emitType(x, |
| 3131 nameType: nameType, | 3228 nameType: nameType, subClass: subClass, className: className)); |
| 3132 hoistType: hoistType, | |
| 3133 subClass: subClass, | |
| 3134 className: className)); | |
| 3135 } else if (lowerGeneric || element == subClass) { | 3229 } else if (lowerGeneric || element == subClass) { |
| 3136 jsArgs = []; | 3230 jsArgs = []; |
| 3137 } | 3231 } |
| 3138 if (jsArgs != null) { | 3232 if (jsArgs != null) { |
| 3139 var genericName = _emitTopLevelName(element, suffix: '\$'); | 3233 var genericName = _emitTopLevelName(element, suffix: '\$'); |
| 3140 var typeRep = js.call('#(#)', [genericName, jsArgs]); | 3234 var typeRep = js.call('#(#)', [genericName, jsArgs]); |
| 3141 return nameType | 3235 return nameType ? _typeTable.nameType(type, typeRep) : typeRep; |
| 3142 ? _typeTable.nameType(type, typeRep, hoistType: hoistType) | |
| 3143 : typeRep; | |
| 3144 } | 3236 } |
| 3145 } | 3237 } |
| 3146 | 3238 |
| 3147 return _emitTopLevelNameNoInterop(element); | 3239 return _emitTopLevelNameNoInterop(element); |
| 3148 } | 3240 } |
| 3149 | 3241 |
| 3150 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 3242 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
| 3151 var interop = _emitJSInterop(e); | 3243 var interop = _emitJSInterop(e); |
| 3152 if (interop != null) return interop; | 3244 if (interop != null) return interop; |
| 3153 return _emitTopLevelNameNoInterop(e, suffix: suffix); | 3245 return _emitTopLevelNameNoInterop(e, suffix: suffix); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3191 } | 3283 } |
| 3192 | 3284 |
| 3193 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions | 3285 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions |
| 3194 // (for example, x is IndexExpression) we evaluate those once. | 3286 // (for example, x is IndexExpression) we evaluate those once. |
| 3195 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3287 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
| 3196 var lhs = _bindLeftHandSide(vars, left, context: context); | 3288 var lhs = _bindLeftHandSide(vars, left, context: context); |
| 3197 Expression inc = AstBuilder.binaryExpression(lhs, op, right) | 3289 Expression inc = AstBuilder.binaryExpression(lhs, op, right) |
| 3198 ..staticElement = element | 3290 ..staticElement = element |
| 3199 ..staticType = getStaticType(lhs); | 3291 ..staticType = getStaticType(lhs); |
| 3200 | 3292 |
| 3201 var castTo = getImplicitAssignmentCast(left); | 3293 var castTo = getImplicitOperationCast(left); |
| 3202 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); | 3294 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); |
| 3203 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 3295 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); |
| 3204 } | 3296 } |
| 3205 | 3297 |
| 3206 JS.Expression _emitSet(Expression left, Expression right) { | 3298 JS.Expression _emitSet(Expression left, Expression right) { |
| 3207 if (left is IndexExpression) { | 3299 if (left is IndexExpression) { |
| 3208 var target = _getTarget(left); | 3300 var target = _getTarget(left); |
| 3209 if (_useNativeJsIndexer(target.staticType)) { | 3301 if (_useNativeJsIndexer(target.staticType)) { |
| 3210 return js.call( | 3302 return js.call( |
| 3211 '#[#] = #', [_visit(target), _visit(left.index), _visit(right)]); | 3303 '#[#] = #', [_visit(target), _visit(left.index), _visit(right)]); |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3514 } else { | 3606 } else { |
| 3515 return _callHelper('#(#, #, #)', | 3607 return _callHelper('#(#, #, #)', |
| 3516 [_emitDynamicOperationName('dsend'), jsTarget, memberName, args]); | 3608 [_emitDynamicOperationName('dsend'), jsTarget, memberName, args]); |
| 3517 } | 3609 } |
| 3518 } | 3610 } |
| 3519 if (_isObjectMemberCall(target, name)) { | 3611 if (_isObjectMemberCall(target, name)) { |
| 3520 assert(typeArgs == null); // Object methods don't take type args. | 3612 assert(typeArgs == null); // Object methods don't take type args. |
| 3521 return _callHelper('#(#, #)', [name, jsTarget, args]); | 3613 return _callHelper('#(#, #)', [name, jsTarget, args]); |
| 3522 } | 3614 } |
| 3523 jsTarget = _emitTargetAccess(jsTarget, memberName, element); | 3615 jsTarget = _emitTargetAccess(jsTarget, memberName, element); |
| 3616 var castTo = getImplicitOperationCast(node); | |
| 3617 if (castTo != null) { | |
| 3618 jsTarget = js.call('#._check(#)', [_emitType(castTo), jsTarget]); | |
| 3619 } | |
| 3524 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 3620 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
| 3525 | |
| 3526 return new JS.Call(jsTarget, args); | 3621 return new JS.Call(jsTarget, args); |
| 3527 } | 3622 } |
| 3528 | 3623 |
| 3529 JS.Expression _emitDynamicInvoke( | 3624 JS.Expression _emitDynamicInvoke( |
| 3530 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { | 3625 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { |
| 3531 var typeArgs = _emitInvokeTypeArguments(node); | 3626 var typeArgs = _emitInvokeTypeArguments(node); |
| 3532 if (typeArgs != null) { | 3627 if (typeArgs != null) { |
| 3533 return _callHelper( | 3628 return _callHelper( |
| 3534 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); | 3629 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); |
| 3535 } else { | 3630 } else { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3585 } | 3680 } |
| 3586 var bang = negated ? '!' : ''; | 3681 var bang = negated ? '!' : ''; |
| 3587 return js.call( | 3682 return js.call( |
| 3588 "${bang}#", new JS.Call(_emitTopLevelName(_coreIdentical), args)); | 3683 "${bang}#", new JS.Call(_emitTopLevelName(_coreIdentical), args)); |
| 3589 } | 3684 } |
| 3590 | 3685 |
| 3591 /// Emits a function call, to a top-level function, local function, or | 3686 /// Emits a function call, to a top-level function, local function, or |
| 3592 /// an expression. | 3687 /// an expression. |
| 3593 JS.Expression _emitFunctionCall(InvocationExpression node, | 3688 JS.Expression _emitFunctionCall(InvocationExpression node, |
| 3594 [Expression function]) { | 3689 [Expression function]) { |
| 3595 if (function == null) { | 3690 function ??= node.function; |
| 3596 function = node.function; | 3691 var castTo = getImplicitOperationCast(function); |
| 3692 if (castTo != null) { | |
| 3693 function = CoercionReifier.castExpression(function, castTo); | |
| 3597 } | 3694 } |
| 3598 if (_isCoreIdentical(function)) { | 3695 if (_isCoreIdentical(function)) { |
| 3599 return _emitCoreIdenticalCall(node.argumentList.arguments); | 3696 return _emitCoreIdenticalCall(node.argumentList.arguments); |
| 3600 } | 3697 } |
| 3601 var fn = _visit(function); | 3698 var fn = _visit(function); |
| 3602 var args = _emitArgumentList(node.argumentList); | 3699 var args = _emitArgumentList(node.argumentList); |
| 3603 if (isDynamicInvoke(function)) { | 3700 if (isDynamicInvoke(function)) { |
| 3604 return _emitDynamicInvoke(node, fn, args); | 3701 return _emitDynamicInvoke(node, fn, args); |
| 3605 } | 3702 } |
| 3606 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); | 3703 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); |
| (...skipping 1524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5131 } | 5228 } |
| 5132 | 5229 |
| 5133 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { | 5230 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { |
| 5134 var then = visitCatchClause(clause); | 5231 var then = visitCatchClause(clause); |
| 5135 | 5232 |
| 5136 // Discard following clauses, if any, as they are unreachable. | 5233 // Discard following clauses, if any, as they are unreachable. |
| 5137 if (clause.exceptionType == null) return then; | 5234 if (clause.exceptionType == null) return then; |
| 5138 | 5235 |
| 5139 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which | 5236 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which |
| 5140 // has special case for typeof. | 5237 // has special case for typeof. |
| 5141 var castType = _emitType(clause.exceptionType.type, | 5238 var castType = _emitType(clause.exceptionType.type); |
| 5142 nameType: options.nameTypeTests || options.hoistTypeTests, | |
| 5143 hoistType: options.hoistTypeTests); | |
| 5144 | 5239 |
| 5145 return new JS.If(js.call('#.is(#)', [castType, _visit(_catchParameter)]), | 5240 return new JS.If(js.call('#.is(#)', [castType, _visit(_catchParameter)]), |
| 5146 then, otherwise); | 5241 then, otherwise); |
| 5147 } | 5242 } |
| 5148 | 5243 |
| 5149 JS.Statement _statement(List<JS.Statement> statements) { | 5244 JS.Statement _statement(List<JS.Statement> statements) { |
| 5150 // TODO(jmesserly): empty block singleton? | 5245 // TODO(jmesserly): empty block singleton? |
| 5151 if (statements.length == 0) return new JS.Block([]); | 5246 if (statements.length == 0) return new JS.Block([]); |
| 5152 if (statements.length == 1) return statements[0]; | 5247 if (statements.length == 1) return statements[0]; |
| 5153 return new JS.Block(statements); | 5248 return new JS.Block(statements); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5389 if (node is BinaryExpression) { | 5484 if (node is BinaryExpression) { |
| 5390 JS.Expression shortCircuit(String code) { | 5485 JS.Expression shortCircuit(String code) { |
| 5391 return finish(js.call(code, | 5486 return finish(js.call(code, |
| 5392 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); | 5487 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); |
| 5393 } | 5488 } |
| 5394 | 5489 |
| 5395 var op = node.operator.type.lexeme; | 5490 var op = node.operator.type.lexeme; |
| 5396 if (op == '&&') return shortCircuit('# && #'); | 5491 if (op == '&&') return shortCircuit('# && #'); |
| 5397 if (op == '||') return shortCircuit('# || #'); | 5492 if (op == '||') return shortCircuit('# || #'); |
| 5398 } | 5493 } |
| 5399 if (node is AsExpression && CoercionReifier.isImplicitCast(node)) { | 5494 if (node is AsExpression && CoercionReifier.isRequiredForSoundness(node)) { |
| 5400 assert(node.staticType == types.boolType); | 5495 assert(node.staticType == types.boolType); |
| 5401 return _callHelper('dtest(#)', _visit(node.expression)); | 5496 return _callHelper('dtest(#)', _visit(node.expression)); |
| 5402 } | 5497 } |
| 5403 JS.Expression result = _visit(node); | 5498 JS.Expression result = _visit(node); |
| 5404 if (isNullable(node)) result = _callHelper('test(#)', result); | 5499 if (isNullable(node)) result = _callHelper('test(#)', result); |
| 5405 return result; | 5500 return result; |
| 5406 } | 5501 } |
| 5407 | 5502 |
| 5408 /// Like [_emitMemberName], but for declaration sites. | 5503 /// Like [_emitMemberName], but for declaration sites. |
| 5409 /// | 5504 /// |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5895 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5990 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5896 var prefix = targetIdentifier.staticElement as PrefixElement; | 5991 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5897 | 5992 |
| 5898 // The library the prefix is referring to must come from a deferred import. | 5993 // The library the prefix is referring to must come from a deferred import. |
| 5899 var containingLibrary = resolutionMap | 5994 var containingLibrary = resolutionMap |
| 5900 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5995 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 5901 .library; | 5996 .library; |
| 5902 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5997 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5903 return imports.length == 1 && imports[0].isDeferred; | 5998 return imports.length == 1 && imports[0].isDeferred; |
| 5904 } | 5999 } |
| OLD | NEW |