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

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1554683002: Update to latest analyzer (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 11 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
« no previous file with comments | « lib/src/codegen/code_generator.dart ('k') | lib/src/codegen/reify_coercions.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
11 import 'package:analyzer/src/generated/constant.dart'; 11 import 'package:analyzer/src/generated/constant.dart';
12 import 'package:analyzer/src/generated/element.dart'; 12 import 'package:analyzer/src/generated/element.dart';
13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; 13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
14 import 'package:analyzer/src/generated/scanner.dart' 14 import 'package:analyzer/src/generated/scanner.dart'
15 show StringToken, Token, TokenType; 15 show StringToken, Token, TokenType;
16 import 'package:analyzer/src/generated/type_system.dart'
17 show StrongTypeSystemImpl;
16 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; 18 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder;
17 import 'package:analyzer/src/task/strong/rules.dart';
18 19
19 import 'ast_builder.dart' show AstBuilder; 20 import 'ast_builder.dart' show AstBuilder;
20 import 'reify_coercions.dart' show CoercionReifier, Tuple2; 21 import 'reify_coercions.dart' show CoercionReifier, Tuple2;
21 22
22 // TODO(jmesserly): import from its own package 23 // TODO(jmesserly): import from its own package
23 import '../js/js_ast.dart' as JS; 24 import '../js/js_ast.dart' as JS;
24 import '../js/js_ast.dart' show js; 25 import '../js/js_ast.dart' show js;
25 26
26 import '../closure/closure_annotator.dart' show ClosureAnnotator; 27 import '../closure/closure_annotator.dart' show ClosureAnnotator;
27 import '../compiler.dart' show AbstractCompiler; 28 import '../compiler.dart' show AbstractCompiler;
(...skipping 22 matching lines...) Expand all
50 const DINDEX = 'dindex'; 51 const DINDEX = 'dindex';
51 const DSETINDEX = 'dsetindex'; 52 const DSETINDEX = 'dsetindex';
52 const DCALL = 'dcall'; 53 const DCALL = 'dcall';
53 const DSEND = 'dsend'; 54 const DSEND = 'dsend';
54 55
55 const ListEquality _listEquality = const ListEquality(); 56 const ListEquality _listEquality = const ListEquality();
56 57
57 class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { 58 class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
58 final AbstractCompiler compiler; 59 final AbstractCompiler compiler;
59 final CodegenOptions options; 60 final CodegenOptions options;
60 final TypeRules rules;
61 final LibraryElement currentLibrary; 61 final LibraryElement currentLibrary;
62 final StrongTypeSystemImpl rules;
62 63
63 /// The global extension type table. 64 /// The global extension type table.
64 final HashSet<ClassElement> _extensionTypes; 65 final HashSet<ClassElement> _extensionTypes;
65 66
66 /// Information that is precomputed for this library, indicates which fields 67 /// Information that is precomputed for this library, indicates which fields
67 /// need storage slots. 68 /// need storage slots.
68 final HashSet<FieldElement> _fieldsNeedingStorage; 69 final HashSet<FieldElement> _fieldsNeedingStorage;
69 70
70 /// The variable for the target of the current `..` cascade expression. 71 /// The variable for the target of the current `..` cascade expression.
71 /// 72 ///
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 ModuleItemLoadOrder _loader; 104 ModuleItemLoadOrder _loader;
104 105
105 /// _interceptors.JSArray<E>, used for List literals. 106 /// _interceptors.JSArray<E>, used for List literals.
106 ClassElement _jsArray; 107 ClassElement _jsArray;
107 108
108 /// The default value of the module object. See [visitLibraryDirective]. 109 /// The default value of the module object. See [visitLibraryDirective].
109 String _jsModuleValue; 110 String _jsModuleValue;
110 111
111 bool _isDartUtils; 112 bool _isDartUtils;
112 113
113 Map<String, DartType> _objectMembers;
114
115 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, 114 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary,
116 this._extensionTypes, this._fieldsNeedingStorage) 115 this._extensionTypes, this._fieldsNeedingStorage)
117 : compiler = compiler, 116 : compiler = compiler,
118 options = compiler.options.codegenOptions, 117 options = compiler.options.codegenOptions,
119 _types = compiler.context.typeProvider { 118 _types = compiler.context.typeProvider {
120 _loader = new ModuleItemLoadOrder(_emitModuleItem); 119 _loader = new ModuleItemLoadOrder(_emitModuleItem);
121 120
122 var context = compiler.context; 121 var context = compiler.context;
123 var src = context.sourceFactory.forUri('dart:_interceptors'); 122 var src = context.sourceFactory.forUri('dart:_interceptors');
124 var interceptors = context.computeLibraryElement(src); 123 var interceptors = context.computeLibraryElement(src);
125 _jsArray = interceptors.getType('JSArray'); 124 _jsArray = interceptors.getType('JSArray');
126 _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils'; 125 _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils';
127
128 _objectMembers = getObjectMemberMap(types);
129 } 126 }
130 127
131 TypeProvider get types => rules.provider; 128 TypeProvider get types => _types;
132 129
133 JS.Program emitLibrary(LibraryUnit library) { 130 JS.Program emitLibrary(LibraryUnit library) {
134 // Modify the AST to make coercions explicit. 131 // Modify the AST to make coercions explicit.
135 new CoercionReifier(library, rules).reify(); 132 new CoercionReifier(library, rules).reify();
136 133
137 // Build the public namespace for this library. This allows us to do 134 // Build the public namespace for this library. This allows us to do
138 // constant time lookups (contrast with `Element.getChild(name)`). 135 // constant time lookups (contrast with `Element.getChild(name)`).
139 if (currentLibrary.publicNamespace == null) { 136 if (currentLibrary.publicNamespace == null) {
140 (currentLibrary as LibraryElementImpl).publicNamespace = 137 (currentLibrary as LibraryElementImpl).publicNamespace =
141 new PublicNamespaceBuilder().build(currentLibrary); 138 new PublicNamespaceBuilder().build(currentLibrary);
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 bool isPublic(String name) => !name.startsWith('_'); 323 bool isPublic(String name) => !name.startsWith('_');
327 324
328 @override 325 @override
329 visitAsExpression(AsExpression node) { 326 visitAsExpression(AsExpression node) {
330 var from = getStaticType(node.expression); 327 var from = getStaticType(node.expression);
331 var to = node.type.type; 328 var to = node.type.type;
332 329
333 var fromExpr = _visit(node.expression); 330 var fromExpr = _visit(node.expression);
334 331
335 // Skip the cast if it's not needed. 332 // Skip the cast if it's not needed.
336 if (rules.isSubTypeOf(from, to)) return fromExpr; 333 if (rules.isSubtypeOf(from, to)) return fromExpr;
337 334
338 // All Dart number types map to a JS double. 335 // All Dart number types map to a JS double.
339 if (_isNumberInJS(from) && _isNumberInJS(to)) { 336 if (_isNumberInJS(from) && _isNumberInJS(to)) {
340 // Make sure to check when converting to int. 337 // Make sure to check when converting to int.
341 if (from != _types.intType && to == _types.intType) { 338 if (from != _types.intType && to == _types.intType) {
342 return js.call('dart.asInt(#)', [fromExpr]); 339 return js.call('dart.asInt(#)', [fromExpr]);
343 } 340 }
344 341
345 // A no-op in JavaScript. 342 // A no-op in JavaScript.
346 return fromExpr; 343 return fromExpr;
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 } 534 }
538 535
539 /// Given a class element and body, complete the class declaration. 536 /// Given a class element and body, complete the class declaration.
540 /// This handles generic type parameters, laziness (in library-cycle cases), 537 /// This handles generic type parameters, laziness (in library-cycle cases),
541 /// and ensuring dependencies are loaded first. 538 /// and ensuring dependencies are loaded first.
542 JS.Statement _finishClassDef(ParameterizedType type, JS.Statement body) { 539 JS.Statement _finishClassDef(ParameterizedType type, JS.Statement body) {
543 var name = type.name; 540 var name = type.name;
544 var genericName = '$name\$'; 541 var genericName = '$name\$';
545 542
546 JS.Statement genericDef = null; 543 JS.Statement genericDef = null;
547 if (type.typeParameters.isNotEmpty) { 544 if (_boundTypeParametersOf(type).isNotEmpty) {
548 genericDef = _emitGenericClassDef(type, body); 545 genericDef = _emitGenericClassDef(type, body);
549 } 546 }
550
551 // The base class and all mixins must be declared before this class. 547 // The base class and all mixins must be declared before this class.
552 if (!_loader.isLoaded(type.element)) { 548 if (!_loader.isLoaded(type.element)) {
553 // TODO(jmesserly): the lazy class def is a simple solution for now. 549 // TODO(jmesserly): the lazy class def is a simple solution for now.
554 // We may want to consider other options in the future. 550 // We may want to consider other options in the future.
555 551
556 if (genericDef != null) { 552 if (genericDef != null) {
557 return js.statement( 553 return js.statement(
558 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', 554 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }',
559 [genericDef, _exportsVar, _propertyName(name), genericName]); 555 [genericDef, _exportsVar, _propertyName(name), genericName]);
560 } 556 }
561 557
562 return js.statement( 558 return js.statement(
563 'dart.defineLazyClass(#, { get #() { #; return #; } });', 559 'dart.defineLazyClass(#, { get #() { #; return #; } });',
564 [_exportsVar, _propertyName(name), body, name]); 560 [_exportsVar, _propertyName(name), body, name]);
565 } 561 }
566 562
567 if (isPublic(name)) _addExport(name); 563 if (isPublic(name)) _addExport(name);
568 564
569 if (genericDef != null) { 565 if (genericDef != null) {
570 var dynType = fillDynamicTypeArgs(type, types); 566 var dynType = fillDynamicTypeArgs(type, types);
571 var genericInst = _emitTypeName(dynType, lowerGeneric: true); 567 var genericInst = _emitTypeName(dynType, lowerGeneric: true);
572 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); 568 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]);
573 } 569 }
574 return body; 570 return body;
575 } 571 }
576 572
577 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { 573 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) {
578 var name = type.name; 574 var name = type.name;
579 var genericName = '$name\$'; 575 var genericName = '$name\$';
580 var typeParams = type.typeParameters.map((p) => p.name); 576 var typeParams = _boundTypeParametersOf(type).map((p) => p.name);
581 if (isPublic(name)) _exports.add(genericName); 577 if (isPublic(name)) _exports.add(genericName);
582 return js.statement('const # = dart.generic(function(#) { #; return #; });', 578 return js.statement('const # = dart.generic(function(#) { #; return #; });',
583 [genericName, typeParams, body, name]); 579 [genericName, typeParams, body, name]);
584 } 580 }
585 581
586 final _hasDeferredSupertype = new HashSet<ClassElement>(); 582 final _hasDeferredSupertype = new HashSet<ClassElement>();
587 583
588 bool _deferIfNeeded(DartType type, ClassElement current) { 584 bool _deferIfNeeded(DartType type, ClassElement current) {
589 if (type is ParameterizedType) { 585 if (type is ParameterizedType) {
590 var typeArguments = type.typeArguments; 586 var typeArguments = type.typeArguments;
(...skipping 13 matching lines...) Expand all
604 if (type.isObject) return null; 600 if (type.isObject) return null;
605 601
606 // Assume we can load eagerly, until proven otherwise. 602 // Assume we can load eagerly, until proven otherwise.
607 _loader.startTopLevel(element); 603 _loader.startTopLevel(element);
608 604
609 // Find the super type 605 // Find the super type
610 JS.Expression heritage; 606 JS.Expression heritage;
611 var supertype = type.superclass; 607 var supertype = type.superclass;
612 if (_deferIfNeeded(supertype, element)) { 608 if (_deferIfNeeded(supertype, element)) {
613 // Fall back to raw type. 609 // Fall back to raw type.
614 supertype = fillDynamicTypeArgs(supertype.element.type, rules.provider); 610 supertype = fillDynamicTypeArgs(supertype.element.type, _types);
615 _hasDeferredSupertype.add(element); 611 _hasDeferredSupertype.add(element);
616 } 612 }
617 heritage = _emitTypeName(supertype); 613 heritage = _emitTypeName(supertype);
618 614
619 if (type.mixins.isNotEmpty) { 615 if (type.mixins.isNotEmpty) {
620 var mixins = type.mixins.map(_emitTypeName).toList(); 616 var mixins = type.mixins.map(_emitTypeName).toList();
621 mixins.insert(0, heritage); 617 mixins.insert(0, heritage);
622 heritage = js.call('dart.mixin(#)', [mixins]); 618 heritage = js.call('dart.mixin(#)', [mixins]);
623 } 619 }
624 620
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
782 var tStatics = <JS.Property>[]; 778 var tStatics = <JS.Property>[];
783 var tMethods = <JS.Property>[]; 779 var tMethods = <JS.Property>[];
784 var sNames = <JS.Expression>[]; 780 var sNames = <JS.Expression>[];
785 for (MethodDeclaration node in methods) { 781 for (MethodDeclaration node in methods) {
786 if (!(node.isSetter || node.isGetter || node.isAbstract)) { 782 if (!(node.isSetter || node.isGetter || node.isAbstract)) {
787 var name = node.name.name; 783 var name = node.name.name;
788 var element = node.element; 784 var element = node.element;
789 var inheritedElement = 785 var inheritedElement =
790 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); 786 classElem.lookUpInheritedConcreteMethod(name, currentLibrary);
791 if (inheritedElement != null && 787 if (inheritedElement != null &&
792 inheritedElement.type == element.type) continue; 788 inheritedElement.type == element.type) {
789 continue;
790 }
793 var memberName = _elementMemberName(element); 791 var memberName = _elementMemberName(element);
794 var parts = _emitFunctionTypeParts(element.type); 792 var parts = _emitFunctionTypeParts(element.type);
795 var property = 793 var property =
796 new JS.Property(memberName, new JS.ArrayInitializer(parts)); 794 new JS.Property(memberName, new JS.ArrayInitializer(parts));
797 if (node.isStatic) { 795 if (node.isStatic) {
798 tStatics.add(property); 796 tStatics.add(property);
799 sNames.add(memberName); 797 sNames.add(memberName);
800 } else { 798 } else {
801 tMethods.add(property); 799 tMethods.add(property);
802 } 800 }
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
914 /// `C() : super() {}`. 912 /// `C() : super() {}`.
915 JS.Method _emitImplicitConstructor( 913 JS.Method _emitImplicitConstructor(
916 ClassDeclaration node, List<FieldDeclaration> fields) { 914 ClassDeclaration node, List<FieldDeclaration> fields) {
917 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); 915 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty);
918 916
919 // If we don't have a method body, skip this. 917 // If we don't have a method body, skip this.
920 var superCall = _superConstructorCall(node.element); 918 var superCall = _superConstructorCall(node.element);
921 if (fields.isEmpty && superCall == null) return null; 919 if (fields.isEmpty && superCall == null) return null;
922 920
923 dynamic body = _initializeFields(node, fields); 921 dynamic body = _initializeFields(node, fields);
924 if (superCall != null) body = [ 922 if (superCall != null) {
925 [body, superCall] 923 body = [
926 ]; 924 [body, superCall]
925 ];
926 }
927 var name = _constructorName(node.element.unnamedConstructor); 927 var name = _constructorName(node.element.unnamedConstructor);
928 return annotateDefaultConstructor( 928 return annotateDefaultConstructor(
929 new JS.Method(name, js.call('function() { #; }', body) as JS.Fun), 929 new JS.Method(name, js.call('function() { #; }', body) as JS.Fun),
930 node.element); 930 node.element);
931 } 931 }
932 932
933 JS.Method _emitConstructor(ConstructorDeclaration node, InterfaceType type, 933 JS.Method _emitConstructor(ConstructorDeclaration node, InterfaceType type,
934 List<FieldDeclaration> fields, bool isObject) { 934 List<FieldDeclaration> fields, bool isObject) {
935 if (_externalOrNative(node)) return null; 935 if (_externalOrNative(node)) return null;
936 936
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
1228 ])); 1228 ]));
1229 } 1229 }
1230 } else if (param.kind == ParameterKind.POSITIONAL) { 1230 } else if (param.kind == ParameterKind.POSITIONAL) {
1231 body.add(js.statement('if (# === void 0) # = #;', 1231 body.add(js.statement('if (# === void 0) # = #;',
1232 [jsParam, jsParam, _defaultParamValue(param)])); 1232 [jsParam, jsParam, _defaultParamValue(param)]));
1233 } 1233 }
1234 1234
1235 // TODO(jmesserly): various problems here, see: 1235 // TODO(jmesserly): various problems here, see:
1236 // https://github.com/dart-lang/dev_compiler/issues/161 1236 // https://github.com/dart-lang/dev_compiler/issues/161
1237 var paramType = param.element.type; 1237 var paramType = param.element.type;
1238 if (!constructor && _hasTypeParameter(paramType)) { 1238 if (!constructor && _hasUnsoundTypeParameter(paramType)) {
1239 body.add(js.statement( 1239 body.add(js
1240 'dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); 1240 .statement('dart.as(#, #);', [jsParam, _emitTypeName(paramType)]));
1241 } 1241 }
1242 } 1242 }
1243 return body.isEmpty ? null : _statement(body); 1243 return body.isEmpty ? null : _statement(body);
1244 } 1244 }
1245 1245
1246 bool _hasTypeParameter(DartType t) => t is TypeParameterType || 1246 bool _isUnsoundTypeParameter(DartType t) =>
1247 t is ParameterizedType && t.typeArguments.any(_hasTypeParameter); 1247 t is TypeParameterType && t.element.enclosingElement is ClassElement;
1248
1249 bool _hasUnsoundTypeParameter(DartType t) =>
1250 _isUnsoundTypeParameter(t) ||
1251 t is ParameterizedType && t.typeArguments.any(_hasUnsoundTypeParameter);
1248 1252
1249 JS.Expression _defaultParamValue(FormalParameter param) { 1253 JS.Expression _defaultParamValue(FormalParameter param) {
1250 if (param is DefaultFormalParameter && param.defaultValue != null) { 1254 if (param is DefaultFormalParameter && param.defaultValue != null) {
1251 return _visit(param.defaultValue); 1255 return _visit(param.defaultValue);
1252 } else { 1256 } else {
1253 return new JS.LiteralNull(); 1257 return new JS.LiteralNull();
1254 } 1258 }
1255 } 1259 }
1256 1260
1257 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { 1261 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) {
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1372 1376
1373 JS.Method _emitTopLevelProperty(FunctionDeclaration node) { 1377 JS.Method _emitTopLevelProperty(FunctionDeclaration node) {
1374 var name = node.name.name; 1378 var name = node.name.name;
1375 return annotate( 1379 return annotate(
1376 new JS.Method(_propertyName(name), _visit(node.functionExpression), 1380 new JS.Method(_propertyName(name), _visit(node.functionExpression),
1377 isGetter: node.isGetter, isSetter: node.isSetter), 1381 isGetter: node.isGetter, isSetter: node.isSetter),
1378 node.element); 1382 node.element);
1379 } 1383 }
1380 1384
1381 bool _executesAtTopLevel(AstNode node) { 1385 bool _executesAtTopLevel(AstNode node) {
1382 var ancestor = node.getAncestor((n) => n is FunctionBody || 1386 var ancestor = node.getAncestor((n) =>
1387 n is FunctionBody ||
1383 (n is FieldDeclaration && n.staticKeyword == null) || 1388 (n is FieldDeclaration && n.staticKeyword == null) ||
1384 (n is ConstructorDeclaration && n.constKeyword == null)); 1389 (n is ConstructorDeclaration && n.constKeyword == null));
1385 return ancestor == null; 1390 return ancestor == null;
1386 } 1391 }
1387 1392
1388 bool _typeIsLoaded(DartType type) { 1393 bool _typeIsLoaded(DartType type) {
1389 if (type is FunctionType && (type.name == '' || type.name == null)) { 1394 if (type is FunctionType && (type.name == '' || type.name == null)) {
1390 return (_typeIsLoaded(type.returnType) && 1395 return (_typeIsLoaded(type.returnType) &&
1391 type.optionalParameterTypes.every(_typeIsLoaded) && 1396 type.optionalParameterTypes.every(_typeIsLoaded) &&
1392 type.namedParameterTypes.values.every(_typeIsLoaded) && 1397 type.namedParameterTypes.values.every(_typeIsLoaded) &&
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1513 } else { 1518 } else {
1514 _asyncStarController = null; 1519 _asyncStarController = null;
1515 jsParams = params; 1520 jsParams = params;
1516 } 1521 }
1517 JS.Expression gen = new JS.Fun(jsParams, _visit(body), isGenerator: true); 1522 JS.Expression gen = new JS.Fun(jsParams, _visit(body), isGenerator: true);
1518 if (JS.This.foundIn(gen)) { 1523 if (JS.This.foundIn(gen)) {
1519 gen = js.call('#.bind(this)', gen); 1524 gen = js.call('#.bind(this)', gen);
1520 } 1525 }
1521 _asyncStarController = savedController; 1526 _asyncStarController = savedController;
1522 1527
1523 var T = _emitTypeName(rules.getExpectedReturnType(body)); 1528 var T = _emitTypeName(_getExpectedReturnType(body));
1524 return js.call('dart.#(#)', [ 1529 return js.call('dart.#(#)', [
1525 kind, 1530 kind,
1526 [gen, T]..addAll(params) 1531 [gen, T]..addAll(params)
1527 ]); 1532 ]);
1528 } 1533 }
1529 1534
1530 @override 1535 @override
1531 JS.Statement visitFunctionDeclarationStatement( 1536 JS.Statement visitFunctionDeclarationStatement(
1532 FunctionDeclarationStatement node) { 1537 FunctionDeclarationStatement node) {
1533 var func = node.functionDeclaration; 1538 var func = node.functionDeclaration;
(...skipping 25 matching lines...) Expand all
1559 var accessor = node.staticElement; 1564 var accessor = node.staticElement;
1560 if (accessor == null) { 1565 if (accessor == null) {
1561 return js.commentExpression( 1566 return js.commentExpression(
1562 'Unimplemented unknown name', new JS.Identifier(node.name)); 1567 'Unimplemented unknown name', new JS.Identifier(node.name));
1563 } 1568 }
1564 1569
1565 // Get the original declaring element. If we had a property accessor, this 1570 // Get the original declaring element. If we had a property accessor, this
1566 // indirects back to a (possibly synthetic) field. 1571 // indirects back to a (possibly synthetic) field.
1567 var element = accessor; 1572 var element = accessor;
1568 if (accessor is PropertyAccessorElement) element = accessor.variable; 1573 if (accessor is PropertyAccessorElement) element = accessor.variable;
1574 if (accessor is FunctionMember) element = accessor.baseElement;
1569 1575
1570 _loader.declareBeforeUse(element); 1576 _loader.declareBeforeUse(element);
1571 1577
1572 var name = element.name; 1578 var name = element.name;
1573 1579
1574 // type literal 1580 // type literal
1575 if (element is ClassElement || 1581 if (element is ClassElement ||
1576 element is DynamicElementImpl || 1582 element is DynamicElementImpl ||
1577 element is FunctionTypeAliasElement) { 1583 element is FunctionTypeAliasElement) {
1578 return _emitTypeName( 1584 return _emitTypeName(
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
1715 1721
1716 // TODO(jmesserly): like constants, should we hoist function types out of 1722 // TODO(jmesserly): like constants, should we hoist function types out of
1717 // methods? Similar issue with generic types. For all of these, we may want 1723 // methods? Similar issue with generic types. For all of these, we may want
1718 // to canonicalize them too, at least when inside the same library. 1724 // to canonicalize them too, at least when inside the same library.
1719 var name = type.name; 1725 var name = type.name;
1720 var element = type.element; 1726 var element = type.element;
1721 if (name == '' || name == null || lowerTypedef) { 1727 if (name == '' || name == null || lowerTypedef) {
1722 var parts = _emitFunctionTypeParts(type as FunctionType); 1728 var parts = _emitFunctionTypeParts(type as FunctionType);
1723 return js.call('dart.functionType(#)', [parts]); 1729 return js.call('dart.functionType(#)', [parts]);
1724 } 1730 }
1731 // For now, reify generic method parameters as dynamic
1732 bool _isGenericTypeParameter(DartType type) =>
1733 (type is TypeParameterType) &&
1734 !(type.element.enclosingElement is ClassElement ||
1735 type.element.enclosingElement is FunctionTypeAliasElement);
1736
1737 if (_isGenericTypeParameter(type)) {
1738 return js.call('dart.dynamic');
1739 }
1725 1740
1726 if (type is TypeParameterType) { 1741 if (type is TypeParameterType) {
1727 return new JS.Identifier(name); 1742 return new JS.Identifier(name);
1728 } 1743 }
1729 1744
1730 if (type is ParameterizedType) { 1745 if (type is ParameterizedType) {
1731 var args = type.typeArguments; 1746 var args = type.typeArguments;
1732 var isCurrentClass = 1747 var isCurrentClass =
1733 args.isNotEmpty && _loader.isCurrentElement(type.element); 1748 args.isNotEmpty && _loader.isCurrentElement(type.element);
1734 Iterable jsArgs = null; 1749 Iterable jsArgs = null;
1735 if (args.any((a) => a != types.dynamicType)) { 1750 if (args
1751 .any((a) => a != types.dynamicType && !_isGenericTypeParameter(a))) {
1736 jsArgs = args.map(_emitTypeName); 1752 jsArgs = args.map(_emitTypeName);
1737 } else if (lowerGeneric || isCurrentClass) { 1753 } else if (lowerGeneric || isCurrentClass) {
1738 // When creating a `new S<dynamic>` we try and use the raw form 1754 // When creating a `new S<dynamic>` we try and use the raw form
1739 // `new S()`, but this does not work if we're inside the same class, 1755 // `new S()`, but this does not work if we're inside the same class,
1740 // because `S` refers to the current S<T> we are generating. 1756 // because `S` refers to the current S<T> we are generating.
1741 jsArgs = []; 1757 jsArgs = [];
1742 } 1758 }
1743 if (jsArgs != null) { 1759 if (jsArgs != null) {
1744 var genericName = _maybeQualifiedName(element, '$name\$'); 1760 var genericName = _maybeQualifiedName(element, '$name\$');
1745 return js.call('#(#)', [genericName, jsArgs]); 1761 return js.call('#(#)', [genericName, jsArgs]);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1807 var inc = AstBuilder.binaryExpression(lhs, op, right); 1823 var inc = AstBuilder.binaryExpression(lhs, op, right);
1808 inc.staticElement = element; 1824 inc.staticElement = element;
1809 inc.staticType = getStaticType(left); 1825 inc.staticType = getStaticType(left);
1810 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); 1826 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]);
1811 } 1827 }
1812 1828
1813 JS.Expression _emitSet(Expression lhs, Expression rhs) { 1829 JS.Expression _emitSet(Expression lhs, Expression rhs) {
1814 if (lhs is IndexExpression) { 1830 if (lhs is IndexExpression) {
1815 var target = _getTarget(lhs); 1831 var target = _getTarget(lhs);
1816 if (_useNativeJsIndexer(target.staticType)) { 1832 if (_useNativeJsIndexer(target.staticType)) {
1817 return js.call( 1833 return js
1818 '#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]); 1834 .call('#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]);
1819 } 1835 }
1820 return _emitSend(target, '[]=', [lhs.index, rhs]); 1836 return _emitSend(target, '[]=', [lhs.index, rhs]);
1821 } 1837 }
1822 1838
1823 Expression target = null; 1839 Expression target = null;
1824 SimpleIdentifier id; 1840 SimpleIdentifier id;
1825 if (lhs is PropertyAccess) { 1841 if (lhs is PropertyAccess) {
1826 if (lhs.operator.lexeme == '?.') { 1842 if (lhs.operator.lexeme == '?.') {
1827 return _emitNullSafeSet(lhs, rhs); 1843 return _emitNullSafeSet(lhs, rhs);
1828 } 1844 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1894 var result = _emitForeignJS(node); 1910 var result = _emitForeignJS(node);
1895 if (result != null) return result; 1911 if (result != null) return result;
1896 1912
1897 String code; 1913 String code;
1898 if (target == null || isLibraryPrefix(target)) { 1914 if (target == null || isLibraryPrefix(target)) {
1899 if (DynamicInvoke.get(node.methodName)) { 1915 if (DynamicInvoke.get(node.methodName)) {
1900 code = 'dart.$DCALL(#, #)'; 1916 code = 'dart.$DCALL(#, #)';
1901 } else { 1917 } else {
1902 code = '#(#)'; 1918 code = '#(#)';
1903 } 1919 }
1904 return js.call( 1920 return js
1905 code, [_visit(node.methodName), _visit(node.argumentList)]); 1921 .call(code, [_visit(node.methodName), _visit(node.argumentList)]);
1906 } 1922 }
1907 1923
1908 var type = getStaticType(target); 1924 var type = getStaticType(target);
1909 var name = node.methodName.name; 1925 var name = node.methodName.name;
1910 var element = node.methodName.staticElement; 1926 var element = node.methodName.staticElement;
1911 bool isStatic = element is ExecutableElement && element.isStatic; 1927 bool isStatic = element is ExecutableElement && element.isStatic;
1912 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); 1928 var memberName = _emitMemberName(name, type: type, isStatic: isStatic);
1913 1929
1914 if (DynamicInvoke.get(target)) { 1930 if (DynamicInvoke.get(target)) {
1915 code = 'dart.$DSEND(#, #, #)'; 1931 code = 'dart.$DSEND(#, #, #)';
1916 } else if (DynamicInvoke.get(node.methodName)) { 1932 } else if (DynamicInvoke.get(node.methodName)) {
1917 // This is a dynamic call to a statically known target. For example: 1933 // This is a dynamic call to a statically known target. For example:
1918 // class Foo { Function bar; } 1934 // class Foo { Function bar; }
1919 // new Foo().bar(); // dynamic call 1935 // new Foo().bar(); // dynamic call
1920 code = 'dart.$DCALL(#.#, #)'; 1936 code = 'dart.$DCALL(#.#, #)';
1921 } else if (_requiresStaticDispatch(target, name)) { 1937 } else if (_requiresStaticDispatch(target, name)) {
1922 assert(rules.objectMembers[name] is FunctionType);
1923 // Object methods require a helper for null checks. 1938 // Object methods require a helper for null checks.
1924 return js.call('dart.#(#, #)', 1939 return js.call('dart.#(#, #)',
1925 [memberName, _visit(target), _visit(node.argumentList)]); 1940 [memberName, _visit(target), _visit(node.argumentList)]);
1926 } else { 1941 } else {
1927 code = '#.#(#)'; 1942 code = '#.#(#)';
1928 } 1943 }
1929 1944
1930 return js.call( 1945 return js
1931 code, [_visit(target), memberName, _visit(node.argumentList)]); 1946 .call(code, [_visit(target), memberName, _visit(node.argumentList)]);
1932 } 1947 }
1933 1948
1934 /// Emits code for the `JS(...)` builtin. 1949 /// Emits code for the `JS(...)` builtin.
1935 _emitForeignJS(MethodInvocation node) { 1950 _emitForeignJS(MethodInvocation node) {
1936 var e = node.methodName.staticElement; 1951 var e = node.methodName.staticElement;
1937 if (isInlineJS(e)) { 1952 if (isInlineJS(e)) {
1938 var args = node.argumentList.arguments; 1953 var args = node.argumentList.arguments;
1939 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` 1954 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer`
1940 var code = args[1]; 1955 var code = args[1];
1941 var templateArgs; 1956 var templateArgs;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
2007 _propertyName(node.name.label.name), _visit(node.expression)); 2022 _propertyName(node.name.label.name), _visit(node.expression));
2008 } 2023 }
2009 2024
2010 bool _isNamedParam(FormalParameter param) => 2025 bool _isNamedParam(FormalParameter param) =>
2011 param.kind == ParameterKind.NAMED; 2026 param.kind == ParameterKind.NAMED;
2012 2027
2013 /// We cannot destructure named params that clash with JS reserved names: 2028 /// We cannot destructure named params that clash with JS reserved names:
2014 /// see discussion in https://github.com/dart-lang/dev_compiler/issues/392. 2029 /// see discussion in https://github.com/dart-lang/dev_compiler/issues/392.
2015 bool _isDestructurableNamedParam(FormalParameter param) => 2030 bool _isDestructurableNamedParam(FormalParameter param) =>
2016 _isNamedParam(param) && 2031 _isNamedParam(param) &&
2017 !invalidVariableName(param.identifier.name) && 2032 !invalidVariableName(param.identifier.name) &&
2018 options.destructureNamedParams; 2033 options.destructureNamedParams;
2019 2034
2020 @override 2035 @override
2021 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) => 2036 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) =>
2022 _emitFormalParameterList(node); 2037 _emitFormalParameterList(node);
2023 2038
2024 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, 2039 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node,
2025 {bool allowDestructuring: true}) { 2040 {bool allowDestructuring: true}) {
2026 var result = <JS.Parameter>[]; 2041 var result = <JS.Parameter>[];
2027 2042
2028 var namedVars = <JS.DestructuredVariable>[]; 2043 var namedVars = <JS.DestructuredVariable>[];
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
2180 } 2195 }
2181 2196
2182 @override 2197 @override
2183 visitVariableDeclaration(VariableDeclaration node) { 2198 visitVariableDeclaration(VariableDeclaration node) {
2184 if (node.element is PropertyInducingElement) return _emitStaticField(node); 2199 if (node.element is PropertyInducingElement) return _emitStaticField(node);
2185 2200
2186 var name = new JS.Identifier(node.name.name); 2201 var name = new JS.Identifier(node.name.name);
2187 return new JS.VariableInitialization(name, _visitInitializer(node)); 2202 return new JS.VariableInitialization(name, _visitInitializer(node));
2188 } 2203 }
2189 2204
2190 bool _isFinalJSDecl(AstNode field) => field is VariableDeclaration && 2205 bool _isFinalJSDecl(AstNode field) =>
2206 field is VariableDeclaration &&
2191 field.isFinal && 2207 field.isFinal &&
2192 _isJSInvocation(field.initializer); 2208 _isJSInvocation(field.initializer);
2193 2209
2194 /// Emits a static or top-level field. 2210 /// Emits a static or top-level field.
2195 JS.Statement _emitStaticField(VariableDeclaration field) { 2211 JS.Statement _emitStaticField(VariableDeclaration field) {
2196 PropertyInducingElement element = field.element; 2212 PropertyInducingElement element = field.element;
2197 assert(element.isStatic); 2213 assert(element.isStatic);
2198 2214
2199 bool eagerInit; 2215 bool eagerInit;
2200 JS.Expression jsInit; 2216 JS.Expression jsInit;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
2282 _findAccessor(element, getter: false))); 2298 _findAccessor(element, getter: false)));
2283 } 2299 }
2284 } 2300 }
2285 2301
2286 JS.Expression objExpr = _exportsVar; 2302 JS.Expression objExpr = _exportsVar;
2287 var target = _lazyFields[0].element.enclosingElement; 2303 var target = _lazyFields[0].element.enclosingElement;
2288 if (target is ClassElement) { 2304 if (target is ClassElement) {
2289 objExpr = new JS.Identifier(target.type.name); 2305 objExpr = new JS.Identifier(target.type.name);
2290 } 2306 }
2291 2307
2292 return js.statement( 2308 return js
2293 'dart.defineLazyProperties(#, { # });', [objExpr, methods]); 2309 .statement('dart.defineLazyProperties(#, { # });', [objExpr, methods]);
2294 } 2310 }
2295 2311
2296 PropertyAccessorElement _findAccessor(VariableElement element, 2312 PropertyAccessorElement _findAccessor(VariableElement element,
2297 {bool getter}) { 2313 {bool getter}) {
2298 var parent = element.enclosingElement; 2314 var parent = element.enclosingElement;
2299 if (parent is ClassElement) { 2315 if (parent is ClassElement) {
2300 return getter 2316 return getter
2301 ? parent.getGetter(element.name) 2317 ? parent.getGetter(element.name)
2302 : parent.getSetter(element.name); 2318 : parent.getSetter(element.name);
2303 } 2319 }
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
2503 } else { 2519 } else {
2504 // TODO(vsm): When do Dart ops not map to JS? 2520 // TODO(vsm): When do Dart ops not map to JS?
2505 code = '# $op #'; 2521 code = '# $op #';
2506 } 2522 }
2507 return js.call(code, [notNull(left), notNull(right)]); 2523 return js.call(code, [notNull(left), notNull(right)]);
2508 } 2524 }
2509 2525
2510 return _emitSend(left, op.lexeme, [right]); 2526 return _emitSend(left, op.lexeme, [right]);
2511 } 2527 }
2512 2528
2513 /// If the type [t] is [int] or [double], returns [num]. 2529 /// If the type [t] is [int] or [double], or a type parameter
2530 /// bounded by [int], [double] or [num] returns [num].
2514 /// Otherwise returns [t]. 2531 /// Otherwise returns [t].
2515 DartType _canonicalizeNumTypes(DartType t) { 2532 DartType _canonicalizeNumTypes(DartType t) {
2516 var numType = types.numType; 2533 var numType = types.numType;
2517 if (t is InterfaceType && t.superclass == numType) return numType; 2534 if (rules.isSubtypeOf(t, numType)) return numType;
2518 return t; 2535 return t;
2519 } 2536 }
2520 2537
2521 bool _canUsePrimitiveEquality(Expression left, Expression right) { 2538 bool _canUsePrimitiveEquality(Expression left, Expression right) {
2522 if (_isNull(left) || _isNull(right)) return true; 2539 if (_isNull(left) || _isNull(right)) return true;
2523 2540
2524 var leftType = _canonicalizeNumTypes(getStaticType(left)); 2541 var leftType = _canonicalizeNumTypes(getStaticType(left));
2525 var rightType = _canonicalizeNumTypes(getStaticType(right)); 2542 var rightType = _canonicalizeNumTypes(getStaticType(right));
2526 return _isJSBuiltinType(leftType) && leftType == rightType; 2543 return _isJSBuiltinType(leftType) && leftType == rightType;
2527 } 2544 }
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
2808 return AstBuilder.propertyAccess(newTarget, node.propertyName); 2825 return AstBuilder.propertyAccess(newTarget, node.propertyName);
2809 } else { 2826 } else {
2810 var invoke = node as MethodInvocation; 2827 var invoke = node as MethodInvocation;
2811 return AstBuilder.methodInvoke( 2828 return AstBuilder.methodInvoke(
2812 newTarget, invoke.methodName, invoke.argumentList.arguments); 2829 newTarget, invoke.methodName, invoke.argumentList.arguments);
2813 } 2830 }
2814 } 2831 }
2815 2832
2816 bool _requiresStaticDispatch(Expression target, String memberName) { 2833 bool _requiresStaticDispatch(Expression target, String memberName) {
2817 var type = getStaticType(target); 2834 var type = getStaticType(target);
2818 if (!rules.objectMembers.containsKey(memberName)) { 2835 if (!_isObjectProperty(memberName)) {
2819 return false; 2836 return false;
2820 } 2837 }
2821 if (!type.isObject && 2838 if (!type.isObject &&
2822 !_isJSBuiltinType(type) && 2839 !_isJSBuiltinType(type) &&
2823 _isNonNullableExpression(target)) { 2840 _isNonNullableExpression(target)) {
2824 return false; 2841 return false;
2825 } 2842 }
2826 return true; 2843 return true;
2827 } 2844 }
2828 2845
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
3019 var createStreamIter = _emitInstanceCreationExpression( 3036 var createStreamIter = _emitInstanceCreationExpression(
3020 StreamIterator_T.element.unnamedConstructor, 3037 StreamIterator_T.element.unnamedConstructor,
3021 StreamIterator_T, 3038 StreamIterator_T,
3022 null, 3039 null,
3023 AstBuilder.argumentList([node.iterable]), 3040 AstBuilder.argumentList([node.iterable]),
3024 false); 3041 false);
3025 var iter = _visit(_createTemporary('it', StreamIterator_T)); 3042 var iter = _visit(_createTemporary('it', StreamIterator_T));
3026 3043
3027 var init = _visit(node.identifier); 3044 var init = _visit(node.identifier);
3028 if (init == null) { 3045 if (init == null) {
3029 init = js.call( 3046 init = js
3030 'let # = #.current', [node.loopVariable.identifier.name, iter]); 3047 .call('let # = #.current', [node.loopVariable.identifier.name, iter]);
3031 } else { 3048 } else {
3032 init = js.call('# = #.current', [init, iter]); 3049 init = js.call('# = #.current', [init, iter]);
3033 } 3050 }
3034 return js.statement( 3051 return js.statement(
3035 '{' 3052 '{'
3036 ' let # = #;' 3053 ' let # = #;'
3037 ' try {' 3054 ' try {'
3038 ' while (#) { #; #; }' 3055 ' while (#) { #; #; }'
3039 ' } finally { #; }' 3056 ' } finally { #; }'
3040 '}', 3057 '}',
3041 [ 3058 [
3042 iter, 3059 iter,
3043 createStreamIter, 3060 createStreamIter,
3044 new JS.Yield(js.call('#.moveNext()', iter)), 3061 new JS.Yield(js.call('#.moveNext()', iter)),
3045 init, 3062 init,
3046 _visit(node.body), 3063 _visit(node.body),
3047 new JS.Yield(js.call('#.cancel()', iter)) 3064 new JS.Yield(js.call('#.cancel()', iter))
3048 ]); 3065 ]);
3049 } 3066 }
3050 3067
3051 @override 3068 @override
3052 visitBreakStatement(BreakStatement node) { 3069 visitBreakStatement(BreakStatement node) {
3053 var label = node.label; 3070 var label = node.label;
3054 return new JS.Break(label?.name); 3071 return new JS.Break(label?.name);
3055 } 3072 }
3056 3073
3057 @override 3074 @override
3058 visitContinueStatement(ContinueStatement node) { 3075 visitContinueStatement(ContinueStatement node) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
3117 /// Visits the catch clause body. This skips the exception type guard, if any. 3134 /// Visits the catch clause body. This skips the exception type guard, if any.
3118 /// That is handled in [_visitCatch]. 3135 /// That is handled in [_visitCatch].
3119 @override 3136 @override
3120 JS.Statement visitCatchClause(CatchClause node) { 3137 JS.Statement visitCatchClause(CatchClause node) {
3121 var body = <JS.Statement>[]; 3138 var body = <JS.Statement>[];
3122 3139
3123 var savedCatch = _catchParameter; 3140 var savedCatch = _catchParameter;
3124 if (node.catchKeyword != null) { 3141 if (node.catchKeyword != null) {
3125 var name = node.exceptionParameter; 3142 var name = node.exceptionParameter;
3126 if (name != null && name != _catchParameter) { 3143 if (name != null && name != _catchParameter) {
3127 body.add(js.statement( 3144 body.add(js
3128 'let # = #;', [_visit(name), _visit(_catchParameter)])); 3145 .statement('let # = #;', [_visit(name), _visit(_catchParameter)]));
3129 _catchParameter = name; 3146 _catchParameter = name;
3130 } 3147 }
3131 if (node.stackTraceParameter != null) { 3148 if (node.stackTraceParameter != null) {
3132 var stackVar = node.stackTraceParameter.name; 3149 var stackVar = node.stackTraceParameter.name;
3133 body.add(js.statement( 3150 body.add(js.statement(
3134 'let # = dart.stackTrace(#);', [stackVar, _visit(name)])); 3151 'let # = dart.stackTrace(#);', [stackVar, _visit(name)]));
3135 } 3152 }
3136 } 3153 }
3137 3154
3138 body.add( 3155 body.add(
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
3306 return result; 3323 return result;
3307 } 3324 }
3308 3325
3309 /// Visits a list of expressions, creating a comma expression if needed in JS. 3326 /// Visits a list of expressions, creating a comma expression if needed in JS.
3310 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 3327 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
3311 if (nodes == null || nodes.isEmpty) return null; 3328 if (nodes == null || nodes.isEmpty) return null;
3312 return new JS.Expression.binary( 3329 return new JS.Expression.binary(
3313 _visitList(nodes) as List<JS.Expression>, operator); 3330 _visitList(nodes) as List<JS.Expression>, operator);
3314 } 3331 }
3315 3332
3333 /// Return the bound type parameters for a ParameterizedType
3334 List<TypeParameterElement> _boundTypeParametersOf(ParameterizedType type) {
3335 return (type is FunctionType)
3336 ? type.boundTypeParameters
3337 : type.typeParameters;
3338 }
3339
3316 /// Like [_emitMemberName], but for declaration sites. 3340 /// Like [_emitMemberName], but for declaration sites.
3317 /// 3341 ///
3318 /// Unlike call sites, we always have an element available, so we can use it 3342 /// Unlike call sites, we always have an element available, so we can use it
3319 /// directly rather than computing the relevant options for [_emitMemberName]. 3343 /// directly rather than computing the relevant options for [_emitMemberName].
3320 JS.Expression _elementMemberName(ExecutableElement e, 3344 JS.Expression _elementMemberName(ExecutableElement e,
3321 {bool allowExtensions: true}) { 3345 {bool allowExtensions: true}) {
3322 String name; 3346 String name;
3323 if (e is PropertyAccessorElement) { 3347 if (e is PropertyAccessorElement) {
3324 name = e.variable.name; 3348 name = e.variable.name;
3325 } else { 3349 } else {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
3394 name = 'unary-'; 3418 name = 'unary-';
3395 } else if (name == 'constructor' || name == 'prototype') { 3419 } else if (name == 'constructor' || name == 'prototype') {
3396 // This uses an illegal (in Dart) character for a member, avoiding the 3420 // This uses an illegal (in Dart) character for a member, avoiding the
3397 // conflict. We could use practically any character for this. 3421 // conflict. We could use practically any character for this.
3398 name = '+$name'; 3422 name = '+$name';
3399 } 3423 }
3400 3424
3401 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 3425 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
3402 if (allowExtensions && 3426 if (allowExtensions &&
3403 _extensionTypes.contains(type.element) && 3427 _extensionTypes.contains(type.element) &&
3404 !_objectMembers.containsKey(name)) { 3428 !_isObjectProperty(name)) {
3405 return js.call('dartx.#', _propertyName(name)); 3429 return js.call('dartx.#', _propertyName(name));
3406 } 3430 }
3407 3431
3408 return _propertyName(name); 3432 return _propertyName(name);
3409 } 3433 }
3410 3434
3411 bool _externalOrNative(node) => 3435 bool _externalOrNative(node) =>
3412 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 3436 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
3413 3437
3414 FunctionBody _functionBody(node) => 3438 FunctionBody _functionBody(node) =>
3415 node is FunctionDeclaration ? node.functionExpression.body : node.body; 3439 node is FunctionDeclaration ? node.functionExpression.body : node.body;
3416 3440
3417 /// Choose a canonical name from the library element. 3441 /// Choose a canonical name from the library element.
3418 /// This never uses the library's name (the identifier in the `library` 3442 /// This never uses the library's name (the identifier in the `library`
3419 /// declaration) as it doesn't have any meaningful rules enforced. 3443 /// declaration) as it doesn't have any meaningful rules enforced.
3420 JS.Identifier _libraryName(LibraryElement library) { 3444 JS.Identifier _libraryName(LibraryElement library) {
3421 if (library == currentLibrary) return _exportsVar; 3445 if (library == currentLibrary) return _exportsVar;
3422 return _imports.putIfAbsent( 3446 return _imports.putIfAbsent(
3423 library, () => new JS.TemporaryId(jsLibraryName(library))); 3447 library, () => new JS.TemporaryId(jsLibraryName(library)));
3424 } 3448 }
3425 3449
3426 DartType getStaticType(Expression e) => rules.getStaticType(e); 3450 DartType getStaticType(Expression e) =>
3451 e.staticType ?? DynamicTypeImpl.instance;
3427 3452
3428 @override 3453 @override
3429 String getQualifiedName(TypeDefiningElement type) { 3454 String getQualifiedName(TypeDefiningElement type) {
3430 JS.TemporaryId id = _imports[type.library]; 3455 JS.TemporaryId id = _imports[type.library];
3431 return id == null ? type.name : '${id.name}.${type.name}'; 3456 return id == null ? type.name : '${id.name}.${type.name}';
3432 } 3457 }
3433 3458
3434 JS.Node annotate(JS.Node method, ExecutableElement e) => 3459 JS.Node annotate(JS.Node method, ExecutableElement e) =>
3435 options.closure && e != null 3460 options.closure && e != null
3436 ? method.withClosureAnnotation( 3461 ? method.withClosureAnnotation(
(...skipping 15 matching lines...) Expand all
3452 options.closure && e != null 3477 options.closure && e != null
3453 ? node.withClosureAnnotation(closureAnnotationForTypeDef(e)) 3478 ? node.withClosureAnnotation(closureAnnotationForTypeDef(e))
3454 : node; 3479 : node;
3455 3480
3456 /// Returns true if this is any kind of object represented by `Number` in JS. 3481 /// Returns true if this is any kind of object represented by `Number` in JS.
3457 /// 3482 ///
3458 /// In practice, this is 4 types: num, int, double, and JSNumber. 3483 /// In practice, this is 4 types: num, int, double, and JSNumber.
3459 /// 3484 ///
3460 /// JSNumber is the type that actually "implements" all numbers, hence it's 3485 /// JSNumber is the type that actually "implements" all numbers, hence it's
3461 /// a subtype of int and double (and num). It's in our "dart:_interceptors". 3486 /// a subtype of int and double (and num). It's in our "dart:_interceptors".
3462 bool _isNumberInJS(DartType t) => rules.isSubTypeOf(t, _types.numType); 3487 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, _types.numType);
3488
3489 bool _isObjectGetter(String name) {
3490 PropertyAccessorElement element = _types.objectType.element.getGetter(name);
3491 return (element != null && !element.isStatic);
3492 }
3493
3494 bool _isObjectMethod(String name) {
3495 MethodElement element = _types.objectType.element.getMethod(name);
3496 return (element != null && !element.isStatic);
3497 }
3498
3499 bool _isObjectProperty(String name) {
3500 return _isObjectGetter(name) || _isObjectMethod(name);
3501 }
3502
3503 // TODO(leafp): Various analyzer pieces computed similar things.
3504 // Share this logic somewhere?
3505 DartType _getExpectedReturnType(FunctionBody body) {
3506 FunctionType functionType;
3507 var parent = body.parent;
3508 if (parent is Declaration) {
3509 functionType = (parent.element as dynamic)?.type;
3510 } else {
3511 assert(parent is FunctionExpression);
3512 functionType = parent.staticType;
3513 }
3514 if (functionType == null) {
3515 return DynamicTypeImpl.instance;
3516 }
3517 var type = functionType.returnType;
3518
3519 InterfaceType expectedType = null;
3520 if (body.isAsynchronous) {
3521 if (body.isGenerator) {
3522 // Stream<T> -> T
3523 expectedType = _types.streamType;
3524 } else {
3525 // Future<T> -> T
3526 // TODO(vsm): Revisit with issue #228.
3527 expectedType = _types.futureType;
3528 }
3529 } else {
3530 if (body.isGenerator) {
3531 // Iterable<T> -> T
3532 expectedType = _types.iterableType;
3533 } else {
3534 // T -> T
3535 return type;
3536 }
3537 }
3538 if (type.isDynamic) {
3539 return type;
3540 } else if (type is InterfaceType && type.element == expectedType.element) {
3541 return type.typeArguments[0];
3542 } else {
3543 // TODO(leafp): The above only handles the case where the return type
3544 // is exactly Future/Stream/Iterable. Handle the subtype case.
3545 return DynamicTypeImpl.instance;
3546 }
3547 }
3463 } 3548 }
3464 3549
3465 class JSGenerator extends CodeGenerator { 3550 class JSGenerator extends CodeGenerator {
3466 final _extensionTypes = new HashSet<ClassElement>(); 3551 final _extensionTypes = new HashSet<ClassElement>();
3467 3552 final TypeProvider _types;
3468 JSGenerator(AbstractCompiler compiler) : super(compiler) { 3553 JSGenerator(AbstractCompiler compiler)
3554 : _types = compiler.context.typeProvider,
3555 super(compiler) {
3469 // TODO(jacobr): determine the the set of types with extension methods from 3556 // TODO(jacobr): determine the the set of types with extension methods from
3470 // the annotations rather than hard coding the list once the analyzer 3557 // the annotations rather than hard coding the list once the analyzer
3471 // supports summaries. 3558 // supports summaries.
3472 var context = compiler.context; 3559 var context = compiler.context;
3473 var src = context.sourceFactory.forUri('dart:_interceptors'); 3560 var src = context.sourceFactory.forUri('dart:_interceptors');
3474 var interceptors = context.computeLibraryElement(src); 3561 var interceptors = context.computeLibraryElement(src);
3475 for (var t in ['JSArray', 'JSString', 'JSNumber', 'JSBool']) { 3562 for (var t in ['JSArray', 'JSString', 'JSNumber', 'JSBool']) {
3476 _addExtensionType(interceptors.getType(t).type); 3563 _addExtensionType(interceptors.getType(t).type);
3477 } 3564 }
3478 // TODO(jmesserly): manually add `int` and `double` 3565 // TODO(jmesserly): manually add `int` and `double`
3479 // Unfortunately our current analyzer rejects "implements int". 3566 // Unfortunately our current analyzer rejects "implements int".
3480 // Fix was landed, so we can remove this hack once we're updated: 3567 // Fix was landed, so we can remove this hack once we're updated:
3481 // https://github.com/dart-lang/sdk/commit/d7cd11f86a02f55269fc8d9843e7758eb eeb81c8 3568 // https://github.com/dart-lang/sdk/commit/d7cd11f86a02f55269fc8d9843e7758eb eeb81c8
3482 _addExtensionType(context.typeProvider.intType); 3569 _addExtensionType(_types.intType);
3483 _addExtensionType(context.typeProvider.doubleType); 3570 _addExtensionType(_types.doubleType);
3484 } 3571 }
3485 3572
3486 void _addExtensionType(InterfaceType t) { 3573 void _addExtensionType(InterfaceType t) {
3487 if (t.isObject || !_extensionTypes.add(t.element)) return; 3574 if (t.isObject || !_extensionTypes.add(t.element)) return;
3488 t = fillDynamicTypeArgs(t, rules.provider) as InterfaceType; 3575 t = fillDynamicTypeArgs(t, _types) as InterfaceType;
3489 t.interfaces.forEach(_addExtensionType); 3576 t.interfaces.forEach(_addExtensionType);
3490 t.mixins.forEach(_addExtensionType); 3577 t.mixins.forEach(_addExtensionType);
3491 _addExtensionType(t.superclass); 3578 _addExtensionType(t.superclass);
3492 } 3579 }
3493 3580
3494 String generateLibrary(LibraryUnit unit) { 3581 String generateLibrary(LibraryUnit unit) {
3495 // Clone the AST first, so we can mutate it. 3582 // Clone the AST first, so we can mutate it.
3496 unit = unit.clone(); 3583 unit = unit.clone();
3497 var library = unit.library.element.library; 3584 var library = unit.library.element.library;
3498 var fields = findFieldsNeedingStorage(unit, _extensionTypes); 3585 var fields = findFieldsNeedingStorage(unit, _extensionTypes);
3586 var rules = new StrongTypeSystemImpl();
3499 var codegen = 3587 var codegen =
3500 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields); 3588 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields);
3501 var module = codegen.emitLibrary(unit); 3589 var module = codegen.emitLibrary(unit);
3502 var out = compiler.getOutputPath(library.source.uri); 3590 var out = compiler.getOutputPath(library.source.uri);
3503 return writeJsLibrary(module, out, 3591 return writeJsLibrary(module, out,
3504 emitSourceMaps: options.emitSourceMaps, 3592 emitSourceMaps: options.emitSourceMaps,
3505 arrowFnBindThisWorkaround: options.arrowFnBindThisWorkaround); 3593 arrowFnBindThisWorkaround: options.arrowFnBindThisWorkaround);
3506 } 3594 }
3507 } 3595 }
3508 3596
(...skipping 15 matching lines...) Expand all
3524 3612
3525 /// A special kind of element created by the compiler, signifying a temporary 3613 /// A special kind of element created by the compiler, signifying a temporary
3526 /// variable. These objects use instance equality, and should be shared 3614 /// variable. These objects use instance equality, and should be shared
3527 /// everywhere in the tree where they are treated as the same variable. 3615 /// everywhere in the tree where they are treated as the same variable.
3528 class TemporaryVariableElement extends LocalVariableElementImpl { 3616 class TemporaryVariableElement extends LocalVariableElementImpl {
3529 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3617 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3530 3618
3531 int get hashCode => identityHashCode(this); 3619 int get hashCode => identityHashCode(this);
3532 bool operator ==(Object other) => identical(this, other); 3620 bool operator ==(Object other) => identical(this, other);
3533 } 3621 }
OLDNEW
« no previous file with comments | « lib/src/codegen/code_generator.dart ('k') | lib/src/codegen/reify_coercions.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698