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

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

Issue 1958193002: optimize self-references in generic type definitions (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 7 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 | « no previous file | test/codegen/language/generic_self_reference_test.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 import 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max; 6 import 'dart:math' show min, max;
7 7
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 if (_isNumberInJS(from) && _isNumberInJS(to)) { 451 if (_isNumberInJS(from) && _isNumberInJS(to)) {
452 // Make sure to check when converting to int. 452 // Make sure to check when converting to int.
453 if (from != types.intType && to == types.intType) { 453 if (from != types.intType && to == types.intType) {
454 return js.call('dart.asInt(#)', [fromExpr]); 454 return js.call('dart.asInt(#)', [fromExpr]);
455 } 455 }
456 456
457 // A no-op in JavaScript. 457 // A no-op in JavaScript.
458 return fromExpr; 458 return fromExpr;
459 } 459 }
460 460
461 return js.call('dart.as(#, #)', [fromExpr, _emitTypeName(to)]); 461 return js.call('dart.as(#, #)', [fromExpr, _emitType(to)]);
462 } 462 }
463 463
464 @override 464 @override
465 visitIsExpression(IsExpression node) { 465 visitIsExpression(IsExpression node) {
466 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. 466 // Generate `is` as `dart.is` or `typeof` depending on the RHS type.
467 JS.Expression result; 467 JS.Expression result;
468 var type = node.type.type; 468 var type = node.type.type;
469 var lhs = _visit(node.expression); 469 var lhs = _visit(node.expression);
470 var typeofName = _jsTypeofName(type); 470 var typeofName = _jsTypeofName(type);
471 if (typeofName != null) { 471 if (typeofName != null) {
472 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); 472 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]);
473 } else { 473 } else {
474 // Always go through a runtime helper, because implicit interfaces. 474 // Always go through a runtime helper, because implicit interfaces.
475 result = js.call('dart.is(#, #)', [lhs, _emitTypeName(type)]); 475 result = js.call('dart.is(#, #)', [lhs, _emitType(type)]);
476 } 476 }
477 477
478 if (node.notOperator != null) { 478 if (node.notOperator != null) {
479 return js.call('!#', result); 479 return js.call('!#', result);
480 } 480 }
481 return result; 481 return result;
482 } 482 }
483 483
484 String _jsTypeofName(DartType t) { 484 String _jsTypeofName(DartType t) {
485 if (_isNumberInJS(t)) return 'number'; 485 if (_isNumberInJS(t)) return 'number';
486 if (t == types.stringType) return 'string'; 486 if (t == types.stringType) return 'string';
487 if (t == types.boolType) return 'boolean'; 487 if (t == types.boolType) return 'boolean';
488 return null; 488 return null;
489 } 489 }
490 490
491 @override 491 @override
492 visitFunctionTypeAlias(FunctionTypeAlias node) { 492 visitFunctionTypeAlias(FunctionTypeAlias node) {
493 FunctionTypeAliasElement element = node.element; 493 FunctionTypeAliasElement element = node.element;
494 494
495 JS.Expression body = annotate( 495 JS.Expression body = annotate(
496 js.call('dart.typedef(#, () => #)', [ 496 js.call('dart.typedef(#, () => #)', [
497 js.string(element.name, "'"), 497 js.string(element.name, "'"),
498 _emitTypeName(element.type, lowerTypedef: true) 498 _emitType(element.type, lowerTypedef: true)
499 ]), 499 ]),
500 node, 500 node,
501 element); 501 element);
502 502
503 var typeFormals = element.typeParameters; 503 var typeFormals = element.typeParameters;
504 if (typeFormals.isNotEmpty) { 504 if (typeFormals.isNotEmpty) {
505 return _defineClassTypeArguments(element, typeFormals, 505 return _defineClassTypeArguments(element, typeFormals,
506 js.statement('const # = #;', [element.name, body])); 506 js.statement('const # = #;', [element.name, body]));
507 } else { 507 } else {
508 return js.statement('# = #;', [_emitTopLevelName(element), body]); 508 return js.statement('# = #;', [_emitTopLevelName(element), body]);
509 } 509 }
510 } 510 }
511 511
512 @override 512 @override
513 JS.Expression visitTypeName(TypeName node) { 513 JS.Expression visitTypeName(TypeName node) {
514 // TODO(jmesserly): should only happen for erroneous code. 514 // TODO(jmesserly): should only happen for erroneous code.
515 if (node.type == null) return js.call('dart.dynamic'); 515 if (node.type == null) return js.call('dart.dynamic');
516 return _emitTypeName(node.type); 516 return _emitType(node.type);
517 } 517 }
518 518
519 @override 519 @override
520 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { 520 JS.Statement visitClassTypeAlias(ClassTypeAlias node) {
521 ClassElement element = node.element; 521 ClassElement element = node.element;
522 522
523 // Forward all generative constructors from the base class. 523 // Forward all generative constructors from the base class.
524 var methods = <JS.Method>[]; 524 var methods = <JS.Method>[];
525 525
526 var supertype = element.supertype; 526 var supertype = element.supertype;
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 // Create static fields for each enum value 734 // Create static fields for each enum value
735 for (var i = 0; i < fields.length; ++i) { 735 for (var i = 0; i < fields.length; ++i) {
736 result.add(js.statement('#.# = dart.const(new #(#));', 736 result.add(js.statement('#.# = dart.const(new #(#));',
737 [id, fields[i].name, id, js.number(i)])); 737 [id, fields[i].name, id, js.number(i)]));
738 } 738 }
739 739
740 // Create static values list 740 // Create static values list
741 var values = new JS.ArrayInitializer(new List<JS.Expression>.from( 741 var values = new JS.ArrayInitializer(new List<JS.Expression>.from(
742 fields.map((f) => js.call('#.#', [id, f.name])))); 742 fields.map((f) => js.call('#.#', [id, f.name]))));
743 result.add(js.statement('#.values = dart.const(dart.list(#, #));', 743 result.add(js.statement('#.values = dart.const(dart.list(#, #));',
744 [id, values, _emitTypeName(type)])); 744 [id, values, _emitType(type)]));
745 745
746 return _statement(result); 746 return _statement(result);
747 } 747 }
748 748
749 /// Wraps a possibly generic class in its type arguments. 749 /// Wraps a possibly generic class in its type arguments.
750 JS.Statement _defineClassTypeArguments(TypeDefiningElement element, 750 JS.Statement _defineClassTypeArguments(TypeDefiningElement element,
751 List<TypeParameterElement> formals, JS.Statement body) { 751 List<TypeParameterElement> formals, JS.Statement body) {
752 assert(formals.isNotEmpty); 752 assert(formals.isNotEmpty);
753 var genericDef = 753 var genericDef =
754 js.statement('# = dart.generic((#) => { #; return #; });', [ 754 js.statement('# = dart.generic((#) => { #; return #; });', [
755 _emitTopLevelName(element, suffix: r'$'), 755 _emitTopLevelName(element, suffix: r'$'),
756 _emitTypeFormals(formals), 756 _emitTypeFormals(formals),
757 body, 757 body,
758 element.name 758 element.name
759 ]); 759 ]);
760 760
761 var dynType = fillDynamicTypeArgs(element.type); 761 var dynType = fillDynamicTypeArgs(element.type);
762 var genericInst = _emitTypeName(dynType, lowerGeneric: true); 762 var genericInst = _emitType(dynType, lowerGeneric: true);
763 return js.statement( 763 return js.statement(
764 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]); 764 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]);
765 } 765 }
766 766
767 bool _deferIfNeeded(DartType type, ClassElement current) { 767 bool _deferIfNeeded(DartType type, ClassElement current) {
768 if (type is ParameterizedType) { 768 if (type is ParameterizedType) {
769 var typeArguments = type.typeArguments; 769 var typeArguments = type.typeArguments;
770 for (var typeArg in typeArguments) { 770 for (var typeArg in typeArguments) {
771 var typeElement = typeArg.element; 771 var typeElement = typeArg.element;
772 // FIXME(vsm): This does not track mutual recursive dependences. 772 // FIXME(vsm): This does not track mutual recursive dependences.
(...skipping 24 matching lines...) Expand all
797 _loader.startTopLevel(element); 797 _loader.startTopLevel(element);
798 798
799 // Find the super type 799 // Find the super type
800 JS.Expression heritage; 800 JS.Expression heritage;
801 var supertype = type.superclass; 801 var supertype = type.superclass;
802 if (_deferIfNeeded(supertype, element)) { 802 if (_deferIfNeeded(supertype, element)) {
803 // Fall back to raw type. 803 // Fall back to raw type.
804 supertype = fillDynamicTypeArgs(supertype.element.type); 804 supertype = fillDynamicTypeArgs(supertype.element.type);
805 _hasDeferredSupertype.add(element); 805 _hasDeferredSupertype.add(element);
806 } 806 }
807 heritage = _emitTypeName(supertype); 807 heritage = _emitType(supertype);
808 808
809 if (type.mixins.isNotEmpty) { 809 if (type.mixins.isNotEmpty) {
810 var mixins = type.mixins.map(_emitTypeName).toList(); 810 var mixins = type.mixins.map(_emitType).toList();
811 mixins.insert(0, heritage); 811 mixins.insert(0, heritage);
812 heritage = js.call('dart.mixin(#)', [mixins]); 812 heritage = js.call('dart.mixin(#)', [mixins]);
813 } 813 }
814 814
815 _loader.finishTopLevel(element); 815 _loader.finishTopLevel(element);
816 816
817 return heritage; 817 return heritage;
818 } 818 }
819 819
820 /// Provide Dart getters and setters that forward to the underlying native 820 /// Provide Dart getters and setters that forward to the underlying native
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
1044 } 1044 }
1045 1045
1046 void _setBaseClass(ClassElement classElem, JS.Expression className, 1046 void _setBaseClass(ClassElement classElem, JS.Expression className,
1047 List<JS.Statement> body) { 1047 List<JS.Statement> body) {
1048 String jsPeerName = _getJSPeerName(classElem); 1048 String jsPeerName = _getJSPeerName(classElem);
1049 JS.Expression newBaseClass; 1049 JS.Expression newBaseClass;
1050 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { 1050 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) {
1051 // TODO(jmesserly): we should really just extend Array in the first place. 1051 // TODO(jmesserly): we should really just extend Array in the first place.
1052 newBaseClass = js.call('dart.global.#', [jsPeerName]); 1052 newBaseClass = js.call('dart.global.#', [jsPeerName]);
1053 } else if (_hasDeferredSupertype.contains(classElem)) { 1053 } else if (_hasDeferredSupertype.contains(classElem)) {
1054 newBaseClass = _emitTypeName(classElem.type.superclass); 1054 newBaseClass = _emitType(classElem.type.superclass,
1055 subClass: classElem, className: className);
1055 } 1056 }
1056 if (newBaseClass != null) { 1057 if (newBaseClass != null) {
1057 body.add( 1058 body.add(
1058 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); 1059 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass]));
1059 } 1060 }
1060 } 1061 }
1061 1062
1062 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, 1063 void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
1063 List<JS.Statement> body, JS.Expression className) { 1064 List<JS.Statement> body, JS.Expression className) {
1064 for (ConstructorDeclaration member in ctors) { 1065 for (ConstructorDeclaration member in ctors) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 List<MethodDeclaration> methods, 1130 List<MethodDeclaration> methods,
1130 ClassElement classElem, 1131 ClassElement classElem,
1131 List<ConstructorDeclaration> ctors, 1132 List<ConstructorDeclaration> ctors,
1132 List<ExecutableElement> extensions, 1133 List<ExecutableElement> extensions,
1133 JS.Expression className, 1134 JS.Expression className,
1134 List<JS.Statement> body) { 1135 List<JS.Statement> body) {
1135 if (classElem.interfaces.isNotEmpty) { 1136 if (classElem.interfaces.isNotEmpty) {
1136 body.add(js.statement('#[dart.implements] = () => #;', [ 1137 body.add(js.statement('#[dart.implements] = () => #;', [
1137 className, 1138 className,
1138 new JS.ArrayInitializer(new List<JS.Expression>.from( 1139 new JS.ArrayInitializer(new List<JS.Expression>.from(
1139 classElem.interfaces.map(_emitTypeName))) 1140 classElem.interfaces.map(_emitType)))
1140 ])); 1141 ]));
1141 } 1142 }
1142 1143
1143 var tStatics = <JS.Property>[]; 1144 var tStatics = <JS.Property>[];
1144 var tMethods = <JS.Property>[]; 1145 var tMethods = <JS.Property>[];
1145 var sNames = <JS.Expression>[]; 1146 var sNames = <JS.Expression>[];
1146 for (MethodDeclaration node in methods) { 1147 for (MethodDeclaration node in methods) {
1147 if (!(node.isSetter || node.isGetter || node.isAbstract)) { 1148 if (!(node.isSetter || node.isGetter || node.isAbstract)) {
1148 var name = node.name.name; 1149 var name = node.name.name;
1149 var element = node.element; 1150 var element = node.element;
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after
1601 body.add(js.statement('if (# === void 0) # = #;', 1602 body.add(js.statement('if (# === void 0) # = #;',
1602 [jsParam, jsParam, _defaultParamValue(param)])); 1603 [jsParam, jsParam, _defaultParamValue(param)]));
1603 } 1604 }
1604 } 1605 }
1605 1606
1606 // TODO(jmesserly): various problems here, see: 1607 // TODO(jmesserly): various problems here, see:
1607 // https://github.com/dart-lang/dev_compiler/issues/161 1608 // https://github.com/dart-lang/dev_compiler/issues/161
1608 var paramType = param.element.type; 1609 var paramType = param.element.type;
1609 if (!constructor && _hasUnsoundTypeParameter(paramType)) { 1610 if (!constructor && _hasUnsoundTypeParameter(paramType)) {
1610 body.add(js 1611 body.add(js
1611 .statement('dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); 1612 .statement('dart.as(#, #);', [jsParam, _emitType(paramType)]));
1612 } 1613 }
1613 } 1614 }
1614 return body.isEmpty ? null : _statement(body); 1615 return body.isEmpty ? null : _statement(body);
1615 } 1616 }
1616 1617
1617 bool _isUnsoundTypeParameter(DartType t) => 1618 bool _isUnsoundTypeParameter(DartType t) =>
1618 t is TypeParameterType && t.element.enclosingElement is ClassElement; 1619 t is TypeParameterType && t.element.enclosingElement is ClassElement;
1619 1620
1620 bool _hasUnsoundTypeParameter(DartType t) => 1621 bool _hasUnsoundTypeParameter(DartType t) =>
1621 _isUnsoundTypeParameter(t) || 1622 _isUnsoundTypeParameter(t) ||
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
1982 _superAllowed = savedSuperAllowed; 1983 _superAllowed = savedSuperAllowed;
1983 _asyncStarController = savedController; 1984 _asyncStarController = savedController;
1984 1985
1985 DartType returnType = _getExpectedReturnType(element); 1986 DartType returnType = _getExpectedReturnType(element);
1986 JS.Expression gen = new JS.Fun(jsParams, jsBody, 1987 JS.Expression gen = new JS.Fun(jsParams, jsBody,
1987 isGenerator: true, returnType: emitTypeRef(returnType)); 1988 isGenerator: true, returnType: emitTypeRef(returnType));
1988 if (JS.This.foundIn(gen)) { 1989 if (JS.This.foundIn(gen)) {
1989 gen = js.call('#.bind(this)', gen); 1990 gen = js.call('#.bind(this)', gen);
1990 } 1991 }
1991 1992
1992 var T = _emitTypeName(returnType); 1993 var T = _emitType(returnType);
1993 return js.call('dart.#(#)', [ 1994 return js.call('dart.#(#)', [
1994 kind, 1995 kind,
1995 [gen, T]..addAll(visitFormalParameterList(parameters, destructure: false)) 1996 [gen, T]..addAll(visitFormalParameterList(parameters, destructure: false))
1996 ]); 1997 ]);
1997 } 1998 }
1998 1999
1999 @override 2000 @override
2000 JS.Statement visitFunctionDeclarationStatement( 2001 JS.Statement visitFunctionDeclarationStatement(
2001 FunctionDeclarationStatement node) { 2002 FunctionDeclarationStatement node) {
2002 var func = node.functionDeclaration; 2003 var func = node.functionDeclaration;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
2045 2046
2046 // Get the original declaring element. If we had a property accessor, this 2047 // Get the original declaring element. If we had a property accessor, this
2047 // indirects back to a (possibly synthetic) field. 2048 // indirects back to a (possibly synthetic) field.
2048 var element = accessor; 2049 var element = accessor;
2049 if (accessor is PropertyAccessorElement) element = accessor.variable; 2050 if (accessor is PropertyAccessorElement) element = accessor.variable;
2050 2051
2051 _loader.declareBeforeUse(element); 2052 _loader.declareBeforeUse(element);
2052 2053
2053 // type literal 2054 // type literal
2054 if (element is TypeDefiningElement) { 2055 if (element is TypeDefiningElement) {
2055 var typeName = _emitTypeName(fillDynamicTypeArgs(element.type)); 2056 var typeName = _emitType(fillDynamicTypeArgs(element.type));
2056 2057
2057 // If the type is a type literal expression in Dart code, wrap the raw 2058 // If the type is a type literal expression in Dart code, wrap the raw
2058 // runtime type in a "Type" instance. 2059 // runtime type in a "Type" instance.
2059 if (!_isInForeignJS && _isTypeLiteral(node)) { 2060 if (!_isInForeignJS && _isTypeLiteral(node)) {
2060 typeName = js.call('dart.wrapType(#)', typeName); 2061 typeName = js.call('dart.wrapType(#)', typeName);
2061 } 2062 }
2062 2063
2063 return typeName; 2064 return typeName;
2064 } 2065 }
2065 2066
2066 // library member 2067 // library member
2067 if (element.enclosingElement is CompilationUnitElement) { 2068 if (element.enclosingElement is CompilationUnitElement) {
2068 return _emitTopLevelName(element); 2069 return _emitTopLevelName(element);
2069 } 2070 }
2070 2071
2071 var name = element.name; 2072 var name = element.name;
2072 2073
2073 // Unqualified class member. This could mean implicit-this, or implicit 2074 // Unqualified class member. This could mean implicit-this, or implicit
2074 // call to a static from the same class. 2075 // call to a static from the same class.
2075 if (element is ClassMemberElement && element is! ConstructorElement) { 2076 if (element is ClassMemberElement && element is! ConstructorElement) {
2076 bool isStatic = element.isStatic; 2077 bool isStatic = element.isStatic;
2077 var type = element.enclosingElement.type; 2078 var type = element.enclosingElement.type;
2078 var member = _emitMemberName(name, isStatic: isStatic, type: type); 2079 var member = _emitMemberName(name, isStatic: isStatic, type: type);
2079 2080
2080 // For static methods, we add the raw type name, without generics or 2081 // For static methods, we add the raw type name, without generics or
2081 // library prefix. We don't need those because static calls can't use 2082 // library prefix. We don't need those because static calls can't use
2082 // the generic type. 2083 // the generic type.
2083 if (isStatic) { 2084 if (isStatic) {
2084 var dynType = _emitTypeName(fillDynamicTypeArgs(type)); 2085 var dynType = _emitType(fillDynamicTypeArgs(type));
2085 return new JS.PropertyAccess(dynType, member); 2086 return new JS.PropertyAccess(dynType, member);
2086 } 2087 }
2087 2088
2088 // For instance members, we add implicit-this. 2089 // For instance members, we add implicit-this.
2089 // For method tear-offs, we ensure it's a bound method. 2090 // For method tear-offs, we ensure it's a bound method.
2090 var tearOff = element is MethodElement && !inInvocationContext(node); 2091 var tearOff = element is MethodElement && !inInvocationContext(node);
2091 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#'; 2092 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#';
2092 return js.call(code, member); 2093 return js.call(code, member);
2093 } 2094 }
2094 2095
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
2150 (p is NormalFormalParameter) 2151 (p is NormalFormalParameter)
2151 ? p.metadata 2152 ? p.metadata
2152 : (p as DefaultFormalParameter).parameter.metadata; 2153 : (p as DefaultFormalParameter).parameter.metadata;
2153 2154
2154 JS.ArrayInitializer _emitTypeNames(List<DartType> types, 2155 JS.ArrayInitializer _emitTypeNames(List<DartType> types,
2155 [List<FormalParameter> parameters]) { 2156 [List<FormalParameter> parameters]) {
2156 var result = <JS.Expression>[]; 2157 var result = <JS.Expression>[];
2157 for (int i = 0; i < types.length; ++i) { 2158 for (int i = 0; i < types.length; ++i) {
2158 var metadata = 2159 var metadata =
2159 parameters != null ? _parameterMetadata(parameters[i]) : []; 2160 parameters != null ? _parameterMetadata(parameters[i]) : [];
2160 var typeName = _emitTypeName(types[i]); 2161 var typeName = _emitType(types[i]);
2161 var value = typeName; 2162 var value = typeName;
2162 // TODO(vsm): Make this optional per #268. 2163 // TODO(vsm): Make this optional per #268.
2163 if (metadata.isNotEmpty) { 2164 if (metadata.isNotEmpty) {
2164 metadata = metadata.map(_instantiateAnnotation).toList(); 2165 metadata = metadata.map(_instantiateAnnotation).toList();
2165 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); 2166 value = new JS.ArrayInitializer([typeName]..addAll(metadata));
2166 } 2167 }
2167 result.add(value); 2168 result.add(value);
2168 } 2169 }
2169 return new JS.ArrayInitializer(result); 2170 return new JS.ArrayInitializer(result);
2170 } 2171 }
2171 2172
2172 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { 2173 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) {
2173 var properties = <JS.Property>[]; 2174 var properties = <JS.Property>[];
2174 types.forEach((name, type) { 2175 types.forEach((name, type) {
2175 var key = _propertyName(name); 2176 var key = _propertyName(name);
2176 var value = _emitTypeName(type); 2177 var value = _emitType(type);
2177 properties.add(new JS.Property(key, value)); 2178 properties.add(new JS.Property(key, value));
2178 }); 2179 });
2179 return new JS.ObjectInitializer(properties); 2180 return new JS.ObjectInitializer(properties);
2180 } 2181 }
2181 2182
2182 /// Emit the pieces of a function type, as an array of return type, 2183 /// Emit the pieces of a function type, as an array of return type,
2183 /// regular args, and optional/named args. 2184 /// regular args, and optional/named args.
2184 List<JS.Expression> _emitFunctionTypeParts(FunctionType type, 2185 List<JS.Expression> _emitFunctionTypeParts(FunctionType type,
2185 {List<FormalParameter> parameters, bool lowerTypedef: false}) { 2186 {List<FormalParameter> parameters, bool lowerTypedef: false}) {
2186 var parameterTypes = type.normalParameterTypes; 2187 var parameterTypes = type.normalParameterTypes;
2187 var optionalTypes = type.optionalParameterTypes; 2188 var optionalTypes = type.optionalParameterTypes;
2188 var namedTypes = type.namedParameterTypes; 2189 var namedTypes = type.namedParameterTypes;
2189 var rt = _emitTypeName(type.returnType); 2190 var rt = _emitType(type.returnType);
2190 var ra = _emitTypeNames(parameterTypes, parameters); 2191 var ra = _emitTypeNames(parameterTypes, parameters);
2191 2192
2192 List<JS.Expression> typeParts; 2193 List<JS.Expression> typeParts;
2193 if (namedTypes.isNotEmpty) { 2194 if (namedTypes.isNotEmpty) {
2194 assert(optionalTypes.isEmpty); 2195 assert(optionalTypes.isEmpty);
2195 // TODO(vsm): Pass in annotations here as well. 2196 // TODO(vsm): Pass in annotations here as well.
2196 var na = _emitTypeProperties(namedTypes); 2197 var na = _emitTypeProperties(namedTypes);
2197 typeParts = [rt, ra, na]; 2198 typeParts = [rt, ra, na];
2198 } else if (optionalTypes.isNotEmpty) { 2199 } else if (optionalTypes.isNotEmpty) {
2199 assert(namedTypes.isEmpty); 2200 assert(namedTypes.isEmpty);
(...skipping 14 matching lines...) Expand all
2214 } 2215 }
2215 return typeParts; 2216 return typeParts;
2216 } 2217 }
2217 2218
2218 /// Emits a Dart [type] into code. 2219 /// Emits a Dart [type] into code.
2219 /// 2220 ///
2220 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a 2221 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a
2221 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form 2222 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form
2222 /// will be used instead of `List`. These flags are used when generating 2223 /// will be used instead of `List`. These flags are used when generating
2223 /// the definitions for typedefs and generic types, respectively. 2224 /// the definitions for typedefs and generic types, respectively.
2224 JS.Expression _emitTypeName(DartType type, 2225 ///
2225 {bool lowerTypedef: false, bool lowerGeneric: false}) { 2226 /// If [subClass] is set, then we are setting the base class for the given
2227 /// class and should emit the given [className], which will already be
2228 /// defined.
2229 JS.Expression _emitType(DartType type,
2230 {bool lowerTypedef: false,
2231 bool lowerGeneric: false,
2232 ClassElement subClass,
2233 JS.Expression className}) {
2226 // The void and dynamic types are not defined in core. 2234 // The void and dynamic types are not defined in core.
2227 if (type.isVoid) { 2235 if (type.isVoid) {
2228 return js.call('dart.void'); 2236 return js.call('dart.void');
2229 } else if (type.isDynamic) { 2237 } else if (type.isDynamic) {
2230 return js.call('dart.dynamic'); 2238 return js.call('dart.dynamic');
2231 } else if (type.isBottom) { 2239 } else if (type.isBottom) {
2232 return js.call('dart.bottom'); 2240 return js.call('dart.bottom');
2233 } 2241 }
2234 2242
2235 _loader.declareBeforeUse(type.element); 2243 _loader.declareBeforeUse(type.element);
2236 2244
2237 // TODO(jmesserly): like constants, should we hoist function types out of 2245 // TODO(jmesserly): like constants, should we hoist function types out of
2238 // methods? Similar issue with generic types. For all of these, we may want 2246 // methods? Similar issue with generic types. For all of these, we may want
2239 // to canonicalize them too, at least when inside the same library. 2247 // to canonicalize them too, at least when inside the same library.
2240 var name = type.name; 2248 var name = type.name;
2241 var element = type.element; 2249 var element = type.element;
2242 if (name == '' || name == null || lowerTypedef) { 2250 if (name == '' || name == null || lowerTypedef) {
2243 // TODO(jmesserly): should we change how typedefs work? They currently 2251 // TODO(jmesserly): should we change how typedefs work? They currently
2244 // go through use similar logic as generic classes. This makes them 2252 // go through use similar logic as generic classes. This makes them
2245 // different from universal function types. 2253 // different from universal function types.
2246 var ft = type as FunctionType; 2254 var ft = type as FunctionType;
2247 var parts = _emitFunctionTypeParts(ft, lowerTypedef: lowerTypedef); 2255 var parts = _emitFunctionTypeParts(ft, lowerTypedef: lowerTypedef);
2248 return js.call('dart.functionType(#)', [parts]); 2256 return js.call('dart.functionType(#)', [parts]);
2249 } 2257 }
2250 2258
2251 if (type is TypeParameterType) { 2259 if (type is TypeParameterType) {
2252 return new JS.Identifier(name); 2260 return new JS.Identifier(name);
2253 } 2261 }
2254 2262
2263 if (type == subClass?.type) {
2264 return className;
2265 }
2266
2255 if (type is ParameterizedType) { 2267 if (type is ParameterizedType) {
2256 var args = type.typeArguments; 2268 var args = type.typeArguments;
2257 Iterable jsArgs = null; 2269 Iterable jsArgs = null;
2258 if (args.any((a) => !a.isDynamic)) { 2270 if (args.any((a) => !a.isDynamic)) {
2259 jsArgs = args.map(_emitTypeName); 2271 jsArgs = args.map(
2272 (x) => _emitType(x, subClass: subClass, className: className));
2260 } else if (lowerGeneric) { 2273 } else if (lowerGeneric) {
2261 jsArgs = []; 2274 jsArgs = [];
2262 } 2275 }
2263 if (jsArgs != null) { 2276 if (jsArgs != null) {
2264 var genericName = _emitTopLevelName(element, suffix: '\$'); 2277 var genericName = _emitTopLevelName(element, suffix: '\$');
2265 return js.call('#(#)', [genericName, jsArgs]); 2278 return js.call('#(#)', [genericName, jsArgs]);
2266 } 2279 }
2267 } 2280 }
2268 2281
2269 return _emitTopLevelName(element); 2282 return _emitTopLevelName(element);
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
2530 2543
2531 /// If `g` is a generic function type, and `f` is an instantiation of it, 2544 /// If `g` is a generic function type, and `f` is an instantiation of it,
2532 /// then this will return the type arguments to apply, otherwise null. 2545 /// then this will return the type arguments to apply, otherwise null.
2533 List<JS.Expression> _emitFunctionTypeArguments(DartType g, DartType f, 2546 List<JS.Expression> _emitFunctionTypeArguments(DartType g, DartType f,
2534 [TypeArgumentList typeArgs]) { 2547 [TypeArgumentList typeArgs]) {
2535 if (g is FunctionType && 2548 if (g is FunctionType &&
2536 g.typeFormals.isNotEmpty && 2549 g.typeFormals.isNotEmpty &&
2537 f is FunctionType && 2550 f is FunctionType &&
2538 f.typeFormals.isEmpty) { 2551 f.typeFormals.isEmpty) {
2539 return _recoverTypeArguments(g, f) 2552 return _recoverTypeArguments(g, f)
2540 .map(_emitTypeName) 2553 .map(_emitType)
2541 .toList(growable: false); 2554 .toList(growable: false);
2542 } else if (typeArgs != null) { 2555 } else if (typeArgs != null) {
2543 // Dynamic calls may have type arguments, even though the function types 2556 // Dynamic calls may have type arguments, even though the function types
2544 // are not known. 2557 // are not known.
2545 // TODO(jmesserly): seems to be mostly broken in Analyzer at the moment: 2558 // TODO(jmesserly): seems to be mostly broken in Analyzer at the moment:
2546 // https://github.com/dart-lang/sdk/issues/26368 2559 // https://github.com/dart-lang/sdk/issues/26368
2547 return typeArgs.arguments.map(visitTypeName).toList(growable: false); 2560 return typeArgs.arguments.map(visitTypeName).toList(growable: false);
2548 } 2561 }
2549 return null; 2562 return null;
2550 } 2563 }
(...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after
2972 if (parent is ClassElement) { 2985 if (parent is ClassElement) {
2973 return getter 2986 return getter
2974 ? parent.getGetter(element.name) 2987 ? parent.getGetter(element.name)
2975 : parent.getSetter(element.name); 2988 : parent.getSetter(element.name);
2976 } 2989 }
2977 return null; 2990 return null;
2978 } 2991 }
2979 2992
2980 JS.Expression _emitConstructorName( 2993 JS.Expression _emitConstructorName(
2981 ConstructorElement element, DartType type, SimpleIdentifier name) { 2994 ConstructorElement element, DartType type, SimpleIdentifier name) {
2982 var typeName = _emitTypeName(type); 2995 var typeName = _emitType(type);
2983 if (name != null || element.isFactory) { 2996 if (name != null || element.isFactory) {
2984 var namedCtor = _constructorName(element); 2997 var namedCtor = _constructorName(element);
2985 return new JS.PropertyAccess(typeName, namedCtor); 2998 return new JS.PropertyAccess(typeName, namedCtor);
2986 } 2999 }
2987 return typeName; 3000 return typeName;
2988 } 3001 }
2989 3002
2990 @override 3003 @override
2991 visitConstructorName(ConstructorName node) { 3004 visitConstructorName(ConstructorName node) {
2992 return _emitConstructorName(node.staticElement, node.type.type, node.name); 3005 return _emitConstructorName(node.staticElement, node.type.type, node.name);
2993 } 3006 }
2994 3007
2995 JS.Expression _emitInstanceCreationExpression( 3008 JS.Expression _emitInstanceCreationExpression(
2996 ConstructorElement element, 3009 ConstructorElement element,
2997 DartType type, 3010 DartType type,
2998 SimpleIdentifier name, 3011 SimpleIdentifier name,
2999 ArgumentList argumentList, 3012 ArgumentList argumentList,
3000 bool isConst) { 3013 bool isConst) {
3001 JS.Expression emitNew() { 3014 JS.Expression emitNew() {
3002 JS.Expression ctor; 3015 JS.Expression ctor;
3003 bool isFactory = false; 3016 bool isFactory = false;
3004 // var element = node.staticElement; 3017 // var element = node.staticElement;
3005 if (element == null) { 3018 if (element == null) {
3006 // TODO(jmesserly): this only happens if we had a static error. 3019 // TODO(jmesserly): this only happens if we had a static error.
3007 // Should we generate a throw instead? 3020 // Should we generate a throw instead?
3008 ctor = _emitTypeName(type); 3021 ctor = _emitType(type);
3009 if (name != null) { 3022 if (name != null) {
3010 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name)); 3023 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name));
3011 } 3024 }
3012 } else { 3025 } else {
3013 ctor = _emitConstructorName(element, type, name); 3026 ctor = _emitConstructorName(element, type, name);
3014 isFactory = element.isFactory; 3027 isFactory = element.isFactory;
3015 } 3028 }
3016 var args = _visit(argumentList) as List<JS.Expression>; 3029 var args = _visit(argumentList) as List<JS.Expression>;
3017 return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args); 3030 return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args);
3018 } 3031 }
(...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after
3924 var then = visitCatchClause(clause); 3937 var then = visitCatchClause(clause);
3925 3938
3926 // Discard following clauses, if any, as they are unreachable. 3939 // Discard following clauses, if any, as they are unreachable.
3927 if (clause.exceptionType == null) return then; 3940 if (clause.exceptionType == null) return then;
3928 3941
3929 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which 3942 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which
3930 // has special case for typeof. 3943 // has special case for typeof.
3931 return new JS.If( 3944 return new JS.If(
3932 js.call('dart.is(#, #)', [ 3945 js.call('dart.is(#, #)', [
3933 _visit(_catchParameter), 3946 _visit(_catchParameter),
3934 _emitTypeName(clause.exceptionType.type), 3947 _emitType(clause.exceptionType.type),
3935 ]), 3948 ]),
3936 then, 3949 then,
3937 otherwise); 3950 otherwise);
3938 } 3951 }
3939 3952
3940 JS.Statement _statement(List<JS.Statement> statements) { 3953 JS.Statement _statement(List<JS.Statement> statements) {
3941 // TODO(jmesserly): empty block singleton? 3954 // TODO(jmesserly): empty block singleton?
3942 if (statements.length == 0) return new JS.Block([]); 3955 if (statements.length == 0) return new JS.Block([]);
3943 if (statements.length == 1) return statements[0]; 3956 if (statements.length == 1) return statements[0];
3944 return new JS.Block(statements); 3957 return new JS.Block(statements);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
4014 4027
4015 @override 4028 @override
4016 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); 4029 visitNullLiteral(NullLiteral node) => new JS.LiteralNull();
4017 4030
4018 @override 4031 @override
4019 visitSymbolLiteral(SymbolLiteral node) { 4032 visitSymbolLiteral(SymbolLiteral node) {
4020 JS.Expression emitSymbol() { 4033 JS.Expression emitSymbol() {
4021 // TODO(vsm): When we canonicalize, we need to treat private symbols 4034 // TODO(vsm): When we canonicalize, we need to treat private symbols
4022 // correctly. 4035 // correctly.
4023 var name = js.string(node.components.join('.'), "'"); 4036 var name = js.string(node.components.join('.'), "'");
4024 return js.call('#.new(#)', [_emitTypeName(types.symbolType), name]); 4037 return js.call('#.new(#)', [_emitType(types.symbolType), name]);
4025 } 4038 }
4026 return _emitConst(emitSymbol); 4039 return _emitConst(emitSymbol);
4027 } 4040 }
4028 4041
4029 @override 4042 @override
4030 visitListLiteral(ListLiteral node) { 4043 visitListLiteral(ListLiteral node) {
4031 JS.Expression emitList() { 4044 JS.Expression emitList() {
4032 JS.Expression list = new JS.ArrayInitializer( 4045 JS.Expression list = new JS.ArrayInitializer(
4033 _visitList(node.elements) as List<JS.Expression>); 4046 _visitList(node.elements) as List<JS.Expression>);
4034 ParameterizedType type = node.staticType; 4047 ParameterizedType type = node.staticType;
4035 var elementType = type.typeArguments.single; 4048 var elementType = type.typeArguments.single;
4036 // TODO(jmesserly): analyzer will usually infer `List<Object>` because 4049 // TODO(jmesserly): analyzer will usually infer `List<Object>` because
4037 // that is the least upper bound of the element types. So we rarely 4050 // that is the least upper bound of the element types. So we rarely
4038 // generate a plain `List<dynamic>` anymore. 4051 // generate a plain `List<dynamic>` anymore.
4039 if (!elementType.isDynamic) { 4052 if (!elementType.isDynamic) {
4040 // dart.list helper internally depends on _interceptors.JSArray. 4053 // dart.list helper internally depends on _interceptors.JSArray.
4041 _loader.declareBeforeUse(_jsArray); 4054 _loader.declareBeforeUse(_jsArray);
4042 list = js.call('dart.list(#, #)', [list, _emitTypeName(elementType)]); 4055 list = js.call('dart.list(#, #)', [list, _emitType(elementType)]);
4043 } 4056 }
4044 return list; 4057 return list;
4045 } 4058 }
4046 if (node.constKeyword != null) return _emitConst(emitList); 4059 if (node.constKeyword != null) return _emitConst(emitList);
4047 return emitList(); 4060 return emitList();
4048 } 4061 }
4049 4062
4050 @override 4063 @override
4051 visitMapLiteral(MapLiteral node) { 4064 visitMapLiteral(MapLiteral node) {
4052 // TODO(jmesserly): we can likely make these faster. 4065 // TODO(jmesserly): we can likely make these faster.
(...skipping 15 matching lines...) Expand all
4068 } else { 4081 } else {
4069 var values = <JS.Expression>[]; 4082 var values = <JS.Expression>[];
4070 for (var e in entries) { 4083 for (var e in entries) {
4071 values.add(_visit(e.key)); 4084 values.add(_visit(e.key));
4072 values.add(_visit(e.value)); 4085 values.add(_visit(e.value));
4073 } 4086 }
4074 mapArguments = new JS.ArrayInitializer(values); 4087 mapArguments = new JS.ArrayInitializer(values);
4075 } 4088 }
4076 var types = <JS.Expression>[]; 4089 var types = <JS.Expression>[];
4077 if (typeArgs != null) { 4090 if (typeArgs != null) {
4078 types.addAll(typeArgs.arguments.map((e) => _emitTypeName(e.type))); 4091 types.addAll(typeArgs.arguments.map((e) => _emitType(e.type)));
4079 } 4092 }
4080 return js.call('dart.map(#, #)', [mapArguments, types]); 4093 return js.call('dart.map(#, #)', [mapArguments, types]);
4081 } 4094 }
4082 if (node.constKeyword != null) return _emitConst(emitMap); 4095 if (node.constKeyword != null) return _emitConst(emitMap);
4083 return emitMap(); 4096 return emitMap();
4084 } 4097 }
4085 4098
4086 @override 4099 @override
4087 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) => 4100 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) =>
4088 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"'); 4101 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"');
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
4394 } 4407 }
4395 4408
4396 bool isLibraryPrefix(Expression node) => 4409 bool isLibraryPrefix(Expression node) =>
4397 node is SimpleIdentifier && node.staticElement is PrefixElement; 4410 node is SimpleIdentifier && node.staticElement is PrefixElement;
4398 4411
4399 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4412 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
4400 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4413 c.computeLibraryElement(c.sourceFactory.forUri(uri));
4401 4414
4402 bool _isDartRuntime(LibraryElement l) => 4415 bool _isDartRuntime(LibraryElement l) =>
4403 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4416 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « no previous file | test/codegen/language/generic_self_reference_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698