Index: lib/compiler/implementation/resolver.dart |
diff --git a/lib/compiler/implementation/resolver.dart b/lib/compiler/implementation/resolver.dart |
index e6f318669266e92f4079050283c060538e33ecf9..24aeb049ff63c347fc423daa0e63dfa823e83fb9 100644 |
--- a/lib/compiler/implementation/resolver.dart |
+++ b/lib/compiler/implementation/resolver.dart |
@@ -216,8 +216,22 @@ class ResolverTask extends CompilerTask { |
Type resolveTypeAnnotation(Element element, TypeAnnotation annotation) { |
if (annotation === null) return compiler.types.dynamicType; |
- ResolverVisitor visitor = new ResolverVisitor(compiler, element); |
- Type result = visitor.resolveTypeAnnotation(annotation); |
+ Scope context = new TopScope(element.getLibrary()); |
ahe
2012/07/30 10:30:05
It seems ad hoc how we build the scope here. I wou
Johnni Winther
2012/08/01 10:12:28
Done.
|
+ Type result; |
+ Element contextElement = element.getEnclosingClassOrTypedef(); |
+ if (contextElement !== null && |
+ (contextElement.isTypedef() || contextElement.isClass())) { |
+ var typeDefinition = contextElement; |
+ context = new TypeVariablesScope(context, contextElement, |
+ typeDefinition.typeParameters); |
+ TypeResolver typeResolver = new TypeResolver(compiler); |
+ result = typeResolver.resolveTypeAnnotation(annotation, |
+ inContext: context, |
+ onFailure: warning); |
+ } else { |
+ ResolverVisitor visitor = new ResolverVisitor(compiler, element); |
+ result = visitor.resolveTypeAnnotation(annotation); |
+ } |
if (result === null) { |
// TODO(karklose): warning. |
return compiler.types.dynamicType; |
@@ -348,8 +362,9 @@ class ResolverTask extends CompilerTask { |
return compiler.withCurrentElement(element, () { |
Typedef node = |
compiler.parser.measure(() => element.parseNode(compiler)); |
- return measure(() => SignatureResolver.analyze( |
- compiler, node.formals, node.returnType, element)); |
+ TypedefResolverVisitor visitor = |
+ new TypedefResolverVisitor(compiler, element.getLibrary(), element); |
ahe
2012/07/30 10:30:05
Construction of the visitor should also be measure
Johnni Winther
2012/08/01 10:12:29
Done.
|
+ return measure(() => visitor.visit(node)); |
}); |
} |
@@ -371,6 +386,11 @@ class ResolverTask extends CompilerTask { |
ResolutionError message = new ResolutionError(kind, arguments); |
compiler.reportError(node, message); |
} |
+ |
+ warning(Node node, MessageKind kind, [arguments = const []]) { |
+ ResolutionWarning message = new ResolutionWarning(kind, arguments); |
+ compiler.reportWarning(node, message); |
+ } |
} |
class InitializerResolver { |
@@ -1635,86 +1655,30 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
} |
} |
-class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
+class TypeDefinitionVisitor extends CommonResolverVisitor<Type> { |
Scope context; |
- ClassElement classElement; |
- |
- ClassResolverVisitor(Compiler compiler, LibraryElement library, |
- ClassElement this.classElement) |
- : context = new TopScope(library), |
- super(compiler); |
- |
- Type visitClassNode(ClassNode node) { |
- compiler.ensure(classElement !== null); |
- compiler.ensure(!classElement.isResolved); |
- |
- classElement.ensureParametersAndType(compiler); |
- context = new TypeVariablesScope(context, classElement); |
- |
- // Resolve the bounds of type variables. |
- Link<Node> parameters = |
- node.typeParameters !== null ? node.typeParameters.nodes |
- : const EmptyLink<TypeVariable>(); |
- for (Link<Node> link = parameters; !link.isEmpty(); link = link.tail) { |
- TypeVariable typeNode = link.head; |
- SourceString variableName = typeNode.name.source; |
- TypeVariableElement variableElement = |
- classElement.typeParameters[variableName]; |
- if (typeNode.bound !== null) { |
- Type boundType = visit(typeNode.bound); |
- if (boundType !== null && boundType.element == variableElement) { |
- warning(node, MessageKind.CYCLIC_TYPE_VARIABLE, |
- [variableElement.name]); |
- } else if (boundType !== null) { |
- variableElement.bound = boundType; |
- } else { |
- variableElement.bound = compiler.objectClass.computeType(compiler); |
- } |
- } |
- } |
+ LibraryElement library; |
+ Element enclosing; |
+ Function report; |
+ |
+ visitTypeRequired(Node node) { |
+ Function oldReport = report; |
+ report = error; |
+ Type result = super.visit(node); |
+ report = oldReport; |
+ return result; |
+ } |
- // Find super type. |
- Type supertype = visit(node.superclass); |
- if (supertype !== null && supertype.element.isExtendable()) { |
- classElement.supertype = supertype; |
- if (isBlackListed(supertype)) { |
- error(node.superclass, MessageKind.CANNOT_EXTEND, [supertype]); |
- } |
- } else if (supertype !== null) { |
- error(node.superclass, MessageKind.TYPE_NAME_EXPECTED); |
- } |
- final objectElement = compiler.objectClass; |
- if (classElement !== objectElement && classElement.supertype === null) { |
- if (objectElement === null) { |
- compiler.internalError("Internal error: cannot resolve Object", |
- node: node); |
- } else if (!objectElement.isResolved) { |
- compiler.resolver.toResolve.add(objectElement); |
- } |
- classElement.supertype = new InterfaceType(objectElement); |
- } |
- if (node.defaultClause !== null) { |
- classElement.defaultClass = visit(node.defaultClause); |
- } |
- for (Link<Node> link = node.interfaces.nodes; |
- !link.isEmpty(); |
- link = link.tail) { |
- Type interfaceType = visit(link.head); |
- if (interfaceType !== null && interfaceType.element.isExtendable()) { |
- classElement.interfaces = |
- classElement.interfaces.prepend(interfaceType); |
- if (isBlackListed(interfaceType)) { |
- error(link.head, MessageKind.CANNOT_IMPLEMENT, [interfaceType]); |
- } |
- } else { |
- error(link.head, MessageKind.TYPE_NAME_EXPECTED); |
- } |
- } |
- calculateAllSupertypes(classElement, new Set<ClassElement>()); |
- addDefaultConstructorIfNeeded(classElement); |
- return classElement.computeType(compiler); |
+ TypeDefinitionVisitor(Compiler compiler, LibraryElement library, |
+ Element this.enclosing) |
+ : this.library = library, |
+ context = new TopScope(library), |
+ super(compiler) { |
+ report = warning; |
ahe
2012/07/30 10:30:05
This creates a new function closure object on each
Johnni Winther
2012/08/01 10:12:29
TODO
|
} |
+ abstract Map<SourceString, Element> get typeParameters(); |
ahe
2012/07/30 10:30:05
What is this for?
Johnni Winther
2012/08/01 10:12:29
Removed.
|
+ |
Type visitTypeAnnotation(TypeAnnotation node) { |
Type type = visit(node.typeName); |
if (type is! InterfaceType) { |
@@ -1750,6 +1714,8 @@ class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
} |
Type visitIdentifier(Identifier node) { |
+ // TODO(karlklose): use a TypeResolver here. |
+ if (node.source.stringValue === 'void') return compiler.types.voidType; |
Element element = context.lookup(node.source); |
if (element === null) { |
error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); |
@@ -1764,8 +1730,6 @@ class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
if (element.isTypeVariable()) { |
TypeVariableElement variableElement = element; |
return variableElement.type; |
- } else if (element.isTypedef()) { |
- compiler.unimplemented('visitIdentifier for typedefs', node: node); |
} else { |
// Type variables are handled in [visitTypeAnnotation]. |
return element.computeType(compiler); |
@@ -1777,24 +1741,177 @@ class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
Type visitSend(Send node) { |
Identifier prefix = node.receiver.asIdentifier(); |
if (prefix === null) { |
- error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
+ report(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
return null; |
} |
Element element = context.lookup(prefix.source); |
if (element === null || element.kind !== ElementKind.PREFIX) { |
- error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
+ report(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
return null; |
} |
PrefixElement prefixElement = element; |
Identifier selector = node.selector.asIdentifier(); |
var e = prefixElement.lookupLocalMember(selector.source); |
if (e === null || !e.impliesType()) { |
- error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]); |
+ report(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]); |
return null; |
} |
return e.computeType(compiler); |
} |
+ createTypeVariables(NodeList node) { |
+ if (node === null) return; |
+ // Create types and elements for type variable. |
+ for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { |
+ TypeVariable typeNode = link.head; |
+ SourceString variableName = typeNode.name.source; |
+ TypeVariableType variableType = new TypeVariableType(variableName); |
+ TypeVariableElement variableElement = |
+ new TypeVariableElement(variableName, enclosing, typeNode, |
+ variableType); |
+ variableType.element = variableElement; |
+ typeParameters[variableName] = variableElement; |
+ } |
+ } |
+ |
+ visitNodeList(NodeList node) { |
+ if (node === null) return; |
+ // Resolve the bounds of type variables. |
+ for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { |
+ TypeVariable typeNode = link.head; |
+ SourceString variableName = typeNode.name.source; |
+ TypeVariableElement variableElement = typeParameters[variableName]; |
+ if (typeNode.bound !== null) { |
+ Type boundType = visit(typeNode.bound); |
+ if (boundType !== null && boundType.element == variableElement) { |
+ report(node, MessageKind.CYCLIC_TYPE_VARIABLE, |
+ [variableElement.name]); |
+ } else if (boundType !== null) { |
+ variableElement.bound = boundType; |
+ } else { |
+ variableElement.bound = compiler.objectClass.computeType(compiler); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+class TypedefResolverVisitor extends TypeDefinitionVisitor { |
+ TypedefElement get typedefElement() => enclosing; |
+ get typeParameters() => typedefElement.typeParameters; |
+ |
+ TypedefResolverVisitor(Compiler compiler, LibraryElement library, |
+ TypedefElement typedefElement) |
+ : super(compiler, library, typedefElement); |
+ |
+ visitVariableDefinitions(VariableDefinitions variables) { |
+ return visit(variables.type); |
+ } |
+ |
+ visitTypedef(Typedef node) { |
+ createTypeVariables(node.typeParameters); |
+ FunctionType type = new FunctionType(compiler.types.dynamicType, |
+ null, typedefElement); |
+ typedefElement.cachedType = type; |
+ context = new TypeVariablesScope(context, enclosing, typeParameters); |
+ Type returnType = visit(node.returnType); |
+ if (returnType === null) { |
+ returnType = compiler.types.dynamicType; |
+ } else if (returnType.element === typedefElement) { |
+ warning(node.returnType, MessageKind.CYCLIC_TYPEDEF); |
+ returnType = compiler.types.dynamicType; |
+ } |
+ LinkBuilder<Type> formalsTypes = new LinkBuilder<Type>(); |
+ TypeResolver typeResolver = new TypeResolver(compiler); |
+ for (Link<Node> formals = node.formals.nodes; |
+ !formals.isEmpty(); |
+ formals = formals.tail) { |
+ if (formals.head.asNodeList() !== null) { |
+ // If there is a NodeList in the formal parameter list, it is the list |
+ // of optional parameters. |
+ // TODO(karlklose): support optional parameters. |
+ break; |
+ } |
+ Type formalType = visit(formals.head); |
+ if (formalType === null) { |
+ formalType = compiler.types.dynamicType; |
+ } else { |
+ if (formalType.element === typedefElement) { |
+ warning(formals.head, MessageKind.CYCLIC_TYPEDEF); |
+ formalType = compiler.types.dynamicType; |
+ } |
+ } |
+ formalsTypes.addLast(formalType); |
+ } |
+ type.parameterTypes = formalsTypes.toLink(); |
+ // Resolve type parameter bounds. |
+ visit(node.typeParameters); |
+ } |
+} |
+ |
+class ClassResolverVisitor extends TypeDefinitionVisitor { |
+ ClassElement get classElement() => enclosing; |
+ |
+ get typeParameters() => classElement.typeParameters; |
+ |
+ ClassResolverVisitor(Compiler compiler, LibraryElement library, |
+ ClassElement classElement) |
+ : super(compiler, library, classElement); |
+ |
+ Type visitClassNode(ClassNode node) { |
+ compiler.ensure(classElement !== null); |
+ compiler.ensure(!classElement.isResolved); |
+ |
+ // TODO(johnniwinther): Unify [ClassElement.ensureParametersAndType] and |
+ // [TypeDefinitionVisitor.createTypeVariables] |
+ classElement.ensureParametersAndType(compiler); |
+ |
+ // Resolve type paramters. |
+ context = new TypeVariablesScope(context, enclosing, typeParameters); |
+ visit(node.typeParameters); |
+ |
+ // Find super type. |
+ Type supertype = visitTypeRequired(node.superclass); |
+ if (supertype !== null && supertype.element.isExtendable()) { |
+ classElement.supertype = supertype; |
+ if (isBlackListed(supertype)) { |
+ error(node.superclass, MessageKind.CANNOT_EXTEND, [supertype]); |
+ } |
+ } else if (supertype !== null) { |
+ error(node.superclass, MessageKind.TYPE_NAME_EXPECTED); |
+ } |
+ final objectElement = compiler.objectClass; |
+ if (classElement !== objectElement && classElement.supertype === null) { |
+ if (objectElement === null) { |
+ compiler.internalError("Internal error: cannot resolve Object", |
+ node: node); |
+ } else if (!objectElement.isResolved) { |
+ compiler.resolver.toResolve.add(objectElement); |
+ } |
+ classElement.supertype = new InterfaceType(objectElement); |
+ } |
+ if (node.defaultClause !== null) { |
+ classElement.defaultClass = visitTypeRequired(node.defaultClause); |
+ } |
+ for (Link<Node> link = node.interfaces.nodes; |
+ !link.isEmpty(); |
+ link = link.tail) { |
+ Type interfaceType = visitTypeRequired(link.head); |
+ if (interfaceType !== null && interfaceType.element.isExtendable()) { |
+ classElement.interfaces = |
+ classElement.interfaces.prepend(interfaceType); |
+ if (isBlackListed(interfaceType)) { |
+ error(link.head, MessageKind.CANNOT_IMPLEMENT, [interfaceType]); |
+ } |
+ } else { |
+ error(link.head, MessageKind.TYPE_NAME_EXPECTED); |
+ } |
+ } |
+ calculateAllSupertypes(classElement, new Set<ClassElement>()); |
+ addDefaultConstructorIfNeeded(classElement); |
+ return classElement.computeType(compiler); |
+ } |
+ |
Link<InterfaceType> getOrCalculateAllSupertypes(ClassElement cls, |
[Set<ClassElement> seen]) { |
Link<InterfaceType> allSupertypes = cls.allSupertypes; |
@@ -2175,13 +2292,16 @@ class Scope { |
} |
class TypeVariablesScope extends Scope { |
- TypeVariablesScope(parent, ClassElement element) : super(parent, element); |
+ final Map<SourceString, TypeVariableElement> variables; |
+ |
+ TypeVariablesScope(parent, element, this.variables) : super(parent, element); |
+ |
Element add(Element newElement) { |
throw "Cannot add element to TypeVariableScope"; |
} |
+ |
Element lookup(SourceString name) { |
- ClassElement cls = element; |
- Element result = cls.lookupTypeParameter(name); |
+ Element result = variables[name]; |
if (result !== null) return result; |
if (parent !== null) return parent.lookup(name); |
} |