Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: pkg/dev_compiler/lib/src/compiler/code_generator.dart

Issue 2954523002: fix #27259, implement covariance checking for strong mode and DDC (Closed)
Patch Set: format Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698