OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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'; |
OLD | NEW |