Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| index 9e1e01859bf7060e6ed1ec4c7da2d56d676a1fc5..9bfa80f28551f9a9f430960e138a946aacc37e11 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| @@ -1050,50 +1050,46 @@ class TypeResolver { |
| return false; |
| } |
| - Element resolveTypeName(Scope scope, TypeAnnotation node) { |
| - Identifier typeName = node.typeName.asIdentifier(); |
| - Send send = node.typeName.asSend(); |
| - return resolveTypeNameInternal(scope, typeName, send); |
| - } |
| - |
| - Element resolveTypeNameInternal(Scope scope, Identifier typeName, Send send) { |
| - if (send != null) { |
| - typeName = send.selector; |
| - } |
| - String stringValue = typeName.source.stringValue; |
| - if (identical(stringValue, 'void')) { |
| - return compiler.types.voidType.element; |
| - } else if (identical(stringValue, 'Dynamic')) { |
| - // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. |
| - compiler.onDeprecatedFeature(typeName, 'Dynamic'); |
| - return compiler.dynamicClass; |
| - } else if (identical(stringValue, 'dynamic')) { |
| - return compiler.dynamicClass; |
| - } else if (send != null) { |
| - Element e = scope.lookup(send.receiver.asIdentifier().source); |
| - if (e != null && identical(e.kind, ElementKind.PREFIX)) { |
| - // The receiver is a prefix. Lookup in the imported members. |
| - PrefixElement prefix = e; |
| - return prefix.lookupLocalMember(typeName.source); |
| - } else if (e != null && identical(e.kind, ElementKind.CLASS)) { |
| - // The receiver is the class part of a named constructor. |
| - return e; |
| + Element resolveTypeName(Scope scope, |
| + SourceString prefixName, |
| + Identifier typeName) { |
| + if (prefixName != null) { |
| + Element e = scope.lookup(prefixName); |
| + if (e != null) { |
| + if (identical(e.kind, ElementKind.PREFIX)) { |
| + // The receiver is a prefix. Lookup in the imported members. |
| + PrefixElement prefix = e; |
| + return prefix.lookupLocalMember(typeName.source); |
| + } else if (identical(e.kind, ElementKind.CLASS)) { |
| + // TODO(johnniwinther): Remove this case. |
| + // The receiver is the class part of a named constructor. |
| + return e; |
| + } |
| } else { |
| return null; |
| } |
| } else { |
| - return scope.lookup(typeName.source); |
| + String stringValue = typeName.source.stringValue; |
| + if (identical(stringValue, 'void')) { |
| + return compiler.types.voidType.element; |
| + } else if (identical(stringValue, 'Dynamic')) { |
| + // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. |
| + compiler.onDeprecatedFeature(typeName, 'Dynamic'); |
| + return compiler.dynamicClass; |
| + } else if (identical(stringValue, 'dynamic')) { |
| + return compiler.dynamicClass; |
| + } else { |
| + return scope.lookup(typeName.source); |
| + } |
| } |
| } |
| // TODO(johnniwinther): Change [onFailure] and [whenResolved] to use boolean |
| // flags instead of closures. |
| - // TODO(johnniwinther): Should never return [null] but instead an erroneous |
| - // type. |
| DartType resolveTypeAnnotation( |
| TypeAnnotation node, |
| Scope scope, |
| - bool inStaticContext, |
| + Element enclosingElement, |
| {onFailure(Node node, MessageKind kind, [List arguments]), |
| whenResolved(Node node, DartType type)}) { |
| if (onFailure == null) { |
| @@ -1105,77 +1101,120 @@ class TypeResolver { |
| if (scope == null) { |
| compiler.internalError('resolveTypeAnnotation: no scope specified'); |
| } |
| - return resolveTypeAnnotationInContext(scope, node, inStaticContext, |
| + return resolveTypeAnnotationInContext(scope, node, enclosingElement, |
| onFailure, whenResolved); |
| } |
| DartType resolveTypeAnnotationInContext(Scope scope, TypeAnnotation node, |
| - bool inStaticContext, |
| + Element enclosingElement, |
| onFailure, whenResolved) { |
| - Element element = resolveTypeName(scope, node); |
| + Identifier typeName; |
| + SourceString prefixName; |
| + Send send = node.typeName.asSend(); |
| + if (send != null) { |
| + // The type name is of the form [: prefix . identifier :]. |
| + prefixName = send.receiver.asIdentifier().source; |
| + typeName = send.selector.asIdentifier(); |
| + } else { |
| + typeName = node.typeName.asIdentifier(); |
| + } |
| + |
| + Element element = resolveTypeName(scope, prefixName, typeName); |
| DartType type; |
| + |
| + DartType reportFailureAndCreateType(MessageKind messageKind, |
| + List messageArguments) { |
| + onFailure(node, messageKind, messageArguments); |
| + var erroneousElement = new ErroneousElement( |
| + messageKind, messageArguments, typeName.source, enclosingElement); |
| + var arguments = new LinkBuilder<DartType>(); |
| + resolveTypeArguments( |
| + node, null, enclosingElement, |
| + scope, onFailure, whenResolved, arguments); |
| + return new MalformedType(erroneousElement, null, arguments.toLink()); |
| + } |
| + |
| + DartType checkNoTypeArguments(DartType type) { |
| + var arguments = new LinkBuilder<DartType>(); |
| + bool typeArgumentCountMismatch = resolveTypeArguments( |
| + node, const Link(), enclosingElement, |
|
ngeoffray
2012/11/30 12:00:40
Link<of what> ?
Johnni Winther
2012/12/04 10:07:17
Done.
|
| + scope, onFailure, whenResolved, arguments); |
| + if (typeArgumentCountMismatch) { |
| + type = new MalformedType( |
| + new ErroneousElement(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, |
| + [node], typeName.source, enclosingElement), |
| + type, arguments.toLink()); |
| + } |
| + return type; |
| + } |
| + |
| if (element == null) { |
| - onFailure(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); |
| + type = reportFailureAndCreateType( |
| + MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); |
| } else if (element.isAmbiguous()) { |
| AmbiguousElement ambiguous = element; |
| - onFailure(node, ambiguous.messageKind, ambiguous.messageArguments); |
| + type = reportFailureAndCreateType( |
| + ambiguous.messageKind, ambiguous.messageArguments); |
| } else if (!element.impliesType()) { |
| - onFailure(node, MessageKind.NOT_A_TYPE, [node.typeName]); |
| + type = reportFailureAndCreateType( |
| + MessageKind.NOT_A_TYPE, [node.typeName]); |
| } else { |
| if (identical(element, compiler.types.voidType.element) || |
| identical(element, compiler.types.dynamicType.element)) { |
| - type = element.computeType(compiler); |
| + type = checkNoTypeArguments(element.computeType(compiler)); |
| } else if (element.isClass()) { |
| ClassElement cls = element; |
| cls.ensureResolved(compiler); |
| - Link<DartType> arguments = |
| - resolveTypeArguments(node, cls.typeVariables, |
| - inStaticContext, scope, |
| - onFailure, whenResolved); |
| - if (cls.typeVariables.isEmpty && arguments.isEmpty) { |
| - // Use the canonical type if it has no type parameters. |
| - type = cls.computeType(compiler); |
| + var arguments = new LinkBuilder<DartType>(); |
| + bool typeArgumentCountMismatch = resolveTypeArguments( |
| + node, cls.typeVariables, enclosingElement, |
| + scope, onFailure, whenResolved, arguments); |
| + if (typeArgumentCountMismatch) { |
| + type = new MalformedType( |
| + new ErroneousElement(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, |
| + [node], typeName.source, enclosingElement), |
| + new InterfaceType(cls.declaration, arguments.toLink())); |
| } else { |
| - // In checked mode malformed-ness of the type argument bubbles up. |
| - if (anyMalformedTypesInThere(arguments) && |
| - compiler.enableTypeAssertions) { |
| - type = new MalformedType( |
| - new MalformedTypeElement(node, element)); |
| + if (arguments.isEmpty) { |
| + type = cls.rawType; |
| } else { |
| - if (arguments.isEmpty) { |
| - // Use the canonical raw type if the class is generic. |
| - type = cls.rawType; |
| - } else { |
| - type = new InterfaceType(cls.declaration, arguments); |
| - } |
| + type = new InterfaceType(cls.declaration, arguments.toLink()); |
| } |
| } |
| } else if (element.isTypedef()) { |
| TypedefElement typdef = element; |
| // TODO(ahe): Should be [ensureResolved]. |
| compiler.resolveTypedef(typdef); |
| - Link<DartType> arguments = resolveTypeArguments( |
| - node, typdef.typeVariables, inStaticContext, |
| - scope, onFailure, whenResolved); |
| - if (typdef.typeVariables.isEmpty && arguments.isEmpty) { |
| - // Return the canonical type if it has no type parameters. |
| - type = typdef.computeType(compiler); |
| + var arguments = new LinkBuilder<DartType>(); |
| + bool typeArgumentCountMismatch = resolveTypeArguments( |
| + node, typdef.typeVariables, enclosingElement, |
| + scope, onFailure, whenResolved, arguments); |
| + if (typeArgumentCountMismatch) { |
| + type = new MalformedType( |
| + new ErroneousElement(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, |
| + [node], typeName.source, enclosingElement), |
| + new TypedefType(typdef, arguments.toLink())); |
| } else { |
| if (arguments.isEmpty) { |
| type = typdef.rawType; |
| } else { |
| - type = new TypedefType(typdef, arguments); |
| + type = new TypedefType(typdef, arguments.toLink()); |
| } |
| } |
| } else if (element.isTypeVariable()) { |
| - if (inStaticContext) { |
| + if (enclosingElement.isInStaticMember()) { |
| compiler.reportWarning(node, |
| MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER.message( |
| - [element])); |
| - type = new MalformedType(new MalformedTypeElement(node, element)); |
| + [node])); |
| + type = new MalformedType( |
| + new ErroneousElement( |
| + MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER, |
| + [node], typeName.source, enclosingElement), |
| + element.computeType(compiler)); |
| } else { |
| type = element.computeType(compiler); |
| } |
| + type = checkNoTypeArguments(type); |
| } else { |
| compiler.cancel("unexpected element kind ${element.kind}", |
| node: node); |
| @@ -1185,34 +1224,45 @@ class TypeResolver { |
| return type; |
| } |
| - Link<DartType> resolveTypeArguments(TypeAnnotation node, |
| - Link<DartType> typeVariables, |
| - bool inStaticContext, |
| - Scope scope, onFailure, whenResolved) { |
| + /** |
| + * Resolves the type arguments of [node] and adds these to [arguments]. |
| + * |
| + * Returns [: true :] if the number of type arguments did not match the |
| + * number of type variables. |
| + */ |
| + bool resolveTypeArguments( |
| + TypeAnnotation node, |
| + Link<DartType> typeVariables, |
| + Element enclosingElement, |
| + Scope scope, |
| + onFailure, whenResolved, |
| + LinkBuilder<DartType> arguments) { |
| if (node.typeArguments == null) { |
| - return const Link<DartType>(); |
| + return false; |
| } |
| - var arguments = new LinkBuilder<DartType>(); |
| + bool typeArgumentCountMismatch = false; |
| for (Link<Node> typeArguments = node.typeArguments.nodes; |
| !typeArguments.isEmpty; |
| typeArguments = typeArguments.tail) { |
| - if (typeVariables.isEmpty) { |
| + if (typeVariables != null && typeVariables.isEmpty) { |
| onFailure(typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); |
| + typeArgumentCountMismatch = true; |
| } |
| DartType argType = resolveTypeAnnotationInContext(scope, |
| - typeArguments.head, |
| - inStaticContext, |
| - onFailure, |
| - whenResolved); |
| + typeArguments.head, |
| + enclosingElement, |
| + onFailure, |
| + whenResolved); |
| arguments.addLast(argType); |
| - if (!typeVariables.isEmpty) { |
| + if (typeVariables != null && !typeVariables.isEmpty) { |
| typeVariables = typeVariables.tail; |
| } |
| } |
| - if (!typeVariables.isEmpty) { |
| + if (typeVariables != null && !typeVariables.isEmpty) { |
| onFailure(node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT); |
| + typeArgumentCountMismatch = true; |
| } |
| - return arguments.toLink(); |
| + return typeArgumentCountMismatch; |
| } |
| } |
| @@ -2106,7 +2156,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| DartType resolveTypeAnnotation(TypeAnnotation node) { |
| Function report = typeRequired ? error : warning; |
| DartType type = typeResolver.resolveTypeAnnotation( |
| - node, scope, enclosingElement.isInStaticMember(), |
| + node, scope, enclosingElement, |
| onFailure: report, whenResolved: useType); |
| if (type == null) return null; |
| if (inCheckContext) { |
| @@ -2474,7 +2524,7 @@ class TypeDefinitionVisitor extends CommonResolverVisitor<DartType> { |
| TypeVariableElement variableElement = typeVariable.element; |
| if (typeNode.bound != null) { |
| DartType boundType = typeResolver.resolveTypeAnnotation( |
| - typeNode.bound, scope, element.isInStaticMember(), |
| + typeNode.bound, scope, element, |
| onFailure: warning); |
| if (boundType != null && boundType.element == variableElement) { |
| // TODO(johnniwinther): Check for more general cycles, like |