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

Unified Diff: compiler/java/com/google/dart/compiler/resolver/Resolver.java

Issue 8786002: Check that interface constructors and default class constructors are compatible. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Check that types of constructors parameters are identical Created 9 years 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 side-by-side diff with in-line comments
Download patch
Index: compiler/java/com/google/dart/compiler/resolver/Resolver.java
diff --git a/compiler/java/com/google/dart/compiler/resolver/Resolver.java b/compiler/java/com/google/dart/compiler/resolver/Resolver.java
index e921e06aeffc90bd64b8682f900278f2b1022301..f838170719921ae22b7b148da1ab3ec41dfd7014 100644
--- a/compiler/java/com/google/dart/compiler/resolver/Resolver.java
+++ b/compiler/java/com/google/dart/compiler/resolver/Resolver.java
@@ -241,11 +241,65 @@ public class Resolver {
checkImplicitDefaultDefaultSuperInvocation(cls, classElement);
}
+ // Check that interface constructors have corresponding methods in default class.
+ if (cls.getDefaultClass() != null) {
+ checkInteraceConstructors(classElement);
+ }
+
context = previousContext;
currentHolder = previousHolder;
return classElement;
}
+ /**
+ * Checks that interface constructors have corresponding methods in default class.
+ */
+ private void checkInteraceConstructors(ClassElement interfaceElement) {
+ String interfaceClassName = interfaceElement.getName();
+ String defaultClassName = interfaceElement.getDefaultClass().getElement().getName();
+ for (ConstructorElement interfaceConstructor : interfaceElement.getConstructors()) {
+ ConstructorElement defaultConstructor =
+ resolveInterfaceConstructorInDefaultClass(
+ interfaceConstructor.getNode(),
+ interfaceConstructor);
+ if (defaultConstructor != null) {
+ // Remember for TypeAnalyzer.
+ interfaceConstructor.setDefaultConstructor(defaultConstructor);
+ // Validate number of required parameters.
+ {
+ int numReqInterface = Elements.getNumberOfRequiredParameters(interfaceConstructor);
+ int numReqDefault = Elements.getNumberOfRequiredParameters(defaultConstructor);
+ if (numReqInterface != numReqDefault) {
+ onError(
+ interfaceConstructor.getNode(),
+ ResolverErrorCode.FACTORY_CONSTRUCTOR_NUMBER_OF_REQUIRED_PARAMETERS,
+ Elements.getRawMethodName(interfaceConstructor),
+ interfaceClassName,
+ numReqInterface,
+ Elements.getRawMethodName(defaultConstructor),
+ defaultClassName,
+ numReqDefault);
+ }
+ }
+ // Validate names of named parameters.
+ {
+ List<String> interfaceNames = Elements.getNamedParameters(interfaceConstructor);
+ List<String> defaultNames = Elements.getNamedParameters(defaultConstructor);
+ if (!interfaceNames.equals(defaultNames)) {
+ onError(
+ interfaceConstructor.getNode(),
+ ResolverErrorCode.FACTORY_CONSTRUCTOR_NAMED_PARAMETERS,
+ Elements.getRawMethodName(interfaceConstructor),
+ interfaceClassName,
+ interfaceNames,
+ Elements.getRawMethodName(defaultConstructor),
+ defaultClassName,
+ defaultNames);
+ }
+ }
+ }
+ }
+ }
/**
* Returns <code>true</code> if the {@link ClassElement} has an implicit or a declared
@@ -902,92 +956,100 @@ public class Resolver {
break;
}
- // If there is a default implementation, lookup the constructor in the default class.
+ // Will check that element is not null.
ConstructorElement constructor = checkIsConstructor(x, element);
- if (constructor != null
- && constructor.getConstructorType().getDefaultClass() != null) {
- element = null;
- // Prepare elements and names for classes.
- ClassElement originalClass = constructor.getConstructorType();
- ClassElement defaultClass = originalClass.getDefaultClass().getElement();
- String originalClassName = originalClass.getName();
- String defaultClassName = defaultClass.getName();
- // Prepare "qualifier.name" for original constructor.
- String rawOriginalMethodName = Elements.getRawMethodName(constructor);
- int originalDotIndex = rawOriginalMethodName.indexOf('.');
- String originalQualifier = StringUtils.substringBefore(rawOriginalMethodName, ".");
- String originalName = StringUtils.substringAfter(rawOriginalMethodName, ".");
- // Separate checks for cases when factory implements interface and not.
- boolean factoryImplementsInterface = Elements.implementsType(defaultClass, originalClass);
- if (factoryImplementsInterface) {
- for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
- String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
- // kI == nI and kF == nF
- if (rawOriginalMethodName.equals(originalClassName)
- && rawDefaultMethodName.equals(defaultClassName)) {
- element = defaultConstructor;
- break;
- }
- // kI == nI.name and kF == nF.name
- if (originalDotIndex != -1) {
- int defaultDotIndex = rawDefaultMethodName.indexOf('.');
- if (defaultDotIndex != -1) {
- String defaultQualifier = StringUtils.substringBefore(rawDefaultMethodName, ".");
- String defaultName = StringUtils.substringAfter(rawDefaultMethodName, ".");
- if (defaultQualifier.equals(defaultClassName)
- && originalQualifier.equals(originalClassName) &&
- defaultName.equals(originalName)) {
- element = defaultConstructor;
- break;
- }
- }
- }
+
+ // try to lookup the constructor in the default class.
+ constructor = resolveInterfaceConstructorInDefaultClass(x.getConstructor(), constructor);
+
+ // Check for using "const" to non-const constructor.
+ if (constructor != null) {
+ if (x.isConst() && !constructor.getModifiers().isConstant()) {
+ onError(x, ResolverErrorCode.CONST_AND_NONCONST_CONSTRUCTOR);
+ }
+ }
+
+ return recordElement(x, constructor);
+ }
+
+ /**
+ * If given {@link ConstructorElement} is declared in interface, try to resolve it in
+ * corresponding default class.
+ *
+ * @return the resolved {@link ConstructorElement}, or same as given.
+ */
+ private ConstructorElement resolveInterfaceConstructorInDefaultClass(DartNode errorTargetNode,
+ ConstructorElement constructor) {
+ // If no default class, use existing constructor.
+ if (constructor == null || constructor.getConstructorType().getDefaultClass() == null) {
+ return constructor;
+ }
+ // Prepare elements and names for classes.
+ ClassElement originalClass = constructor.getConstructorType();
+ ClassElement defaultClass = originalClass.getDefaultClass().getElement();
+ String originalClassName = originalClass.getName();
+ String defaultClassName = defaultClass.getName();
+ // Prepare "qualifier.name" for original constructor.
+ String rawOriginalMethodName = Elements.getRawMethodName(constructor);
+ int originalDotIndex = rawOriginalMethodName.indexOf('.');
+ String originalQualifier = StringUtils.substringBefore(rawOriginalMethodName, ".");
+ String originalName = StringUtils.substringAfter(rawOriginalMethodName, ".");
+ // Separate checks for cases when factory implements interface and not.
+ boolean factoryImplementsInterface = Elements.implementsType(defaultClass, originalClass);
+ if (factoryImplementsInterface) {
+ for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
+ String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
+ // kI == nI and kF == nF
+ if (rawOriginalMethodName.equals(originalClassName)
+ && rawDefaultMethodName.equals(defaultClassName)) {
+ return defaultConstructor;
}
- } else {
- for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
- String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
- if (rawDefaultMethodName.equals(rawOriginalMethodName)) {
- element = defaultConstructor;
- break;
+ // kI == nI.name and kF == nF.name
+ if (originalDotIndex != -1) {
+ int defaultDotIndex = rawDefaultMethodName.indexOf('.');
+ if (defaultDotIndex != -1) {
+ String defaultQualifier = StringUtils.substringBefore(rawDefaultMethodName, ".");
+ String defaultName = StringUtils.substringAfter(rawDefaultMethodName, ".");
+ if (defaultQualifier.equals(defaultClassName)
+ && originalQualifier.equals(originalClassName)
+ && defaultName.equals(originalName)) {
+ return defaultConstructor;
+ }
}
}
}
- // If constructor not found, try implicit default constructor of the default class.
- if (element == null
- && x.getArgs().isEmpty()
- && Elements.needsImplicitDefaultConstructor(defaultClass)) {
- element = new SyntheticDefaultConstructorElement(null, defaultClass, typeProvider);
- }
- // If factory constructor not resolved, report error with specific message for each case.
- if (element == null) {
- String expectedFactoryConstructorName;
- if (factoryImplementsInterface) {
- if (originalDotIndex == -1) {
- expectedFactoryConstructorName = defaultClassName;
- } else {
- expectedFactoryConstructorName = defaultClassName + "." + originalName;
- }
- } else {
- expectedFactoryConstructorName = rawOriginalMethodName;
+ } else {
+ for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
+ String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
+ if (rawDefaultMethodName.equals(rawOriginalMethodName)) {
+ return defaultConstructor;
}
- onError(
- x.getConstructor(),
- ResolverErrorCode.NEW_EXPRESSION_FACTORY_CONSTRUCTOR,
- expectedFactoryConstructorName,
- defaultClassName);
- return null;
}
- // Will check that element is not null.
- constructor = checkIsConstructor(x, element);
}
-
- if (constructor != null) {
- if (x.isConst() && !constructor.getModifiers().isConstant()) {
- onError(x, ResolverErrorCode.CONST_AND_NONCONST_CONSTRUCTOR);
+ // If constructor not found, try implicit default constructor of the default class.
+ if (constructor.getParameters().isEmpty()
+ && Elements.needsImplicitDefaultConstructor(defaultClass)) {
+ return new SyntheticDefaultConstructorElement(null, defaultClass, typeProvider);
+ }
+ // Factory constructor not resolved, report error with specific message for each case.
+ {
+ String expectedFactoryConstructorName;
+ if (factoryImplementsInterface) {
+ if (originalDotIndex == -1) {
+ expectedFactoryConstructorName = defaultClassName;
+ } else {
+ expectedFactoryConstructorName = defaultClassName + "." + originalName;
+ }
+ } else {
+ expectedFactoryConstructorName = rawOriginalMethodName;
}
+ onError(
+ errorTargetNode,
+ ResolverErrorCode.FACTORY_CONSTRUCTOR_UNRESOLVED,
+ expectedFactoryConstructorName,
+ defaultClassName);
+ return null;
}
-
- return recordElement(x, constructor);
}
@Override
@@ -1357,6 +1419,11 @@ public class Resolver {
DartPropertyAccess prop = (DartPropertyAccess)parameter.getName();
prop.setReferencedElement(element);
prop.getName().setReferencedElement(element);
+
+ // If no type specified, use type of field.
+ if (parameter.getTypeNode() == null && element != null) {
+ Elements.setType(parameter.getSymbol(), element.getType());
+ }
} else {
onError(parameter.getName(),
ResolverErrorCode.PARAMETER_INIT_OUTSIDE_CONSTRUCTOR);

Powered by Google App Engine
This is Rietveld 408576698