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

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

Powered by Google App Engine
This is Rietveld 408576698