Index: lib/compiler/implementation/resolver.dart |
diff --git a/lib/compiler/implementation/resolver.dart b/lib/compiler/implementation/resolver.dart |
index 38909e31f51a14e1d32e72ff97a4216f3cc95f6b..f918f17a61e73ad6c3b72f71a2f6343239e5cd77 100644 |
--- a/lib/compiler/implementation/resolver.dart |
+++ b/lib/compiler/implementation/resolver.dart |
@@ -5,19 +5,29 @@ |
interface TreeElements { |
Element operator[](Node node); |
Selector getSelector(Send send); |
+ Type getType(TypeAnnotation annotation); |
} |
class TreeElementMapping implements TreeElements { |
Map<Node, Element> map; |
Map<Send, Selector> selectors; |
+ Map<TypeAnnotation, Type> types; |
+ |
TreeElementMapping() |
: map = new LinkedHashMap<Node, Element>(), |
- selectors = new LinkedHashMap<Send, Selector>(); |
+ selectors = new LinkedHashMap<Send, Selector>(), |
+ types = new LinkedHashMap<TypeAnnotation, Type>(); |
operator []=(Node node, Element element) => map[node] = element; |
operator [](Node node) => map[node]; |
void remove(Node node) { map.remove(node); } |
+ void setType(TypeAnnotation annotation, Type type) { |
+ types[annotation] = type; |
+ } |
+ |
+ Type getType(TypeAnnotation annotation) => types[annotation]; |
+ |
void setSelector(Send send, Selector selector) { |
selectors[send] = selector; |
} |
@@ -590,43 +600,10 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
} |
} |
- visitTypeAnnotation(TypeAnnotation node) { |
- Send send = node.typeName.asSend(); |
- Element element; |
- if (send !== null) { |
- if (typeRequired) { |
- element = resolveSend(send); |
- } else { |
- // Not calling resolveSend as it will emit an error instead of |
- // a warning if the type is bogus. |
- // TODO(ahe): Change resolveSend so it can emit a warning when needed. |
- return null; |
- } |
- } else { |
- element = context.lookup(node.typeName.asIdentifier().source); |
- } |
- if (element === null) { |
- if (typeRequired) { |
- error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); |
- } else { |
- warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); |
- } |
- } else if (!element.impliesType()) { |
- if (typeRequired) { |
- error(node, MessageKind.NOT_A_TYPE, [node.typeName]); |
- } else { |
- warning(node, MessageKind.NOT_A_TYPE, [node.typeName]); |
- } |
- } else { |
- if (element.isClass()) { |
- // TODO(ngeoffray): Should we also resolve typedef? |
- ClassElement cls = element; |
- compiler.resolver.toResolve.add(element); |
- } |
- // TODO(ahe): This should be a Type. |
- useElement(node, element); |
- } |
- return element; |
+ ClassElement visitTypeAnnotation(TypeAnnotation node) { |
+ Type type = resolveTypeAnnotation(node); |
+ if (type !== null) return type.element; |
+ return null; |
} |
Element defineElement(Node node, Element element, |
@@ -647,6 +624,14 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
return mapping[node] = element; |
} |
+ Type useType(TypeAnnotation annotation, Type type) { |
+ if (type !== null) { |
+ mapping.setType(annotation, type); |
+ useElement(annotation, type.element); |
ahe
2012/04/12 15:05:23
Long term, could we avoid setting the element?
|
+ } |
+ return type; |
+ } |
+ |
void setupFunction(FunctionExpression node, FunctionElement function) { |
context = new MethodScope(context, function); |
// Put the parameters in scope. |
@@ -818,12 +803,14 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
return target; |
} |
- resolveTypeTest(Node argument) { |
+ Type resolveTypeTest(Node argument) { |
TypeAnnotation node = argument.asTypeAnnotation(); |
if (node == null) { |
ahe
2012/04/12 15:05:23
===
|
- node = argument.asSend().receiver; |
+ // node is of the form !Type. |
+ node = argument.asSend().receiver.asTypeAnnotation(); |
+ if (node === null) compiler.cancel("malformed send"); |
} |
- resolveTypeRequired(node); |
+ return resolveTypeRequired(node); |
} |
void handleArguments(Send node) { |
@@ -986,27 +973,115 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
return null; |
} |
+ TypeAnnotation getTypeAnnotationFromSend(Send send) { |
+ if (send.selector.asTypeAnnotation() !== null) { |
+ return send.selector; |
+ } else if (send.selector.asSend() !== null) { |
+ Send selector = send.selector; |
+ if (selector.receiver.asTypeAnnotation() !== null) { |
+ return selector.receiver; |
+ } |
+ } else { |
+ compiler.internalError("malformed send in new expression"); |
+ } |
+ } |
+ |
FunctionElement resolveConstructor(NewExpression node) { |
FunctionElement constructor = |
node.accept(new ConstructorResolver(compiler, this)); |
+ TypeAnnotation annotation = getTypeAnnotationFromSend(node.send); |
+ Type type = resolveTypeRequired(annotation); |
if (constructor === null) { |
- Element resolved = resolveTypeRequired(node.send.selector); |
+ Element resolved = (type != null) ? type.element : null; |
if (resolved !== null && resolved.kind === ElementKind.TYPE_VARIABLE) { |
- error(node, WarningKind.TYPE_VARIABLE_AS_CONSTRUCTOR); |
+ error(node, MessageKind.TYPE_VARIABLE_AS_CONSTRUCTOR); |
return null; |
} else { |
error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]); |
+ return null; |
} |
} |
return constructor; |
} |
- Element resolveTypeRequired(Node node) { |
+ Type resolveTypeRequired(TypeAnnotation node) { |
bool old = typeRequired; |
typeRequired = true; |
- Element element = visit(node); |
+ Type result = resolveTypeAnnotation(node); |
typeRequired = old; |
- return element; |
+ return result; |
+ } |
+ |
+ Element resolveTypeName(node) { |
+ Identifier typeName = node.typeName.asIdentifier(); |
+ Send send = node.typeName.asSend(); |
+ if (send !== null) { |
+ typeName = send.selector; |
+ } |
+ if (typeName.source == Types.VOID) return compiler.types.voidType.element; |
+ if (typeName.source == Types.DYNAMIC || |
+ typeName.source.stringValue == "var") { |
ahe
2012/04/12 15:05:23
Is it necessary to test for "var"? Also, it should
|
+ return compiler.types.dynamicType.element; |
+ } |
+ if (send !== null) { |
+ Element e = context.lookup(send.receiver.asIdentifier().source); |
+ if (e !== null && 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 && e.kind === ElementKind.CLASS) { |
+ // The receiver is the class part of a named constructor. |
+ return e; |
+ } else { |
+ error(send.receiver, MessageKind.CANNOT_RESOLVE); |
ahe
2012/04/12 15:05:23
Shouldn't this be a warning if typeRequired is fal
|
+ } |
+ } else { |
+ return context.lookup(typeName.source); |
+ } |
+ } |
+ |
+ Type resolveTypeAnnotation(TypeAnnotation node) { |
+ Element element = resolveTypeName(node); |
+ Type type; |
+ if (element === null) { |
+ if (typeRequired) { |
+ error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); |
+ } else { |
+ warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); |
+ } |
+ } else if (!element.impliesType()) { |
+ if (typeRequired) { |
+ error(node, MessageKind.NOT_A_TYPE, [node.typeName]); |
+ } else { |
+ warning(node, MessageKind.NOT_A_TYPE, [node.typeName]); |
+ } |
+ } else { |
+ if (element == compiler.types.voidType.element) { |
ahe
2012/04/12 15:05:23
===
|
+ type = compiler.types.voidType; |
ahe
2012/04/12 15:05:23
Why not just:
type = element.type;
|
+ } else if (element == compiler.types.dynamicType.element) { |
ahe
2012/04/12 15:05:23
===
|
+ type = compiler.types.dynamicType; |
+ } else if (element.isClass()) { |
+ // TODO(ngeoffray): Should we also resolve typedef? |
ahe
2012/04/12 15:05:23
I think this TODO is obsolete.
|
+ ClassElement cls = element; |
+ compiler.resolver.toResolve.add(cls); |
+ LinkBuilder<Type> arguments = new LinkBuilder<Type>(); |
+ if (node.typeArguments !== null) { |
+ for (Link<Node> typeArguments = node.typeArguments.nodes; |
+ !typeArguments.isEmpty(); |
+ typeArguments = typeArguments.tail) { |
+ arguments.addLast(resolveTypeAnnotation(typeArguments.head)); |
+ } |
+ } |
ahe
2012/04/12 15:05:23
I don't think you're validating that the number of
|
+ type = new InterfaceType(element.name, element, arguments.toLink()); |
ahe
2012/04/12 15:05:23
This means you create a new object every time you
|
+ } else if (element.isTypedef()) { |
+ // TODO(karlklose): implement typedefs. We return a fake type that the |
+ // code generator can use to detect typedefs in is-checks. |
+ type = new SimpleType(element.name, element); |
ahe
2012/04/12 15:05:23
Why not:
type = element.type;
|
+ } else { |
+ type = element.computeType(compiler); |
ahe
2012/04/12 15:05:23
I'm not sure about this.
|
+ } |
+ } |
+ return useType(node, type); |
} |
visitModifiers(Modifiers node) { |
@@ -1632,7 +1707,17 @@ class SignatureResolver extends CommonResolverVisitor<Element> { |
// TODO(ahe): This is temporary. |
void resolveType(Node node) { |
if (node == null) return; |
- node.accept(new ResolverVisitor(compiler, enclosingElement)); |
+ // Find the correct member context to perform the lookup in. |
ahe
2012/04/12 15:05:23
This method was a temporary wrapper around calling
|
+ Element outer = enclosingElement; |
+ Element context = outer; |
+ while (outer !== null) { |
+ if (outer.isMember()) { |
+ context = outer; |
+ break; |
+ } |
+ outer = outer.enclosingElement; |
+ } |
+ node.accept(new ResolverVisitor(compiler, context)); |
} |
// TODO(ahe): This is temporary. |