Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(900)

Unified Diff: dart/lib/compiler/implementation/resolver.dart

Issue 10855125: Ensure supertypes are loaded safely. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: More cleanup of ClassElement.cloneMembersTo Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: dart/lib/compiler/implementation/resolver.dart
diff --git a/dart/lib/compiler/implementation/resolver.dart b/dart/lib/compiler/implementation/resolver.dart
index f3960bccdfa1f43402857eb41edeb20ef80951d9..9bb919a1b08c3c29135899fcbc628f782278bd42 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(interfaceSupertypes !== 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;
@@ -2128,7 +2218,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]);
}
@@ -2152,7 +2241,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]);

Powered by Google App Engine
This is Rietveld 408576698