Chromium Code Reviews| Index: frog/leg/resolver.dart |
| diff --git a/frog/leg/resolver.dart b/frog/leg/resolver.dart |
| index 3b5390ad5fec7e21a9e4e231c73c5156450a5902..a3c28b3e3002cba3d5f896938423e200f9217f1c 100644 |
| --- a/frog/leg/resolver.dart |
| +++ b/frog/leg/resolver.dart |
| @@ -410,16 +410,16 @@ class CommonResolverVisitor<R> extends AbstractVisitor<R> { |
| interface LabelScope { |
| LabelScope get outer(); |
| - LabelElement lookup(String label); |
| + LabelElement lookup(String label, [bool inStaticContext]); |
|
ngeoffray
2012/03/15 11:47:40
Why would labels care about a static context?
karlklose
2012/03/16 14:58:47
Done, removed all the static context booleans.
|
| } |
| class LabeledStatementLabelScope implements LabelScope { |
| final LabelScope outer; |
| final LabelElement label; |
| LabeledStatementLabelScope(this.outer, this.label); |
| - LabelElement lookup(String labelName) { |
| + LabelElement lookup(String labelName, [bool inStaticContext = false]) { |
| if (this.label.labelName == labelName) return label; |
| - return outer.lookup(labelName); |
| + return outer.lookup(labelName, inStaticContext); |
| } |
| } |
| @@ -429,16 +429,16 @@ class SwitchLabelScope implements LabelScope { |
| SwitchLabelScope(this.outer, this.caseLabels); |
| - LabelElement lookup(String labelName) { |
| + LabelElement lookup(String labelName, [bool inStaticContext = false]) { |
| LabelElement result = caseLabels[labelName]; |
| if (result !== null) return result; |
| - return outer.lookup(labelName); |
| + return outer.lookup(labelName, inStaticContext); |
| } |
| } |
| class EmptyLabelScope implements LabelScope { |
| const EmptyLabelScope(); |
| - LabelElement lookup(String label) => null; |
| + LabelElement lookup(String label, [bool inStaticContext = false]) => null; |
| LabelScope get outer() { |
| throw 'internal error: empty label scope has no outer'; |
| } |
| @@ -457,9 +457,9 @@ class StatementScope { |
| breakTargetStack = const EmptyLink<TargetElement>(), |
| continueTargetStack = const EmptyLink<TargetElement>(); |
| - LabelElement lookupLabel(String label) => |
| - labels.lookup(label); |
| - |
| + LabelElement lookupLabel(String label, [bool inStaticContext = false]) { |
| + return labels.lookup(label, inStaticContext); |
| + } |
| TargetElement currentBreakTarget() => |
| breakTargetStack.isEmpty() ? null : breakTargetStack.head; |
| @@ -525,7 +525,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| super(compiler); |
| Element lookup(Node node, SourceString name) { |
| - Element result = context.lookup(name); |
| + Element result = context.lookup(name, !inInstanceContext); |
| if (!inInstanceContext && result != null && result.isInstanceMember()) { |
| error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); |
| } |
| @@ -547,8 +547,9 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| inStaticContext(action()) { |
| bool wasInstanceContext = inInstanceContext; |
| inInstanceContext = false; |
| - action(); |
| + var result = action(); |
| inInstanceContext = wasInstanceContext; |
| + return result; |
| } |
| visitInStaticContext(Node node) { |
| @@ -593,7 +594,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| } |
| if (className == const SourceString('var')) return null; |
| if (className == const SourceString('void')) return null; |
| - Element element = context.lookup(className); |
| + Element element = context.lookup(className, !inInstanceContext); |
| if (element === null) { |
| if (typeRequired) { |
| error(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]); |
| @@ -956,9 +957,15 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| FunctionElement resolveConstructor(NewExpression node) { |
| FunctionElement constructor = |
| - node.accept(new ConstructorResolver(compiler, this)); |
| + node.accept(new ConstructorResolver(compiler, this)); |
| if (constructor === null) { |
| - error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]); |
| + Element resolved = resolveTypeRequired(node.send.selector); |
| + if (resolved !== null && resolved.kind === ElementKind.TYPE_VARIABLE) { |
| + error(node, WarningKind.TYPE_VARIABLE_AS_CONSTRUCTOR); |
| + return null; |
| + } else { |
| + error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]); |
| + } |
| } |
| return constructor; |
| } |
| @@ -1196,54 +1203,120 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
| Scope context; |
| + ClassElement classElement; |
| ClassResolverVisitor(Compiler compiler, LibraryElement library) |
| : context = new TopScope(library), |
| super(compiler); |
| Type visitClassNode(ClassNode node) { |
| - ClassElement element = context.lookup(node.name.source); |
| - compiler.ensure(element !== null); |
| - compiler.ensure(!element.isResolved); |
| - element.supertype = visit(node.superclass); |
| - if (element.name != Types.OBJECT && element.supertype === null) { |
| + classElement = context.lookup(node.name.source); |
| + compiler.ensure(classElement !== null); |
| + compiler.ensure(!classElement.isResolved); |
| + final Link<TypeVariable> parameters = |
| + node.typeParameters !== null ? node.typeParameters.nodes |
| + : const EmptyLink<TypeVariable>(); |
| + // Create types and elements for type variable. |
| + for (Link<TypeVariable> link = parameters; |
| + !link.isEmpty(); |
| + link = link.tail) { |
| + TypeVariable typeNode = link.head; |
| + SourceString variableName = typeNode.name.source; |
| + TypeVariableType variableType = new TypeVariableType(variableName); |
| + TypeVariableElement variableElement = |
| + new TypeVariableElement(variableName, classElement, node, |
| + variableType); |
| + variableType.element = variableElement; |
| + classElement.typeParameters[variableName] = variableElement; |
| + context = new TypeVariableScope(context, variableElement); |
| + } |
| + // Resolve the bounds of type variables. |
| + for (Link<TypeVariable> 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); |
| + } |
| + } |
| + } |
| + // Find super type. |
| + Type supertype = visit(node.superclass); |
| + if (supertype !== null && supertype.element.impliesType()) { |
| + classElement.supertype = supertype; |
| + } else if (supertype !== null) { |
| + error(node.superclass, MessageKind.TYPE_NAME_EXPECTED); |
| + } |
| + if (classElement.name != Types.OBJECT && classElement.supertype === null) { |
| ClassElement objectElement = context.lookup(Types.OBJECT); |
| if (objectElement !== null && !objectElement.isResolved) { |
| compiler.resolver.toResolve.add(objectElement); |
| } else if (objectElement === null){ |
| error(node, MessageKind.CANNOT_RESOLVE_TYPE, [Types.OBJECT]); |
| } |
| - element.supertype = new SimpleType(Types.OBJECT, objectElement); |
| + classElement.supertype = new SimpleType(Types.OBJECT, objectElement); |
| } |
| if (node.defaultClause !== null) { |
| - element.defaultClass = visit(node.defaultClause.nodes.head); |
| + classElement.defaultClass = visit(node.defaultClause); |
| } |
| for (Link<Node> link = node.interfaces.nodes; |
| !link.isEmpty(); |
| link = link.tail) { |
| - element.interfaces = element.interfaces.prepend(visit(link.head)); |
| + Type interfaceType = visit(link.head); |
| + if (interfaceType !== null && interfaceType.element.impliesType()) { |
|
ngeoffray
2012/03/15 11:47:40
IMO interfaceType.element.impliesType should alway
karlklose
2012/03/16 14:58:47
It could be a type variable, which is illegal.
|
| + classElement.interfaces = |
| + classElement.interfaces.prepend(interfaceType); |
| + } else { |
| + error(link.head, MessageKind.TYPE_NAME_EXPECTED); |
| + } |
| } |
| - calculateAllSupertypes(element, new Set<ClassElement>()); |
| - addDefaultConstructorIfNeeded(element); |
| - return element.computeType(compiler); |
| + calculateAllSupertypes(classElement, new Set<ClassElement>()); |
| + addDefaultConstructorIfNeeded(classElement); |
| + return classElement.computeType(compiler); |
| } |
| Type visitTypeAnnotation(TypeAnnotation node) { |
| return visit(node.typeName); |
| } |
| + Type visitTypeVariable(TypeVariable node) { |
|
ngeoffray
2012/03/15 11:47:40
Is that really necessary? And it's not obvious tha
karlklose
2012/03/16 14:58:47
Done, removed.
|
| + if (node.bound === null) { |
| + return compiler.objectClass; |
| + } |
| + return visit(node.bound); |
| + } |
| + |
| Type visitIdentifier(Identifier node) { |
| Element element = context.lookup(node.source); |
| if (element === null) { |
| error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); |
| - } else if (!element.impliesType()) { |
| + return null; |
| + } else if (!element.impliesType() && !element.isTypeVariable()) { |
| error(node, MessageKind.NOT_A_TYPE, [node]); |
| + return null; |
| } else { |
| if (element.isClass()) { |
| compiler.resolver.toResolve.add(element); |
| } |
| - // TODO(ngeoffray): Use type variables. |
| - return element.computeType(compiler); |
| + if (element.isTypeVariable()) { |
| + TypeVariableElement variableElement = element; |
| + return variableElement.type; |
| + } else if (element.isTypedef()) { |
| + compiler.unimplemented('visitIdentifier for typedefs'); |
| + } else { |
| + // TODO(ngeoffray): Use type variables. |
|
ngeoffray
2012/03/15 11:47:40
I believe you can remove this TODO now.
karlklose
2012/03/16 14:58:47
Done.
|
| + return element.computeType(compiler); |
| + } |
| } |
| return null; |
| } |
| @@ -1612,16 +1685,29 @@ class Scope { |
| abstract Element lookup(SourceString name); |
| } |
| +class TypeVariableScope extends Scope { |
| + TypeVariableScope(parent, element) : super(parent, element); |
| + Element add(Element element) { |
| + throw "Cannot add element to TypeVariableScope"; |
| + } |
| + Element lookup(SourceString name, [bool inStaticContext = false]) { |
| + if (!inStaticContext && name == element.name) { |
|
ahe
2012/03/15 11:17:33
I don't believe this is correct. The scope should
karlklose
2012/03/16 14:58:47
Done, removed.
|
| + return element; |
| + } |
| + if (parent !== null) return parent.lookup(name); |
| + } |
| +} |
| + |
| class MethodScope extends Scope { |
| final Map<SourceString, Element> elements; |
| MethodScope(Scope parent, Element element) |
| : super(parent, element), this.elements = new Map<SourceString, Element>(); |
| - Element lookup(SourceString name) { |
| + Element lookup(SourceString name, [bool inStaticContext = false]) { |
| Element element = elements[name]; |
| if (element !== null) return element; |
| - return parent.lookup(name); |
| + return parent.lookup(name, inStaticContext); |
| } |
| Element add(Element element) { |
| @@ -1639,12 +1725,15 @@ class ClassScope extends Scope { |
| ClassScope(ClassElement element, LibraryElement library) |
| : super(new TopScope(library), element); |
| - Element lookup(SourceString name) { |
| + Element lookup(SourceString name, [bool inStaticContext = false]) { |
| ClassElement cls = element; |
| - Element memberElement = cls.lookupLocalMember(name); |
| - if (memberElement != null) return memberElement; |
| - memberElement = parent.lookup(name); |
| - if (memberElement != null) return memberElement; |
| + Element result = cls.lookupLocalMember(name); |
| + if (result !== null) return result; |
| + if (!inStaticContext) { |
| + result = cls.lookupTypeParameter(name); |
| + } |
| + result = parent.lookup(name); |
| + if (result != null) return result; |
| return cls.lookupSuperMember(name); |
| } |
| @@ -1657,7 +1746,9 @@ class TopScope extends Scope { |
| LibraryElement get library() => element; |
| TopScope(LibraryElement library) : super(null, library); |
| - Element lookup(SourceString name) => library.find(name); |
| + Element lookup(SourceString name, [bool inStaticContext = false]) { |
| + return library.find(name); |
| + } |
| Element add(Element element) { |
| throw "Cannot add an element in the top scope"; |