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 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 _moduleItems.add(js.statement( | 677 _moduleItems.add(js.statement( |
673 '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name])); | 678 '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name])); |
674 } | 679 } |
675 } | 680 } |
676 | 681 |
677 @override | 682 @override |
678 visitAsExpression(AsExpression node) { | 683 visitAsExpression(AsExpression node) { |
679 Expression fromExpr = node.expression; | 684 Expression fromExpr = node.expression; |
680 var from = getStaticType(fromExpr); | 685 var from = getStaticType(fromExpr); |
681 var to = node.type.type; | 686 var to = node.type.type; |
682 | |
683 JS.Expression jsFrom = _visit(fromExpr); | 687 JS.Expression jsFrom = _visit(fromExpr); |
684 | 688 |
685 // Skip the cast if it's not needed. | 689 // If the check was put here by static analysis to ensure soundness, we |
686 if (rules.isSubtypeOf(from, to)) return jsFrom; | 690 // can't skip it. This happens because of unsound covariant generics: |
| 691 // |
| 692 // typedef F<T>(T t); |
| 693 // class C<T> { |
| 694 // F<T> f; |
| 695 // add(T t) { |
| 696 // // required check `t as T` |
| 697 // } |
| 698 // } |
| 699 // main() { |
| 700 // C<Object> c = new C<int>()..f = (int x) => x.isEven; |
| 701 // c.f('hi'); // required check `c.f as F<Object>` |
| 702 // c.add('hi); |
| 703 // } |
| 704 // |
| 705 // NOTE: due to implementation details, we do not currently reify the the |
| 706 // `C<T>.add` check in CoercionReifier, so it does not reach this point; |
| 707 // rather we check for it explicitly when emitting methods and fields. |
| 708 // However we do reify the `c.f` check, so we must not eliminate it. |
| 709 var isRequiredForSoundness = CoercionReifier.isRequiredForSoundness(node); |
| 710 if (!isRequiredForSoundness && rules.isSubtypeOf(from, to)) return jsFrom; |
687 | 711 |
688 // All Dart number types map to a JS double. | 712 // All Dart number types map to a JS double. |
689 if (typeRep.isNumber(from) && typeRep.isNumber(to)) { | 713 if (typeRep.isNumber(from) && typeRep.isNumber(to)) { |
690 // Make sure to check when converting to int. | 714 // Make sure to check when converting to int. |
691 if (from != types.intType && to == types.intType) { | 715 if (from != types.intType && to == types.intType) { |
692 // TODO(jmesserly): fuse this with notNull check. | 716 // TODO(jmesserly): fuse this with notNull check. |
| 717 // TODO(jmesserly): this does not correctly distinguish user casts from |
| 718 // required-for-soundness casts. |
693 return _callHelper('asInt(#)', jsFrom); | 719 return _callHelper('asInt(#)', jsFrom); |
694 } | 720 } |
695 | 721 |
696 // A no-op in JavaScript. | 722 // A no-op in JavaScript. |
697 return jsFrom; | 723 return jsFrom; |
698 } | 724 } |
699 | 725 |
700 var type = _emitType(to, | 726 var code = isRequiredForSoundness ? '#._check(#)' : '#.as(#)'; |
701 nameType: options.nameTypeTests || options.hoistTypeTests, | 727 return js.call(code, [_emitType(to), jsFrom]); |
702 hoistType: options.hoistTypeTests); | |
703 if (CoercionReifier.isImplicitCast(node)) { | |
704 return js.call('#._check(#)', [type, jsFrom]); | |
705 } else { | |
706 return js.call('#.as(#)', [type, jsFrom]); | |
707 } | |
708 } | 728 } |
709 | 729 |
710 @override | 730 @override |
711 visitIsExpression(IsExpression node) { | 731 visitIsExpression(IsExpression node) { |
712 // 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. |
713 JS.Expression result; | 733 JS.Expression result; |
714 var type = node.type.type; | 734 var type = node.type.type; |
715 var lhs = _visit(node.expression); | 735 var lhs = _visit(node.expression); |
716 var typeofName = _jsTypeofName(type); | 736 var typeofName = _jsTypeofName(type); |
717 // Inline primitives other than int (which requires a Math.floor check). | 737 // Inline primitives other than int (which requires a Math.floor check). |
718 if (typeofName != null && type != types.intType) { | 738 if (typeofName != null && type != types.intType) { |
719 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); | 739 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); |
720 } else { | 740 } else { |
721 // Always go through a runtime helper, because implicit interfaces. | 741 // Always go through a runtime helper, because implicit interfaces. |
722 | 742 |
723 var castType = _emitType(type, | 743 var castType = _emitType(type); |
724 nameType: options.nameTypeTests || options.hoistTypeTests, | |
725 hoistType: options.hoistTypeTests); | |
726 | 744 |
727 result = js.call('#.is(#)', [castType, lhs]); | 745 result = js.call('#.is(#)', [castType, lhs]); |
728 } | 746 } |
729 | 747 |
730 if (node.notOperator != null) { | 748 if (node.notOperator != null) { |
731 return js.call('!#', result); | 749 return js.call('!#', result); |
732 } | 750 } |
733 return result; | 751 return result; |
734 } | 752 } |
735 | 753 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 ClassElement classElem = node.element; | 811 ClassElement classElem = node.element; |
794 var supertype = classElem.supertype; | 812 var supertype = classElem.supertype; |
795 | 813 |
796 var typeFormals = classElem.typeParameters; | 814 var typeFormals = classElem.typeParameters; |
797 var isGeneric = typeFormals.isNotEmpty; | 815 var isGeneric = typeFormals.isNotEmpty; |
798 | 816 |
799 // 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. |
800 // The resulting 'class' is a mixable class in this case. | 818 // The resulting 'class' is a mixable class in this case. |
801 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; | 819 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; |
802 | 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); |
803 var classExpr = isMixinAlias | 828 var classExpr = isMixinAlias |
804 ? _emitClassHeritage(classElem) | 829 ? _emitClassHeritage(classElem) |
805 : _emitClassExpression(classElem, []); | 830 : _emitClassExpression(classElem, jsMethods); |
806 var className = isGeneric | 831 var className = isGeneric |
807 ? new JS.Identifier(classElem.name) | 832 ? new JS.Identifier(classElem.name) |
808 : _emitTopLevelName(classElem); | 833 : _emitTopLevelName(classElem); |
809 var block = <JS.Statement>[]; | 834 var block = <JS.Statement>[]; |
810 | 835 |
811 if (isGeneric) { | 836 if (isGeneric) { |
812 if (isMixinAlias) { | 837 if (isMixinAlias) { |
813 block.add(js.statement('const # = #;', [className, classExpr])); | 838 block.add(js.statement('const # = #;', [className, classExpr])); |
814 } else { | 839 } else { |
815 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... |
879 JS.Expression className; | 904 JS.Expression className; |
880 if (classElem.typeParameters.isNotEmpty) { | 905 if (classElem.typeParameters.isNotEmpty) { |
881 // 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 |
882 // type parameter. So we can use their local variable name directly. | 907 // type parameter. So we can use their local variable name directly. |
883 className = new JS.Identifier(classElem.name); | 908 className = new JS.Identifier(classElem.name); |
884 } else { | 909 } else { |
885 className = _emitTopLevelName(classElem); | 910 className = _emitTopLevelName(classElem); |
886 } | 911 } |
887 | 912 |
888 var savedClassProperties = _classProperties; | 913 var savedClassProperties = _classProperties; |
889 _classProperties = | 914 _classProperties = new ClassPropertyModel.build( |
890 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); | 915 _extensionTypes, |
| 916 virtualFields, |
| 917 classElem, |
| 918 getClassCovariantParameters(node), |
| 919 _usedCovariantPrivateMembers); |
891 | 920 |
892 var jsCtors = _defineConstructors(classElem, className, fields, ctors); | 921 var jsCtors = _defineConstructors(classElem, className, fields, ctors); |
893 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), | 922 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), |
894 fields: allFields); | 923 fields: allFields); |
895 | 924 |
896 var body = <JS.Statement>[]; | 925 var body = <JS.Statement>[]; |
897 _initExtensionSymbols(classElem, methods, fields, body); | 926 _initExtensionSymbols(classElem, methods, fields, body); |
898 _emitSuperHelperSymbols(body); | 927 _emitSuperHelperSymbols(body); |
899 | 928 |
900 // 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... |
1416 // (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` |
1417 // 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 |
1418 // 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.) |
1419 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 1448 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
1420 jsMethods.add(_emitIterable(type)); | 1449 jsMethods.add(_emitIterable(type)); |
1421 } | 1450 } |
1422 | 1451 |
1423 // Add all of the super helper methods | 1452 // Add all of the super helper methods |
1424 jsMethods.addAll(_superHelpers.values); | 1453 jsMethods.addAll(_superHelpers.values); |
1425 | 1454 |
| 1455 _emitSuperclassCovarianceChecks(node, jsMethods); |
1426 return jsMethods.where((m) => m != null).toList(growable: false); | 1456 return jsMethods.where((m) => m != null).toList(growable: false); |
1427 } | 1457 } |
1428 | 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 |
1429 /// Emits a Dart factory constructor to a JS static method. | 1537 /// Emits a Dart factory constructor to a JS static method. |
1430 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { | 1538 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { |
1431 var element = node.element; | 1539 var element = node.element; |
1432 var returnType = emitTypeRef(element.returnType); | 1540 var returnType = emitTypeRef(element.returnType); |
1433 var name = _constructorName(element); | 1541 var name = _constructorName(element); |
1434 JS.Fun fun; | 1542 JS.Fun fun; |
1435 | 1543 |
1436 var redirect = node.redirectedConstructor; | 1544 var redirect = node.redirectedConstructor; |
1437 if (redirect != null) { | 1545 if (redirect != null) { |
1438 // 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... |
1559 if (!mocks.containsKey(element.name)) { | 1667 if (!mocks.containsKey(element.name)) { |
1560 var getter = js.call('function() { return this[#]; }', [virtualField]); | 1668 var getter = js.call('function() { return this[#]; }', [virtualField]); |
1561 result.add(new JS.Method(name, getter, isGetter: true)); | 1669 result.add(new JS.Method(name, getter, isGetter: true)); |
1562 } | 1670 } |
1563 | 1671 |
1564 if (!mocks.containsKey(element.name + '=')) { | 1672 if (!mocks.containsKey(element.name + '=')) { |
1565 var args = field.isFinal | 1673 var args = field.isFinal |
1566 ? [new JS.Super(), name] | 1674 ? [new JS.Super(), name] |
1567 : [new JS.This(), virtualField]; | 1675 : [new JS.This(), virtualField]; |
1568 | 1676 |
1569 result.add(new JS.Method( | 1677 String jsCode; |
1570 name, js.call('function(value) { #[#] = value; }', args), | 1678 var setter = element.setter; |
1571 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)); |
1572 } | 1690 } |
1573 | 1691 |
1574 return result; | 1692 return result; |
1575 } | 1693 } |
1576 | 1694 |
1577 /// 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 |
1578 /// 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 |
1579 /// (alternatively, a setter), then there is an implicit override of the | 1697 /// (alternatively, a setter), then there is an implicit override of the |
1580 /// setter (alternatively, the getter) that does nothing. | 1698 /// setter (alternatively, the getter) that does nothing. |
1581 JS.Method _emitSuperAccessorWrapper( | 1699 JS.Method _emitSuperAccessorWrapper( |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1920 // overriding has a different reified type from ourselves, we must | 2038 // overriding has a different reified type from ourselves, we must |
1921 // emit a signature on this class. Otherwise we will inherit the | 2039 // emit a signature on this class. Otherwise we will inherit the |
1922 // signature from the superclass. | 2040 // signature from the superclass. |
1923 var needsSignature = getOverride(name, currentLibrary) == null || | 2041 var needsSignature = getOverride(name, currentLibrary) == null || |
1924 elementToType( | 2042 elementToType( |
1925 lookup(name, library: currentLibrary, thisType: false)) != | 2043 lookup(name, library: currentLibrary, thisType: false)) != |
1926 reifiedType; | 2044 reifiedType; |
1927 | 2045 |
1928 var type = _emitAnnotatedFunctionType(reifiedType, node.metadata, | 2046 var type = _emitAnnotatedFunctionType(reifiedType, node.metadata, |
1929 parameters: node.parameters?.parameters, | 2047 parameters: node.parameters?.parameters, |
1930 nameType: options.hoistSignatureTypes, | 2048 nameType: false, |
1931 hoistType: options.hoistSignatureTypes, | |
1932 definite: true); | 2049 definite: true); |
1933 | 2050 |
1934 if (needsSignature) { | 2051 if (needsSignature) { |
1935 var memberName = _declareMemberName(element); | 2052 var memberName = _declareMemberName(element); |
1936 var property = new JS.Property(memberName, type); | 2053 var property = new JS.Property(memberName, type); |
1937 tMember.add(property); | 2054 tMember.add(property); |
1938 // We record the names of static methods separately so we can | 2055 // We record the names of static methods separately so we can |
1939 // attach metadata to them individually. | 2056 // attach metadata to them individually. |
1940 // TODO(leafp): Revisit this. | 2057 // TODO(leafp): Revisit this. |
1941 if (node.isStatic && !node.isGetter && !node.isSetter) { | 2058 if (node.isStatic && !node.isGetter && !node.isSetter) { |
(...skipping 20 matching lines...) Expand all Loading... |
1962 } | 2079 } |
1963 } | 2080 } |
1964 | 2081 |
1965 var tCtors = <JS.Property>[]; | 2082 var tCtors = <JS.Property>[]; |
1966 if (options.emitMetadata) { | 2083 if (options.emitMetadata) { |
1967 for (ConstructorDeclaration node in ctors) { | 2084 for (ConstructorDeclaration node in ctors) { |
1968 var element = node.element; | 2085 var element = node.element; |
1969 var memberName = _constructorName(element); | 2086 var memberName = _constructorName(element); |
1970 var type = _emitAnnotatedFunctionType(element.type, node.metadata, | 2087 var type = _emitAnnotatedFunctionType(element.type, node.metadata, |
1971 parameters: node.parameters.parameters, | 2088 parameters: node.parameters.parameters, |
1972 nameType: options.hoistSignatureTypes, | 2089 nameType: false, |
1973 hoistType: options.hoistSignatureTypes, | |
1974 definite: true); | 2090 definite: true); |
1975 var property = new JS.Property(memberName, type); | 2091 var property = new JS.Property(memberName, type); |
1976 tCtors.add(property); | 2092 tCtors.add(property); |
1977 } | 2093 } |
1978 } | 2094 } |
1979 var sigFields = <JS.Property>[]; | 2095 var sigFields = <JS.Property>[]; |
1980 _buildSignatureField(sigFields, 'constructors', tCtors); | 2096 _buildSignatureField(sigFields, 'constructors', tCtors); |
1981 _buildSignatureField(sigFields, 'fields', tInstanceFields); | 2097 _buildSignatureField(sigFields, 'fields', tInstanceFields); |
1982 _buildSignatureField(sigFields, 'getters', tInstanceGetters); | 2098 _buildSignatureField(sigFields, 'getters', tInstanceGetters); |
1983 _buildSignatureField(sigFields, 'setters', tInstanceSetters); | 2099 _buildSignatureField(sigFields, 'setters', tInstanceSetters); |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2264 /// Emits argument initializers, which handles optional/named args, as well | 2380 /// Emits argument initializers, which handles optional/named args, as well |
2265 /// as generic type checks needed due to our covariance. | 2381 /// as generic type checks needed due to our covariance. |
2266 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { | 2382 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { |
2267 // Constructor argument initializers are emitted earlier in the code, rather | 2383 // Constructor argument initializers are emitted earlier in the code, rather |
2268 // than always when we visit the function body, so we control it explicitly. | 2384 // than always when we visit the function body, so we control it explicitly. |
2269 if (node is ConstructorDeclaration != constructor) return null; | 2385 if (node is ConstructorDeclaration != constructor) return null; |
2270 | 2386 |
2271 var parameters = _parametersOf(node); | 2387 var parameters = _parametersOf(node); |
2272 if (parameters == null) return null; | 2388 if (parameters == null) return null; |
2273 | 2389 |
| 2390 var covariantParams = _classProperties?.covariantParameters; |
| 2391 |
2274 var body = <JS.Statement>[]; | 2392 var body = <JS.Statement>[]; |
2275 for (var param in parameters.parameters) { | 2393 for (var param in parameters.parameters) { |
2276 var jsParam = _emitSimpleIdentifier(param.identifier); | 2394 var jsParam = _emitSimpleIdentifier(param.identifier); |
2277 | 2395 |
2278 if (!options.destructureNamedParams) { | 2396 if (!options.destructureNamedParams) { |
2279 if (param.kind == ParameterKind.NAMED) { | 2397 if (param.kind == ParameterKind.NAMED) { |
2280 // Parameters will be passed using their real names, not the (possibly | 2398 // Parameters will be passed using their real names, not the (possibly |
2281 // renamed) local variable. | 2399 // renamed) local variable. |
2282 var paramName = js.string(param.identifier.name, "'"); | 2400 var paramName = js.string(param.identifier.name, "'"); |
2283 | 2401 |
2284 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. | 2402 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. |
2285 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 2403 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
2286 jsParam, | 2404 jsParam, |
2287 namedArgumentTemp, | 2405 namedArgumentTemp, |
2288 paramName, | 2406 paramName, |
2289 namedArgumentTemp, | 2407 namedArgumentTemp, |
2290 namedArgumentTemp, | 2408 namedArgumentTemp, |
2291 paramName, | 2409 paramName, |
2292 _defaultParamValue(param), | 2410 _defaultParamValue(param), |
2293 ])); | 2411 ])); |
2294 } else if (param.kind == ParameterKind.POSITIONAL) { | 2412 } else if (param.kind == ParameterKind.POSITIONAL) { |
2295 body.add(js.statement('if (# === void 0) # = #;', | 2413 body.add(js.statement('if (# === void 0) # = #;', |
2296 [jsParam, jsParam, _defaultParamValue(param)])); | 2414 [jsParam, jsParam, _defaultParamValue(param)])); |
2297 } | 2415 } |
2298 } | 2416 } |
2299 | 2417 |
2300 // TODO(jmesserly): various problems here, see: | 2418 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); |
2301 // https://github.com/dart-lang/sdk/issues/27259 | 2419 if (paramElement.isCovariant || |
2302 var paramType = | 2420 covariantParams != null && covariantParams.contains(paramElement)) { |
2303 resolutionMap.elementDeclaredByFormalParameter(param).type; | 2421 var castType = _emitType(paramElement.type); |
2304 if (node is MethodDeclaration && | |
2305 (resolutionMap.elementDeclaredByFormalParameter(param).isCovariant || | |
2306 _unsoundCovariant(paramType, true))) { | |
2307 var castType = _emitType(paramType, | |
2308 nameType: options.nameTypeTests || options.hoistTypeTests, | |
2309 hoistType: options.hoistTypeTests); | |
2310 body.add(js.statement('#._check(#);', [castType, jsParam])); | 2422 body.add(js.statement('#._check(#);', [castType, jsParam])); |
2311 } | 2423 } |
2312 } | 2424 } |
2313 return body.isEmpty ? null : _statement(body); | 2425 return body.isEmpty ? null : _statement(body); |
2314 } | 2426 } |
2315 | 2427 |
2316 /// Given a type [t], return whether or not t is unsoundly covariant. | |
2317 /// If [contravariant] is true, then t appears in a contravariant | |
2318 /// position. | |
2319 bool _unsoundCovariant(DartType t, bool contravariant) { | |
2320 if (t is TypeParameterType) { | |
2321 return contravariant && t.element.enclosingElement is ClassElement; | |
2322 } | |
2323 if (t is FunctionType) { | |
2324 if (_unsoundCovariant(t.returnType, contravariant)) return true; | |
2325 return t.parameters.any((p) => _unsoundCovariant(p.type, !contravariant)); | |
2326 } | |
2327 if (t is ParameterizedType) { | |
2328 return t.typeArguments.any((t) => _unsoundCovariant(t, contravariant)); | |
2329 } | |
2330 return false; | |
2331 } | |
2332 | |
2333 JS.Expression _defaultParamValue(FormalParameter param) { | 2428 JS.Expression _defaultParamValue(FormalParameter param) { |
2334 if (param is DefaultFormalParameter && param.defaultValue != null) { | 2429 if (param is DefaultFormalParameter && param.defaultValue != null) { |
2335 return _visit(param.defaultValue); | 2430 return _visit(param.defaultValue); |
2336 } else { | 2431 } else { |
2337 return new JS.LiteralNull(); | 2432 return new JS.LiteralNull(); |
2338 } | 2433 } |
2339 } | 2434 } |
2340 | 2435 |
2341 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { | 2436 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { |
2342 String name = | 2437 String name = |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2593 FunctionType type = element.type; | 2688 FunctionType type = element.type; |
2594 | 2689 |
2595 // normal function (sync), vs (sync*, async, async*) | 2690 // normal function (sync), vs (sync*, async, async*) |
2596 var stdFn = !(element.isAsynchronous || element.isGenerator); | 2691 var stdFn = !(element.isAsynchronous || element.isGenerator); |
2597 var formals = _emitFormalParameterList(parameters, destructure: stdFn); | 2692 var formals = _emitFormalParameterList(parameters, destructure: stdFn); |
2598 JS.Block code = stdFn | 2693 JS.Block code = stdFn |
2599 ? _visit(body) | 2694 ? _visit(body) |
2600 : new JS.Block( | 2695 : new JS.Block( |
2601 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); | 2696 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); |
2602 var typeFormals = _emitTypeFormals(type.typeFormals); | 2697 var typeFormals = _emitTypeFormals(type.typeFormals); |
| 2698 |
2603 var returnType = emitTypeRef(type.returnType); | 2699 var returnType = emitTypeRef(type.returnType); |
2604 if (type.typeFormals.isNotEmpty) { | 2700 if (type.typeFormals.isNotEmpty) { |
2605 code = new JS.Block( | 2701 var block = <JS.Statement>[ |
2606 [new JS.Block(_typeTable.discharge(type.typeFormals)), code]); | 2702 new JS.Block(_typeTable.discharge(type.typeFormals)) |
| 2703 ]; |
| 2704 |
| 2705 var covariantParams = _classProperties?.covariantParameters; |
| 2706 if (covariantParams != null && |
| 2707 type.typeFormals.any(covariantParams.contains)) { |
| 2708 block.add(js.statement('#.checkBounds(#);', |
| 2709 [_emitType(type), new JS.ArrayInitializer(typeFormals)])); |
| 2710 } |
| 2711 |
| 2712 code = new JS.Block(block..add(code)); |
2607 } | 2713 } |
2608 | 2714 |
2609 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { | 2715 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { |
2610 // []= methods need to return the value. We could also address this at | 2716 // []= methods need to return the value. We could also address this at |
2611 // call sites, but it's cleaner to instead transform the operator method. | 2717 // call sites, but it's cleaner to instead transform the operator method. |
2612 code = _alwaysReturnLastParameter(code, formals.last); | 2718 code = _alwaysReturnLastParameter(code, formals.last); |
2613 } | 2719 } |
2614 | 2720 |
2615 if (body is BlockFunctionBody) { | 2721 if (body is BlockFunctionBody) { |
2616 var params = element.parameters.map((e) => e.name).toSet(); | 2722 var params = element.parameters.map((e) => e.name).toSet(); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2854 JS.Expression _emitAnnotatedResult( | 2960 JS.Expression _emitAnnotatedResult( |
2855 JS.Expression result, List<Annotation> metadata) { | 2961 JS.Expression result, List<Annotation> metadata) { |
2856 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { | 2962 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { |
2857 result = new JS.ArrayInitializer( | 2963 result = new JS.ArrayInitializer( |
2858 [result]..addAll(metadata.map(_instantiateAnnotation))); | 2964 [result]..addAll(metadata.map(_instantiateAnnotation))); |
2859 } | 2965 } |
2860 return result; | 2966 return result; |
2861 } | 2967 } |
2862 | 2968 |
2863 JS.Expression _emitAnnotatedType(DartType type, List<Annotation> metadata, | 2969 JS.Expression _emitAnnotatedType(DartType type, List<Annotation> metadata, |
2864 {bool nameType: true, bool hoistType: true}) { | 2970 {bool nameType: true}) { |
2865 metadata ??= []; | 2971 metadata ??= []; |
2866 var typeName = _emitType(type, nameType: nameType, hoistType: hoistType); | 2972 var typeName = _emitType(type, nameType: nameType); |
2867 return _emitAnnotatedResult(typeName, metadata); | 2973 return _emitAnnotatedResult(typeName, metadata); |
2868 } | 2974 } |
2869 | 2975 |
2870 JS.Expression _emitFieldSignature(DartType type, | 2976 JS.Expression _emitFieldSignature(DartType type, |
2871 {List<Annotation> metadata, bool isFinal: true}) { | 2977 {List<Annotation> metadata, bool isFinal: true}) { |
2872 var args = [_emitType(type)]; | 2978 var args = [_emitType(type)]; |
2873 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { | 2979 if (options.emitMetadata && metadata != null && metadata.isNotEmpty) { |
2874 args.add(new JS.ArrayInitializer( | 2980 args.add(new JS.ArrayInitializer( |
2875 metadata.map(_instantiateAnnotation).toList())); | 2981 metadata.map(_instantiateAnnotation).toList())); |
2876 } | 2982 } |
2877 return _callHelper(isFinal ? 'finalFieldType(#)' : 'fieldType(#)', [args]); | 2983 return _callHelper(isFinal ? 'finalFieldType(#)' : 'fieldType(#)', [args]); |
2878 } | 2984 } |
2879 | 2985 |
2880 JS.ArrayInitializer _emitTypeNames( | 2986 JS.ArrayInitializer _emitTypeNames( |
2881 List<DartType> types, List<FormalParameter> parameters, | 2987 List<DartType> types, List<FormalParameter> parameters, |
2882 {bool nameType: true, bool hoistType: true}) { | 2988 {bool nameType: true}) { |
2883 var result = <JS.Expression>[]; | 2989 var result = <JS.Expression>[]; |
2884 for (int i = 0; i < types.length; ++i) { | 2990 for (int i = 0; i < types.length; ++i) { |
2885 var metadata = parameters != null | 2991 var metadata = parameters != null |
2886 ? _parameterMetadata(parameters[i]) | 2992 ? _parameterMetadata(parameters[i]) |
2887 : <Annotation>[]; | 2993 : <Annotation>[]; |
2888 result.add(_emitAnnotatedType(types[i], metadata)); | 2994 result.add(_emitAnnotatedType(types[i], metadata)); |
2889 } | 2995 } |
2890 return new JS.ArrayInitializer(result); | 2996 return new JS.ArrayInitializer(result); |
2891 } | 2997 } |
2892 | 2998 |
2893 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 2999 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
2894 var properties = <JS.Property>[]; | 3000 var properties = <JS.Property>[]; |
2895 types.forEach((name, type) { | 3001 types.forEach((name, type) { |
2896 var key = _propertyName(name); | 3002 var key = _propertyName(name); |
2897 var value = _emitType(type); | 3003 var value = _emitType(type); |
2898 properties.add(new JS.Property(key, value)); | 3004 properties.add(new JS.Property(key, value)); |
2899 }); | 3005 }); |
2900 return new JS.ObjectInitializer(properties); | 3006 return new JS.ObjectInitializer(properties); |
2901 } | 3007 } |
2902 | 3008 |
2903 /// Emit the pieces of a function type, as an array of return type, | 3009 /// Emit the pieces of a function type, as an array of return type, |
2904 /// regular args, and optional/named args. | 3010 /// regular args, and optional/named args. |
2905 JS.Expression _emitFunctionType(FunctionType type, | 3011 JS.Expression _emitFunctionType(FunctionType type, |
2906 {List<FormalParameter> parameters, | 3012 {List<FormalParameter> parameters, |
2907 bool lowerTypedef: false, | 3013 bool lowerTypedef: false, |
2908 bool nameType: true, | 3014 bool nameType: true, |
2909 bool hoistType: true, | |
2910 definite: false}) { | 3015 definite: false}) { |
2911 var parameterTypes = type.normalParameterTypes; | 3016 var parameterTypes = type.normalParameterTypes; |
2912 var optionalTypes = type.optionalParameterTypes; | 3017 var optionalTypes = type.optionalParameterTypes; |
2913 var namedTypes = type.namedParameterTypes; | 3018 var namedTypes = type.namedParameterTypes; |
2914 var rt = | 3019 var rt = _emitType(type.returnType, nameType: nameType); |
2915 _emitType(type.returnType, nameType: nameType, hoistType: hoistType); | |
2916 | 3020 |
2917 var ra = _emitTypeNames(parameterTypes, parameters, | 3021 var ra = _emitTypeNames(parameterTypes, parameters, nameType: nameType); |
2918 nameType: nameType, hoistType: hoistType); | |
2919 | 3022 |
2920 List<JS.Expression> typeParts; | 3023 List<JS.Expression> typeParts; |
2921 if (namedTypes.isNotEmpty) { | 3024 if (namedTypes.isNotEmpty) { |
2922 assert(optionalTypes.isEmpty); | 3025 assert(optionalTypes.isEmpty); |
2923 // TODO(vsm): Pass in annotations here as well. | 3026 // TODO(vsm): Pass in annotations here as well. |
2924 var na = _emitTypeProperties(namedTypes); | 3027 var na = _emitTypeProperties(namedTypes); |
2925 typeParts = [rt, ra, na]; | 3028 typeParts = [rt, ra, na]; |
2926 } else if (optionalTypes.isNotEmpty) { | 3029 } else if (optionalTypes.isNotEmpty) { |
2927 assert(namedTypes.isEmpty); | 3030 assert(namedTypes.isEmpty); |
2928 var oa = _emitTypeNames( | 3031 var oa = _emitTypeNames( |
2929 optionalTypes, parameters?.sublist(parameterTypes.length), | 3032 optionalTypes, parameters?.sublist(parameterTypes.length), |
2930 nameType: nameType, hoistType: hoistType); | 3033 nameType: nameType); |
2931 typeParts = [rt, ra, oa]; | 3034 typeParts = [rt, ra, oa]; |
2932 } else { | 3035 } else { |
2933 typeParts = [rt, ra]; | 3036 typeParts = [rt, ra]; |
2934 } | 3037 } |
2935 | 3038 |
2936 JS.Expression fullType; | 3039 JS.Expression fullType; |
2937 var typeFormals = type.typeFormals; | 3040 var typeFormals = type.typeFormals; |
2938 String helperCall; | 3041 String helperCall; |
2939 if (typeFormals.isNotEmpty) { | 3042 if (typeFormals.isNotEmpty) { |
2940 var tf = _emitTypeFormals(typeFormals); | 3043 var tf = _emitTypeFormals(typeFormals); |
(...skipping 12 matching lines...) Expand all Loading... |
2953 // If any explicit bounds were passed, emit them. | 3056 // If any explicit bounds were passed, emit them. |
2954 if (typeFormals.any((t) => t.bound != null)) { | 3057 if (typeFormals.any((t) => t.bound != null)) { |
2955 var bounds = typeFormals.map((t) => _emitType(t.type.bound)).toList(); | 3058 var bounds = typeFormals.map((t) => _emitType(t.type.bound)).toList(); |
2956 typeParts.add(addTypeFormalsAsParameters(bounds)); | 3059 typeParts.add(addTypeFormalsAsParameters(bounds)); |
2957 } | 3060 } |
2958 } else { | 3061 } else { |
2959 helperCall = definite ? 'fnType(#)' : 'fnTypeFuzzy(#)'; | 3062 helperCall = definite ? 'fnType(#)' : 'fnTypeFuzzy(#)'; |
2960 } | 3063 } |
2961 fullType = _callHelper(helperCall, [typeParts]); | 3064 fullType = _callHelper(helperCall, [typeParts]); |
2962 if (!nameType) return fullType; | 3065 if (!nameType) return fullType; |
2963 return _typeTable.nameType(type, fullType, | 3066 return _typeTable.nameType(type, fullType, definite: definite); |
2964 hoistType: hoistType, definite: definite); | |
2965 } | 3067 } |
2966 | 3068 |
2967 JS.Expression _emitAnnotatedFunctionType( | 3069 JS.Expression _emitAnnotatedFunctionType( |
2968 FunctionType type, List<Annotation> metadata, | 3070 FunctionType type, List<Annotation> metadata, |
2969 {List<FormalParameter> parameters, | 3071 {List<FormalParameter> parameters, |
2970 bool lowerTypedef: false, | 3072 bool lowerTypedef: false, |
2971 bool nameType: true, | 3073 bool nameType: true, |
2972 bool hoistType: true, | |
2973 bool definite: false}) { | 3074 bool definite: false}) { |
2974 var result = _emitFunctionType(type, | 3075 var result = _emitFunctionType(type, |
2975 parameters: parameters, | 3076 parameters: parameters, |
2976 lowerTypedef: lowerTypedef, | 3077 lowerTypedef: lowerTypedef, |
2977 nameType: nameType, | 3078 nameType: nameType, |
2978 hoistType: hoistType, | |
2979 definite: definite); | 3079 definite: definite); |
2980 return _emitAnnotatedResult(result, metadata); | 3080 return _emitAnnotatedResult(result, metadata); |
2981 } | 3081 } |
2982 | 3082 |
2983 /// Emits an expression that lets you access statics on a [type] from code. | 3083 /// Emits an expression that lets you access statics on a [type] from code. |
2984 /// | 3084 /// |
2985 /// If [nameType] is true, then the type will be named. In addition, | 3085 /// If [nameType] is true, then the type will be named. In addition, |
2986 /// if [hoistType] is true, then the named type will be hoisted. | 3086 /// if [hoistType] is true, then the named type will be hoisted. |
2987 JS.Expression _emitConstructorAccess(DartType type, | 3087 JS.Expression _emitConstructorAccess(DartType type, {bool nameType: true}) { |
2988 {bool nameType: true, bool hoistType: true}) { | 3088 return _emitJSInterop(type.element) ?? _emitType(type, nameType: nameType); |
2989 return _emitJSInterop(type.element) ?? | |
2990 _emitType(type, nameType: nameType, hoistType: hoistType); | |
2991 } | 3089 } |
2992 | 3090 |
2993 /// Emits an expression that lets you access statics on a [type] from code. | 3091 /// Emits an expression that lets you access statics on a [type] from code. |
2994 JS.Expression _emitStaticAccess(DartType type) { | 3092 JS.Expression _emitStaticAccess(DartType type) { |
2995 // Make sure we aren't attempting to emit a static access path to a type | 3093 // Make sure we aren't attempting to emit a static access path to a type |
2996 // that does not have a valid static access path. | 3094 // that does not have a valid static access path. |
2997 assert(!type.isVoid && | 3095 assert(!type.isVoid && |
2998 !type.isDynamic && | 3096 !type.isDynamic && |
2999 !type.isBottom && | 3097 !type.isBottom && |
3000 type is! TypeParameterType); | 3098 type is! TypeParameterType); |
(...skipping 23 matching lines...) Expand all Loading... |
3024 /// If [subClass] is set, then we are setting the base class for the given | 3122 /// If [subClass] is set, then we are setting the base class for the given |
3025 /// class and should emit the given [className], which will already be | 3123 /// class and should emit the given [className], which will already be |
3026 /// defined. | 3124 /// defined. |
3027 /// | 3125 /// |
3028 /// If [nameType] is true, then the type will be named. In addition, | 3126 /// If [nameType] is true, then the type will be named. In addition, |
3029 /// if [hoistType] is true, then the named type will be hoisted. | 3127 /// if [hoistType] is true, then the named type will be hoisted. |
3030 JS.Expression _emitType(DartType type, | 3128 JS.Expression _emitType(DartType type, |
3031 {bool lowerTypedef: false, | 3129 {bool lowerTypedef: false, |
3032 bool lowerGeneric: false, | 3130 bool lowerGeneric: false, |
3033 bool nameType: true, | 3131 bool nameType: true, |
3034 bool hoistType: true, | |
3035 ClassElement subClass, | 3132 ClassElement subClass, |
3036 JS.Expression className}) { | 3133 JS.Expression className}) { |
3037 // The void and dynamic types are not defined in core. | 3134 // The void and dynamic types are not defined in core. |
3038 if (type.isVoid) { | 3135 if (type.isVoid) { |
3039 return _callHelper('void'); | 3136 return _callHelper('void'); |
3040 } else if (type.isDynamic) { | 3137 } else if (type.isDynamic) { |
3041 return _callHelper('dynamic'); | 3138 return _callHelper('dynamic'); |
3042 } else if (type.isBottom) { | 3139 } else if (type.isBottom) { |
3043 return _callHelper('bottom'); | 3140 return _callHelper('bottom'); |
3044 } | 3141 } |
(...skipping 27 matching lines...) Expand all Loading... |
3072 | 3169 |
3073 // TODO(jmesserly): like constants, should we hoist function types out of | 3170 // TODO(jmesserly): like constants, should we hoist function types out of |
3074 // methods? Similar issue with generic types. For all of these, we may want | 3171 // methods? Similar issue with generic types. For all of these, we may want |
3075 // to canonicalize them too, at least when inside the same library. | 3172 // to canonicalize them too, at least when inside the same library. |
3076 var name = type.name; | 3173 var name = type.name; |
3077 if (name == '' || name == null || lowerTypedef) { | 3174 if (name == '' || name == null || lowerTypedef) { |
3078 // TODO(jmesserly): should we change how typedefs work? They currently | 3175 // TODO(jmesserly): should we change how typedefs work? They currently |
3079 // go through use similar logic as generic classes. This makes them | 3176 // go through use similar logic as generic classes. This makes them |
3080 // different from universal function types. | 3177 // different from universal function types. |
3081 return _emitFunctionType(type as FunctionType, | 3178 return _emitFunctionType(type as FunctionType, |
3082 lowerTypedef: lowerTypedef, nameType: nameType, hoistType: hoistType); | 3179 lowerTypedef: lowerTypedef, nameType: nameType); |
3083 } | 3180 } |
3084 | 3181 |
3085 if (type is TypeParameterType) { | 3182 if (type is TypeParameterType) { |
3086 _typeParamInConst?.add(type); | 3183 _typeParamInConst?.add(type); |
3087 return new JS.Identifier(name); | 3184 return new JS.Identifier(name); |
3088 } | 3185 } |
3089 | 3186 |
3090 if (type == subClass?.type) return className; | 3187 if (type == subClass?.type) return className; |
3091 | 3188 |
3092 if (type is ParameterizedType) { | 3189 if (type is ParameterizedType) { |
3093 var args = type.typeArguments; | 3190 var args = type.typeArguments; |
3094 Iterable jsArgs = null; | 3191 Iterable jsArgs = null; |
3095 if (args.any((a) => !a.isDynamic)) { | 3192 if (args.any((a) => !a.isDynamic)) { |
3096 jsArgs = args.map((x) => _emitType(x, | 3193 jsArgs = args.map((x) => _emitType(x, |
3097 nameType: nameType, | 3194 nameType: nameType, subClass: subClass, className: className)); |
3098 hoistType: hoistType, | |
3099 subClass: subClass, | |
3100 className: className)); | |
3101 } else if (lowerGeneric || element == subClass) { | 3195 } else if (lowerGeneric || element == subClass) { |
3102 jsArgs = []; | 3196 jsArgs = []; |
3103 } | 3197 } |
3104 if (jsArgs != null) { | 3198 if (jsArgs != null) { |
3105 var genericName = _emitTopLevelNameNoInterop(element, suffix: '\$'); | 3199 var genericName = _emitTopLevelNameNoInterop(element, suffix: '\$'); |
3106 var typeRep = js.call('#(#)', [genericName, jsArgs]); | 3200 var typeRep = js.call('#(#)', [genericName, jsArgs]); |
3107 return nameType | 3201 return nameType ? _typeTable.nameType(type, typeRep) : typeRep; |
3108 ? _typeTable.nameType(type, typeRep, hoistType: hoistType) | |
3109 : typeRep; | |
3110 } | 3202 } |
3111 } | 3203 } |
3112 | 3204 |
3113 return _emitTopLevelNameNoInterop(element); | 3205 return _emitTopLevelNameNoInterop(element); |
3114 } | 3206 } |
3115 | 3207 |
3116 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 3208 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
3117 return _emitJSInterop(e) ?? _emitTopLevelNameNoInterop(e, suffix: suffix); | 3209 return _emitJSInterop(e) ?? _emitTopLevelNameNoInterop(e, suffix: suffix); |
3118 } | 3210 } |
3119 | 3211 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3155 } | 3247 } |
3156 | 3248 |
3157 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions | 3249 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions |
3158 // (for example, x is IndexExpression) we evaluate those once. | 3250 // (for example, x is IndexExpression) we evaluate those once. |
3159 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3251 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
3160 var lhs = _bindLeftHandSide(vars, left, context: context); | 3252 var lhs = _bindLeftHandSide(vars, left, context: context); |
3161 Expression inc = AstBuilder.binaryExpression(lhs, op, right) | 3253 Expression inc = AstBuilder.binaryExpression(lhs, op, right) |
3162 ..staticElement = element | 3254 ..staticElement = element |
3163 ..staticType = getStaticType(lhs); | 3255 ..staticType = getStaticType(lhs); |
3164 | 3256 |
3165 var castTo = getImplicitAssignmentCast(left); | 3257 var castTo = getImplicitOperationCast(left); |
3166 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); | 3258 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); |
3167 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 3259 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); |
3168 } | 3260 } |
3169 | 3261 |
3170 JS.Expression _emitSet(Expression left, Expression right) { | 3262 JS.Expression _emitSet(Expression left, Expression right) { |
3171 if (left is IndexExpression) { | 3263 if (left is IndexExpression) { |
3172 var target = _getTarget(left); | 3264 var target = _getTarget(left); |
3173 if (_useNativeJsIndexer(target.staticType)) { | 3265 if (_useNativeJsIndexer(target.staticType)) { |
3174 return js.call( | 3266 return js.call( |
3175 '#[#] = #', [_visit(target), _visit(left.index), _visit(right)]); | 3267 '#[#] = #', [_visit(target), _visit(left.index), _visit(right)]); |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3476 } else { | 3568 } else { |
3477 return _callHelper('#(#, #, #)', | 3569 return _callHelper('#(#, #, #)', |
3478 [_emitDynamicOperationName('dsend'), jsTarget, jsName, args]); | 3570 [_emitDynamicOperationName('dsend'), jsTarget, jsName, args]); |
3479 } | 3571 } |
3480 } | 3572 } |
3481 if (_isObjectMemberCall(target, name)) { | 3573 if (_isObjectMemberCall(target, name)) { |
3482 assert(typeArgs == null); // Object methods don't take type args. | 3574 assert(typeArgs == null); // Object methods don't take type args. |
3483 return _callHelper('#(#, #)', [name, jsTarget, args]); | 3575 return _callHelper('#(#, #)', [name, jsTarget, args]); |
3484 } | 3576 } |
3485 jsTarget = _emitTargetAccess(jsTarget, jsName, element); | 3577 jsTarget = _emitTargetAccess(jsTarget, jsName, element); |
| 3578 var castTo = getImplicitOperationCast(node); |
| 3579 if (castTo != null) { |
| 3580 jsTarget = js.call('#._check(#)', [_emitType(castTo), jsTarget]); |
| 3581 } |
3486 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 3582 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
3487 | |
3488 return new JS.Call(jsTarget, args); | 3583 return new JS.Call(jsTarget, args); |
3489 } | 3584 } |
3490 | 3585 |
3491 JS.Expression _emitDynamicInvoke( | 3586 JS.Expression _emitDynamicInvoke( |
3492 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { | 3587 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { |
3493 var typeArgs = _emitInvokeTypeArguments(node); | 3588 var typeArgs = _emitInvokeTypeArguments(node); |
3494 if (typeArgs != null) { | 3589 if (typeArgs != null) { |
3495 return _callHelper( | 3590 return _callHelper( |
3496 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); | 3591 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); |
3497 } else { | 3592 } else { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3547 } | 3642 } |
3548 var bang = negated ? '!' : ''; | 3643 var bang = negated ? '!' : ''; |
3549 return js.call( | 3644 return js.call( |
3550 "${bang}#", new JS.Call(_emitTopLevelName(_coreIdentical), args)); | 3645 "${bang}#", new JS.Call(_emitTopLevelName(_coreIdentical), args)); |
3551 } | 3646 } |
3552 | 3647 |
3553 /// Emits a function call, to a top-level function, local function, or | 3648 /// Emits a function call, to a top-level function, local function, or |
3554 /// an expression. | 3649 /// an expression. |
3555 JS.Expression _emitFunctionCall(InvocationExpression node, | 3650 JS.Expression _emitFunctionCall(InvocationExpression node, |
3556 [Expression function]) { | 3651 [Expression function]) { |
3557 if (function == null) { | 3652 function ??= node.function; |
3558 function = node.function; | 3653 var castTo = getImplicitOperationCast(function); |
| 3654 if (castTo != null) { |
| 3655 function = CoercionReifier.castExpression(function, castTo); |
3559 } | 3656 } |
3560 if (_isCoreIdentical(function)) { | 3657 if (_isCoreIdentical(function)) { |
3561 return _emitCoreIdenticalCall(node.argumentList.arguments); | 3658 return _emitCoreIdenticalCall(node.argumentList.arguments); |
3562 } | 3659 } |
3563 var fn = _visit(function); | 3660 var fn = _visit(function); |
3564 var args = _emitArgumentList(node.argumentList); | 3661 var args = _emitArgumentList(node.argumentList); |
3565 if (isDynamicInvoke(function)) { | 3662 if (isDynamicInvoke(function)) { |
3566 return _emitDynamicInvoke(node, fn, args); | 3663 return _emitDynamicInvoke(node, fn, args); |
3567 } | 3664 } |
3568 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); | 3665 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); |
(...skipping 1526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5095 } | 5192 } |
5096 | 5193 |
5097 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { | 5194 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { |
5098 var then = visitCatchClause(clause); | 5195 var then = visitCatchClause(clause); |
5099 | 5196 |
5100 // Discard following clauses, if any, as they are unreachable. | 5197 // Discard following clauses, if any, as they are unreachable. |
5101 if (clause.exceptionType == null) return then; | 5198 if (clause.exceptionType == null) return then; |
5102 | 5199 |
5103 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which | 5200 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which |
5104 // has special case for typeof. | 5201 // has special case for typeof. |
5105 var castType = _emitType(clause.exceptionType.type, | 5202 var castType = _emitType(clause.exceptionType.type); |
5106 nameType: options.nameTypeTests || options.hoistTypeTests, | |
5107 hoistType: options.hoistTypeTests); | |
5108 | 5203 |
5109 return new JS.If(js.call('#.is(#)', [castType, _visit(_catchParameter)]), | 5204 return new JS.If(js.call('#.is(#)', [castType, _visit(_catchParameter)]), |
5110 then, otherwise); | 5205 then, otherwise); |
5111 } | 5206 } |
5112 | 5207 |
5113 JS.Statement _statement(List<JS.Statement> statements) { | 5208 JS.Statement _statement(List<JS.Statement> statements) { |
5114 // TODO(jmesserly): empty block singleton? | 5209 // TODO(jmesserly): empty block singleton? |
5115 if (statements.length == 0) return new JS.Block([]); | 5210 if (statements.length == 0) return new JS.Block([]); |
5116 if (statements.length == 1) return statements[0]; | 5211 if (statements.length == 1) return statements[0]; |
5117 return new JS.Block(statements); | 5212 return new JS.Block(statements); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5353 if (node is BinaryExpression) { | 5448 if (node is BinaryExpression) { |
5354 JS.Expression shortCircuit(String code) { | 5449 JS.Expression shortCircuit(String code) { |
5355 return finish(js.call(code, | 5450 return finish(js.call(code, |
5356 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); | 5451 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); |
5357 } | 5452 } |
5358 | 5453 |
5359 var op = node.operator.type.lexeme; | 5454 var op = node.operator.type.lexeme; |
5360 if (op == '&&') return shortCircuit('# && #'); | 5455 if (op == '&&') return shortCircuit('# && #'); |
5361 if (op == '||') return shortCircuit('# || #'); | 5456 if (op == '||') return shortCircuit('# || #'); |
5362 } | 5457 } |
5363 if (node is AsExpression && CoercionReifier.isImplicitCast(node)) { | 5458 if (node is AsExpression && CoercionReifier.isRequiredForSoundness(node)) { |
5364 assert(node.staticType == types.boolType); | 5459 assert(node.staticType == types.boolType); |
5365 return _callHelper('dtest(#)', _visit(node.expression)); | 5460 return _callHelper('dtest(#)', _visit(node.expression)); |
5366 } | 5461 } |
5367 JS.Expression result = _visit(node); | 5462 JS.Expression result = _visit(node); |
5368 if (isNullable(node)) result = _callHelper('test(#)', result); | 5463 if (isNullable(node)) result = _callHelper('test(#)', result); |
5369 return result; | 5464 return result; |
5370 } | 5465 } |
5371 | 5466 |
5372 /// Like [_emitMemberName], but for declaration sites. | 5467 /// Like [_emitMemberName], but for declaration sites. |
5373 /// | 5468 /// |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5869 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5964 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5870 var prefix = targetIdentifier.staticElement as PrefixElement; | 5965 var prefix = targetIdentifier.staticElement as PrefixElement; |
5871 | 5966 |
5872 // The library the prefix is referring to must come from a deferred import. | 5967 // The library the prefix is referring to must come from a deferred import. |
5873 var containingLibrary = resolutionMap | 5968 var containingLibrary = resolutionMap |
5874 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5969 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5875 .library; | 5970 .library; |
5876 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5971 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5877 return imports.length == 1 && imports[0].isDeferred; | 5972 return imports.length == 1 && imports[0].isDeferred; |
5878 } | 5973 } |
OLD | NEW |