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 |