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

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

Powered by Google App Engine
This is Rietveld 408576698