Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: pkg/dev_compiler/lib/src/compiler/code_generator.dart

Issue 2938713002: fix super from constructors (Closed)
Patch Set: fix Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/language_strong/super_from_constructor_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/language_strong/super_from_constructor_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698