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); |