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

Unified Diff: frog/leg/resolver.dart

Issue 9616058: Implement parsing and resolving of type-variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix merge error. Created 8 years, 9 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: 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";

Powered by Google App Engine
This is Rietveld 408576698