Chromium Code Reviews| 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); |
| } |