Index: dart/lib/compiler/implementation/resolver.dart |
diff --git a/dart/lib/compiler/implementation/resolver.dart b/dart/lib/compiler/implementation/resolver.dart |
index e8a31ab6bedc4d9acf0b7a8c9eec15f06d9910b2..18bda8a82018aea265848aa2063b65997db20b9d 100644 |
--- a/dart/lib/compiler/implementation/resolver.dart |
+++ b/dart/lib/compiler/implementation/resolver.dart |
@@ -36,14 +36,12 @@ class TreeElementMapping implements TreeElements { |
} |
class ResolverTask extends CompilerTask { |
- Queue<ClassElement> toResolve; |
- |
// Caches the elements of analyzed constructors to make them available |
// for inlining in later tasks. |
Map<FunctionElement, TreeElements> constructorElements; |
ResolverTask(Compiler compiler) |
- : super(compiler), toResolve = new Queue<ClassElement>(), |
+ : super(compiler), |
constructorElements = new Map<FunctionElement, TreeElements>(); |
String get name() => 'Resolver'; |
@@ -141,11 +139,6 @@ class ResolverTask extends CompilerTask { |
} |
visitBody(visitor, tree.body); |
- // Resolve the type annotations encountered in the method. |
- while (!toResolve.isEmpty()) { |
- ClassElement classElement = toResolve.removeFirst(); |
- classElement.ensureResolved(compiler); |
- } |
if (isConstructor) { |
constructorElements[element] = visitor.mapping; |
} |
@@ -168,6 +161,8 @@ class ResolverTask extends CompilerTask { |
} |
ClassElement defaultClass = defaultType.element; |
defaultClass.ensureResolved(compiler); |
+ assert(defaultClass.resolutionState == ClassElement.STATE_DONE); |
+ assert(defaultClass.supertypeLoadState == ClassElement.STATE_DONE); |
if (defaultClass.isInterface()) { |
error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE, |
[defaultClass.name]); |
@@ -225,27 +220,63 @@ class ResolverTask extends CompilerTask { |
return result; |
} |
+ /** |
+ * Load and resolve the supertypes of [cls]. |
+ * |
+ * Warning: do not call this method directly. It should only be |
+ * called by [resolveClass] and [ClassSupertypeResolver]. |
+ */ |
+ void loadSupertypes(ClassElement cls, Node from) { |
+ compiler.withCurrentElement(cls, () => measure(() { |
+ if (cls.supertypeLoadState == ClassElement.STATE_DONE) return; |
+ if (cls.supertypeLoadState == ClassElement.STATE_STARTED) { |
+ compiler.reportMessage( |
+ compiler.spanFromNode(from), |
+ MessageKind.CYCLIC_CLASS_HIERARCHY.error([cls.name]), |
+ api.Diagnostic.ERROR); |
+ cls.supertypeLoadState = ClassElement.STATE_DONE; |
+ cls.allSupertypes = const EmptyLink<Type>().prepend( |
+ compiler.objectClass.computeType(compiler)); |
+ return; |
+ } |
+ cls.supertypeLoadState = ClassElement.STATE_STARTED; |
+ compiler.withCurrentElement(cls, () { |
+ // TODO(ahe): Cache the node in cls. |
+ cls.parseNode(compiler).accept(new ClassSupertypeResolver(compiler, |
+ cls)); |
+ if (cls.supertypeLoadState != ClassElement.STATE_DONE) { |
+ cls.supertypeLoadState = ClassElement.STATE_DONE; |
+ } |
+ }); |
+ })); |
+ } |
+ |
+ /** |
+ * Resolve the class [element]. |
+ * |
+ * Before calling this method, [element] was constructed by the |
+ * scanner and most fields are null or empty. This method fills in |
+ * these fields and also ensure that the supertypes of [element] are |
+ * resolved. |
+ * |
+ * Warning: Do not call this method directly. Instead use |
+ * [:element.ensureResolved(compiler):]. |
+ */ |
void resolveClass(ClassElement element) { |
- if (element.isResolved || element.isBeingResolved) return; |
- element.isBeingResolved = true; |
- measure(() { |
+ assert(element.resolutionState == ClassElement.STATE_NOT_STARTED); |
+ element.resolutionState = ClassElement.STATE_STARTED; |
+ compiler.withCurrentElement(element, () => measure(() { |
ClassNode tree = element.parseNode(compiler); |
+ loadSupertypes(element, tree); |
+ |
ClassResolverVisitor visitor = |
new ClassResolverVisitor(compiler, element); |
visitor.visit(tree); |
- element.isBeingResolved = false; |
- element.isResolved = true; |
- |
- while (!toResolve.isEmpty()) { |
- ClassElement classElement = toResolve.removeFirst(); |
- classElement.ensureResolved(compiler); |
- } |
- |
- checkMembers(element); |
- }); |
+ element.resolutionState = ClassElement.STATE_DONE; |
+ })); |
} |
- checkMembers(ClassElement cls) { |
+ void checkMembers(ClassElement cls) { |
if (cls === compiler.objectClass) return; |
cls.forEachMember((holder, member) { |
checkAbstractField(member); |
@@ -288,7 +319,6 @@ class ResolverTask extends CompilerTask { |
api.Diagnostic.INFO); |
} |
- |
void checkValidOverride(Element member, Element superMember) { |
if (superMember === null) return; |
if (member.modifiers.isStatic()) { |
@@ -450,7 +480,7 @@ class InitializerResolver { |
ClassElement superClass = classElement.superclass; |
if (classElement != visitor.compiler.objectClass) { |
assert(superClass !== null); |
- assert(superClass.isResolved); |
+ assert(superClass.resolutionState == ClassElement.STATE_DONE); |
var element = resolveSuperOrThis(constructor, true, true, |
const SourceString(''), |
Selector.INVOCATION_0, functionNode); |
@@ -769,7 +799,7 @@ class TypeResolver { |
type = element.computeType(compiler); |
} else if (element.isClass()) { |
ClassElement cls = element; |
- if (!cls.isResolved) compiler.resolveClass(cls); |
+ cls.ensureResolved(compiler); |
Link<Type> arguments = |
resolveTypeArguments(node, cls.typeVariables, scope, |
onFailure, whenResolved); |
@@ -1718,6 +1748,18 @@ class TypeDefinitionVisitor extends CommonResolverVisitor<Type> { |
} |
} |
+/** |
+ * The implementation of [ResolverTask.resolveClass]. |
+ * |
+ * This visitor has to be extra careful as it is building the basic |
+ * element information, and cannot safely look at other elements as |
+ * this may lead to cycles. |
+ * |
+ * This visitor can assume that the supertypes have already been |
+ * resolved, but it cannot call [ResolverTask.resolveClass] directly |
+ * or indirectly (through [ClassElement.ensureResolved]) for any other |
+ * types. |
+ */ |
class ClassResolverVisitor extends TypeDefinitionVisitor { |
ClassElement get element() => super.element; |
@@ -1726,7 +1768,7 @@ class ClassResolverVisitor extends TypeDefinitionVisitor { |
Type visitClassNode(ClassNode node) { |
compiler.ensure(element !== null); |
- compiler.ensure(!element.isResolved); |
+ compiler.ensure(element.resolutionState == ClassElement.STATE_STARTED); |
InterfaceType type = element.computeType(compiler); |
scope = new TypeDeclarationScope(scope, element); |
@@ -1750,22 +1792,20 @@ class ClassResolverVisitor extends TypeDefinitionVisitor { |
if (objectElement === null) { |
compiler.internalError("Internal error: cannot resolve Object", |
node: node); |
- } else if (!objectElement.isResolved) { |
- compiler.resolver.toResolve.add(objectElement); |
+ } else { |
+ objectElement.ensureResolved(compiler); |
} |
// TODO(ahe): This should be objectElement.computeType(...). |
element.supertype = new InterfaceType(objectElement); |
} |
- if (node.defaultClause !== null) { |
- element.defaultClass = visit(node.defaultClause); |
- } |
+ assert(element.interfaces === null); |
+ Link<Type> interfaces = const EmptyLink<Type>(); |
for (Link<Node> link = node.interfaces.nodes; |
!link.isEmpty(); |
link = link.tail) { |
Type interfaceType = visit(link.head); |
if (interfaceType !== null && interfaceType.element.isExtendable()) { |
- element.interfaces = |
- element.interfaces.prepend(interfaceType); |
+ interfaces = interfaces.prepend(interfaceType); |
if (isBlackListed(interfaceType)) { |
error(link.head, MessageKind.CANNOT_IMPLEMENT, [interfaceType]); |
} |
@@ -1773,7 +1813,12 @@ class ClassResolverVisitor extends TypeDefinitionVisitor { |
error(link.head, MessageKind.TYPE_NAME_EXPECTED); |
} |
} |
- calculateAllSupertypes(element, new Set<ClassElement>()); |
+ element.interfaces = interfaces; |
+ calculateAllSupertypes(element); |
+ |
+ if (node.defaultClause !== null) { |
+ element.defaultClass = visit(node.defaultClause); |
+ } |
addDefaultConstructorIfNeeded(element); |
return element.computeType(compiler); |
} |
@@ -1791,9 +1836,6 @@ class ClassResolverVisitor extends TypeDefinitionVisitor { |
error(node, MessageKind.NOT_A_TYPE, [node]); |
return null; |
} else { |
- if (element.isClass()) { |
- compiler.resolver.toResolve.add(element); |
- } |
if (element.isTypeVariable()) { |
TypeVariableElement variableElement = element; |
return variableElement.type; |
@@ -1828,53 +1870,28 @@ class ClassResolverVisitor extends TypeDefinitionVisitor { |
return e.computeType(compiler); |
} |
- Link<Type> getOrCalculateAllSupertypes(ClassElement cls, |
- [Set<ClassElement> seen]) { |
- Link<Type> allSupertypes = cls.allSupertypes; |
- if (allSupertypes !== null) return allSupertypes; |
- if (seen === null) { |
- seen = new Set<ClassElement>(); |
- } |
- if (seen.contains(cls)) { |
- error(cls.parseNode(compiler), |
- MessageKind.CYCLIC_CLASS_HIERARCHY, |
- [cls.name]); |
- cls.allSupertypes = const EmptyLink<Type>(); |
- } else { |
- cls.ensureResolved(compiler); |
- calculateAllSupertypes(cls, seen); |
- } |
- return cls.allSupertypes; |
- } |
- |
- void calculateAllSupertypes(ClassElement cls, Set<ClassElement> seen) { |
+ void calculateAllSupertypes(ClassElement cls) { |
// TODO(karlklose): substitute type variables. |
// TODO(karlklose): check if type arguments match, if a classelement occurs |
// more than once in the supertypes. |
if (cls.allSupertypes !== null) return; |
final Type supertype = cls.supertype; |
- if (seen.contains(cls)) { |
- error(cls.parseNode(compiler), |
- MessageKind.CYCLIC_CLASS_HIERARCHY, |
- [cls.name]); |
- cls.allSupertypes = const EmptyLink<Type>(); |
- } else if (supertype != null) { |
- seen.add(cls); |
- Link<Type> superSupertypes = |
- getOrCalculateAllSupertypes(supertype.element, seen); |
+ if (supertype != null) { |
+ Link<Type> superSupertypes = supertype.element.allSupertypes; |
+ assert(superSupertypes !== null); |
Link<Type> supertypes = new Link<Type>(supertype, superSupertypes); |
for (Link<Type> interfaces = cls.interfaces; |
!interfaces.isEmpty(); |
interfaces = interfaces.tail) { |
Element element = interfaces.head.element; |
- Link<Type> interfaceSupertypes = |
- getOrCalculateAllSupertypes(element, seen); |
+ Link<Type> interfaceSupertypes = element.allSupertypes; |
+ assert(superSupertypes !== null); |
supertypes = supertypes.reversePrependAll(interfaceSupertypes); |
supertypes = supertypes.prepend(interfaces.head); |
} |
- seen.remove(cls); |
cls.allSupertypes = supertypes; |
} else { |
+ assert(cls === compiler.objectClass); |
cls.allSupertypes = const EmptyLink<Type>(); |
} |
} |
@@ -1915,6 +1932,79 @@ class ClassResolverVisitor extends TypeDefinitionVisitor { |
} |
} |
+class ClassSupertypeResolver extends CommonResolverVisitor { |
+ Scope context; |
+ ClassElement classElement; |
+ |
+ ClassSupertypeResolver(Compiler compiler, ClassElement cls) |
+ : context = new TopScope(cls.getLibrary()), |
+ this.classElement = cls, |
+ super(compiler); |
+ |
+ void loadSupertype(ClassElement element, Node from) { |
+ compiler.resolver.loadSupertypes(element, from); |
+ element.ensureResolved(compiler); |
+ } |
+ |
+ void visitClassNode(ClassNode node) { |
+ if (node.superclass === null) { |
+ if (classElement !== compiler.objectClass) { |
+ loadSupertype(compiler.objectClass, node); |
+ } |
+ } else { |
+ node.superclass.accept(this); |
+ } |
+ for (Link<Node> link = node.interfaces.nodes; |
+ !link.isEmpty(); |
+ link = link.tail) { |
+ link.head.accept(this); |
+ } |
+ } |
+ |
+ void visitTypeAnnotation(TypeAnnotation node) { |
+ node.typeName.accept(this); |
+ } |
+ |
+ void visitIdentifier(Identifier node) { |
+ Element element = context.lookup(node.source); |
+ if (element === null) { |
+ error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); |
+ } else if (!element.impliesType()) { |
+ error(node, MessageKind.NOT_A_TYPE, [node]); |
+ } else { |
+ if (element.isClass()) { |
+ loadSupertype(element, node); |
+ } else { |
+ compiler.reportMessage( |
+ compiler.spanFromNode(node), |
+ MessageKind.TYPE_NAME_EXPECTED.error([]), |
+ api.Diagnostic.ERROR); |
+ } |
+ } |
+ } |
+ |
+ void visitSend(Send node) { |
+ Identifier prefix = node.receiver.asIdentifier(); |
+ if (prefix === null) { |
+ error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
+ return; |
+ } |
+ Element element = context.lookup(prefix.source); |
+ if (element === null || element.kind !== ElementKind.PREFIX) { |
+ error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
+ return; |
+ } |
+ 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]); |
+ return; |
+ } |
+ loadSupertype(e, node); |
+ } |
+} |
+ |
class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> { |
VariableDefinitions definitions; |
ResolverVisitor resolver; |
@@ -2129,7 +2219,6 @@ class ConstructorResolver extends CommonResolverVisitor<Element> { |
if (e !== null && e.kind === ElementKind.CLASS) { |
ClassElement cls = e; |
cls.ensureResolved(compiler); |
- compiler.resolver.toResolve.add(cls); |
if (cls.isInterface() && (cls.defaultClass === null)) { |
error(selector, MessageKind.CANNOT_INSTANTIATE_INTERFACE, [cls.name]); |
} |
@@ -2153,7 +2242,6 @@ class ConstructorResolver extends CommonResolverVisitor<Element> { |
if (e.kind === ElementKind.CLASS) { |
ClassElement cls = e; |
cls.ensureResolved(compiler); |
- compiler.resolver.toResolve.add(cls); |
if (cls.isInterface() && (cls.defaultClass === null)) { |
error(node.receiver, MessageKind.CANNOT_INSTANTIATE_INTERFACE, |
[cls.name]); |