| 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 0e2c4e1fb36cff978140216b00aff76b6fe09985..3402cc07ac8d3c4c14f5320a551e4934223ad754 100644
|
| --- a/compiler/java/com/google/dart/compiler/resolver/Resolver.java
|
| +++ b/compiler/java/com/google/dart/compiler/resolver/Resolver.java
|
| @@ -41,6 +41,7 @@ import com.google.dart.compiler.ast.DartNamedExpression;
|
| import com.google.dart.compiler.ast.DartNewExpression;
|
| import com.google.dart.compiler.ast.DartNode;
|
| import com.google.dart.compiler.ast.DartParameter;
|
| +import com.google.dart.compiler.ast.DartParameterizedTypeNode;
|
| import com.google.dart.compiler.ast.DartPropertyAccess;
|
| import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
|
| import com.google.dart.compiler.ast.DartReturnStatement;
|
| @@ -54,17 +55,16 @@ import com.google.dart.compiler.ast.DartSwitchStatement;
|
| import com.google.dart.compiler.ast.DartThisExpression;
|
| import com.google.dart.compiler.ast.DartTryStatement;
|
| import com.google.dart.compiler.ast.DartTypeNode;
|
| +import com.google.dart.compiler.ast.DartTypeParameter;
|
| import com.google.dart.compiler.ast.DartUnit;
|
| import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
|
| import com.google.dart.compiler.ast.DartVariable;
|
| import com.google.dart.compiler.ast.DartVariableStatement;
|
| import com.google.dart.compiler.ast.DartWhileStatement;
|
| import com.google.dart.compiler.ast.Modifiers;
|
| -import com.google.dart.compiler.type.FunctionType;
|
| import com.google.dart.compiler.type.InterfaceType;
|
| import com.google.dart.compiler.type.InterfaceType.Member;
|
| import com.google.dart.compiler.type.Type;
|
| -import com.google.dart.compiler.type.TypeVariable;
|
| import com.google.dart.compiler.util.StringUtils;
|
|
|
| import java.util.ArrayList;
|
| @@ -245,9 +245,30 @@ public class Resolver {
|
| checkImplicitDefaultDefaultSuperInvocation(cls, classElement);
|
| }
|
|
|
| - // Check that interface constructors have corresponding methods in default class.
|
| - if (cls.getDefaultClass() != null) {
|
| + if (cls.getDefaultClass() != null && classElement.getDefaultClass() == null) {
|
| + onError(cls.getDefaultClass(), ResolverErrorCode.NO_SUCH_TYPE, cls.getDefaultClass());
|
| + } else if (classElement.getDefaultClass() != null) {
|
| +
|
| + bindDefaultTypeParameters(classElement.getDefaultClass().getElement().getTypeParameters(),
|
| + cls.getDefaultClass().getTypeParameters(),
|
| + context);
|
| +
|
| + // Make sure the 'default' clause matches the referenced class type parameters
|
| + checkDefaultClassTypeParamsToDefaultDecl(classElement.getDefaultClass(),
|
| + cls.getDefaultClass());
|
| +
|
| + ClassElement defaultClass = classElement.getDefaultClass().getElement();
|
| + if (defaultClass.isInterface()) {
|
| + onError(cls.getDefaultClass(), ResolverErrorCode.DEFAULT_MUST_SPECIFY_CLASS);
|
| + }
|
| +
|
| + // Make sure the default class matches the interface type parameters
|
| + checkInterfaceTypeParamsToDefault(classElement, defaultClass);
|
| +
|
| + // Check that interface constructors have corresponding methods in default class.
|
| checkInteraceConstructors(classElement);
|
| +
|
| +
|
| }
|
|
|
| context = previousContext;
|
| @@ -256,11 +277,114 @@ public class Resolver {
|
| }
|
|
|
| /**
|
| + * Sets the type in the AST of the default clause of an inteterface so that the type
|
| + * parameters to resolve back to the default class.
|
| + */
|
| + private void bindDefaultTypeParameters(List<? extends Type> parameterTypes,
|
| + List<DartTypeParameter> parameterNodes,
|
| + ResolutionContext classContext) {
|
| + Iterator<? extends Type> typeIterator = parameterTypes.iterator();
|
| + Iterator<DartTypeParameter> nodeIterator = parameterNodes.iterator();
|
| +
|
| + while(typeIterator.hasNext() && nodeIterator.hasNext()) {
|
| +
|
| + Type type = typeIterator.next();
|
| + DartTypeParameter node = nodeIterator.next();
|
| +
|
| + if (type.getElement().getName().equals(node.getName().getTargetName())) {
|
| + node.setType(type);
|
| + } else {
|
| + node.setType(typeProvider.getDynamicType());
|
| + }
|
| +
|
| + TypeVariableElement variable = (TypeVariableElement)type.getElement();
|
| + DartTypeNode boundNode = node.getBound();
|
| + Type bound;
|
| + if (boundNode != null) {
|
| + bound =
|
| + classContext.resolveType(
|
| + boundNode,
|
| + false,
|
| + false,
|
| + ResolverErrorCode.NO_SUCH_TYPE);
|
| + boundNode.setType(bound);
|
| + } else {
|
| + bound = typeProvider.getObjectType();
|
| + }
|
| + variable.setBound(bound);
|
| + }
|
| +
|
| + while (nodeIterator.hasNext()) {
|
| + DartTypeParameter node = nodeIterator.next();
|
| + node.setType(typeProvider.getDynamicType());
|
| + }
|
| + }
|
| + /**
|
| + * If type parameters are present, the type parameters of the default statement
|
| + * must exactly match those of those declared in the class it references.
|
| + *
|
| + */
|
| + private void checkDefaultClassTypeParamsToDefaultDecl(InterfaceType defaultClassType,
|
| + DartParameterizedTypeNode defaultClassRef) {
|
| + if (defaultClassRef.getTypeParameters().isEmpty()) {
|
| + return;
|
| + }
|
| + DartClass defaultClass = (DartClass)defaultClassType.getElement().getNode();
|
| + boolean match = true;
|
| + if (defaultClass.getTypeParameters().isEmpty()) {
|
| + match = false;
|
| + } else {
|
| + // TODO(zundel): This is effective in catching mistakes, but highlights the entire type
|
| + // expression - A more specific indication of where the error started might be appreciated.
|
| + DartParameterizedTypeNode temp = new DartParameterizedTypeNode(defaultClass.getName(),
|
| + defaultClass.getTypeParameters());
|
| + String refSource = defaultClassRef.toSource();
|
| + String defaultClassSource = temp.toSource();
|
| + if (!refSource.equals(defaultClassSource)) {
|
| + match = false;
|
| + }
|
| + }
|
| + if (!match) {
|
| + // TODO(zundel): work harder to point out where the type param match failure starts.
|
| + onError(defaultClassRef, ResolverErrorCode.TYPE_PARAMETERS_MUST_MATCH_EXACTLY);
|
| + }
|
| + }
|
| +
|
| + private void checkInterfaceTypeParamsToDefault(ClassElement interfaceElement,
|
| + ClassElement defaultClassElement) {
|
| +
|
| + List<? extends Type> interfaceTypeParams = interfaceElement.getTypeParameters();
|
| +
|
| + List<? extends Type> defaultTypeParams = defaultClassElement.getTypeParameters();
|
| +
|
| +
|
| + if (defaultTypeParams.size() != interfaceTypeParams.size()) {
|
| +
|
| + onError(((DartClass) interfaceElement.getNode()).getName(),
|
| + ResolverErrorCode.DEFAULT_CLASS_MUST_HAVE_SAME_TYPE_PARAMS);
|
| + } else {
|
| + Iterator<? extends Type> interfaceIterator = interfaceTypeParams.iterator();
|
| + Iterator<? extends Type> defaultIterator = defaultTypeParams.iterator();
|
| + while (interfaceIterator.hasNext()) {
|
| + Type iVar = interfaceIterator.next();
|
| + Type dVar = defaultIterator.next();
|
| + String iVarName = iVar.getElement().getName();
|
| + String dVarName = dVar.getElement().getName();
|
| + if (!iVarName.equals(dVarName)) {
|
| + onError(iVar.getElement().getNode(), ResolverErrorCode.TYPE_VARIABLE_DOES_NOT_MATCH,
|
| + iVarName, dVarName, defaultClassElement.getName());
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| * 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(
|
| @@ -276,7 +400,7 @@ public class Resolver {
|
| if (numReqInterface != numReqDefault) {
|
| onError(
|
| interfaceConstructor.getNode(),
|
| - ResolverErrorCode.FACTORY_CONSTRUCTOR_NUMBER_OF_REQUIRED_PARAMETERS,
|
| + ResolverErrorCode.DEFAULT_CONSTRUCTOR_NUMBER_OF_REQUIRED_PARAMETERS,
|
| Elements.getRawMethodName(interfaceConstructor),
|
| interfaceClassName,
|
| numReqInterface,
|
| @@ -292,7 +416,7 @@ public class Resolver {
|
| if (!interfaceNames.equals(defaultNames)) {
|
| onError(
|
| interfaceConstructor.getNode(),
|
| - ResolverErrorCode.FACTORY_CONSTRUCTOR_NAMED_PARAMETERS,
|
| + ResolverErrorCode.DEFAULT_CONSTRUCTOR_NAMED_PARAMETERS,
|
| Elements.getRawMethodName(interfaceConstructor),
|
| interfaceClassName,
|
| interfaceNames,
|
| @@ -359,11 +483,6 @@ public class Resolver {
|
| DartFunction functionNode = node.getFunction();
|
| List<DartParameter> parameters = functionNode.getParams();
|
|
|
| - FunctionType type = (FunctionType) member.getType();
|
| - for (TypeVariable typeVariable : type.getTypeVariables()) {
|
| - context.declare(typeVariable.getElement());
|
| - }
|
| -
|
| // First declare all normal parameters in the scope, putting them in the
|
| // scope of the default expressions so we can report better errors.
|
| for (DartParameter parameter : parameters) {
|
| @@ -533,6 +652,7 @@ public class Resolver {
|
| resolveType(
|
| node.getTypeNode(),
|
| inStaticContext(currentMethod),
|
| + inFactoryContext(currentMethod),
|
| TypeErrorCode.NO_SUCH_TYPE);
|
| for (DartVariable variable : node.getVariables()) {
|
| Elements.setType(resolveVariable(variable, node.getModifiers()), type);
|
| @@ -572,7 +692,7 @@ public class Resolver {
|
| MethodElement previousFunction = innermostFunction;
|
| innermostFunction = element;
|
| DartFunction functionNode = x.getFunction();
|
| - resolveFunction(functionNode, element, null);
|
| + resolveFunction(functionNode, element);
|
| resolve(functionNode.getBody());
|
| innermostFunction = previousFunction;
|
| getContext().popScope();
|
| @@ -819,7 +939,8 @@ public class Resolver {
|
|
|
| @Override
|
| public Element visitTypeNode(DartTypeNode x) {
|
| - return resolveType(x, inStaticContext(currentMethod), ResolverErrorCode.NO_SUCH_TYPE).getElement();
|
| + return resolveType(x, inStaticContext(currentMethod), inFactoryContext(currentMethod),
|
| + ResolverErrorCode.NO_SUCH_TYPE).getElement();
|
| }
|
|
|
| @Override
|
| @@ -992,10 +1113,11 @@ public class Resolver {
|
|
|
| Element element = x.getConstructor().accept(getContext().new Selector() {
|
| // Only 'new' expressions can have a type in a property access.
|
| - @Override public Element visitTypeNode(DartTypeNode type) {
|
| - return recordType(
|
| - type,
|
| - resolveType(type, inStaticContext(currentMethod), ResolverErrorCode.NO_SUCH_TYPE));
|
| + @Override
|
| + public Element visitTypeNode(DartTypeNode type) {
|
| + return recordType(type, resolveType(type, inStaticContext(currentMethod),
|
| + inFactoryContext(currentMethod),
|
| + ResolverErrorCode.NO_SUCH_TYPE));
|
| }
|
|
|
| @Override public Element visitPropertyAccess(DartPropertyAccess node) {
|
| @@ -1117,7 +1239,7 @@ public class Resolver {
|
| }
|
| onError(
|
| errorTargetNode,
|
| - ResolverErrorCode.FACTORY_CONSTRUCTOR_UNRESOLVED,
|
| + ResolverErrorCode.DEFAULT_CONSTRUCTOR_UNRESOLVED,
|
| expectedFactoryConstructorName,
|
| defaultClassName);
|
| return null;
|
| @@ -1371,6 +1493,7 @@ public class Resolver {
|
| node,
|
| typeArgs,
|
| inStaticContext(currentMethod),
|
| + inFactoryContext(currentMethod),
|
| ResolverErrorCode.NO_SUCH_TYPE);
|
| // instantiateParametersType() will complain for wrong number of parameters (!=2)
|
| recordType(node, type);
|
| @@ -1387,6 +1510,7 @@ public class Resolver {
|
| node,
|
| typeArgs,
|
| inStaticContext(currentMethod),
|
| + inFactoryContext(currentMethod),
|
| ResolverErrorCode.NO_SUCH_TYPE);
|
| // instantiateParametersType() will complain for wrong number of parameters (!=1)
|
| recordType(node, type);
|
| @@ -1521,8 +1645,15 @@ public class Resolver {
|
| }
|
|
|
| private boolean inStaticContext(Element element) {
|
| - return element == null || Elements.isTopLevel(element)
|
| - || element.getModifiers().isStatic() || element.getModifiers().isFactory();
|
| + return element == null || Elements.isTopLevel(element)
|
| + || element.getModifiers().isStatic() || element.getModifiers().isFactory();
|
| + }
|
| +
|
| + private boolean inFactoryContext(Element element) {
|
| + if (element != null) {
|
| + return element.getModifiers().isFactory();
|
| + }
|
| + return false;
|
| }
|
|
|
| @Override
|
| @@ -1530,6 +1661,11 @@ public class Resolver {
|
| return inStaticContext(currentMethod);
|
| }
|
|
|
| + @Override
|
| + boolean isFactoryContext() {
|
| + return inFactoryContext(currentMethod);
|
| + }
|
| +
|
| boolean isStaticContextOrInitializer() {
|
| return inStaticContext(currentMethod) || inInitializer;
|
| }
|
|
|