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 892 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
903 | 903 |
904 JS.Expression className; | 904 JS.Expression className; |
905 if (classElem.typeParameters.isNotEmpty) { | 905 if (classElem.typeParameters.isNotEmpty) { |
906 // Generic classes will be defined inside a function that closes over the | 906 // Generic classes will be defined inside a function that closes over the |
907 // type parameter. So we can use their local variable name directly. | 907 // type parameter. So we can use their local variable name directly. |
908 className = new JS.Identifier(classElem.name); | 908 className = new JS.Identifier(classElem.name); |
909 } else { | 909 } else { |
910 className = _emitTopLevelName(classElem); | 910 className = _emitTopLevelName(classElem); |
911 } | 911 } |
912 | 912 |
913 var extensions = _extensionsToImplement(classElem); | |
914 var savedClassProperties = _classProperties; | 913 var savedClassProperties = _classProperties; |
915 _classProperties = | 914 _classProperties = |
916 new ClassPropertyModel.build(virtualFields, classElem, extensions); | 915 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); |
917 | 916 |
918 var classExpr = _emitClassExpression( | 917 var classExpr = _emitClassExpression( |
919 classElem, _emitClassMethods(node, ctors, fields), | 918 classElem, _emitClassMethods(node, ctors, fields), |
920 fields: allFields); | 919 fields: allFields); |
921 | 920 |
922 var body = <JS.Statement>[]; | 921 var body = <JS.Statement>[]; |
923 _initExtensionSymbols(classElem, methods, fields, body); | 922 _initExtensionSymbols(classElem, methods, fields, body); |
924 _emitSuperHelperSymbols(_superHelperSymbols, body); | 923 _emitSuperHelperSymbols(_superHelperSymbols, body); |
925 | 924 |
926 // Emit the class, e.g. `core.Object = class Object { ... }` | 925 // Emit the class, e.g. `core.Object = class Object { ... }` |
927 _defineClass(classElem, className, classExpr, isCallable, body); | 926 _defineClass(classElem, className, classExpr, isCallable, body); |
928 | 927 |
929 // Emit things that come after the ES6 `class ... { ... }`. | 928 // Emit things that come after the ES6 `class ... { ... }`. |
930 var jsPeerNames = _getJSPeerNames(classElem); | 929 var jsPeerNames = _getJSPeerNames(classElem); |
931 JS.Statement deferredBaseClass = | 930 JS.Statement deferredBaseClass = |
932 _setBaseClass(classElem, className, jsPeerNames, body); | 931 _setBaseClass(classElem, className, jsPeerNames, body); |
933 | 932 |
934 _emitClassTypeTests(classElem, className, body); | 933 _emitClassTypeTests(classElem, className, body); |
935 | 934 |
936 _defineNamedConstructors(ctors, body, className, isCallableTransitive); | 935 _defineNamedConstructors(ctors, body, className, isCallableTransitive); |
937 _emitVirtualFieldSymbols(classElem, body); | 936 _emitVirtualFieldSymbols(classElem, body); |
938 _emitClassSignature( | 937 _emitClassSignature(methods, allFields, classElem, ctors, className, body); |
939 methods, allFields, classElem, ctors, extensions, className, body); | 938 _defineExtensionMembers(className, body); |
940 _defineExtensionMembers(extensions, className, body); | |
941 _emitClassMetadata(node.metadata, className, body); | 939 _emitClassMetadata(node.metadata, className, body); |
942 | 940 |
943 JS.Statement classDef = _statement(body); | 941 JS.Statement classDef = _statement(body); |
944 | 942 |
945 var typeFormals = classElem.typeParameters; | 943 var typeFormals = classElem.typeParameters; |
946 if (typeFormals.isNotEmpty) { | 944 if (typeFormals.isNotEmpty) { |
947 classDef = _defineClassTypeArguments( | 945 classDef = _defineClassTypeArguments( |
948 classElem, typeFormals, classDef, className, deferredBaseClass); | 946 classElem, typeFormals, classDef, className, deferredBaseClass); |
949 } | 947 } |
950 | 948 |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1477 jsMethods.add(_emitIterable(type)); | 1475 jsMethods.add(_emitIterable(type)); |
1478 } | 1476 } |
1479 } else if (m is FieldDeclaration) { | 1477 } else if (m is FieldDeclaration) { |
1480 if (_extensionTypes.isNativeClass(element)) { | 1478 if (_extensionTypes.isNativeClass(element)) { |
1481 jsMethods.addAll(_emitNativeFieldAccessors(m)); | 1479 jsMethods.addAll(_emitNativeFieldAccessors(m)); |
1482 continue; | 1480 continue; |
1483 } | 1481 } |
1484 if (m.isStatic) continue; | 1482 if (m.isStatic) continue; |
1485 for (VariableDeclaration field in m.fields.variables) { | 1483 for (VariableDeclaration field in m.fields.variables) { |
1486 if (virtualFields.containsKey(field.element)) { | 1484 if (virtualFields.containsKey(field.element)) { |
1487 jsMethods.addAll(_emitVirtualFieldAccessor(field, virtualFields)); | 1485 jsMethods.addAll(_emitVirtualFieldAccessor(field)); |
1488 } | 1486 } |
1489 } | 1487 } |
1490 } | 1488 } |
1491 } | 1489 } |
1492 | 1490 |
1493 jsMethods.addAll(_implementMockInterfaces(type)); | 1491 jsMethods.addAll(_classProperties.mockMembers.values |
1492 .map((e) => _implementMockMember(e, type))); | |
1494 | 1493 |
1495 // If the type doesn't have an `iterator`, but claims to implement Iterable, | 1494 // If the type doesn't have an `iterator`, but claims to implement Iterable, |
1496 // we inject the adaptor method here, as it's less code size to put the | 1495 // we inject the adaptor method here, as it's less code size to put the |
1497 // helper on a parent class. This pattern is common in the core libraries | 1496 // helper on a parent class. This pattern is common in the core libraries |
1498 // (e.g. IterableMixin<E> and IterableBase<E>). | 1497 // (e.g. IterableMixin<E> and IterableBase<E>). |
1499 // | 1498 // |
1500 // (We could do this same optimization for any interface with an `iterator` | 1499 // (We could do this same optimization for any interface with an `iterator` |
1501 // method, but that's more expensive to check for, so it doesn't seem worth | 1500 // method, but that's more expensive to check for, so it doesn't seem worth |
1502 // it. The above case for an explicit `iterator` method will catch those.) | 1501 // it. The above case for an explicit `iterator` method will catch those.) |
1503 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 1502 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
1504 jsMethods.add(_emitIterable(type)); | 1503 jsMethods.add(_emitIterable(type)); |
1505 } | 1504 } |
1506 | 1505 |
1507 // Add all of the super helper methods | 1506 // Add all of the super helper methods |
1508 jsMethods.addAll(_superHelpers); | 1507 jsMethods.addAll(_superHelpers); |
1509 _superHelpers.clear(); | 1508 _superHelpers.clear(); |
1510 | 1509 |
1511 return jsMethods.where((m) => m != null).toList(growable: false); | 1510 return jsMethods.where((m) => m != null).toList(growable: false); |
1512 } | 1511 } |
1513 | 1512 |
1514 Iterable<ExecutableElement> _collectMockMethods(InterfaceType type) { | |
1515 var element = type.element; | |
1516 if (!_hasNoSuchMethod(element)) { | |
1517 return []; | |
1518 } | |
1519 | |
1520 // Collect all unimplemented members. | |
1521 // | |
1522 // Initially, we track abstract and concrete members separately, then | |
1523 // remove concrete from the abstract set. This is done because abstract | |
1524 // members are allowed to "override" concrete ones in Dart. | |
1525 // (In that case, it will still be treated as a concrete member and can be | |
1526 // called at run time.) | |
1527 var abstractMembers = new Map<String, ExecutableElement>(); | |
1528 var concreteMembers = new HashSet<String>(); | |
1529 | |
1530 void visit(InterfaceType type, bool isAbstract) { | |
1531 if (type == null) return; | |
1532 visit(type.superclass, isAbstract); | |
1533 for (var m in type.mixins) visit(m, isAbstract); | |
1534 for (var i in type.interfaces) visit(i, true); | |
1535 | |
1536 var members = <ExecutableElement>[] | |
1537 ..addAll(type.methods) | |
1538 ..addAll(type.accessors); | |
1539 for (var m in members) { | |
1540 if (isAbstract || m.isAbstract) { | |
1541 // Inconsistent signatures are disallowed, even with nSM, so we don't | |
1542 // need to worry too much about which abstract member we save. | |
1543 abstractMembers[m.name] = m; | |
1544 } else { | |
1545 concreteMembers.add(m.name); | |
1546 } | |
1547 } | |
1548 } | |
1549 | |
1550 visit(type, false); | |
1551 | |
1552 concreteMembers.forEach(abstractMembers.remove); | |
1553 return abstractMembers.values; | |
1554 } | |
1555 | |
1556 Iterable<JS.Method> _implementMockInterfaces(InterfaceType type) { | |
1557 // TODO(jmesserly): every type with nSM will generate new stubs for all | |
1558 // abstract members. For example: | |
1559 // | |
1560 // class C { m(); noSuchMethod(...) { ... } } | |
1561 // class D extends C { m(); noSuchMethod(...) { ... } } | |
1562 // | |
1563 // We'll generate D.m even though it is not necessary. | |
1564 // | |
1565 // Doing better is a bit tricky, as our current codegen strategy for the | |
1566 // mock methods encodes information about the number of arguments (and type | |
1567 // arguments) that D expects. | |
1568 return _collectMockMethods(type) | |
1569 .map((method) => _implementMockMethod(method, type)); | |
1570 } | |
1571 | |
1572 /// Given a class C that implements method M from interface I, but does not | 1513 /// Given a class C that implements method M from interface I, but does not |
1573 /// declare M, this will generate an implementation that forwards to | 1514 /// declare M, this will generate an implementation that forwards to |
1574 /// noSuchMethod. | 1515 /// noSuchMethod. |
1575 /// | 1516 /// |
1576 /// For example: | 1517 /// For example: |
1577 /// | 1518 /// |
1578 /// class Cat { | 1519 /// class Cat { |
1579 /// bool eatFood(String food) => true; | 1520 /// bool eatFood(String food) => true; |
1580 /// } | 1521 /// } |
1581 /// class MockCat implements Cat { | 1522 /// class MockCat implements Cat { |
1582 /// noSuchMethod(Invocation invocation) => 3; | 1523 /// noSuchMethod(Invocation invocation) => 3; |
1583 /// } | 1524 /// } |
1584 /// | 1525 /// |
1585 /// It will generate an `eatFood` that looks like: | 1526 /// It will generate an `eatFood` that looks like: |
1586 /// | 1527 /// |
1587 /// eatFood(...args) { | 1528 /// eatFood(...args) { |
1588 /// return core.bool.as(this.noSuchMethod( | 1529 /// return core.bool.as(this.noSuchMethod( |
1589 /// new dart.InvocationImpl('eatFood', args))); | 1530 /// new dart.InvocationImpl('eatFood', args))); |
1590 /// } | 1531 /// } |
1591 JS.Method _implementMockMethod(ExecutableElement method, InterfaceType type) { | 1532 JS.Method _implementMockMember(ExecutableElement method, InterfaceType type) { |
1592 var invocationProps = <JS.Property>[]; | 1533 var invocationProps = <JS.Property>[]; |
1593 addProperty(String name, JS.Expression value) { | 1534 addProperty(String name, JS.Expression value) { |
1594 invocationProps.add(new JS.Property(js.string(name), value)); | 1535 invocationProps.add(new JS.Property(js.string(name), value)); |
1595 } | 1536 } |
1596 | 1537 |
1597 var args = new JS.TemporaryId('args'); | 1538 var args = new JS.TemporaryId('args'); |
1598 var fnArgs = <JS.Parameter>[]; | 1539 var fnArgs = <JS.Parameter>[]; |
1599 JS.Expression positionalArgs; | 1540 JS.Expression positionalArgs; |
1600 | 1541 |
1601 if (method.type.namedParameterTypes.isNotEmpty) { | 1542 if (method.type.namedParameterTypes.isNotEmpty) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1639 // We have a similar issue with `dgsend` helpers. | 1580 // We have a similar issue with `dgsend` helpers. |
1640 return new JS.Method( | 1581 return new JS.Method( |
1641 _declareMemberName(method, | 1582 _declareMemberName(method, |
1642 useExtension: _extensionTypes.isNativeClass(type.element)), | 1583 useExtension: _extensionTypes.isNativeClass(type.element)), |
1643 _makeGenericFunction(fn), | 1584 _makeGenericFunction(fn), |
1644 isGetter: method is PropertyAccessorElement && method.isGetter, | 1585 isGetter: method is PropertyAccessorElement && method.isGetter, |
1645 isSetter: method is PropertyAccessorElement && method.isSetter, | 1586 isSetter: method is PropertyAccessorElement && method.isSetter, |
1646 isStatic: false); | 1587 isStatic: false); |
1647 } | 1588 } |
1648 | 1589 |
1649 /// Return `true` if the given [classElement] has a noSuchMethod() method | |
1650 /// distinct from the one declared in class Object, as per the Dart Language | |
1651 /// Specification (section 10.4). | |
1652 // TODO(jmesserly): this was taken from error_verifier.dart | |
1653 bool _hasNoSuchMethod(ClassElement classElement) { | |
1654 // TODO(jmesserly): this is slow in Analyzer. It's a linear scan through all | |
1655 // methods, up through the class hierarchy. | |
1656 MethodElement method = classElement.lookUpMethod( | |
1657 FunctionElement.NO_SUCH_METHOD_METHOD_NAME, classElement.library); | |
1658 var definingClass = method?.enclosingElement; | |
1659 return definingClass != null && !definingClass.type.isObject; | |
1660 } | |
1661 | |
1662 /// This is called whenever a derived class needs to introduce a new field, | 1590 /// This is called whenever a derived class needs to introduce a new field, |
1663 /// shadowing a field or getter/setter pair on its parent. | 1591 /// shadowing a field or getter/setter pair on its parent. |
1664 /// | 1592 /// |
1665 /// This is important because otherwise, trying to read or write the field | 1593 /// This is important because otherwise, trying to read or write the field |
1666 /// would end up calling the getter or setter, and one of those might not even | 1594 /// would end up calling the getter or setter, and one of those might not even |
1667 /// exist, resulting in a runtime error. Even if they did exist, that's the | 1595 /// exist, resulting in a runtime error. Even if they did exist, that's the |
1668 /// wrong behavior if a new field was declared. | 1596 /// wrong behavior if a new field was declared. |
1669 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field, | 1597 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field) { |
1670 Map<FieldElement, JS.TemporaryId> virtualFields) { | 1598 var element = field.element as FieldElement; |
1671 var virtualField = virtualFields[field.element]; | 1599 var virtualField = _classProperties.virtualFields[element]; |
1672 var result = <JS.Method>[]; | 1600 var result = <JS.Method>[]; |
1673 var name = _declareMemberName((field.element as FieldElement).getter); | 1601 var name = _declareMemberName(element.getter); |
1674 var getter = js.call('function() { return this[#]; }', [virtualField]); | |
1675 result.add(new JS.Method(name, getter, isGetter: true)); | |
1676 | 1602 |
1677 if (field.isFinal) { | 1603 var mocks = _classProperties.mockMembers; |
1678 var setter = js.call('function(value) { super[#] = value; }', [name]); | 1604 if (!mocks.containsKey(element.name)) { |
1679 result.add(new JS.Method(name, setter, isSetter: true)); | 1605 var getter = js.call('function() { return this[#]; }', [virtualField]); |
1680 } else { | 1606 result.add(new JS.Method(name, getter, isGetter: true)); |
1681 var setter = | 1607 } |
1682 js.call('function(value) { this[#] = value; }', [virtualField]); | 1608 |
1683 result.add(new JS.Method(name, setter, isSetter: true)); | 1609 if (!mocks.containsKey(element.name + '=')) { |
1610 var args = field.isFinal | |
1611 ? [new JS.Super(), name] | |
1612 : [new JS.This(), virtualField]; | |
1613 | |
1614 result.add(new JS.Method( | |
1615 name, js.call('function(value) { #[#] = value; }', args), | |
1616 isSetter: true)); | |
1684 } | 1617 } |
1685 | 1618 |
1686 return result; | 1619 return result; |
1687 } | 1620 } |
1688 | 1621 |
1689 /// Emit a getter or setter that simply forwards to the superclass getter or | 1622 /// Emit a getter or setter that simply forwards to the superclass getter or |
1690 /// setter. This is needed because in ES6, if you only override a getter | 1623 /// setter. This is needed because in ES6, if you only override a getter |
1691 /// (alternatively, a setter), then there is an implicit override of the | 1624 /// (alternatively, a setter), then there is an implicit override of the |
1692 /// setter (alternatively, the getter) that does nothing. | 1625 /// setter (alternatively, the getter) that does nothing. |
1693 JS.Method _emitSuperAccessorWrapper( | 1626 JS.Method _emitSuperAccessorWrapper( |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1854 className, | 1787 className, |
1855 _runtimeModule, | 1788 _runtimeModule, |
1856 new JS.ArrayInitializer( | 1789 new JS.ArrayInitializer( |
1857 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation))) | 1790 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation))) |
1858 ])); | 1791 ])); |
1859 } | 1792 } |
1860 } | 1793 } |
1861 | 1794 |
1862 /// If a concrete class implements one of our extensions, we might need to | 1795 /// If a concrete class implements one of our extensions, we might need to |
1863 /// add forwarders. | 1796 /// add forwarders. |
1864 void _defineExtensionMembers(List<ExecutableElement> extensions, | 1797 void _defineExtensionMembers( |
1865 JS.Expression className, List<JS.Statement> body) { | 1798 JS.Expression className, List<JS.Statement> body) { |
1866 // If a concrete class implements one of our extensions, we might need to | 1799 void emitExtenstions( |
vsm
2017/04/07 20:57:35
nit: emitExtenstions -> emitExtensions
| |
1867 // add forwarders. | 1800 JS.Expression target, Iterable<ExecutableElement> extensions) { |
1868 if (extensions.isNotEmpty) { | 1801 if (extensions.isEmpty) return; |
1869 var methodNames = <JS.Expression>[]; | 1802 |
1870 for (var e in extensions) { | 1803 var names = extensions |
1871 methodNames.add(_declareMemberName(e, useExtension: false)); | 1804 .map((e) => _declareMemberName(e, useExtension: false)) |
1872 } | 1805 .toList(); |
1873 body.add(_callHelperStatement('defineExtensionMembers(#, #);', [ | 1806 body.add(_callHelperStatement('defineExtensionMembers(#, #);', [ |
1874 className, | 1807 target, |
1875 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) | 1808 new JS.ArrayInitializer(names, multiline: names.length > 4) |
1876 ])); | 1809 ])); |
1877 } | 1810 } |
1811 | |
1812 // Define mixin members (if any) on the mixin class. | |
1813 var mixinClass = js.call('#.__proto__', [className]); | |
1814 emitExtenstions(mixinClass, _classProperties.mixinExtensionMembers); | |
1815 emitExtenstions(className, _classProperties.extensionMembers); | |
1878 } | 1816 } |
1879 | 1817 |
1880 JS.Property _buildSignatureField(String name, List<JS.Property> elements) { | 1818 JS.Property _buildSignatureField(String name, List<JS.Property> elements) { |
1881 var o = new JS.ObjectInitializer(elements, multiline: elements.length > 1); | 1819 var o = new JS.ObjectInitializer(elements, multiline: elements.length > 1); |
1882 // TODO(vsm): Remove | 1820 // TODO(vsm): Remove |
1883 var e = js.call('() => #', o); | 1821 var e = js.call('() => #', o); |
1884 return new JS.Property(_propertyName(name), e); | 1822 return new JS.Property(_propertyName(name), e); |
1885 } | 1823 } |
1886 | 1824 |
1887 /// Emit the signature on the class recording the runtime type information | 1825 /// Emit the signature on the class recording the runtime type information |
1888 void _emitClassSignature( | 1826 void _emitClassSignature( |
1889 List<MethodDeclaration> methods, | 1827 List<MethodDeclaration> methods, |
1890 List<FieldDeclaration> fields, | 1828 List<FieldDeclaration> fields, |
1891 ClassElement classElem, | 1829 ClassElement classElem, |
1892 List<ConstructorDeclaration> ctors, | 1830 List<ConstructorDeclaration> ctors, |
1893 List<ExecutableElement> extensions, | |
1894 JS.Expression className, | 1831 JS.Expression className, |
1895 List<JS.Statement> body) { | 1832 List<JS.Statement> body) { |
1896 if (classElem.interfaces.isNotEmpty) { | 1833 if (classElem.interfaces.isNotEmpty) { |
1897 body.add(js.statement('#[#.implements] = () => #;', [ | 1834 body.add(js.statement('#[#.implements] = () => #;', [ |
1898 className, | 1835 className, |
1899 _runtimeModule, | 1836 _runtimeModule, |
1900 new JS.ArrayInitializer( | 1837 new JS.ArrayInitializer( |
1901 new List<JS.Expression>.from(classElem.interfaces.map(_emitType))) | 1838 new List<JS.Expression>.from(classElem.interfaces.map(_emitType))) |
1902 ])); | 1839 ])); |
1903 } | 1840 } |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2032 } | 1969 } |
2033 if (!tStaticMethods.isEmpty) { | 1970 if (!tStaticMethods.isEmpty) { |
2034 assert(!sNames.isEmpty); | 1971 assert(!sNames.isEmpty); |
2035 // Emit names so that we can lazily attach metadata to statics | 1972 // Emit names so that we can lazily attach metadata to statics |
2036 // TODO(leafp): revisit this strategy | 1973 // TODO(leafp): revisit this strategy |
2037 var aNames = new JS.Property( | 1974 var aNames = new JS.Property( |
2038 _propertyName('names'), new JS.ArrayInitializer(sNames)); | 1975 _propertyName('names'), new JS.ArrayInitializer(sNames)); |
2039 sigFields.add(_buildSignatureField('statics', tStaticMethods)); | 1976 sigFields.add(_buildSignatureField('statics', tStaticMethods)); |
2040 sigFields.add(aNames); | 1977 sigFields.add(aNames); |
2041 } | 1978 } |
2042 if (!sigFields.isEmpty || extensions.isNotEmpty) { | 1979 // We set signature here, even if empty, to simplify the work of |
1980 // defineExtensionMembers at runtime. See _defineExtensionMembers. | |
1981 if (!sigFields.isEmpty || | |
1982 _classProperties.extensionMembers.isNotEmpty || | |
1983 _classProperties.mixinExtensionMembers.isNotEmpty) { | |
2043 var sig = new JS.ObjectInitializer(sigFields); | 1984 var sig = new JS.ObjectInitializer(sigFields); |
2044 body.add(_callHelperStatement('setSignature(#, #);', [className, sig])); | 1985 body.add(_callHelperStatement('setSignature(#, #);', [className, sig])); |
2045 } | 1986 } |
2046 // Add static property dart._runtimeType to Object. | 1987 // Add static property dart._runtimeType to Object. |
2047 // All other Dart classes will (statically) inherit this property. | 1988 // All other Dart classes will (statically) inherit this property. |
2048 if (classElem == objectClass) { | 1989 if (classElem == objectClass) { |
2049 body.add(_callHelperStatement('tagComputed(#, () => #.#);', | 1990 body.add(_callHelperStatement('tagComputed(#, () => #.#);', |
2050 [className, emitLibraryName(dartCoreLibrary), 'Type'])); | 1991 [className, emitLibraryName(dartCoreLibrary), 'Type'])); |
2051 } | 1992 } |
2052 } | 1993 } |
(...skipping 23 matching lines...) Expand all Loading... | |
2076 } | 2017 } |
2077 } | 2018 } |
2078 } | 2019 } |
2079 if (dartxNames.isNotEmpty) { | 2020 if (dartxNames.isNotEmpty) { |
2080 body.add(_callHelperStatement('defineExtensionNames(#)', | 2021 body.add(_callHelperStatement('defineExtensionNames(#)', |
2081 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 2022 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
2082 } | 2023 } |
2083 } | 2024 } |
2084 } | 2025 } |
2085 | 2026 |
2086 List<ExecutableElement> _extensionsToImplement(ClassElement element) { | |
2087 if (_extensionTypes.isNativeClass(element)) return []; | |
2088 | |
2089 // Collect all extension types we implement. | |
2090 var type = element.type; | |
2091 var types = _extensionTypes.collectNativeInterfaces(element); | |
2092 if (types.isEmpty) return []; | |
2093 | |
2094 var members = new Set<ExecutableElement>(); | |
2095 // Collect all possible extension method names. | |
2096 var extensionMembers = new HashSet<String>(); | |
2097 for (var t in types) { | |
2098 for (var m in [t.methods, t.accessors].expand((e) => e)) { | |
2099 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name); | |
2100 } | |
2101 } | |
2102 | |
2103 // Collect all of extension methods this type implements. | |
2104 for (var m in [type.methods, type.accessors].expand((e) => e)) { | |
2105 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { | |
2106 members.add(m); | |
2107 } | |
2108 } | |
2109 members.addAll(_collectMockMethods(type) | |
2110 .where((m) => extensionMembers.contains(m.name))); | |
2111 return members.toList(); | |
2112 } | |
2113 | |
2114 /// Generates the implicit default constructor for class C of the form | 2027 /// Generates the implicit default constructor for class C of the form |
2115 /// `C() : super() {}`. | 2028 /// `C() : super() {}`. |
2116 JS.Method _emitImplicitConstructor( | 2029 JS.Method _emitImplicitConstructor( |
2117 ClassDeclaration node, | 2030 ClassDeclaration node, |
2118 List<FieldDeclaration> fields, | 2031 List<FieldDeclaration> fields, |
2119 Map<FieldElement, JS.TemporaryId> virtualFields) { | 2032 Map<FieldElement, JS.TemporaryId> virtualFields) { |
2120 // If we don't have a method body, skip this. | 2033 // If we don't have a method body, skip this. |
2121 var superCall = _superConstructorCall(node.element); | 2034 var superCall = _superConstructorCall(node.element); |
2122 if (fields.isEmpty && superCall == null) return null; | 2035 if (fields.isEmpty && superCall == null) return null; |
2123 | 2036 |
(...skipping 3911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6035 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5948 if (targetIdentifier.staticElement is! PrefixElement) return false; |
6036 var prefix = targetIdentifier.staticElement as PrefixElement; | 5949 var prefix = targetIdentifier.staticElement as PrefixElement; |
6037 | 5950 |
6038 // The library the prefix is referring to must come from a deferred import. | 5951 // The library the prefix is referring to must come from a deferred import. |
6039 var containingLibrary = resolutionMap | 5952 var containingLibrary = resolutionMap |
6040 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5953 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
6041 .library; | 5954 .library; |
6042 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5955 var imports = containingLibrary.getImportsWithPrefix(prefix); |
6043 return imports.length == 1 && imports[0].isDeferred; | 5956 return imports.length == 1 && imports[0].isDeferred; |
6044 } | 5957 } |
OLD | NEW |