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 |