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