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 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 if (isGeneric) { | 820 if (isGeneric) { |
821 if (isMixinAlias) { | 821 if (isMixinAlias) { |
822 block.add(js.statement('const # = #;', [className, classExpr])); | 822 block.add(js.statement('const # = #;', [className, classExpr])); |
823 } else { | 823 } else { |
824 block.add(new JS.ClassDeclaration(classExpr)); | 824 block.add(new JS.ClassDeclaration(classExpr)); |
825 } | 825 } |
826 } else { | 826 } else { |
827 block.add(js.statement('# = #;', [className, classExpr])); | 827 block.add(js.statement('# = #;', [className, classExpr])); |
828 } | 828 } |
829 | 829 |
830 if (!isMixinAlias) _defineConstructors(classElem, className, [], block, []); | 830 if (!isMixinAlias) { |
| 831 block.addAll(_defineConstructors(classElem, className, [], [])); |
| 832 } |
831 | 833 |
832 if (classElem.interfaces.isNotEmpty) { | 834 if (classElem.interfaces.isNotEmpty) { |
833 block.add(js.statement('#[#.implements] = () => #;', [ | 835 block.add(js.statement('#[#.implements] = () => #;', [ |
834 className, | 836 className, |
835 _runtimeModule, | 837 _runtimeModule, |
836 new JS.ArrayInitializer(classElem.interfaces.map(_emitType).toList()) | 838 new JS.ArrayInitializer(classElem.interfaces.map(_emitType).toList()) |
837 ])); | 839 ])); |
838 } | 840 } |
839 | 841 |
840 if (isGeneric) { | 842 if (isGeneric) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
889 // type parameter. So we can use their local variable name directly. | 891 // type parameter. So we can use their local variable name directly. |
890 className = new JS.Identifier(classElem.name); | 892 className = new JS.Identifier(classElem.name); |
891 } else { | 893 } else { |
892 className = _emitTopLevelName(classElem); | 894 className = _emitTopLevelName(classElem); |
893 } | 895 } |
894 | 896 |
895 var savedClassProperties = _classProperties; | 897 var savedClassProperties = _classProperties; |
896 _classProperties = | 898 _classProperties = |
897 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); | 899 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); |
898 | 900 |
| 901 var jsCtors = _defineConstructors(classElem, className, fields, ctors); |
899 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), | 902 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), |
900 fields: allFields); | 903 fields: allFields); |
901 | 904 |
902 var body = <JS.Statement>[]; | 905 var body = <JS.Statement>[]; |
903 _initExtensionSymbols(classElem, methods, fields, body); | 906 _initExtensionSymbols(classElem, methods, fields, body); |
904 _emitSuperHelperSymbols(_superHelperSymbols, body); | 907 _emitSuperHelperSymbols(_superHelperSymbols, body); |
905 | 908 |
906 // Emit the class, e.g. `core.Object = class Object { ... }` | 909 // Emit the class, e.g. `core.Object = class Object { ... }` |
907 _defineClass(classElem, className, classExpr, body); | 910 _defineClass(classElem, className, classExpr, body); |
908 _defineConstructors(classElem, className, fields, body, ctors); | 911 body.addAll(jsCtors); |
909 | 912 |
910 // Emit things that come after the ES6 `class ... { ... }`. | 913 // Emit things that come after the ES6 `class ... { ... }`. |
911 var jsPeerNames = _getJSPeerNames(classElem); | 914 var jsPeerNames = _getJSPeerNames(classElem); |
912 JS.Statement deferredBaseClass = | 915 JS.Statement deferredBaseClass = |
913 _setBaseClass(classElem, className, jsPeerNames, body); | 916 _setBaseClass(classElem, className, jsPeerNames, body); |
914 | 917 |
915 _emitClassTypeTests(classElem, className, body); | 918 _emitClassTypeTests(classElem, className, body); |
916 | 919 |
917 _emitVirtualFieldSymbols(classElem, body); | 920 _emitVirtualFieldSymbols(classElem, body); |
918 _emitClassSignature(methods, allFields, classElem, ctors, className, body); | 921 _emitClassSignature(methods, allFields, classElem, ctors, className, body); |
(...skipping 789 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1708 } | 1711 } |
1709 var deferredBaseClass = _callHelperStatement( | 1712 var deferredBaseClass = _callHelperStatement( |
1710 'setBaseClass(#, #);', [className, newBaseClass]); | 1713 'setBaseClass(#, #);', [className, newBaseClass]); |
1711 if (typeFormals.isNotEmpty) return deferredBaseClass; | 1714 if (typeFormals.isNotEmpty) return deferredBaseClass; |
1712 body.add(deferredBaseClass); | 1715 body.add(deferredBaseClass); |
1713 } | 1716 } |
1714 return null; | 1717 return null; |
1715 } | 1718 } |
1716 | 1719 |
1717 /// Defines all constructors for this class as ES5 constructors. | 1720 /// Defines all constructors for this class as ES5 constructors. |
1718 void _defineConstructors( | 1721 List<JS.Statement> _defineConstructors( |
1719 ClassElement classElem, | 1722 ClassElement classElem, |
1720 JS.Expression className, | 1723 JS.Expression className, |
1721 List<FieldDeclaration> fields, | 1724 List<FieldDeclaration> fields, |
1722 List<JS.Statement> body, | |
1723 List<ConstructorDeclaration> ctors) { | 1725 List<ConstructorDeclaration> ctors) { |
1724 // See if we have a "call" with a statically known function type: | 1726 // See if we have a "call" with a statically known function type: |
1725 // | 1727 // |
1726 // - if it's a method, then it does because all methods do, | 1728 // - if it's a method, then it does because all methods do, |
1727 // - if it's a getter, check the return type. | 1729 // - if it's a getter, check the return type. |
1728 // | 1730 // |
1729 // Other cases like a getter returning dynamic/Object/Function will be | 1731 // Other cases like a getter returning dynamic/Object/Function will be |
1730 // handled at runtime by the dynamic call mechanism. So we only | 1732 // handled at runtime by the dynamic call mechanism. So we only |
1731 // concern ourselves with statically known function types. | 1733 // concern ourselves with statically known function types. |
1732 // | 1734 // |
1733 // For the same reason, we can ignore "noSuchMethod". | 1735 // For the same reason, we can ignore "noSuchMethod". |
1734 // call-implemented-by-nSM will be dispatched by dcall at runtime. | 1736 // call-implemented-by-nSM will be dispatched by dcall at runtime. |
1735 bool isCallable = classElem.lookUpMethod('call', null) != null || | 1737 bool isCallable = classElem.lookUpMethod('call', null) != null || |
1736 classElem.lookUpGetter('call', null)?.returnType is FunctionType; | 1738 classElem.lookUpGetter('call', null)?.returnType is FunctionType; |
1737 | 1739 |
| 1740 var body = <JS.Statement>[]; |
1738 void addConstructor(ConstructorElement element, JS.Expression jsCtor) { | 1741 void addConstructor(ConstructorElement element, JS.Expression jsCtor) { |
1739 var ctorName = _constructorName(element); | 1742 var ctorName = _constructorName(element); |
1740 if (JS.invalidStaticFieldName(element.name)) { | 1743 if (JS.invalidStaticFieldName(element.name)) { |
1741 jsCtor = | 1744 jsCtor = |
1742 _callHelper('defineValue(#, #, #)', [className, ctorName, jsCtor]); | 1745 _callHelper('defineValue(#, #, #)', [className, ctorName, jsCtor]); |
1743 } else { | 1746 } else { |
1744 jsCtor = js.call('#.# = #', [className, ctorName, jsCtor]); | 1747 jsCtor = js.call('#.# = #', [className, ctorName, jsCtor]); |
1745 } | 1748 } |
1746 body.add(js.statement('#.prototype = #.prototype;', [jsCtor, className])); | 1749 body.add(js.statement('#.prototype = #.prototype;', [jsCtor, className])); |
1747 } | 1750 } |
1748 | 1751 |
1749 if (classElem.isMixinApplication) { | 1752 if (classElem.isMixinApplication) { |
1750 var supertype = classElem.supertype; | 1753 var supertype = classElem.supertype; |
1751 for (var ctor in classElem.constructors) { | 1754 for (var ctor in classElem.constructors) { |
1752 List<JS.Identifier> jsParams = _emitParametersForElement(ctor); | 1755 List<JS.Identifier> jsParams = _emitParametersForElement(ctor); |
1753 var superCtor = supertype.lookUpConstructor(ctor.name, ctor.library); | 1756 var superCtor = supertype.lookUpConstructor(ctor.name, ctor.library); |
1754 var superCall = | 1757 var superCall = |
1755 _superConstructorCall(classElem, className, superCtor, jsParams); | 1758 _superConstructorCall(classElem, className, superCtor, jsParams); |
1756 addConstructor( | 1759 addConstructor( |
1757 ctor, | 1760 ctor, |
1758 _finishConstructorFunction( | 1761 _finishConstructorFunction( |
1759 jsParams, | 1762 jsParams, |
1760 new JS.Block(superCall != null ? [superCall] : []), | 1763 new JS.Block(superCall != null ? [superCall] : []), |
1761 isCallable)); | 1764 isCallable)); |
1762 } | 1765 } |
1763 return; | 1766 return body; |
1764 } | 1767 } |
1765 | 1768 |
1766 // Iff no constructor is specified for a class C, it implicitly has a | 1769 // Iff no constructor is specified for a class C, it implicitly has a |
1767 // default constructor `C() : super() {}`, unless C is class Object. | 1770 // default constructor `C() : super() {}`, unless C is class Object. |
1768 if (ctors.isEmpty) { | 1771 if (ctors.isEmpty) { |
1769 var superCall = _superConstructorCall(classElem, className); | 1772 var superCall = _superConstructorCall(classElem, className); |
1770 List<JS.Statement> body = [_initializeFields(fields)]; | 1773 var ctorBody = <JS.Statement>[_initializeFields(fields)]; |
1771 if (superCall != null) body.add(superCall); | 1774 if (superCall != null) ctorBody.add(superCall); |
1772 | 1775 |
1773 addConstructor(classElem.unnamedConstructor, | 1776 addConstructor(classElem.unnamedConstructor, |
1774 _finishConstructorFunction([], new JS.Block(body), isCallable)); | 1777 _finishConstructorFunction([], new JS.Block(ctorBody), isCallable)); |
1775 return; | 1778 return body; |
1776 } | 1779 } |
1777 | 1780 |
1778 bool foundConstructor = false; | 1781 bool foundConstructor = false; |
1779 for (var ctor in ctors) { | 1782 for (var ctor in ctors) { |
1780 var element = ctor.element; | 1783 var element = ctor.element; |
1781 if (element.isFactory || _externalOrNative(ctor)) continue; | 1784 if (element.isFactory || _externalOrNative(ctor)) continue; |
1782 | 1785 |
1783 addConstructor( | 1786 addConstructor( |
1784 element, _emitConstructor(ctor, fields, isCallable, className)); | 1787 element, _emitConstructor(ctor, fields, isCallable, className)); |
1785 foundConstructor = true; | 1788 foundConstructor = true; |
1786 } | 1789 } |
1787 | 1790 |
1788 // If classElement has only factory constructors, and it can be mixed in, | 1791 // If classElement has only factory constructors, and it can be mixed in, |
1789 // then we need to emit a special hidden default constructor for use by | 1792 // then we need to emit a special hidden default constructor for use by |
1790 // mixins. | 1793 // mixins. |
1791 if (!foundConstructor && classElem.supertype.isObject) { | 1794 if (!foundConstructor && classElem.supertype.isObject) { |
1792 body.add( | 1795 body.add( |
1793 js.statement('(#[#] = function() { # }).prototype = #.prototype;', [ | 1796 js.statement('(#[#] = function() { # }).prototype = #.prototype;', [ |
1794 className, | 1797 className, |
1795 _callHelper('mixinNew'), | 1798 _callHelper('mixinNew'), |
1796 [_initializeFields(fields)], | 1799 [_initializeFields(fields)], |
1797 className | 1800 className |
1798 ])); | 1801 ])); |
1799 } | 1802 } |
| 1803 |
| 1804 return body; |
1800 } | 1805 } |
1801 | 1806 |
1802 /// Emits static fields for a class, and initialize them eagerly if possible, | 1807 /// Emits static fields for a class, and initialize them eagerly if possible, |
1803 /// otherwise define them as lazy properties. | 1808 /// otherwise define them as lazy properties. |
1804 void _emitStaticFields(List<FieldDeclaration> staticFields, | 1809 void _emitStaticFields(List<FieldDeclaration> staticFields, |
1805 ClassElement classElem, List<JS.Statement> body) { | 1810 ClassElement classElem, List<JS.Statement> body) { |
1806 var lazyStatics = staticFields.expand((f) => f.fields.variables).toList(); | 1811 var lazyStatics = staticFields.expand((f) => f.fields.variables).toList(); |
1807 if (lazyStatics.isNotEmpty) { | 1812 if (lazyStatics.isNotEmpty) { |
1808 body.add(_emitLazyFields(classElem, lazyStatics)); | 1813 body.add(_emitLazyFields(classElem, lazyStatics)); |
1809 } | 1814 } |
(...skipping 4116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5926 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5931 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5927 var prefix = targetIdentifier.staticElement as PrefixElement; | 5932 var prefix = targetIdentifier.staticElement as PrefixElement; |
5928 | 5933 |
5929 // The library the prefix is referring to must come from a deferred import. | 5934 // The library the prefix is referring to must come from a deferred import. |
5930 var containingLibrary = resolutionMap | 5935 var containingLibrary = resolutionMap |
5931 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5936 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5932 .library; | 5937 .library; |
5933 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5938 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5934 return imports.length == 1 && imports[0].isDeferred; | 5939 return imports.length == 1 && imports[0].isDeferred; |
5935 } | 5940 } |
OLD | NEW |