mirror of
https://github.com/dart-lang/sdk
synced 2024-09-04 16:03:44 +00:00
Eliminate retarded constructors.
Modified: Resolver, Normalizer and GenerateJavascriptAST to special case implicit default constructors. Would be simpler if there was a notion of synthetics, but this is not the time to add such a scheme -- if nothing else it would disrupt the IDE. BUG=4562150 Review URL: https://chromereviews.googleplex.com/3522019 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@64 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
705be03363
commit
1fae22da51
|
@ -131,6 +131,7 @@ LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A02/t02:
|
|||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A02/t03: Fail # Bug 5371670.
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A02/t04: Fail # Bug 5371670.
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A03/t01: Fail # Bug 5371670.
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A03/t02: Fail # Bug 5371670. This will no longer valid due to language spec changes.
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A06/t04: Fail # Bug 5371670.
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A10/t01: Fail # Bug 5371670.
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A13/t01: Fail # Bug 5371670.
|
||||
|
@ -216,7 +217,6 @@ LibTest/core/Set/every/Set/every/A01/t04: Skip
|
|||
|
||||
LangGuideTest/02_Language_Constructs/02_11_Exceptions/A05/t01: Fail
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A05/t01: Fail
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A12/t01: Fail
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A12/t02: Fail
|
||||
LangGuideTest/02_Language_Constructs/02_1_Class/A02/t04: Skip # Times out.
|
||||
LangGuideTest/02_Language_Constructs/02_5_Meaning_of_Names/A02/t02: Fail
|
||||
|
|
|
@ -33,6 +33,8 @@ public enum DartCompilerErrorCode implements ErrorCode {
|
|||
CANNOT_RESOLVE_LABEL("cannot resolve label %s"),
|
||||
CANNOT_RESOLVE_METHOD("cannot resolve method %s"),
|
||||
CANNOT_RESOLVE_SUPER_CONSTRUCTOR("cannot resolve method %s"),
|
||||
CANNOT_RESOLVE_IMPLICIT_CALL_TO_SUPER_CONSTRUCTOR(
|
||||
"super type %s does not have a default constructor"),
|
||||
CATCH_OR_FINALLY_EXPECTED("catch or finally clause expected."),
|
||||
CONSTRUCTOR_CANNOT_BE_ABSTRACT("A constructor cannot be asbstract"),
|
||||
CONSTRUCTOR_CANNOT_BE_STATIC("A constructor cannot be static"),
|
||||
|
|
|
@ -442,6 +442,11 @@ public class GenerateJavascriptAST {
|
|||
for (Element element : classElement.getMembers()) {
|
||||
classMembers.add(element);
|
||||
}
|
||||
|
||||
if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
||||
addImplicitDefaultConstructor(x, classElement, classMembers);
|
||||
}
|
||||
|
||||
for (Element member : classMembers) {
|
||||
switch(ElementKind.of(member)) {
|
||||
case METHOD: {
|
||||
|
@ -491,6 +496,19 @@ public class GenerateJavascriptAST {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void addImplicitDefaultConstructor(DartClass x, ClassElement classElement,
|
||||
List<Element> classElementMembers) {
|
||||
for (DartNode member : x.getMembers()) {
|
||||
if (member instanceof DartMethodDefinition) {
|
||||
DartMethodDefinition method = (DartMethodDefinition) member;
|
||||
MethodElement symbol = method.getSymbol();
|
||||
if (symbol.isConstructor() && "".equals(symbol.getName())) {
|
||||
classElementMembers.add(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classElement
|
||||
*
|
||||
|
@ -846,12 +864,6 @@ public class GenerateJavascriptAST {
|
|||
Iterator<DartInitializer> iterator = initializers.iterator();
|
||||
Iterator<DartField> fieldIterator = fieldInitializers.iterator();
|
||||
|
||||
if (hasConstructorInvocation) {
|
||||
// skip the super call
|
||||
DartInitializer first = iterator.next();
|
||||
assert first.isInvocation();
|
||||
}
|
||||
|
||||
List<JsStatement> jsInitializers = initFunction.getBody().getStatements();
|
||||
|
||||
// Do the field inline initializers first. If there are any assignments in the initializer
|
||||
|
@ -861,14 +873,19 @@ public class GenerateJavascriptAST {
|
|||
jsInitializers.add(initializer.makeStmt());
|
||||
}
|
||||
|
||||
DartInvocation initInvocation = null;
|
||||
while (iterator.hasNext()) {
|
||||
jsInitializers.add((JsStatement) generate(iterator.next()));
|
||||
DartInitializer initializer = iterator.next();
|
||||
if (!initializer.isInvocation()) {
|
||||
jsInitializers.add((JsStatement) generate(initializer));
|
||||
} else {
|
||||
initInvocation = (DartInvocation) initializer.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasConstructorInvocation) {
|
||||
// Call the super initializer function in the initializer.
|
||||
// Compute the super constructor initializer to call.
|
||||
DartInvocation initInvocation = (DartInvocation) initializers.get(0).getValue();
|
||||
ConstructorElement superElement = (ConstructorElement) initInvocation.getSymbol();
|
||||
// TODO(floitsch): it would be better if we had a js-name and not just a string.
|
||||
// This way the debugging information would be better.
|
||||
|
@ -930,10 +947,11 @@ public class GenerateJavascriptAST {
|
|||
// If there are initializers, populate the initializer function.
|
||||
List<DartInitializer> initializers = constructor.getInitializers();
|
||||
if (!initializers.isEmpty()) {
|
||||
DartInitializer firstInit = initializers.get(0);
|
||||
if (firstInit.isInvocation()) {
|
||||
JsExprStmt statement = (JsExprStmt) generate(firstInit);
|
||||
return (JsInvocation) statement.getExpression();
|
||||
for (DartInitializer init : initializers) {
|
||||
if (init.isInvocation()) {
|
||||
JsExprStmt statement = (JsExprStmt) generate(init);
|
||||
return (JsInvocation) statement.getExpression();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -2141,10 +2159,6 @@ public class GenerateJavascriptAST {
|
|||
return expr;
|
||||
}
|
||||
|
||||
private JsNameRef nameref(JsName qualifier, String prop) {
|
||||
return AstUtil.newNameRef(qualifier.makeRef(), prop);
|
||||
}
|
||||
|
||||
private JsBinaryOperation assign(JsNameRef op1, JsExpression op2) {
|
||||
return AstUtil.newAssignment(op1, op2);
|
||||
}
|
||||
|
@ -2157,14 +2171,6 @@ public class GenerateJavascriptAST {
|
|||
return new JsBinaryOperation(JsBinaryOperator.OR, op1, op2);
|
||||
}
|
||||
|
||||
private JsPrefixOperation not(JsExpression op1) {
|
||||
return new JsPrefixOperation(JsUnaryOperator.NOT, op1);
|
||||
}
|
||||
|
||||
private JsBinaryOperation and(JsExpression op1, JsExpression op2) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.AND, op1, op2);
|
||||
}
|
||||
|
||||
private JsNumberLiteral number(double num) {
|
||||
return translationContext.getProgram().getNumberLiteral(num);
|
||||
}
|
||||
|
@ -3026,14 +3032,23 @@ public class GenerateJavascriptAST {
|
|||
// Must use SuperClass.call(this, ...) to get the correct 'this' context in the callee:
|
||||
// <super-class>.<name>$Constructor.call(this, ...).
|
||||
ConstructorElement element = (ConstructorElement) x.getSymbol();
|
||||
Element classElement;
|
||||
String elementName;
|
||||
if (element == null) {
|
||||
classElement = ((ClassElement) currentHolder).getSupertype().getElement();
|
||||
elementName = classElement.getName();
|
||||
} else {
|
||||
classElement = element.getEnclosingElement();
|
||||
elementName = element.getName();
|
||||
}
|
||||
|
||||
// TODO(floitsch): it would be good, if we could get a js-name instead of just a string.
|
||||
// This way the debugging information would be better.
|
||||
// We need to generate the JsName (for the initializer/factory) once only and store it
|
||||
// in some hashtable. Then instead of reusing the mangler, we should reuse those JsNames.
|
||||
// The debugging information would then contain a link from the property-access to the
|
||||
// constructor. Without JsName the debugger just assumes we access some random property.
|
||||
String name = mangler.mangleConstructor(element.getName(), unitLibrary);
|
||||
Element classElement = element.getEnclosingElement();
|
||||
String name = mangler.mangleConstructor(elementName, unitLibrary);
|
||||
JsNameRef constructorRef = AstUtil.newNameRef(getJsName(classElement).makeRef(), name);
|
||||
return generateInvocation(x, constructorRef, true, null, element);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.google.dart.compiler.ast.DartArrayAccess;
|
|||
import com.google.dart.compiler.ast.DartBinaryExpression;
|
||||
import com.google.dart.compiler.ast.DartBlock;
|
||||
import com.google.dart.compiler.ast.DartCase;
|
||||
import com.google.dart.compiler.ast.DartClass;
|
||||
import com.google.dart.compiler.ast.DartClassMember;
|
||||
import com.google.dart.compiler.ast.DartContext;
|
||||
import com.google.dart.compiler.ast.DartDefault;
|
||||
|
@ -35,8 +36,10 @@ import com.google.dart.compiler.ast.DartNodeTraverser;
|
|||
import com.google.dart.compiler.ast.DartParameter;
|
||||
import com.google.dart.compiler.ast.DartParenthesizedExpression;
|
||||
import com.google.dart.compiler.ast.DartPropertyAccess;
|
||||
import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
|
||||
import com.google.dart.compiler.ast.DartReturnStatement;
|
||||
import com.google.dart.compiler.ast.DartStatement;
|
||||
import com.google.dart.compiler.ast.DartSuperConstructorInvocation;
|
||||
import com.google.dart.compiler.ast.DartSwitchMember;
|
||||
import com.google.dart.compiler.ast.DartSwitchStatement;
|
||||
import com.google.dart.compiler.ast.DartThrowStatement;
|
||||
|
@ -52,11 +55,17 @@ import com.google.dart.compiler.resolver.ClassElement;
|
|||
import com.google.dart.compiler.resolver.ConstructorElement;
|
||||
import com.google.dart.compiler.resolver.CoreTypeProvider;
|
||||
import com.google.dart.compiler.resolver.Element;
|
||||
import com.google.dart.compiler.resolver.ElementKind;
|
||||
import com.google.dart.compiler.resolver.Elements;
|
||||
import com.google.dart.compiler.resolver.EnclosingElement;
|
||||
import com.google.dart.compiler.resolver.FieldElement;
|
||||
import com.google.dart.compiler.resolver.LabelElement;
|
||||
import com.google.dart.compiler.resolver.MethodElement;
|
||||
import com.google.dart.compiler.resolver.VariableElement;
|
||||
import com.google.dart.compiler.type.FunctionType;
|
||||
import com.google.dart.compiler.type.InterfaceType;
|
||||
import com.google.dart.compiler.type.Type;
|
||||
import com.google.dart.compiler.type.Types;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -579,6 +588,112 @@ public class Normalizer {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DartNode visitClass(DartClass node) {
|
||||
final ClassElement classElement = node.getSymbol();
|
||||
if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
||||
DartMethodDefinition method = createImplicitDefaultConstructor(classElement);
|
||||
|
||||
// TODO - We should really normalize the class itself.
|
||||
node.getMembers().add(method);
|
||||
}
|
||||
return super.visitClass(node);
|
||||
}
|
||||
|
||||
static class SyntheticDefaultConstructorElement implements ConstructorElement {
|
||||
private final DartMethodDefinition method;
|
||||
private final ClassElement enclosingClass;
|
||||
|
||||
SyntheticDefaultConstructorElement(DartMethodDefinition method, ClassElement enclosingClass) {
|
||||
this.method = method;
|
||||
this.enclosingClass = enclosingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalSymbolName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DartNode getNode() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNode(DartLabel node) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Modifiers getModifiers() {
|
||||
return Modifiers.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementKind getKind() {
|
||||
return ElementKind.CONSTRUCTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnclosingElement getEnclosingElement() {
|
||||
return enclosingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstructor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getReturnType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VariableElement> getParameters() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionType getFunctionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassElement getConstructorType() {
|
||||
return enclosingClass;
|
||||
}
|
||||
}
|
||||
|
||||
private DartMethodDefinition createImplicitDefaultConstructor(final ClassElement classElement) {
|
||||
assert (Elements.needsImplicitDefaultConstructor(classElement));
|
||||
DartFunction function = new DartFunction(Collections.<DartParameter>emptyList(),
|
||||
new DartBlock(Collections.<DartStatement>emptyList()), null);
|
||||
final DartMethodDefinition method =
|
||||
DartMethodDefinition.create(new DartIdentifier(""), function, Modifiers.NONE, null, null);
|
||||
method.setSymbol(new SyntheticDefaultConstructorElement(method, classElement));
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DartExpression visitBinaryExpression(DartBinaryExpression node) {
|
||||
node.visitChildren(this);
|
||||
|
@ -605,15 +720,62 @@ public class Normalizer {
|
|||
return node;
|
||||
}
|
||||
|
||||
static class NeedsImplicitSuperInvocationDeterminant extends DartNodeTraverser<Void> {
|
||||
private boolean needsSuperInvocation = true;
|
||||
|
||||
@Override
|
||||
public Void visitSuperConstructorInvocation(DartSuperConstructorInvocation node) {
|
||||
needsSuperInvocation = false;
|
||||
return super.visitSuperConstructorInvocation(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRedirectConstructorInvocation(DartRedirectConstructorInvocation node) {
|
||||
needsSuperInvocation = false;
|
||||
return super.visitRedirectConstructorInvocation(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitMethodDefinition(DartMethodDefinition node) {
|
||||
// Ignore everything except the initializers
|
||||
for (DartInitializer initializer : node.getInitializers()) {
|
||||
initializer.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DartMethodDefinition visitMethodDefinition(DartMethodDefinition node) {
|
||||
super.visitMethodDefinition(node);
|
||||
if (Elements.isNonFactoryConstructor(node.getSymbol())) {
|
||||
normalizeParameterInitializer(node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DartNode visitNewExpression(DartNewExpression node) {
|
||||
ConstructorElement symbol = node.getSymbol();
|
||||
if (symbol == null) {
|
||||
InterfaceType constructorType = Types.constructorType(node);
|
||||
|
||||
// HACK use proper normalized node
|
||||
ClassElement classToInstantiate = constructorType.getElement();
|
||||
if (classToInstantiate.getDefaultClass() != null) {
|
||||
classToInstantiate = classToInstantiate.getDefaultClass().getElement();
|
||||
}
|
||||
|
||||
if (classToInstantiate != null && Elements.needsImplicitDefaultConstructor(classToInstantiate)) {
|
||||
DartMethodDefinition implicitDefaultConstructor = createImplicitDefaultConstructor(classToInstantiate);
|
||||
node.setSymbol(implicitDefaultConstructor.getSymbol());
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitNewExpression(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DartNode visitSwitchStatement(DartSwitchStatement node) {
|
||||
node.getExpression().accept(this);
|
||||
|
@ -647,10 +809,28 @@ public class Normalizer {
|
|||
nInit.add(di);
|
||||
}
|
||||
}
|
||||
|
||||
EnclosingElement enclosingElement = node.getSymbol().getEnclosingElement();
|
||||
if (ElementKind.of(enclosingElement) == ElementKind.CLASS) {
|
||||
ClassElement classElement = (ClassElement) enclosingElement;
|
||||
if (!classElement.isObject()) {
|
||||
NeedsImplicitSuperInvocationDeterminant superLocator = new NeedsImplicitSuperInvocationDeterminant();
|
||||
node.accept(superLocator);
|
||||
if (superLocator.needsSuperInvocation) {
|
||||
DartSuperConstructorInvocation superInvocation = new DartSuperConstructorInvocation(
|
||||
new DartIdentifier(""), Collections.<DartExpression>emptyList());
|
||||
superInvocation.setSymbol(new SyntheticDefaultConstructorElement(null,
|
||||
classElement.getSupertype().getElement()));
|
||||
nInit.add(new DartInitializer(null, superInvocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nInit.isEmpty()) {
|
||||
if (!node.getInitializers().isEmpty()) {
|
||||
nInit.addAll(0, node.getInitializers());
|
||||
}
|
||||
|
||||
DartMethodDefinition nConstructor = DartMethodDefinition.create(
|
||||
node.getName(), node.getFunction(), node.getModifiers(), nInit, null);
|
||||
nConstructor.setSymbol(node.getSymbol());
|
||||
|
|
|
@ -209,4 +209,11 @@ public class Elements {
|
|||
public static Element voidElement() {
|
||||
return VoidElement.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the class needs an implicit default constructor.
|
||||
*/
|
||||
public static boolean needsImplicitDefaultConstructor(ClassElement classElement) {
|
||||
return !classElement.isObject() && classElement.getConstructors().isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,11 +237,51 @@ public class Resolver {
|
|||
}
|
||||
|
||||
checkRedirectConstructorCycle(classElement.getConstructors(), context);
|
||||
if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
||||
checkImplicitDefaultDefaultSuperInvocation(cls, classElement);
|
||||
}
|
||||
|
||||
context = previousContext;
|
||||
currentHolder = previousHolder;
|
||||
return classElement;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the {@link ClassElement} has an implicit or a declared
|
||||
* default constructor.
|
||||
*/
|
||||
boolean hasDefaultConstructor(ClassElement classElement) {
|
||||
if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ConstructorElement defaultCtor = Elements.lookupConstructor(classElement, "");
|
||||
if (defaultCtor != null) {
|
||||
return defaultCtor.getParameters().isEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkImplicitDefaultDefaultSuperInvocation(DartClass cls,
|
||||
ClassElement classElement) {
|
||||
assert (Elements.needsImplicitDefaultConstructor(classElement));
|
||||
|
||||
InterfaceType supertype = classElement.getSupertype();
|
||||
if (supertype != null) {
|
||||
ClassElement superElement = supertype.getElement();
|
||||
if (!superElement.isDynamic()) {
|
||||
ConstructorElement superCtor = Elements.lookupConstructor(superElement, "");
|
||||
if (superCtor != null && !superCtor.getParameters().isEmpty()) {
|
||||
resolutionError(cls.getName(),
|
||||
DartCompilerErrorCode.CANNOT_RESOLVE_IMPLICIT_CALL_TO_SUPER_CONSTRUCTOR,
|
||||
cls.getSuperclass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Element resolve(DartNode node) {
|
||||
if (node == null) {
|
||||
return null;
|
||||
|
@ -832,11 +872,27 @@ public class Resolver {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
if (ElementKind.of(element).equals(ElementKind.CLASS)) {
|
||||
// Just calling the unnamed constructor.
|
||||
element = Elements.lookupConstructor(((ClassElement) element), "");
|
||||
// Check for default constructor or implicit default constructor
|
||||
ClassElement classElement = (ClassElement) element;
|
||||
element = Elements.lookupConstructor(classElement, "");
|
||||
if (element == null) {
|
||||
// Check that the class needs an implicit ctor and no extra args are passed
|
||||
if (Elements.needsImplicitDefaultConstructor(classElement) && x.getArgs().isEmpty()) {
|
||||
InterfaceType defaultClass = classElement.getDefaultClass();
|
||||
if (defaultClass != null) {
|
||||
classElement = defaultClass.getElement();
|
||||
element = Elements.lookupConstructor(classElement, "");
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return recordElement(x, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If there is a default implementation, lookup the constructor in the
|
||||
// default class.
|
||||
ConstructorElement constructor = checkIsConstructor(x, element);
|
||||
|
@ -850,7 +906,15 @@ public class Resolver {
|
|||
// If the constructor hasn't been found, try the constructor of the default class.
|
||||
// TODO(ngeoffray): check earlier if the default class implements the interface.
|
||||
element = Elements.lookupConstructor(defaultClass, constructor.getName());
|
||||
if (element == null && Elements.needsImplicitDefaultConstructor(defaultClass)) {
|
||||
/*
|
||||
* Record the element and prevent checkIsConstructor from reporting errors below
|
||||
* since we know that w don't have an element.
|
||||
*/
|
||||
return recordElement(x, element);
|
||||
}
|
||||
}
|
||||
|
||||
// Will check that element is not null.
|
||||
constructor = checkIsConstructor(x, element);
|
||||
}
|
||||
|
@ -1106,17 +1170,30 @@ public class Resolver {
|
|||
}
|
||||
|
||||
private void checkConstructor(DartMethodDefinition node,
|
||||
ConstructorElement superCall,
|
||||
boolean firstIsSuper) {
|
||||
ConstructorElement superCall) {
|
||||
ClassElement currentClass = (ClassElement) currentHolder;
|
||||
if (superCall == null) {
|
||||
// Look for a default constructor in our super type
|
||||
InterfaceType supertype = currentClass.getSupertype();
|
||||
if (supertype != null) {
|
||||
superCall = Elements.lookupConstructor(supertype.getElement(), "");
|
||||
}
|
||||
}
|
||||
|
||||
if ((superCall == null)
|
||||
&& !currentClass.isObject()
|
||||
&& !currentClass.isObjectChild()) {
|
||||
resolutionError(node, DartCompilerErrorCode.CONSTRUCTOR_MUST_CALL_SUPER);
|
||||
} else if (!firstIsSuper
|
||||
&& !currentClass.isObject()
|
||||
&& !currentClass.isObjectChild()) {
|
||||
resolutionError(node, DartCompilerErrorCode.SUPER_CALL_MUST_BE_FIRST);
|
||||
InterfaceType supertype = currentClass.getSupertype();
|
||||
if (supertype != null) {
|
||||
ClassElement superElement = supertype.getElement();
|
||||
if (superElement != null) {
|
||||
if (!hasDefaultConstructor(superElement)) {
|
||||
resolutionError(node,
|
||||
DartCompilerErrorCode.CANNOT_RESOLVE_IMPLICIT_CALL_TO_SUPER_CONSTRUCTOR,
|
||||
superElement.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((superCall != null)
|
||||
&& node.getModifiers().isConstant()
|
||||
&& !superCall.getModifiers().isConstant()) {
|
||||
|
@ -1180,22 +1257,17 @@ public class Resolver {
|
|||
|
||||
private void resolveInitializers(DartMethodDefinition node) {
|
||||
assert null != node;
|
||||
Element firstElement = null;
|
||||
DartNode firstNode = null;
|
||||
Iterator<DartInitializer> initializers = node.getInitializers().iterator();
|
||||
if (initializers.hasNext()) {
|
||||
firstNode = initializers.next();
|
||||
firstElement = resolve(firstNode);
|
||||
}
|
||||
ConstructorElement constructorElement = null;
|
||||
while (initializers.hasNext()) {
|
||||
resolve(initializers.next());
|
||||
DartInitializer initializer = initializers.next();
|
||||
Element element = resolve(initializer);
|
||||
if (ElementKind.of(element) == ElementKind.CONSTRUCTOR) {
|
||||
constructorElement = (ConstructorElement) element;
|
||||
}
|
||||
}
|
||||
boolean firstIsConstructorInvocation =
|
||||
ElementKind.of(firstElement).equals(ElementKind.CONSTRUCTOR);
|
||||
if (firstElement != null && !firstIsConstructorInvocation) {
|
||||
firstElement = null;
|
||||
}
|
||||
checkConstructor(node, (ConstructorElement) firstElement, firstIsConstructorInvocation);
|
||||
|
||||
checkConstructor(node, constructorElement);
|
||||
}
|
||||
|
||||
private void resolutionError(DartNode node, DartCompilerErrorCode errorCode,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// expect one failure - Sub.A omits call to const super.
|
||||
// expect no failures - Sub.A omits call to const super, but one will be added
|
||||
|
||||
class Base {
|
||||
const Base(a);
|
|
@ -66,15 +66,15 @@ public class NegativeResolverTest extends CompilerTestCase {
|
|||
}
|
||||
|
||||
public void testConstSuperNegativeTest1() {
|
||||
checkNumErrors("ConstSuperNegativeTest1.dart", 1);
|
||||
checkNumErrors("ConstSuperNegativeTest1.dart", 0);
|
||||
}
|
||||
|
||||
public void testConstSuperNegativeTest2() {
|
||||
checkNumErrors("ConstSuperNegativeTest2.dart", 1);
|
||||
}
|
||||
|
||||
public void testConstSuperNegativeTest3() {
|
||||
checkNumErrors("ConstSuperNegativeTest3.dart", 1);
|
||||
public void testConstSuperTest() {
|
||||
checkNumErrors("ConstSuperTest.dart", 0);
|
||||
}
|
||||
|
||||
public void testParameterInitializerNegativeTest1() {
|
||||
|
|
|
@ -214,6 +214,71 @@ public class ResolverTest extends ResolverTestCase {
|
|||
checkExpectedErrors();
|
||||
}
|
||||
|
||||
public void testImplicitDefaultConstructor() {
|
||||
// Check that the implicit constructor is resolved correctly
|
||||
resolve(parseUnit(
|
||||
"class Object {}",
|
||||
"class B {}",
|
||||
"class C { main() { new B(); } }"), getContext());
|
||||
checkExpectedErrors();
|
||||
|
||||
/*
|
||||
* We should check for signature mismatch but that is a TypeAnalyzer issue.
|
||||
*/
|
||||
}
|
||||
|
||||
public void testImplicitDefaultConstructor_ThroughFactories() {
|
||||
// Check that we generate implicit constructors through factories also.
|
||||
resolve(parseUnit(
|
||||
"class Object {}",
|
||||
"interface B factory C {}",
|
||||
"class C {}",
|
||||
"class D { main() { new B(); } }"), getContext());
|
||||
checkExpectedErrors();
|
||||
}
|
||||
|
||||
public void testImplicitDefaultConstructor_WithConstCtor() {
|
||||
setExpectedErrors(1);
|
||||
// Check that we generate an error if the implicit constructor would violate const.
|
||||
resolve(parseUnit(
|
||||
"class Object {}",
|
||||
"class B { const B() {} }",
|
||||
"class C extends B {}",
|
||||
"class D { main() { new C(); } }"), getContext());
|
||||
checkExpectedErrors();
|
||||
}
|
||||
|
||||
public void testImplicitSuperCall_ImplicitCtor() {
|
||||
// Check that we can properly resolve the super ctor that exists.
|
||||
resolve(parseUnit(
|
||||
"class Object {}",
|
||||
"class B { B() {} }",
|
||||
"class C extends B {}",
|
||||
"class D { main() { new C(); } }"), getContext());
|
||||
checkExpectedErrors();
|
||||
}
|
||||
|
||||
public void testImplicitSuperCall_OnExistingCtor() {
|
||||
// Check that we can properly resolve the super ctor that exists.
|
||||
resolve(parseUnit(
|
||||
"class Object {}",
|
||||
"class B { B() {} }",
|
||||
"class C extends B { C(){} }",
|
||||
"class D { main() { new C(); } }"), getContext());
|
||||
checkExpectedErrors();
|
||||
}
|
||||
|
||||
public void testImplicitSuperCall_NonExistentSuper() {
|
||||
setExpectedErrors(1);
|
||||
// Check that we generate an error if the implicit constructor would call a non-existent super.
|
||||
resolve(parseUnit(
|
||||
"class Object {}",
|
||||
"class B { B(Object o) {} }",
|
||||
"class C extends B {}",
|
||||
"class D { main() { new C(); } }"), getContext());
|
||||
checkExpectedErrors();
|
||||
}
|
||||
|
||||
public void testCyclicSupertype() {
|
||||
setExpectedErrors(8);
|
||||
resolve(parseUnit(
|
||||
|
|
|
@ -67,7 +67,6 @@ Prefix11NegativeTest: Fail # Bug 5406175
|
|||
Prefix12NegativeTest: Fail,Crash # Bug 5406175
|
||||
FunctionTypeParameterNegativeTest: Fail # Bug 4568007
|
||||
ImplicitScopeTest: FAIL # Nested statements can be declarations
|
||||
ResolveTest: FAIL # 4254120 (implicit constructors)
|
||||
ConstConstructor1NegativeTest: FAIL # 5142545
|
||||
ConstConstructor2NegativeTest: FAIL # 5142545
|
||||
MathTest: FAIL # 5165080
|
||||
|
@ -75,7 +74,6 @@ StringConcatTest: FAIL # 5196164
|
|||
NamedParametersTest: Fail # Implementation in progress.
|
||||
NamedParametersTypeTest: Fail # Implementation in progress.
|
||||
NamedParametersWithConversionsTest: Fail # Implementation in progress.
|
||||
BadNamedParameters2Test: Fail # Implementation in progress.
|
||||
NamedParametersNegativeTest: Skip # Implementation in progress.
|
||||
NamedParameters2NegativeTest: Skip # Implementation in progress.
|
||||
NamedParameters3NegativeTest: Skip # Implementation in progress.
|
||||
|
@ -91,13 +89,13 @@ RegExp3Test: Fail # 5299683
|
|||
InterfaceFactory3NegativeTest: Fail # 5387405
|
||||
GenericParameterizedExtendsTest: Skip # Bug 5392297
|
||||
ConstObjectsAreImmutableTest: Fail # Bug 5202940
|
||||
SuperNegativeTest: Fail # Now that super calls are automatically injected this test doesn't make sense
|
||||
|
||||
# Crashes in dartc.
|
||||
FunctionTypeAliasTest: Crash # Bug 4519208.
|
||||
|
||||
# Other bugs (or unimplemented features) in dartc.
|
||||
GenericTest: Fail # Bug 5393302 (missing call to super constructor)
|
||||
GenericInheritanceTest: Fail # Bug 4562150 (implicit constructors).
|
||||
Throw7NegativeTest: Fail # Bug 4208459.
|
||||
Throw3Test: Fail # Bug 4205624.
|
||||
SwitchLabelTest: Fail # Bug 4208467.
|
||||
|
@ -108,7 +106,6 @@ PseudoKWNegativeTest: Fail # Bug 4979760.
|
|||
OverriddenNoSuchMethodTest: Fail # Bug 4202974.
|
||||
ManyOverriddenNoSuchMethodTest: Fail # Bug 4202974.
|
||||
NoSuchMethodTest: Fail # Bug 4202974.
|
||||
BadNamedParametersTest: Fail # Bug 4202974.
|
||||
NumbersTest: Fail # Fails because numbers are mapped to doubles.
|
||||
LocalFunctionTest: Fail # Bug in test. Bug 4202989 (shadowing).
|
||||
LocalFunction3Test: Fail # Bug 4202974.
|
||||
|
@ -131,7 +128,6 @@ OverrideFieldMethod3NegativeTest: Fail # Bug 5215249
|
|||
OverrideFieldMethod4NegativeTest: Fail # Bug 5215249
|
||||
OverrideFieldMethod5NegativeTest: Fail # Bug 5215249
|
||||
OverrideFieldMethod6NegativeTest: Fail # Bug 5215249
|
||||
DeoptimizationTest: Fail # Bug 4254120
|
||||
CharEscapeTest: Fail
|
||||
FunctionTypeParameter2NegativeTest: Fail # Bug 4568007
|
||||
|
||||
|
|
Loading…
Reference in a new issue