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 |
| 709 bool isImplicit = CoercionReifier.isImplicitCast(node); | |
| 710 | |
| 705 // Skip the cast if it's not needed. | 711 // Skip the cast if it's not needed. |
| 706 if (rules.isSubtypeOf(from, to)) return jsFrom; | 712 if (!isImplicit && rules.isSubtypeOf(from, to)) return jsFrom; |
|
vsm
2017/07/05 22:57:34
Can you add a comment wrt my earlier question?
Jennifer Messerly
2017/07/06 01:11:10
Ah, sure, I guess I got worried about copying the
| |
| 707 | 713 |
| 708 // All Dart number types map to a JS double. | 714 // All Dart number types map to a JS double. |
| 709 if (typeRep.isNumber(from) && typeRep.isNumber(to)) { | 715 if (typeRep.isNumber(from) && typeRep.isNumber(to)) { |
| 710 // Make sure to check when converting to int. | 716 // Make sure to check when converting to int. |
| 711 if (from != types.intType && to == types.intType) { | 717 if (from != types.intType && to == types.intType) { |
| 712 // TODO(jmesserly): fuse this with notNull check. | 718 // TODO(jmesserly): fuse this with notNull check. |
| 713 return _callHelper('asInt(#)', jsFrom); | 719 return _callHelper('asInt(#)', jsFrom); |
| 714 } | 720 } |
| 715 | 721 |
| 716 // A no-op in JavaScript. | 722 // A no-op in JavaScript. |
| 717 return jsFrom; | 723 return jsFrom; |
| 718 } | 724 } |
| 719 | 725 |
| 720 var type = _emitType(to, | 726 var type = _emitType(to); |
| 721 nameType: options.nameTypeTests || options.hoistTypeTests, | 727 return js.call(isImplicit ? '#._check(#)' : '#.as(#)', [type, 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 } | 728 } |
| 729 | 729 |
| 730 @override | 730 @override |
| 731 visitIsExpression(IsExpression node) { | 731 visitIsExpression(IsExpression node) { |
| 732 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. | 732 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. |
| 733 JS.Expression result; | 733 JS.Expression result; |
| 734 var type = node.type.type; | 734 var type = node.type.type; |
| 735 var lhs = _visit(node.expression); | 735 var lhs = _visit(node.expression); |
| 736 var typeofName = _jsTypeofName(type); | 736 var typeofName = _jsTypeofName(type); |
| 737 // Inline primitives other than int (which requires a Math.floor check). | 737 // Inline primitives other than int (which requires a Math.floor check). |
| 738 if (typeofName != null && type != types.intType) { | 738 if (typeofName != null && type != types.intType) { |
| 739 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); | 739 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); |
| 740 } else { | 740 } else { |
| 741 // Always go through a runtime helper, because implicit interfaces. | 741 // Always go through a runtime helper, because implicit interfaces. |
| 742 | 742 |
| 743 var castType = _emitType(type, | 743 var castType = _emitType(type); |
| 744 nameType: options.nameTypeTests || options.hoistTypeTests, | |
| 745 hoistType: options.hoistTypeTests); | |
| 746 | 744 |
| 747 result = js.call('#.is(#)', [castType, lhs]); | 745 result = js.call('#.is(#)', [castType, lhs]); |
| 748 } | 746 } |
| 749 | 747 |
| 750 if (node.notOperator != null) { | 748 if (node.notOperator != null) { |
| 751 return js.call('!#', result); | 749 return js.call('!#', result); |
| 752 } | 750 } |
| 753 return result; | 751 return result; |
| 754 } | 752 } |
| 755 | 753 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 813 ClassElement classElem = node.element; | 811 ClassElement classElem = node.element; |
| 814 var supertype = classElem.supertype; | 812 var supertype = classElem.supertype; |
| 815 | 813 |
| 816 var typeFormals = classElem.typeParameters; | 814 var typeFormals = classElem.typeParameters; |
| 817 var isGeneric = typeFormals.isNotEmpty; | 815 var isGeneric = typeFormals.isNotEmpty; |
| 818 | 816 |
| 819 // Special case where supertype is Object, and we mixin a single class. | 817 // Special case where supertype is Object, and we mixin a single class. |
| 820 // The resulting 'class' is a mixable class in this case. | 818 // The resulting 'class' is a mixable class in this case. |
| 821 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; | 819 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; |
| 822 | 820 |
| 821 // TODO(jmesserly): what do we do if the mixin alias has implied superclass | |
| 822 // covariance checks (due to new interfaces)? We can't add them without | |
| 823 // messing up the inheritance chain and breaking the ability of the mixin | |
| 824 // alias to be mixed in elsewhere. We're going to need something special, | |
| 825 // like adding these checks when we copy in the methods. | |
| 826 var jsMethods = <JS.Method>[]; | |
| 827 _emitSuperclassCovarianceChecks(node, jsMethods); | |
| 823 var classExpr = isMixinAlias | 828 var classExpr = isMixinAlias |
| 824 ? _emitClassHeritage(classElem) | 829 ? _emitClassHeritage(classElem) |
| 825 : _emitClassExpression(classElem, []); | 830 : _emitClassExpression(classElem, jsMethods); |
| 826 var className = isGeneric | 831 var className = isGeneric |
| 827 ? new JS.Identifier(classElem.name) | 832 ? new JS.Identifier(classElem.name) |
| 828 : _emitTopLevelName(classElem); | 833 : _emitTopLevelName(classElem); |
| 829 var block = <JS.Statement>[]; | 834 var block = <JS.Statement>[]; |
| 830 | 835 |
| 831 if (isGeneric) { | 836 if (isGeneric) { |
| 832 if (isMixinAlias) { | 837 if (isMixinAlias) { |
| 833 block.add(js.statement('const # = #;', [className, classExpr])); | 838 block.add(js.statement('const # = #;', [className, classExpr])); |
| 834 } else { | 839 } else { |
| 835 block.add(new JS.ClassDeclaration(classExpr)); | 840 block.add(new JS.ClassDeclaration(classExpr)); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 JS.Expression className; | 904 JS.Expression className; |
| 900 if (classElem.typeParameters.isNotEmpty) { | 905 if (classElem.typeParameters.isNotEmpty) { |
| 901 // Generic classes will be defined inside a function that closes over the | 906 // Generic classes will be defined inside a function that closes over the |
| 902 // type parameter. So we can use their local variable name directly. | 907 // type parameter. So we can use their local variable name directly. |
| 903 className = new JS.Identifier(classElem.name); | 908 className = new JS.Identifier(classElem.name); |
| 904 } else { | 909 } else { |
| 905 className = _emitTopLevelName(classElem); | 910 className = _emitTopLevelName(classElem); |
| 906 } | 911 } |
| 907 | 912 |
| 908 var savedClassProperties = _classProperties; | 913 var savedClassProperties = _classProperties; |
| 909 _classProperties = | 914 _classProperties = new ClassPropertyModel.build( |
| 910 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); | 915 _extensionTypes, |
| 916 virtualFields, | |
| 917 classElem, | |
| 918 getClassCovariantParameters(node), | |
| 919 _usedCovariantPrivateMembers); | |
| 911 | 920 |
| 912 var jsCtors = _defineConstructors(classElem, className, fields, ctors); | 921 var jsCtors = _defineConstructors(classElem, className, fields, ctors); |
| 913 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), | 922 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), |
| 914 fields: allFields); | 923 fields: allFields); |
| 915 | 924 |
| 916 var body = <JS.Statement>[]; | 925 var body = <JS.Statement>[]; |
| 917 _initExtensionSymbols(classElem, methods, fields, body); | 926 _initExtensionSymbols(classElem, methods, fields, body); |
| 918 _emitSuperHelperSymbols(body); | 927 _emitSuperHelperSymbols(body); |
| 919 | 928 |
| 920 // Emit the class, e.g. `core.Object = class Object { ... }` | 929 // 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` | 1445 // (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 | 1446 // 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.) | 1447 // it. The above case for an explicit `iterator` method will catch those.) |
| 1439 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 1448 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
| 1440 jsMethods.add(_emitIterable(type)); | 1449 jsMethods.add(_emitIterable(type)); |
| 1441 } | 1450 } |
| 1442 | 1451 |
| 1443 // Add all of the super helper methods | 1452 // Add all of the super helper methods |
| 1444 jsMethods.addAll(_superHelpers.values); | 1453 jsMethods.addAll(_superHelpers.values); |
| 1445 | 1454 |
| 1455 _emitSuperclassCovarianceChecks(node, jsMethods); | |
| 1446 return jsMethods.where((m) => m != null).toList(growable: false); | 1456 return jsMethods.where((m) => m != null).toList(growable: false); |
| 1447 } | 1457 } |
| 1448 | 1458 |
| 1459 void _emitSuperclassCovarianceChecks( | |
| 1460 Declaration node, List<JS.Method> methods) { | |
| 1461 var covariantParams = getSuperclassCovariantParameters(node); | |
| 1462 if (covariantParams == null) return; | |
| 1463 | |
| 1464 for (var member in covariantParams.map((p) => p.enclosingElement).toSet()) { | |
| 1465 var name = _declareMemberName(member); | |
| 1466 if (member is PropertyAccessorElement) { | |
| 1467 var param = member.parameters[0]; | |
| 1468 assert(covariantParams.contains(param)); | |
| 1469 methods.add(new JS.Method( | |
| 1470 name, | |
| 1471 js.call('function(x) { return super.#(#._check(x)); }', | |
| 1472 [name, _emitType(param.type)]), | |
| 1473 isSetter: true)); | |
| 1474 methods.add(new JS.Method( | |
| 1475 name, js.call('function() { return super.#; }', [name]), | |
| 1476 isGetter: true)); | |
| 1477 } else if (member is MethodElement) { | |
| 1478 var type = member.type; | |
| 1479 | |
| 1480 var body = <JS.Statement>[]; | |
| 1481 var typeFormals = _emitTypeFormals(type.typeFormals); | |
| 1482 if (type.typeFormals.any(covariantParams.contains)) { | |
| 1483 body.add(js.statement( | |
| 1484 '#.checkBounds([#]);', [_emitType(type), typeFormals])); | |
| 1485 } | |
| 1486 | |
| 1487 var jsParams = <JS.Parameter>[]; | |
| 1488 bool foundNamedParams = false; | |
| 1489 for (var param in member.parameters) { | |
| 1490 JS.Parameter jsParam; | |
| 1491 if (param.kind == ParameterKind.NAMED) { | |
| 1492 foundNamedParams = true; | |
| 1493 if (covariantParams.contains(param)) { | |
| 1494 var name = _propertyName(param.name); | |
| 1495 body.add(js.statement('if (# in #) #._check(#.#);', [ | |
| 1496 name, | |
| 1497 namedArgumentTemp, | |
| 1498 _emitType(param.type), | |
| 1499 namedArgumentTemp, | |
| 1500 name | |
| 1501 ])); | |
| 1502 } | |
| 1503 } else { | |
| 1504 jsParam = _emitParameter(param); | |
| 1505 jsParams.add(jsParam); | |
| 1506 if (covariantParams.contains(param)) { | |
| 1507 if (param.kind == ParameterKind.POSITIONAL) { | |
| 1508 body.add(js.statement('if (# !== void 0) #._check(#);', | |
| 1509 [jsParam, _emitType(param.type), jsParam])); | |
| 1510 } else { | |
| 1511 body.add(js.statement( | |
| 1512 '#._check(#);', [_emitType(param.type), jsParam])); | |
| 1513 } | |
| 1514 } | |
| 1515 } | |
| 1516 } | |
| 1517 | |
| 1518 if (foundNamedParams) jsParams.add(namedArgumentTemp); | |
| 1519 | |
| 1520 if (typeFormals.isEmpty) { | |
| 1521 body.add(js.statement('return super.#(#);', [name, jsParams])); | |
| 1522 } else { | |
| 1523 body.add(js.statement( | |
| 1524 'return super.#(#)(#);', [name, typeFormals, jsParams])); | |
| 1525 } | |
| 1526 var fn = new JS.Fun(jsParams, new JS.Block(body), | |
| 1527 typeParams: typeFormals, returnType: emitTypeRef(type.returnType)); | |
| 1528 methods.add(new JS.Method(name, _makeGenericFunction(fn))); | |
| 1529 } else { | |
| 1530 throw new StateError( | |
| 1531 'unable to generate a covariant check for element: `$member` ' | |
| 1532 '(${member.runtimeType})'); | |
| 1533 } | |
| 1534 } | |
| 1535 } | |
| 1536 | |
| 1449 /// Emits a Dart factory constructor to a JS static method. | 1537 /// Emits a Dart factory constructor to a JS static method. |
| 1450 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { | 1538 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { |
| 1451 var element = node.element; | 1539 var element = node.element; |
| 1452 var returnType = emitTypeRef(element.returnType); | 1540 var returnType = emitTypeRef(element.returnType); |
| 1453 var name = _constructorName(element); | 1541 var name = _constructorName(element); |
| 1454 JS.Fun fun; | 1542 JS.Fun fun; |
| 1455 | 1543 |
| 1456 var redirect = node.redirectedConstructor; | 1544 var redirect = node.redirectedConstructor; |
| 1457 if (redirect != null) { | 1545 if (redirect != null) { |
| 1458 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; | 1546 // 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)) { | 1667 if (!mocks.containsKey(element.name)) { |
| 1580 var getter = js.call('function() { return this[#]; }', [virtualField]); | 1668 var getter = js.call('function() { return this[#]; }', [virtualField]); |
| 1581 result.add(new JS.Method(name, getter, isGetter: true)); | 1669 result.add(new JS.Method(name, getter, isGetter: true)); |
| 1582 } | 1670 } |
| 1583 | 1671 |
| 1584 if (!mocks.containsKey(element.name + '=')) { | 1672 if (!mocks.containsKey(element.name + '=')) { |
| 1585 var args = field.isFinal | 1673 var args = field.isFinal |
| 1586 ? [new JS.Super(), name] | 1674 ? [new JS.Super(), name] |
| 1587 : [new JS.This(), virtualField]; | 1675 : [new JS.This(), virtualField]; |
| 1588 | 1676 |
| 1589 result.add(new JS.Method( | 1677 String jsCode; |
| 1590 name, js.call('function(value) { #[#] = value; }', args), | 1678 var setter = element.setter; |
| 1591 isSetter: true)); | 1679 var covariantParams = _classProperties.covariantParameters; |
| 1680 if (setter != null && | |
| 1681 covariantParams != null && | |
| 1682 covariantParams.contains(setter.parameters[0])) { | |
| 1683 args.add(_emitType(setter.parameters[0].type)); | |
| 1684 jsCode = 'function(value) { #[#] = #._check(value); }'; | |
| 1685 } else { | |
| 1686 jsCode = 'function(value) { #[#] = value; }'; | |
| 1687 } | |
| 1688 | |
| 1689 result.add(new JS.Method(name, js.call(jsCode, args), isSetter: true)); | |
| 1592 } | 1690 } |
| 1593 | 1691 |
| 1594 return result; | 1692 return result; |
| 1595 } | 1693 } |
| 1596 | 1694 |
| 1597 /// Emit a getter or setter that simply forwards to the superclass getter or | 1695 /// 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 | 1696 /// 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 | 1697 /// (alternatively, a setter), then there is an implicit override of the |
| 1600 /// setter (alternatively, the getter) that does nothing. | 1698 /// setter (alternatively, the getter) that does nothing. |
| 1601 JS.Method _emitSuperAccessorWrapper( | 1699 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 | 2041 // overriding has a different reified type from ourselves, we must |
| 1944 // emit a signature on this class. Otherwise we will inherit the | 2042 // emit a signature on this class. Otherwise we will inherit the |
| 1945 // signature from the superclass. | 2043 // signature from the superclass. |
| 1946 var needsSignature = getOverride(name, currentLibrary) == null || | 2044 var needsSignature = getOverride(name, currentLibrary) == null || |
| 1947 elementToType( | 2045 elementToType( |
| 1948 lookup(name, library: currentLibrary, thisType: false)) != | 2046 lookup(name, library: currentLibrary, thisType: false)) != |
| 1949 reifiedType; | 2047 reifiedType; |
| 1950 | 2048 |
| 1951 var type = _emitAnnotatedFunctionType(reifiedType, node.metadata, | 2049 var type = _emitAnnotatedFunctionType(reifiedType, node.metadata, |
| 1952 parameters: node.parameters?.parameters, | 2050 parameters: node.parameters?.parameters, |
| 1953 nameType: options.hoistSignatureTypes, | 2051 nameType: false, |
| 1954 hoistType: options.hoistSignatureTypes, | |
| 1955 definite: true); | 2052 definite: true); |
| 1956 | 2053 |
| 1957 if (needsSignature) { | 2054 if (needsSignature) { |
| 1958 var memberName = _declareMemberName(element); | 2055 var memberName = _declareMemberName(element); |
| 1959 var property = new JS.Property(memberName, type); | 2056 var property = new JS.Property(memberName, type); |
| 1960 tMember.add(property); | 2057 tMember.add(property); |
| 1961 // We record the names of static methods separately so we can | 2058 // We record the names of static methods separately so we can |
| 1962 // attach metadata to them individually. | 2059 // attach metadata to them individually. |
| 1963 // TODO(leafp): Revisit this. | 2060 // TODO(leafp): Revisit this. |
| 1964 if (node.isStatic && !node.isGetter && !node.isSetter) { | 2061 if (node.isStatic && !node.isGetter && !node.isSetter) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1985 } | 2082 } |
| 1986 } | 2083 } |
| 1987 | 2084 |
| 1988 var tCtors = <JS.Property>[]; | 2085 var tCtors = <JS.Property>[]; |
| 1989 if (options.emitMetadata) { | 2086 if (options.emitMetadata) { |
| 1990 for (ConstructorDeclaration node in ctors) { | 2087 for (ConstructorDeclaration node in ctors) { |
| 1991 var element = node.element; | 2088 var element = node.element; |
| 1992 var memberName = _constructorName(element); | 2089 var memberName = _constructorName(element); |
| 1993 var type = _emitAnnotatedFunctionType(element.type, node.metadata, | 2090 var type = _emitAnnotatedFunctionType(element.type, node.metadata, |
| 1994 parameters: node.parameters.parameters, | 2091 parameters: node.parameters.parameters, |
| 1995 nameType: options.hoistSignatureTypes, | 2092 nameType: false, |
| 1996 hoistType: options.hoistSignatureTypes, | |
| 1997 definite: true); | 2093 definite: true); |
| 1998 var property = new JS.Property(memberName, type); | 2094 var property = new JS.Property(memberName, type); |
| 1999 tCtors.add(property); | 2095 tCtors.add(property); |
| 2000 } | 2096 } |
| 2001 } | 2097 } |
| 2002 var sigFields = <JS.Property>[]; | 2098 var sigFields = <JS.Property>[]; |
| 2003 _buildSignatureField(sigFields, 'constructors', tCtors); | 2099 _buildSignatureField(sigFields, 'constructors', tCtors); |
| 2004 _buildSignatureField(sigFields, 'fields', tInstanceFields); | 2100 _buildSignatureField(sigFields, 'fields', tInstanceFields); |
| 2005 _buildSignatureField(sigFields, 'getters', tInstanceGetters); | 2101 _buildSignatureField(sigFields, 'getters', tInstanceGetters); |
| 2006 _buildSignatureField(sigFields, 'setters', tInstanceSetters); | 2102 _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 | 2383 /// Emits argument initializers, which handles optional/named args, as well |
| 2288 /// as generic type checks needed due to our covariance. | 2384 /// as generic type checks needed due to our covariance. |
| 2289 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { | 2385 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { |
| 2290 // Constructor argument initializers are emitted earlier in the code, rather | 2386 // Constructor argument initializers are emitted earlier in the code, rather |
| 2291 // than always when we visit the function body, so we control it explicitly. | 2387 // than always when we visit the function body, so we control it explicitly. |
| 2292 if (node is ConstructorDeclaration != constructor) return null; | 2388 if (node is ConstructorDeclaration != constructor) return null; |
| 2293 | 2389 |
| 2294 var parameters = _parametersOf(node); | 2390 var parameters = _parametersOf(node); |
| 2295 if (parameters == null) return null; | 2391 if (parameters == null) return null; |
| 2296 | 2392 |
| 2393 var covariantParams = _classProperties?.covariantParameters; | |
| 2394 | |
| 2297 var body = <JS.Statement>[]; | 2395 var body = <JS.Statement>[]; |
| 2298 for (var param in parameters.parameters) { | 2396 for (var param in parameters.parameters) { |
| 2299 var jsParam = _emitSimpleIdentifier(param.identifier); | 2397 var jsParam = _emitSimpleIdentifier(param.identifier); |
| 2300 | 2398 |
| 2301 if (!options.destructureNamedParams) { | 2399 if (!options.destructureNamedParams) { |
| 2302 if (param.kind == ParameterKind.NAMED) { | 2400 if (param.kind == ParameterKind.NAMED) { |
| 2303 // Parameters will be passed using their real names, not the (possibly | 2401 // Parameters will be passed using their real names, not the (possibly |
| 2304 // renamed) local variable. | 2402 // renamed) local variable. |
| 2305 var paramName = js.string(param.identifier.name, "'"); | 2403 var paramName = js.string(param.identifier.name, "'"); |
| 2306 | 2404 |
| 2307 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. | 2405 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. |
| 2308 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 2406 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
| 2309 jsParam, | 2407 jsParam, |
| 2310 namedArgumentTemp, | 2408 namedArgumentTemp, |
| 2311 paramName, | 2409 paramName, |
| 2312 namedArgumentTemp, | 2410 namedArgumentTemp, |
| 2313 namedArgumentTemp, | 2411 namedArgumentTemp, |
| 2314 paramName, | 2412 paramName, |
| 2315 _defaultParamValue(param), | 2413 _defaultParamValue(param), |
| 2316 ])); | 2414 ])); |
| 2317 } else if (param.kind == ParameterKind.POSITIONAL) { | 2415 } else if (param.kind == ParameterKind.POSITIONAL) { |
| 2318 body.add(js.statement('if (# === void 0) # = #;', | 2416 body.add(js.statement('if (# === void 0) # = #;', |
| 2319 [jsParam, jsParam, _defaultParamValue(param)])); | 2417 [jsParam, jsParam, _defaultParamValue(param)])); |
| 2320 } | 2418 } |
| 2321 } | 2419 } |
| 2322 | 2420 |
| 2323 // TODO(jmesserly): various problems here, see: | 2421 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); |
| 2324 // https://github.com/dart-lang/sdk/issues/27259 | 2422 if (paramElement.isCovariant || |
| 2325 var paramType = | 2423 covariantParams != null && covariantParams.contains(paramElement)) { |
| 2326 resolutionMap.elementDeclaredByFormalParameter(param).type; | 2424 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])); | 2425 body.add(js.statement('#._check(#);', [castType, jsParam])); |
| 2334 } | 2426 } |
| 2335 } | 2427 } |
| 2336 return body.isEmpty ? null : _statement(body); | 2428 return body.isEmpty ? null : _statement(body); |
| 2337 } | 2429 } |
| 2338 | 2430 |
| 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) { | 2431 JS.Expression _defaultParamValue(FormalParameter param) { |
| 2357 if (param is DefaultFormalParameter && param.defaultValue != null) { | 2432 if (param is DefaultFormalParameter && param.defaultValue != null) { |
| 2358 return _visit(param.defaultValue); | 2433 return _visit(param.defaultValue); |
| 2359 } else { | 2434 } else { |
| 2360 return new JS.LiteralNull(); | 2435 return new JS.LiteralNull(); |
| 2361 } | 2436 } |
| 2362 } | 2437 } |
| 2363 | 2438 |
| 2364 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { | 2439 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { |
| 2365 String name = | 2440 String name = |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2616 FunctionType type = element.type; | 2691 FunctionType type = element.type; |
| 2617 | 2692 |
| 2618 // normal function (sync), vs (sync*, async, async*) | 2693 // normal function (sync), vs (sync*, async, async*) |
| 2619 var stdFn = !(element.isAsynchronous || element.isGenerator); | 2694 var stdFn = !(element.isAsynchronous || element.isGenerator); |
| 2620 var formals = _emitFormalParameterList(parameters, destructure: stdFn); | 2695 var formals = _emitFormalParameterList(parameters, destructure: stdFn); |
| 2621 JS.Block code = stdFn | 2696 JS.Block code = stdFn |
| 2622 ? _visit(body) | 2697 ? _visit(body) |
| 2623 : new JS.Block( | 2698 : new JS.Block( |
| 2624 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); | 2699 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); |
| 2625 var typeFormals = _emitTypeFormals(type.typeFormals); | 2700 var typeFormals = _emitTypeFormals(type.typeFormals); |
| 2701 | |
| 2626 var returnType = emitTypeRef(type.returnType); | 2702 var returnType = emitTypeRef(type.returnType); |
| 2627 if (type.typeFormals.isNotEmpty) { | 2703 if (type.typeFormals.isNotEmpty) { |
| 2628 code = new JS.Block( | 2704 var block = <JS.Statement>[ |
| 2629 [new JS.Block(_typeTable.discharge(type.typeFormals)), code]); | 2705 new JS.Block(_typeTable.discharge(type.typeFormals)) |
| 2706 ]; | |
| 2707 | |
| 2708 var covariantParams = _classProperties?.covariantParameters; | |
| 2709 if (covariantParams != null && | |
| 2710 type.typeFormals.any(covariantParams.contains)) { | |
| 2711 block.add(js.statement('#.checkBounds(#);', | |
| 2712 [_emitType(type), new JS.ArrayInitializer(typeFormals)])); | |
| 2713 } | |
| 2714 | |
| 2715 code = new JS.Block(block..add(code)); | |
| 2630 } | 2716 } |
| 2631 | 2717 |
| 2632 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { | 2718 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { |
| 2633 // []= methods need to return the value. We could also address this at | 2719 // []= 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. | 2720 // call sites, but it's cleaner to instead transform the operator method. |
| 2635 code = _alwaysReturnLastParameter(code, formals.last); | 2721 code = _alwaysReturnLastParameter(code, formals.last); |
| 2636 } | 2722 } |
| 2637 | 2723 |
| 2638 if (body is BlockFunctionBody) { | 2724 if (body is BlockFunctionBody) { |
| 2639 var params = element.parameters.map((e) => e.name).toSet(); | 2725 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( | 2972 JS.Expression _emitAnnotatedResult( |
| 2887 JS.Expression result, List<Annotation> metadata) { | 2973 JS.Expression result, List<Annotation> metadata) { |
| 2888 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { | 2974 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { |
| 2889 result = new JS.ArrayInitializer( | 2975 result = new JS.ArrayInitializer( |
| 2890 [result]..addAll(metadata.map(_instantiateAnnotation))); | 2976 [result]..addAll(metadata.map(_instantiateAnnotation))); |
| 2891 } | 2977 } |
| 2892 return result; | 2978 return result; |
| 2893 } | 2979 } |
| 2894 | 2980 |
| 2895 JS.Expression _emitAnnotatedType(DartType type, List<Annotation> metadata, | 2981 JS.Expression _emitAnnotatedType(DartType type, List<Annotation> metadata, |
| 2896 {bool nameType: true, bool hoistType: true}) { | 2982 {bool nameType: true}) { |
| 2897 metadata ??= []; | 2983 metadata ??= []; |
| 2898 var typeName = _emitType(type, nameType: nameType, hoistType: hoistType); | 2984 var typeName = _emitType(type, nameType: nameType); |
| 2899 return _emitAnnotatedResult(typeName, metadata); | 2985 return _emitAnnotatedResult(typeName, metadata); |
| 2900 } | 2986 } |
| 2901 | 2987 |
| 2902 JS.Expression _emitFieldSignature(DartType type, | 2988 JS.Expression _emitFieldSignature(DartType type, |
| 2903 {List<Annotation> metadata, bool isFinal: true}) { | 2989 {List<Annotation> metadata, bool isFinal: true}) { |
| 2904 var args = [_emitType(type)]; | 2990 var args = [_emitType(type)]; |
| 2905 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { | 2991 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { |
| 2906 args.add(new JS.ArrayInitializer( | 2992 args.add(new JS.ArrayInitializer( |
| 2907 metadata.map(_instantiateAnnotation).toList())); | 2993 metadata.map(_instantiateAnnotation).toList())); |
| 2908 } | 2994 } |
| 2909 return _callHelper(isFinal ? 'finalFieldType(#)' : 'fieldType(#)', [args]); | 2995 return _callHelper(isFinal ? 'finalFieldType(#)' : 'fieldType(#)', [args]); |
| 2910 } | 2996 } |
| 2911 | 2997 |
| 2912 JS.ArrayInitializer _emitTypeNames( | 2998 JS.ArrayInitializer _emitTypeNames( |
| 2913 List<DartType> types, List<FormalParameter> parameters, | 2999 List<DartType> types, List<FormalParameter> parameters, |
| 2914 {bool nameType: true, bool hoistType: true}) { | 3000 {bool nameType: true}) { |
| 2915 var result = <JS.Expression>[]; | 3001 var result = <JS.Expression>[]; |
| 2916 for (int i = 0; i < types.length; ++i) { | 3002 for (int i = 0; i < types.length; ++i) { |
| 2917 var metadata = parameters != null | 3003 var metadata = parameters != null |
| 2918 ? _parameterMetadata(parameters[i]) | 3004 ? _parameterMetadata(parameters[i]) |
| 2919 : <Annotation>[]; | 3005 : <Annotation>[]; |
| 2920 result.add(_emitAnnotatedType(types[i], metadata)); | 3006 result.add(_emitAnnotatedType(types[i], metadata)); |
| 2921 } | 3007 } |
| 2922 return new JS.ArrayInitializer(result); | 3008 return new JS.ArrayInitializer(result); |
| 2923 } | 3009 } |
| 2924 | 3010 |
| 2925 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 3011 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
| 2926 var properties = <JS.Property>[]; | 3012 var properties = <JS.Property>[]; |
| 2927 types.forEach((name, type) { | 3013 types.forEach((name, type) { |
| 2928 var key = _propertyName(name); | 3014 var key = _propertyName(name); |
| 2929 var value = _emitType(type); | 3015 var value = _emitType(type); |
| 2930 properties.add(new JS.Property(key, value)); | 3016 properties.add(new JS.Property(key, value)); |
| 2931 }); | 3017 }); |
| 2932 return new JS.ObjectInitializer(properties); | 3018 return new JS.ObjectInitializer(properties); |
| 2933 } | 3019 } |
| 2934 | 3020 |
| 2935 /// Emit the pieces of a function type, as an array of return type, | 3021 /// Emit the pieces of a function type, as an array of return type, |
| 2936 /// regular args, and optional/named args. | 3022 /// regular args, and optional/named args. |
| 2937 JS.Expression _emitFunctionType(FunctionType type, | 3023 JS.Expression _emitFunctionType(FunctionType type, |
| 2938 {List<FormalParameter> parameters, | 3024 {List<FormalParameter> parameters, |
| 2939 bool lowerTypedef: false, | 3025 bool lowerTypedef: false, |
| 2940 bool nameType: true, | 3026 bool nameType: true, |
| 2941 bool hoistType: true, | |
| 2942 definite: false}) { | 3027 definite: false}) { |
| 2943 var parameterTypes = type.normalParameterTypes; | 3028 var parameterTypes = type.normalParameterTypes; |
| 2944 var optionalTypes = type.optionalParameterTypes; | 3029 var optionalTypes = type.optionalParameterTypes; |
| 2945 var namedTypes = type.namedParameterTypes; | 3030 var namedTypes = type.namedParameterTypes; |
| 2946 var rt = | 3031 var rt = _emitType(type.returnType, nameType: nameType); |
| 2947 _emitType(type.returnType, nameType: nameType, hoistType: hoistType); | |
| 2948 | 3032 |
| 2949 var ra = _emitTypeNames(parameterTypes, parameters, | 3033 var ra = _emitTypeNames(parameterTypes, parameters, nameType: nameType); |
| 2950 nameType: nameType, hoistType: hoistType); | |
| 2951 | 3034 |
| 2952 List<JS.Expression> typeParts; | 3035 List<JS.Expression> typeParts; |
| 2953 if (namedTypes.isNotEmpty) { | 3036 if (namedTypes.isNotEmpty) { |
| 2954 assert(optionalTypes.isEmpty); | 3037 assert(optionalTypes.isEmpty); |
| 2955 // TODO(vsm): Pass in annotations here as well. | 3038 // TODO(vsm): Pass in annotations here as well. |
| 2956 var na = _emitTypeProperties(namedTypes); | 3039 var na = _emitTypeProperties(namedTypes); |
| 2957 typeParts = [rt, ra, na]; | 3040 typeParts = [rt, ra, na]; |
| 2958 } else if (optionalTypes.isNotEmpty) { | 3041 } else if (optionalTypes.isNotEmpty) { |
| 2959 assert(namedTypes.isEmpty); | 3042 assert(namedTypes.isEmpty); |
| 2960 var oa = _emitTypeNames( | 3043 var oa = _emitTypeNames( |
| 2961 optionalTypes, parameters?.sublist(parameterTypes.length), | 3044 optionalTypes, parameters?.sublist(parameterTypes.length), |
| 2962 nameType: nameType, hoistType: hoistType); | 3045 nameType: nameType); |
| 2963 typeParts = [rt, ra, oa]; | 3046 typeParts = [rt, ra, oa]; |
| 2964 } else { | 3047 } else { |
| 2965 typeParts = [rt, ra]; | 3048 typeParts = [rt, ra]; |
| 2966 } | 3049 } |
| 2967 | 3050 |
| 2968 JS.Expression fullType; | 3051 JS.Expression fullType; |
| 2969 var typeFormals = type.typeFormals; | 3052 var typeFormals = type.typeFormals; |
| 2970 String helperCall; | 3053 String helperCall; |
| 2971 if (typeFormals.isNotEmpty) { | 3054 if (typeFormals.isNotEmpty) { |
| 2972 var tf = _emitTypeFormals(typeFormals); | 3055 var tf = _emitTypeFormals(typeFormals); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 2985 // If any explicit bounds were passed, emit them. | 3068 // If any explicit bounds were passed, emit them. |
| 2986 if (typeFormals.any((t) => t.bound != null)) { | 3069 if (typeFormals.any((t) => t.bound != null)) { |
| 2987 var bounds = typeFormals.map((t) => _emitType(t.type.bound)).toList(); | 3070 var bounds = typeFormals.map((t) => _emitType(t.type.bound)).toList(); |
| 2988 typeParts.add(addTypeFormalsAsParameters(bounds)); | 3071 typeParts.add(addTypeFormalsAsParameters(bounds)); |
| 2989 } | 3072 } |
| 2990 } else { | 3073 } else { |
| 2991 helperCall = definite ? 'fnType(#)' : 'fnTypeFuzzy(#)'; | 3074 helperCall = definite ? 'fnType(#)' : 'fnTypeFuzzy(#)'; |
| 2992 } | 3075 } |
| 2993 fullType = _callHelper(helperCall, [typeParts]); | 3076 fullType = _callHelper(helperCall, [typeParts]); |
| 2994 if (!nameType) return fullType; | 3077 if (!nameType) return fullType; |
| 2995 return _typeTable.nameType(type, fullType, | 3078 return _typeTable.nameType(type, fullType, definite: definite); |
| 2996 hoistType: hoistType, definite: definite); | |
| 2997 } | 3079 } |
| 2998 | 3080 |
| 2999 JS.Expression _emitAnnotatedFunctionType( | 3081 JS.Expression _emitAnnotatedFunctionType( |
| 3000 FunctionType type, List<Annotation> metadata, | 3082 FunctionType type, List<Annotation> metadata, |
| 3001 {List<FormalParameter> parameters, | 3083 {List<FormalParameter> parameters, |
| 3002 bool lowerTypedef: false, | 3084 bool lowerTypedef: false, |
| 3003 bool nameType: true, | 3085 bool nameType: true, |
| 3004 bool hoistType: true, | |
| 3005 bool definite: false}) { | 3086 bool definite: false}) { |
| 3006 var result = _emitFunctionType(type, | 3087 var result = _emitFunctionType(type, |
| 3007 parameters: parameters, | 3088 parameters: parameters, |
| 3008 lowerTypedef: lowerTypedef, | 3089 lowerTypedef: lowerTypedef, |
| 3009 nameType: nameType, | 3090 nameType: nameType, |
| 3010 hoistType: hoistType, | |
| 3011 definite: definite); | 3091 definite: definite); |
| 3012 return _emitAnnotatedResult(result, metadata); | 3092 return _emitAnnotatedResult(result, metadata); |
| 3013 } | 3093 } |
| 3014 | 3094 |
| 3015 /// Emits an expression that lets you access statics on a [type] from code. | 3095 /// Emits an expression that lets you access statics on a [type] from code. |
| 3016 /// | 3096 /// |
| 3017 /// If [nameType] is true, then the type will be named. In addition, | 3097 /// If [nameType] is true, then the type will be named. In addition, |
| 3018 /// if [hoistType] is true, then the named type will be hoisted. | 3098 /// if [hoistType] is true, then the named type will be hoisted. |
| 3019 JS.Expression _emitConstructorAccess(DartType type, | 3099 JS.Expression _emitConstructorAccess(DartType type, {bool nameType: true}) { |
| 3020 {bool nameType: true, bool hoistType: true}) { | 3100 return _emitJSInterop(type.element) ?? _emitType(type, nameType: nameType); |
| 3021 return _emitJSInterop(type.element) ?? | |
| 3022 _emitType(type, nameType: nameType, hoistType: hoistType); | |
| 3023 } | 3101 } |
| 3024 | 3102 |
| 3025 /// Emits an expression that lets you access statics on a [type] from code. | 3103 /// Emits an expression that lets you access statics on a [type] from code. |
| 3026 JS.Expression _emitStaticAccess(DartType type) { | 3104 JS.Expression _emitStaticAccess(DartType type) { |
| 3027 // Make sure we aren't attempting to emit a static access path to a type | 3105 // 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. | 3106 // that does not have a valid static access path. |
| 3029 assert(!type.isVoid && | 3107 assert(!type.isVoid && |
| 3030 !type.isDynamic && | 3108 !type.isDynamic && |
| 3031 !type.isBottom && | 3109 !type.isBottom && |
| 3032 type is! TypeParameterType); | 3110 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 | 3134 /// 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 | 3135 /// class and should emit the given [className], which will already be |
| 3058 /// defined. | 3136 /// defined. |
| 3059 /// | 3137 /// |
| 3060 /// If [nameType] is true, then the type will be named. In addition, | 3138 /// If [nameType] is true, then the type will be named. In addition, |
| 3061 /// if [hoistType] is true, then the named type will be hoisted. | 3139 /// if [hoistType] is true, then the named type will be hoisted. |
| 3062 JS.Expression _emitType(DartType type, | 3140 JS.Expression _emitType(DartType type, |
| 3063 {bool lowerTypedef: false, | 3141 {bool lowerTypedef: false, |
| 3064 bool lowerGeneric: false, | 3142 bool lowerGeneric: false, |
| 3065 bool nameType: true, | 3143 bool nameType: true, |
| 3066 bool hoistType: true, | |
| 3067 ClassElement subClass, | 3144 ClassElement subClass, |
| 3068 JS.Expression className}) { | 3145 JS.Expression className}) { |
| 3069 // The void and dynamic types are not defined in core. | 3146 // The void and dynamic types are not defined in core. |
| 3070 if (type.isVoid) { | 3147 if (type.isVoid) { |
| 3071 return _callHelper('void'); | 3148 return _callHelper('void'); |
| 3072 } else if (type.isDynamic) { | 3149 } else if (type.isDynamic) { |
| 3073 return _callHelper('dynamic'); | 3150 return _callHelper('dynamic'); |
| 3074 } else if (type.isBottom) { | 3151 } else if (type.isBottom) { |
| 3075 return _callHelper('bottom'); | 3152 return _callHelper('bottom'); |
| 3076 } | 3153 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 3106 | 3183 |
| 3107 // TODO(jmesserly): like constants, should we hoist function types out of | 3184 // 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 | 3185 // 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. | 3186 // to canonicalize them too, at least when inside the same library. |
| 3110 var name = type.name; | 3187 var name = type.name; |
| 3111 if (name == '' || name == null || lowerTypedef) { | 3188 if (name == '' || name == null || lowerTypedef) { |
| 3112 // TODO(jmesserly): should we change how typedefs work? They currently | 3189 // TODO(jmesserly): should we change how typedefs work? They currently |
| 3113 // go through use similar logic as generic classes. This makes them | 3190 // go through use similar logic as generic classes. This makes them |
| 3114 // different from universal function types. | 3191 // different from universal function types. |
| 3115 return _emitFunctionType(type as FunctionType, | 3192 return _emitFunctionType(type as FunctionType, |
| 3116 lowerTypedef: lowerTypedef, nameType: nameType, hoistType: hoistType); | 3193 lowerTypedef: lowerTypedef, nameType: nameType); |
| 3117 } | 3194 } |
| 3118 | 3195 |
| 3119 if (type is TypeParameterType) { | 3196 if (type is TypeParameterType) { |
| 3120 _typeParamInConst?.add(type); | 3197 _typeParamInConst?.add(type); |
| 3121 return new JS.Identifier(name); | 3198 return new JS.Identifier(name); |
| 3122 } | 3199 } |
| 3123 | 3200 |
| 3124 if (type == subClass?.type) return className; | 3201 if (type == subClass?.type) return className; |
| 3125 | 3202 |
| 3126 if (type is ParameterizedType) { | 3203 if (type is ParameterizedType) { |
| 3127 var args = type.typeArguments; | 3204 var args = type.typeArguments; |
| 3128 Iterable jsArgs = null; | 3205 Iterable jsArgs = null; |
| 3129 if (args.any((a) => !a.isDynamic)) { | 3206 if (args.any((a) => !a.isDynamic)) { |
| 3130 jsArgs = args.map((x) => _emitType(x, | 3207 jsArgs = args.map((x) => _emitType(x, |
| 3131 nameType: nameType, | 3208 nameType: nameType, subClass: subClass, className: className)); |
| 3132 hoistType: hoistType, | |
| 3133 subClass: subClass, | |
| 3134 className: className)); | |
| 3135 } else if (lowerGeneric || element == subClass) { | 3209 } else if (lowerGeneric || element == subClass) { |
| 3136 jsArgs = []; | 3210 jsArgs = []; |
| 3137 } | 3211 } |
| 3138 if (jsArgs != null) { | 3212 if (jsArgs != null) { |
| 3139 var genericName = _emitTopLevelName(element, suffix: '\$'); | 3213 var genericName = _emitTopLevelName(element, suffix: '\$'); |
| 3140 var typeRep = js.call('#(#)', [genericName, jsArgs]); | 3214 var typeRep = js.call('#(#)', [genericName, jsArgs]); |
| 3141 return nameType | 3215 return nameType ? _typeTable.nameType(type, typeRep) : typeRep; |
| 3142 ? _typeTable.nameType(type, typeRep, hoistType: hoistType) | |
| 3143 : typeRep; | |
| 3144 } | 3216 } |
| 3145 } | 3217 } |
| 3146 | 3218 |
| 3147 return _emitTopLevelNameNoInterop(element); | 3219 return _emitTopLevelNameNoInterop(element); |
| 3148 } | 3220 } |
| 3149 | 3221 |
| 3150 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 3222 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
| 3151 var interop = _emitJSInterop(e); | 3223 var interop = _emitJSInterop(e); |
| 3152 if (interop != null) return interop; | 3224 if (interop != null) return interop; |
| 3153 return _emitTopLevelNameNoInterop(e, suffix: suffix); | 3225 return _emitTopLevelNameNoInterop(e, suffix: suffix); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3191 } | 3263 } |
| 3192 | 3264 |
| 3193 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions | 3265 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions |
| 3194 // (for example, x is IndexExpression) we evaluate those once. | 3266 // (for example, x is IndexExpression) we evaluate those once. |
| 3195 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3267 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
| 3196 var lhs = _bindLeftHandSide(vars, left, context: context); | 3268 var lhs = _bindLeftHandSide(vars, left, context: context); |
| 3197 Expression inc = AstBuilder.binaryExpression(lhs, op, right) | 3269 Expression inc = AstBuilder.binaryExpression(lhs, op, right) |
| 3198 ..staticElement = element | 3270 ..staticElement = element |
| 3199 ..staticType = getStaticType(lhs); | 3271 ..staticType = getStaticType(lhs); |
| 3200 | 3272 |
| 3201 var castTo = getImplicitAssignmentCast(left); | 3273 var castTo = getImplicitOperationCast(left); |
| 3202 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); | 3274 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); |
| 3203 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 3275 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); |
| 3204 } | 3276 } |
| 3205 | 3277 |
| 3206 JS.Expression _emitSet(Expression left, Expression right) { | 3278 JS.Expression _emitSet(Expression left, Expression right) { |
| 3207 if (left is IndexExpression) { | 3279 if (left is IndexExpression) { |
| 3208 var target = _getTarget(left); | 3280 var target = _getTarget(left); |
| 3209 if (_useNativeJsIndexer(target.staticType)) { | 3281 if (_useNativeJsIndexer(target.staticType)) { |
| 3210 return js.call( | 3282 return js.call( |
| 3211 '#[#] = #', [_visit(target), _visit(left.index), _visit(right)]); | 3283 '#[#] = #', [_visit(target), _visit(left.index), _visit(right)]); |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3514 } else { | 3586 } else { |
| 3515 return _callHelper('#(#, #, #)', | 3587 return _callHelper('#(#, #, #)', |
| 3516 [_emitDynamicOperationName('dsend'), jsTarget, memberName, args]); | 3588 [_emitDynamicOperationName('dsend'), jsTarget, memberName, args]); |
| 3517 } | 3589 } |
| 3518 } | 3590 } |
| 3519 if (_isObjectMemberCall(target, name)) { | 3591 if (_isObjectMemberCall(target, name)) { |
| 3520 assert(typeArgs == null); // Object methods don't take type args. | 3592 assert(typeArgs == null); // Object methods don't take type args. |
| 3521 return _callHelper('#(#, #)', [name, jsTarget, args]); | 3593 return _callHelper('#(#, #)', [name, jsTarget, args]); |
| 3522 } | 3594 } |
| 3523 jsTarget = _emitTargetAccess(jsTarget, memberName, element); | 3595 jsTarget = _emitTargetAccess(jsTarget, memberName, element); |
| 3596 var castTo = getImplicitOperationCast(node); | |
| 3597 if (castTo != null) { | |
| 3598 jsTarget = js.call('#._check(#)', [_emitType(castTo), jsTarget]); | |
| 3599 } | |
| 3524 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 3600 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
| 3525 | |
| 3526 return new JS.Call(jsTarget, args); | 3601 return new JS.Call(jsTarget, args); |
| 3527 } | 3602 } |
| 3528 | 3603 |
| 3529 JS.Expression _emitDynamicInvoke( | 3604 JS.Expression _emitDynamicInvoke( |
| 3530 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { | 3605 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { |
| 3531 var typeArgs = _emitInvokeTypeArguments(node); | 3606 var typeArgs = _emitInvokeTypeArguments(node); |
| 3532 if (typeArgs != null) { | 3607 if (typeArgs != null) { |
| 3533 return _callHelper( | 3608 return _callHelper( |
| 3534 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); | 3609 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); |
| 3535 } else { | 3610 } else { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3585 } | 3660 } |
| 3586 var bang = negated ? '!' : ''; | 3661 var bang = negated ? '!' : ''; |
| 3587 return js.call( | 3662 return js.call( |
| 3588 "${bang}#", new JS.Call(_emitTopLevelName(_coreIdentical), args)); | 3663 "${bang}#", new JS.Call(_emitTopLevelName(_coreIdentical), args)); |
| 3589 } | 3664 } |
| 3590 | 3665 |
| 3591 /// Emits a function call, to a top-level function, local function, or | 3666 /// Emits a function call, to a top-level function, local function, or |
| 3592 /// an expression. | 3667 /// an expression. |
| 3593 JS.Expression _emitFunctionCall(InvocationExpression node, | 3668 JS.Expression _emitFunctionCall(InvocationExpression node, |
| 3594 [Expression function]) { | 3669 [Expression function]) { |
| 3595 if (function == null) { | 3670 function ??= node.function; |
| 3596 function = node.function; | 3671 var castTo = getImplicitOperationCast(function); |
| 3672 if (castTo != null) { | |
| 3673 function = CoercionReifier.castExpression(function, castTo); | |
| 3597 } | 3674 } |
| 3598 if (_isCoreIdentical(function)) { | 3675 if (_isCoreIdentical(function)) { |
| 3599 return _emitCoreIdenticalCall(node.argumentList.arguments); | 3676 return _emitCoreIdenticalCall(node.argumentList.arguments); |
| 3600 } | 3677 } |
| 3601 var fn = _visit(function); | 3678 var fn = _visit(function); |
| 3602 var args = _emitArgumentList(node.argumentList); | 3679 var args = _emitArgumentList(node.argumentList); |
| 3603 if (isDynamicInvoke(function)) { | 3680 if (isDynamicInvoke(function)) { |
| 3604 return _emitDynamicInvoke(node, fn, args); | 3681 return _emitDynamicInvoke(node, fn, args); |
| 3605 } | 3682 } |
| 3606 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); | 3683 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); |
| (...skipping 1524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5131 } | 5208 } |
| 5132 | 5209 |
| 5133 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { | 5210 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { |
| 5134 var then = visitCatchClause(clause); | 5211 var then = visitCatchClause(clause); |
| 5135 | 5212 |
| 5136 // Discard following clauses, if any, as they are unreachable. | 5213 // Discard following clauses, if any, as they are unreachable. |
| 5137 if (clause.exceptionType == null) return then; | 5214 if (clause.exceptionType == null) return then; |
| 5138 | 5215 |
| 5139 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which | 5216 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which |
| 5140 // has special case for typeof. | 5217 // has special case for typeof. |
| 5141 var castType = _emitType(clause.exceptionType.type, | 5218 var castType = _emitType(clause.exceptionType.type); |
| 5142 nameType: options.nameTypeTests || options.hoistTypeTests, | |
| 5143 hoistType: options.hoistTypeTests); | |
| 5144 | 5219 |
| 5145 return new JS.If(js.call('#.is(#)', [castType, _visit(_catchParameter)]), | 5220 return new JS.If(js.call('#.is(#)', [castType, _visit(_catchParameter)]), |
| 5146 then, otherwise); | 5221 then, otherwise); |
| 5147 } | 5222 } |
| 5148 | 5223 |
| 5149 JS.Statement _statement(List<JS.Statement> statements) { | 5224 JS.Statement _statement(List<JS.Statement> statements) { |
| 5150 // TODO(jmesserly): empty block singleton? | 5225 // TODO(jmesserly): empty block singleton? |
| 5151 if (statements.length == 0) return new JS.Block([]); | 5226 if (statements.length == 0) return new JS.Block([]); |
| 5152 if (statements.length == 1) return statements[0]; | 5227 if (statements.length == 1) return statements[0]; |
| 5153 return new JS.Block(statements); | 5228 return new JS.Block(statements); |
| (...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5895 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5970 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5896 var prefix = targetIdentifier.staticElement as PrefixElement; | 5971 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5897 | 5972 |
| 5898 // The library the prefix is referring to must come from a deferred import. | 5973 // The library the prefix is referring to must come from a deferred import. |
| 5899 var containingLibrary = resolutionMap | 5974 var containingLibrary = resolutionMap |
| 5900 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5975 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 5901 .library; | 5976 .library; |
| 5902 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5977 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5903 return imports.length == 1 && imports[0].isDeferred; | 5978 return imports.length == 1 && imports[0].isDeferred; |
| 5904 } | 5979 } |
| OLD | NEW |