| 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 | 2 |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
| 7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 className = new JS.Identifier(classElem.name); | 731 className = new JS.Identifier(classElem.name); |
| 732 } else { | 732 } else { |
| 733 className = _emitTopLevelName(classElem); | 733 className = _emitTopLevelName(classElem); |
| 734 } | 734 } |
| 735 | 735 |
| 736 var allFields = fields.toList()..addAll(staticFields); | 736 var allFields = fields.toList()..addAll(staticFields); |
| 737 var superclasses = getSuperclasses(classElem); | 737 var superclasses = getSuperclasses(classElem); |
| 738 var virtualFields = <FieldElement, JS.TemporaryId>{}; | 738 var virtualFields = <FieldElement, JS.TemporaryId>{}; |
| 739 var virtualFieldSymbols = <JS.Statement>[]; | 739 var virtualFieldSymbols = <JS.Statement>[]; |
| 740 var staticFieldOverrides = new HashSet<FieldElement>(); | 740 var staticFieldOverrides = new HashSet<FieldElement>(); |
| 741 var extensions = _extensionsToImplement(classElem); |
| 741 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 742 _registerPropertyOverrides(classElem, className, superclasses, allFields, |
| 742 virtualFields, virtualFieldSymbols, staticFieldOverrides); | 743 virtualFields, virtualFieldSymbols, staticFieldOverrides, extensions); |
| 743 | 744 |
| 744 var classExpr = _emitClassExpression(classElem, | 745 var classExpr = _emitClassExpression(classElem, |
| 745 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 746 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
| 746 fields: allFields); | 747 fields: allFields); |
| 747 | 748 |
| 748 var body = <JS.Statement>[]; | 749 var body = <JS.Statement>[]; |
| 749 var extensions = _extensionsToImplement(classElem); | |
| 750 _initExtensionSymbols(classElem, methods, fields, body); | 750 _initExtensionSymbols(classElem, methods, fields, body); |
| 751 _emitSuperHelperSymbols(_superHelperSymbols, body); | 751 _emitSuperHelperSymbols(_superHelperSymbols, body); |
| 752 | 752 |
| 753 // Emit the class, e.g. `core.Object = class Object { ... }` | 753 // Emit the class, e.g. `core.Object = class Object { ... }` |
| 754 _defineClass(classElem, className, classExpr, isCallable, body); | 754 _defineClass(classElem, className, classExpr, isCallable, body); |
| 755 | 755 |
| 756 // Emit things that come after the ES6 `class ... { ... }`. | 756 // Emit things that come after the ES6 `class ... { ... }`. |
| 757 var jsPeerNames = _getJSPeerNames(classElem); | 757 var jsPeerNames = _getJSPeerNames(classElem); |
| 758 _setBaseClass(classElem, className, jsPeerNames, body); | 758 _setBaseClass(classElem, className, jsPeerNames, body); |
| 759 | 759 |
| 760 _emitClassTypeTests(classElem, className, body); | 760 _emitClassTypeTests(classElem, className, body); |
| 761 | 761 |
| 762 _defineNamedConstructors(ctors, body, className, isCallable); | 762 _defineNamedConstructors(ctors, body, className, isCallable); |
| 763 _emitVirtualFieldSymbols(virtualFieldSymbols, body); | 763 body.addAll(virtualFieldSymbols); |
| 764 _emitClassSignature( | 764 _emitClassSignature( |
| 765 methods, allFields, classElem, ctors, extensions, className, body); | 765 methods, allFields, classElem, ctors, extensions, className, body); |
| 766 _defineExtensionMembers(extensions, className, body); | 766 _defineExtensionMembers(extensions, className, body); |
| 767 _emitClassMetadata(node.metadata, className, body); | 767 _emitClassMetadata(node.metadata, className, body); |
| 768 | 768 |
| 769 JS.Statement classDef = _statement(body); | 769 JS.Statement classDef = _statement(body); |
| 770 var typeFormals = classElem.typeParameters; | 770 var typeFormals = classElem.typeParameters; |
| 771 if (typeFormals.isNotEmpty) { | 771 if (typeFormals.isNotEmpty) { |
| 772 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); | 772 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); |
| 773 } | 773 } |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 superHelperSymbols.clear(); | 994 superHelperSymbols.clear(); |
| 995 } | 995 } |
| 996 | 996 |
| 997 void _registerPropertyOverrides( | 997 void _registerPropertyOverrides( |
| 998 ClassElement classElem, | 998 ClassElement classElem, |
| 999 JS.Expression className, | 999 JS.Expression className, |
| 1000 List<ClassElement> superclasses, | 1000 List<ClassElement> superclasses, |
| 1001 List<FieldDeclaration> fields, | 1001 List<FieldDeclaration> fields, |
| 1002 Map<FieldElement, JS.TemporaryId> virtualFields, | 1002 Map<FieldElement, JS.TemporaryId> virtualFields, |
| 1003 List<JS.Statement> virtualFieldSymbols, | 1003 List<JS.Statement> virtualFieldSymbols, |
| 1004 Set<FieldElement> staticFieldOverrides) { | 1004 Set<FieldElement> staticFieldOverrides, |
| 1005 Iterable<ExecutableElement> extensionMembers) { |
| 1006 var extensionNames = |
| 1007 new HashSet<String>.from(extensionMembers.map((e) => e.name)); |
| 1005 for (var field in fields) { | 1008 for (var field in fields) { |
| 1006 for (VariableDeclaration field in field.fields.variables) { | 1009 for (VariableDeclaration fieldDecl in field.fields.variables) { |
| 1007 var overrideInfo = | 1010 var field = fieldDecl.element as FieldElement; |
| 1008 checkForPropertyOverride(field.element, superclasses); | 1011 var overrideInfo = checkForPropertyOverride(field, superclasses); |
| 1009 if (overrideInfo.foundGetter || overrideInfo.foundSetter) { | 1012 if (overrideInfo.foundGetter || |
| 1010 if (field.element.isStatic) { | 1013 overrideInfo.foundSetter || |
| 1011 staticFieldOverrides.add(field.element); | 1014 extensionNames.contains(field.name)) { |
| 1015 if (field.isStatic) { |
| 1016 staticFieldOverrides.add(field); |
| 1012 } else { | 1017 } else { |
| 1013 var fieldName = | 1018 var virtualField = new JS.TemporaryId(field.name); |
| 1014 _emitMemberName(field.element.name, type: classElem.type); | 1019 virtualFields[field] = virtualField; |
| 1015 var virtualField = new JS.TemporaryId(field.element.name); | |
| 1016 virtualFields[field.element] = virtualField; | |
| 1017 virtualFieldSymbols.add(js.statement( | 1020 virtualFieldSymbols.add(js.statement( |
| 1018 'const # = Symbol(#.name + "." + #.toString());', | 1021 'const # = Symbol(#.name + "." + #.toString());', |
| 1019 [virtualField, className, fieldName])); | 1022 [virtualField, className, _declareMemberName(field.getter)])); |
| 1020 } | 1023 } |
| 1021 } | 1024 } |
| 1022 } | 1025 } |
| 1023 } | 1026 } |
| 1024 } | 1027 } |
| 1025 | 1028 |
| 1026 void _defineClass(ClassElement classElem, JS.Expression className, | 1029 void _defineClass(ClassElement classElem, JS.Expression className, |
| 1027 JS.ClassExpression classExpr, bool isCallable, List<JS.Statement> body) { | 1030 JS.ClassExpression classExpr, bool isCallable, List<JS.Statement> body) { |
| 1028 JS.Expression callableClass; | 1031 JS.Expression callableClass; |
| 1029 if (isCallable && classElem.unnamedConstructor != null) { | 1032 if (isCallable && classElem.unnamedConstructor != null) { |
| 1030 callableClass = | 1033 callableClass = |
| 1031 _emitCallableClass(classExpr, classElem.unnamedConstructor); | 1034 _emitCallableClass(classExpr, classElem.unnamedConstructor); |
| 1032 } | 1035 } |
| 1033 | 1036 |
| 1034 if (classElem.typeParameters.isNotEmpty) { | 1037 if (classElem.typeParameters.isNotEmpty) { |
| 1035 if (callableClass != null) { | 1038 if (callableClass != null) { |
| 1036 body.add(js.statement('const # = #;', [classExpr.name, callableClass])); | 1039 body.add(js.statement('const # = #;', [classExpr.name, callableClass])); |
| 1037 } else { | 1040 } else { |
| 1038 body.add(new JS.ClassDeclaration(classExpr)); | 1041 body.add(new JS.ClassDeclaration(classExpr)); |
| 1039 } | 1042 } |
| 1040 } else { | 1043 } else { |
| 1041 body.add(js.statement('# = #;', [className, callableClass ?? classExpr])); | 1044 body.add(js.statement('# = #;', [className, callableClass ?? classExpr])); |
| 1042 } | 1045 } |
| 1043 } | 1046 } |
| 1044 | 1047 |
| 1045 void _emitVirtualFieldSymbols( | |
| 1046 List<JS.Statement> virtualFields, List<JS.Statement> body) { | |
| 1047 body.addAll(virtualFields); | |
| 1048 } | |
| 1049 | |
| 1050 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { | 1048 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { |
| 1051 return typeFormals | 1049 return typeFormals |
| 1052 .map((t) => new JS.Identifier(t.name)) | 1050 .map((t) => new JS.Identifier(t.name)) |
| 1053 .toList(growable: false); | 1051 .toList(growable: false); |
| 1054 } | 1052 } |
| 1055 | 1053 |
| 1056 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED | 1054 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED |
| 1057 /// (e.g. `class Foo { i: string; }`) | 1055 /// (e.g. `class Foo { i: string; }`) |
| 1058 JS.VariableDeclarationList _emitTypeScriptField(FieldDeclaration field) { | 1056 JS.VariableDeclarationList _emitTypeScriptField(FieldDeclaration field) { |
| 1059 return new JS.VariableDeclarationList( | 1057 return new JS.VariableDeclarationList( |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1207 // Alternatively, perhaps it could be meta-programmed directly in | 1205 // Alternatively, perhaps it could be meta-programmed directly in |
| 1208 // dart.registerExtensions? | 1206 // dart.registerExtensions? |
| 1209 var jsMethods = <JS.Method>[]; | 1207 var jsMethods = <JS.Method>[]; |
| 1210 if (!node.isStatic) { | 1208 if (!node.isStatic) { |
| 1211 for (var decl in node.fields.variables) { | 1209 for (var decl in node.fields.variables) { |
| 1212 var field = decl.element as FieldElement; | 1210 var field = decl.element as FieldElement; |
| 1213 var name = getAnnotationName(field, isJsName) ?? field.name; | 1211 var name = getAnnotationName(field, isJsName) ?? field.name; |
| 1214 // Generate getter | 1212 // Generate getter |
| 1215 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); | 1213 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); |
| 1216 var method = | 1214 var method = |
| 1217 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); | 1215 new JS.Method(_declareMemberName(field.getter), fn, isGetter: true); |
| 1218 jsMethods.add(method); | 1216 jsMethods.add(method); |
| 1219 | 1217 |
| 1220 // Generate setter | 1218 // Generate setter |
| 1221 if (!decl.isFinal) { | 1219 if (!decl.isFinal) { |
| 1222 var value = new JS.TemporaryId('value'); | 1220 var value = new JS.TemporaryId('value'); |
| 1223 fn = new JS.Fun( | 1221 fn = new JS.Fun( |
| 1224 [value], js.statement('{ this.# = #; }', [name, value])); | 1222 [value], js.statement('{ this.# = #; }', [name, value])); |
| 1225 method = new JS.Method(_elementMemberName(field.setter), fn, | 1223 method = new JS.Method(_declareMemberName(field.setter), fn, |
| 1226 isSetter: true); | 1224 isSetter: true); |
| 1227 jsMethods.add(method); | 1225 jsMethods.add(method); |
| 1228 } | 1226 } |
| 1229 } | 1227 } |
| 1230 } | 1228 } |
| 1231 return jsMethods; | 1229 return jsMethods; |
| 1232 } | 1230 } |
| 1233 | 1231 |
| 1234 List<JS.Method> _emitClassMethods( | 1232 List<JS.Method> _emitClassMethods( |
| 1235 ClassDeclaration node, | 1233 ClassDeclaration node, |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1427 } else if (property.isSetter) { | 1425 } else if (property.isSetter) { |
| 1428 addProperty('isSetter', js.boolean(true)); | 1426 addProperty('isSetter', js.boolean(true)); |
| 1429 | 1427 |
| 1430 fnArgs.add(args); | 1428 fnArgs.add(args); |
| 1431 positionalArgs = new JS.ArrayInitializer([args]); | 1429 positionalArgs = new JS.ArrayInitializer([args]); |
| 1432 } | 1430 } |
| 1433 } | 1431 } |
| 1434 | 1432 |
| 1435 var fnBody = | 1433 var fnBody = |
| 1436 js.call('this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [ | 1434 js.call('this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [ |
| 1437 _elementMemberName(method), | 1435 _declareMemberName(method), |
| 1438 positionalArgs, | 1436 positionalArgs, |
| 1439 new JS.ObjectInitializer(invocationProps) | 1437 new JS.ObjectInitializer(invocationProps) |
| 1440 ]); | 1438 ]); |
| 1441 | 1439 |
| 1442 if (!method.returnType.isDynamic) { | 1440 if (!method.returnType.isDynamic) { |
| 1443 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); | 1441 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); |
| 1444 } | 1442 } |
| 1445 | 1443 |
| 1446 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), | 1444 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), |
| 1447 typeParams: _emitTypeFormals(method.type.typeFormals)); | 1445 typeParams: _emitTypeFormals(method.type.typeFormals)); |
| 1448 | 1446 |
| 1449 // TODO(jmesserly): generic type arguments will get dropped. | 1447 // TODO(jmesserly): generic type arguments will get dropped. |
| 1450 // We have a similar issue with `dgsend` helpers. | 1448 // We have a similar issue with `dgsend` helpers. |
| 1451 return new JS.Method( | 1449 return new JS.Method( |
| 1452 _elementMemberName(method, | 1450 _declareMemberName(method, |
| 1453 useExtension: | 1451 useExtension: |
| 1454 _extensionTypes.isNativeClass(method.enclosingElement)), | 1452 _extensionTypes.isNativeClass(method.enclosingElement)), |
| 1455 _makeGenericFunction(fn), | 1453 _makeGenericFunction(fn), |
| 1456 isGetter: method is PropertyAccessorElement && method.isGetter, | 1454 isGetter: method is PropertyAccessorElement && method.isGetter, |
| 1457 isSetter: method is PropertyAccessorElement && method.isSetter, | 1455 isSetter: method is PropertyAccessorElement && method.isSetter, |
| 1458 isStatic: false); | 1456 isStatic: false); |
| 1459 } | 1457 } |
| 1460 | 1458 |
| 1461 /// Return `true` if the given [classElement] has a noSuchMethod() method | 1459 /// Return `true` if the given [classElement] has a noSuchMethod() method |
| 1462 /// distinct from the one declared in class Object, as per the Dart Language | 1460 /// distinct from the one declared in class Object, as per the Dart Language |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1475 /// shadowing a field or getter/setter pair on its parent. | 1473 /// shadowing a field or getter/setter pair on its parent. |
| 1476 /// | 1474 /// |
| 1477 /// This is important because otherwise, trying to read or write the field | 1475 /// This is important because otherwise, trying to read or write the field |
| 1478 /// would end up calling the getter or setter, and one of those might not even | 1476 /// would end up calling the getter or setter, and one of those might not even |
| 1479 /// exist, resulting in a runtime error. Even if they did exist, that's the | 1477 /// exist, resulting in a runtime error. Even if they did exist, that's the |
| 1480 /// wrong behavior if a new field was declared. | 1478 /// wrong behavior if a new field was declared. |
| 1481 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field, | 1479 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field, |
| 1482 Map<FieldElement, JS.TemporaryId> virtualFields) { | 1480 Map<FieldElement, JS.TemporaryId> virtualFields) { |
| 1483 var virtualField = virtualFields[field.element]; | 1481 var virtualField = virtualFields[field.element]; |
| 1484 var result = <JS.Method>[]; | 1482 var result = <JS.Method>[]; |
| 1485 var name = _emitMemberName(field.element.name, | 1483 var name = _declareMemberName((field.element as FieldElement).getter); |
| 1486 type: (field.element.enclosingElement as ClassElement).type); | |
| 1487 var getter = js.call('function() { return this[#]; }', [virtualField]); | 1484 var getter = js.call('function() { return this[#]; }', [virtualField]); |
| 1488 result.add(new JS.Method(name, getter, isGetter: true)); | 1485 result.add(new JS.Method(name, getter, isGetter: true)); |
| 1489 | 1486 |
| 1490 if (field.isFinal) { | 1487 if (field.isFinal) { |
| 1491 var setter = js.call('function(value) { super[#] = value; }', [name]); | 1488 var setter = js.call('function(value) { super[#] = value; }', [name]); |
| 1492 result.add(new JS.Method(name, setter, isSetter: true)); | 1489 result.add(new JS.Method(name, setter, isSetter: true)); |
| 1493 } else { | 1490 } else { |
| 1494 var setter = | 1491 var setter = |
| 1495 js.call('function(value) { this[#] = value; }', [virtualField]); | 1492 js.call('function(value) { this[#] = value; }', [virtualField]); |
| 1496 result.add(new JS.Method(name, setter, isSetter: true)); | 1493 result.add(new JS.Method(name, setter, isSetter: true)); |
| 1497 } | 1494 } |
| 1498 | 1495 |
| 1499 return result; | 1496 return result; |
| 1500 } | 1497 } |
| 1501 | 1498 |
| 1502 /// Emit a getter or setter that simply forwards to the superclass getter or | 1499 /// Emit a getter or setter that simply forwards to the superclass getter or |
| 1503 /// setter. This is needed because in ES6, if you only override a getter | 1500 /// setter. This is needed because in ES6, if you only override a getter |
| 1504 /// (alternatively, a setter), then there is an implicit override of the | 1501 /// (alternatively, a setter), then there is an implicit override of the |
| 1505 /// setter (alternatively, the getter) that does nothing. | 1502 /// setter (alternatively, the getter) that does nothing. |
| 1506 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, | 1503 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, |
| 1507 InterfaceType type, List<ClassElement> superclasses) { | 1504 InterfaceType type, List<ClassElement> superclasses) { |
| 1508 var methodElement = method.element as PropertyAccessorElement; | 1505 var methodElement = method.element as PropertyAccessorElement; |
| 1509 var field = methodElement.variable; | 1506 var field = methodElement.variable; |
| 1510 if (!field.isSynthetic) return null; | 1507 if (!field.isSynthetic) return null; |
| 1511 var propertyOverrideResult = | 1508 var propertyOverrideResult = |
| 1512 checkForPropertyOverride(methodElement.variable, superclasses); | 1509 checkForPropertyOverride(methodElement.variable, superclasses); |
| 1513 | 1510 |
| 1514 // Generate a corresponding virtual getter / setter. | 1511 // Generate a corresponding virtual getter / setter. |
| 1515 var name = _elementMemberName(methodElement, | 1512 var name = _declareMemberName(methodElement); |
| 1516 useExtension: _extensionTypes.isNativeClass(type.element)); | |
| 1517 if (method.isGetter) { | 1513 if (method.isGetter) { |
| 1518 // Generate a setter | 1514 // Generate a setter |
| 1519 if (field.setter != null || !propertyOverrideResult.foundSetter) | 1515 if (field.setter != null || !propertyOverrideResult.foundSetter) |
| 1520 return null; | 1516 return null; |
| 1521 var fn = js.call('function(value) { super[#] = value; }', [name]); | 1517 var fn = js.call('function(value) { super[#] = value; }', [name]); |
| 1522 return new JS.Method(name, fn, isSetter: true); | 1518 return new JS.Method(name, fn, isSetter: true); |
| 1523 } else { | 1519 } else { |
| 1524 // Generate a getter | 1520 // Generate a getter |
| 1525 if (field.getter != null || !propertyOverrideResult.foundGetter) | 1521 if (field.getter != null || !propertyOverrideResult.foundGetter) |
| 1526 return null; | 1522 return null; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1669 | 1665 |
| 1670 /// If a concrete class implements one of our extensions, we might need to | 1666 /// If a concrete class implements one of our extensions, we might need to |
| 1671 /// add forwarders. | 1667 /// add forwarders. |
| 1672 void _defineExtensionMembers(List<ExecutableElement> extensions, | 1668 void _defineExtensionMembers(List<ExecutableElement> extensions, |
| 1673 JS.Expression className, List<JS.Statement> body) { | 1669 JS.Expression className, List<JS.Statement> body) { |
| 1674 // If a concrete class implements one of our extensions, we might need to | 1670 // If a concrete class implements one of our extensions, we might need to |
| 1675 // add forwarders. | 1671 // add forwarders. |
| 1676 if (extensions.isNotEmpty) { | 1672 if (extensions.isNotEmpty) { |
| 1677 var methodNames = <JS.Expression>[]; | 1673 var methodNames = <JS.Expression>[]; |
| 1678 for (var e in extensions) { | 1674 for (var e in extensions) { |
| 1679 methodNames.add(_elementMemberName(e, useExtension: false)); | 1675 methodNames.add(_declareMemberName(e, useExtension: false)); |
| 1680 } | 1676 } |
| 1681 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ | 1677 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ |
| 1682 className, | 1678 className, |
| 1683 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) | 1679 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) |
| 1684 ])); | 1680 ])); |
| 1685 } | 1681 } |
| 1686 } | 1682 } |
| 1687 | 1683 |
| 1688 /// Emit the signature on the class recording the runtime type information | 1684 /// Emit the signature on the class recording the runtime type information |
| 1689 void _emitClassSignature( | 1685 void _emitClassSignature( |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1735 type = _emitAnnotatedFunctionType(element.type, node.metadata, | 1731 type = _emitAnnotatedFunctionType(element.type, node.metadata, |
| 1736 parameters: node.parameters?.parameters, | 1732 parameters: node.parameters?.parameters, |
| 1737 nameType: options.hoistSignatureTypes, | 1733 nameType: options.hoistSignatureTypes, |
| 1738 hoistType: options.hoistSignatureTypes, | 1734 hoistType: options.hoistSignatureTypes, |
| 1739 definite: true); | 1735 definite: true); |
| 1740 | 1736 |
| 1741 var inheritedElement = lookup(name, currentLibrary); | 1737 var inheritedElement = lookup(name, currentLibrary); |
| 1742 if (inheritedElement != null && inheritedElement.type == element.type) { | 1738 if (inheritedElement != null && inheritedElement.type == element.type) { |
| 1743 continue; | 1739 continue; |
| 1744 } | 1740 } |
| 1745 var memberName = _elementMemberName(element, | 1741 var memberName = _declareMemberName(element); |
| 1746 useExtension: _extensionTypes.isNativeClass(classElem)); | |
| 1747 var property = new JS.Property(memberName, type); | 1742 var property = new JS.Property(memberName, type); |
| 1748 tMember.add(property); | 1743 tMember.add(property); |
| 1749 // TODO(vsm): Why do we need this? | 1744 // TODO(vsm): Why do we need this? |
| 1750 if (node.isStatic && !node.isGetter && !node.isSetter) { | 1745 if (node.isStatic && !node.isGetter && !node.isSetter) { |
| 1751 sNames.add(memberName); | 1746 sNames.add(memberName); |
| 1752 } | 1747 } |
| 1753 } | 1748 } |
| 1754 | 1749 |
| 1755 var tInstanceFields = <JS.Property>[]; | 1750 var tInstanceFields = <JS.Property>[]; |
| 1756 var tStaticFields = <JS.Property>[]; | 1751 var tStaticFields = <JS.Property>[]; |
| 1757 for (FieldDeclaration node in fields) { | 1752 for (FieldDeclaration node in fields) { |
| 1758 for (VariableDeclaration field in node.fields.variables) { | 1753 for (VariableDeclaration field in node.fields.variables) { |
| 1759 var element = field.element as FieldElement; | 1754 var element = field.element as FieldElement; |
| 1760 var memberName = _elementMemberName(element.getter, | 1755 var memberName = _declareMemberName(element.getter); |
| 1761 useExtension: _extensionTypes.isNativeClass(classElem)); | |
| 1762 var type = _emitAnnotatedType(element.type, node.metadata); | 1756 var type = _emitAnnotatedType(element.type, node.metadata); |
| 1763 var property = new JS.Property(memberName, type); | 1757 var property = new JS.Property(memberName, type); |
| 1764 (node.isStatic ? tStaticFields : tInstanceFields).add(property); | 1758 (node.isStatic ? tStaticFields : tInstanceFields).add(property); |
| 1765 } | 1759 } |
| 1766 } | 1760 } |
| 1767 | 1761 |
| 1768 var tCtors = <JS.Property>[]; | 1762 var tCtors = <JS.Property>[]; |
| 1769 for (ConstructorDeclaration node in ctors) { | 1763 for (ConstructorDeclaration node in ctors) { |
| 1770 var memberName = _constructorName(node.element); | 1764 var memberName = _constructorName(node.element); |
| 1771 var element = node.element; | 1765 var element = node.element; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1834 /// Ensure `dartx.` symbols we will use are present. | 1828 /// Ensure `dartx.` symbols we will use are present. |
| 1835 void _initExtensionSymbols( | 1829 void _initExtensionSymbols( |
| 1836 ClassElement classElem, | 1830 ClassElement classElem, |
| 1837 List<MethodDeclaration> methods, | 1831 List<MethodDeclaration> methods, |
| 1838 List<FieldDeclaration> fields, | 1832 List<FieldDeclaration> fields, |
| 1839 List<JS.Statement> body) { | 1833 List<JS.Statement> body) { |
| 1840 if (_extensionTypes.hasNativeSubtype(classElem.type)) { | 1834 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
| 1841 var dartxNames = <JS.Expression>[]; | 1835 var dartxNames = <JS.Expression>[]; |
| 1842 for (var m in methods) { | 1836 for (var m in methods) { |
| 1843 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1837 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
| 1844 dartxNames.add(_elementMemberName(m.element, useExtension: false)); | 1838 dartxNames.add(_declareMemberName(m.element, useExtension: false)); |
| 1845 } | 1839 } |
| 1846 } | 1840 } |
| 1847 for (var fieldDecl in fields) { | 1841 for (var fieldDecl in fields) { |
| 1848 if (!fieldDecl.isStatic) { | 1842 if (!fieldDecl.isStatic) { |
| 1849 for (var field in fieldDecl.fields.variables) { | 1843 for (var field in fieldDecl.fields.variables) { |
| 1850 var e = field.element as FieldElement; | 1844 var e = field.element as FieldElement; |
| 1851 if (e.isPublic) { | 1845 if (e.isPublic) { |
| 1852 dartxNames.add(_elementMemberName(e.getter, useExtension: false)); | 1846 dartxNames.add(_declareMemberName(e.getter, useExtension: false)); |
| 1853 } | 1847 } |
| 1854 } | 1848 } |
| 1855 } | 1849 } |
| 1856 } | 1850 } |
| 1857 if (dartxNames.isNotEmpty) { | 1851 if (dartxNames.isNotEmpty) { |
| 1858 body.add(js.statement('dart.defineExtensionNames(#)', | 1852 body.add(js.statement('dart.defineExtensionNames(#)', |
| 1859 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1853 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
| 1860 } | 1854 } |
| 1861 } | 1855 } |
| 1862 } | 1856 } |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 if (fieldNode.initializer != null) { | 2140 if (fieldNode.initializer != null) { |
| 2147 value = _visit(fieldNode.initializer); | 2141 value = _visit(fieldNode.initializer); |
| 2148 } else { | 2142 } else { |
| 2149 value = new JS.LiteralNull(); | 2143 value = new JS.LiteralNull(); |
| 2150 } | 2144 } |
| 2151 fields[element] = value; | 2145 fields[element] = value; |
| 2152 }); | 2146 }); |
| 2153 | 2147 |
| 2154 var body = <JS.Statement>[]; | 2148 var body = <JS.Statement>[]; |
| 2155 fields.forEach((FieldElement e, JS.Expression initialValue) { | 2149 fields.forEach((FieldElement e, JS.Expression initialValue) { |
| 2156 if (virtualFields.containsKey(e)) { | 2150 JS.Expression access = virtualFields[e] ?? _declareMemberName(e.getter); |
| 2157 body.add( | 2151 body.add(js.statement('this.# = #;', [access, initialValue])); |
| 2158 js.statement('this[#] = #;', [virtualFields[e], initialValue])); | |
| 2159 } else { | |
| 2160 var access = _emitMemberName(e.name, type: e.enclosingElement.type); | |
| 2161 body.add(js.statement('this.# = #;', [access, initialValue])); | |
| 2162 } | |
| 2163 }); | 2152 }); |
| 2164 | 2153 |
| 2165 if (isConst) _loader.finishTopLevel(cls.element); | 2154 if (isConst) _loader.finishTopLevel(cls.element); |
| 2166 return _statement(body); | 2155 return _statement(body); |
| 2167 } | 2156 } |
| 2168 | 2157 |
| 2169 FormalParameterList _parametersOf(node) { | 2158 FormalParameterList _parametersOf(node) { |
| 2170 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we | 2159 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we |
| 2171 // could handle argument initializers more consistently in a separate | 2160 // could handle argument initializers more consistently in a separate |
| 2172 // lowering pass. | 2161 // lowering pass. |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2290 fn.params.isNotEmpty) { | 2279 fn.params.isNotEmpty) { |
| 2291 // []= methods need to return the value. We could also address this at | 2280 // []= methods need to return the value. We could also address this at |
| 2292 // call sites, but it's cleaner to instead transform the operator method
. | 2281 // call sites, but it's cleaner to instead transform the operator method
. |
| 2293 fn = _alwaysReturnLastParameter(fn); | 2282 fn = _alwaysReturnLastParameter(fn); |
| 2294 } | 2283 } |
| 2295 | 2284 |
| 2296 fn = _makeGenericFunction(fn); | 2285 fn = _makeGenericFunction(fn); |
| 2297 } | 2286 } |
| 2298 | 2287 |
| 2299 return annotate( | 2288 return annotate( |
| 2300 new JS.Method( | 2289 new JS.Method(_declareMemberName(node.element), fn, |
| 2301 _elementMemberName(node.element, | |
| 2302 useExtension: _extensionTypes.isNativeClass(type.element)), | |
| 2303 fn, | |
| 2304 isGetter: node.isGetter, | 2290 isGetter: node.isGetter, |
| 2305 isSetter: node.isSetter, | 2291 isSetter: node.isSetter, |
| 2306 isStatic: node.isStatic), | 2292 isStatic: node.isStatic), |
| 2307 node, | 2293 node, |
| 2308 node.element); | 2294 node.element); |
| 2309 } | 2295 } |
| 2310 | 2296 |
| 2311 /// Transform the function so the last parameter is always returned. | 2297 /// Transform the function so the last parameter is always returned. |
| 2312 /// | 2298 /// |
| 2313 /// This is useful for indexed set methods, which otherwise would not have | 2299 /// This is useful for indexed set methods, which otherwise would not have |
| (...skipping 2896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5210 } | 5196 } |
| 5211 JS.Expression result = _visit(node); | 5197 JS.Expression result = _visit(node); |
| 5212 if (isNullable(node)) result = js.call('dart.test(#)', result); | 5198 if (isNullable(node)) result = js.call('dart.test(#)', result); |
| 5213 return result; | 5199 return result; |
| 5214 } | 5200 } |
| 5215 | 5201 |
| 5216 /// Like [_emitMemberName], but for declaration sites. | 5202 /// Like [_emitMemberName], but for declaration sites. |
| 5217 /// | 5203 /// |
| 5218 /// Unlike call sites, we always have an element available, so we can use it | 5204 /// Unlike call sites, we always have an element available, so we can use it |
| 5219 /// directly rather than computing the relevant options for [_emitMemberName]. | 5205 /// directly rather than computing the relevant options for [_emitMemberName]. |
| 5220 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) { | 5206 JS.Expression _declareMemberName(ExecutableElement e, {bool useExtension}) { |
| 5221 String name; | 5207 String name; |
| 5222 if (e is PropertyAccessorElement) { | 5208 if (e is PropertyAccessorElement) { |
| 5223 name = e.variable.name; | 5209 name = e.variable.name; |
| 5224 } else { | 5210 } else { |
| 5225 name = e.name; | 5211 name = e.name; |
| 5226 } | 5212 } |
| 5227 return _emitMemberName(name, | 5213 return _emitMemberName(name, |
| 5228 type: (e.enclosingElement as ClassElement).type, | |
| 5229 unary: e.parameters.isEmpty, | 5214 unary: e.parameters.isEmpty, |
| 5230 isStatic: e.isStatic, | 5215 isStatic: e.isStatic, |
| 5231 useExtension: useExtension); | 5216 useExtension: |
| 5217 useExtension ?? _extensionTypes.isNativeClass(e.enclosingElement)); |
| 5232 } | 5218 } |
| 5233 | 5219 |
| 5234 /// This handles member renaming for private names and operators. | 5220 /// This handles member renaming for private names and operators. |
| 5235 /// | 5221 /// |
| 5236 /// Private names are generated using ES6 symbols: | 5222 /// Private names are generated using ES6 symbols: |
| 5237 /// | 5223 /// |
| 5238 /// // At the top of the module: | 5224 /// // At the top of the module: |
| 5239 /// let _x = Symbol('_x'); | 5225 /// let _x = Symbol('_x'); |
| 5240 /// let _y = Symbol('_y'); | 5226 /// let _y = Symbol('_y'); |
| 5241 /// ... | 5227 /// ... |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5519 } | 5505 } |
| 5520 | 5506 |
| 5521 bool isLibraryPrefix(Expression node) => | 5507 bool isLibraryPrefix(Expression node) => |
| 5522 node is SimpleIdentifier && node.staticElement is PrefixElement; | 5508 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 5523 | 5509 |
| 5524 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 5510 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 5525 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 5511 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 5526 | 5512 |
| 5527 bool _isDartRuntime(LibraryElement l) => | 5513 bool _isDartRuntime(LibraryElement l) => |
| 5528 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 5514 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |