Index: lib/compiler/implementation/elements/elements.dart |
diff --git a/lib/compiler/implementation/elements/elements.dart b/lib/compiler/implementation/elements/elements.dart |
index a104749521a57a0089f9f97975d1dc8d53b23074..dfe3f202266dade3983f0fcc65d99ef33d9aa2ab 100644 |
--- a/lib/compiler/implementation/elements/elements.dart |
+++ b/lib/compiler/implementation/elements/elements.dart |
@@ -38,7 +38,7 @@ class ElementCategory { |
static final int IMPLIES_TYPE = CLASS | ALIAS | TYPE_VARIABLE; |
- static final int IS_EXTENDABLE = CLASS | ALIAS; |
+ static final int IS_EXTENDABLE = CLASS; |
} |
class ElementKind { |
@@ -214,6 +214,18 @@ class Element implements Hashable { |
return null; |
} |
+ /** |
+ * Creates the scope for this element. The scope of the |
+ * enclosing element will be the parent scope. |
+ */ |
+ Scope buildScope() => buildEnclosingScope(); |
+ |
+ /** |
+ * Creates the scope for the enclosing element. The scope of the |
+ * enclosing element will be the parent scope. |
ahe
2012/08/02 06:43:14
Could you explain what the difference between thes
|
+ */ |
+ Scope buildEnclosingScope() => enclosingElement.buildScope(); |
+ |
String toString() { |
// TODO(johnniwinther): Test for nullness of name, or make non-nullness an |
// invariant for all element types? |
@@ -394,6 +406,8 @@ class LibraryElement extends CompilationUnitElement { |
return path.substring(path.lastIndexOf('/') + 1); |
} |
} |
+ |
+ Scope buildEnclosingScope() => new TopScope(this); |
} |
class PrefixElement extends Element { |
@@ -418,19 +432,39 @@ class PrefixElement extends Element { |
Token position() => firstPosition; |
} |
-class TypedefElement extends Element { |
- Type cachedType; |
+class TypedefElement extends Element implements TypeDeclarationElement { |
+ TypedefElement(SourceString name, Element enclosing) |
+ : super(name, ElementKind.TYPEDEF, enclosing); |
+ |
+ TypedefType cachedType; |
+ Type alias; |
Typedef cachedNode; |
- TypedefElement(SourceString name, Element enclosing) |
- : super(name, ElementKind.TYPEDEF, enclosing); |
+ /** |
+ * Function signature for a typedef of a function type. The signature is |
+ * kept to provide full information about parameter names through the mirror |
+ * system. |
+ * |
+ * The [functionSignature] is not available until the typedef element has been |
+ * resolved. |
+ */ |
+ FunctionSignature functionSignature; |
- Type computeType(Compiler compiler) { |
- if (cachedType !== null) return cachedType; |
- cachedType = compiler.computeFunctionType( |
- this, compiler.resolveTypedef(this)); |
+ TypedefType computeType(Compiler compiler) { |
+ if (cachedType == null) { |
+ Typedef node = parseNode(compiler); |
+ Link<TypeVariableType> parameters = |
+ createTypeVariables(this, node.typeParameters); |
ahe
2012/08/02 06:43:14
How about adding:
assert(cachedType === null);
|
+ cachedType = new TypedefType(this, parameters); |
+ } |
return cachedType; |
} |
+ |
+ |
+ Link<TypeVariableType> get typeVariables() => cachedType.typeArguments; |
+ |
+ Scope buildScope() => |
+ new TypeDeclarationScope(enclosingElement.buildScope(), this); |
} |
class VariableElement extends Element { |
@@ -505,8 +539,8 @@ class VariableListElement extends Element { |
/** |
* Function signature for a variable with a function type. The signature is |
- * kept to provide full information about parameter names through the the |
- * mirror system. |
+ * kept to provide full information about parameter names through the mirror |
+ * system. |
*/ |
FunctionSignature functionSignature; |
@@ -613,6 +647,8 @@ class AbstractFieldElement extends Element { |
} |
} |
+// TODO(johnniwinther): [FunctionSignature] should be merged with |
+// [FunctionType]. |
class FunctionSignature { |
Link<Element> requiredParameters; |
Link<Element> optionalParameters; |
@@ -811,30 +847,84 @@ class VoidElement extends Element { |
bool impliesType() => true; |
} |
-class ClassElement extends ContainerElement { |
+/** |
+ * [TypeDeclarationElement] defines the common interface for class/interface |
+ * declarations and typedefs. |
+ */ |
+interface TypeDeclarationElement extends Element { |
+ /** |
+ * The type variables declared on this declaration. The type variables are not |
+ * available until the type of the element has been computed through |
+ * [computeType]. |
+ */ |
+ // TODO(johnniwinther): Find a (better) way to decouple [typeVariables] from |
+ // [Compiler]. |
+ final Link<TypeVariableType> typeVariables; |
+} |
+ |
+/** |
+ * Creates the type variables, their type and corresponding element, for the |
+ * type variables declared in [parameter] on [element]. The bounds of the type |
+ * variables are not set until [element] has been resolved. |
+ */ |
+Link<TypeVariableType> createTypeVariables(TypeDeclarationElement element, |
+ NodeList parameters) { |
+ if (parameters === null) return const EmptyLink<TypeVariableType>(); |
+ |
+ // Create types and elements for type variable. |
+ var arguments = new LinkBuilder<TypeVariableType>(); |
+ for (Link<Node> link = parameters.nodes; !link.isEmpty(); link = link.tail) { |
+ TypeVariable typeNode = link.head; |
+ SourceString variableName = typeNode.name.source; |
+ TypeVariableType variableType = new TypeVariableType(variableName); |
+ arguments.addLast(variableType); |
+ TypeVariableElement variableElement = |
+ new TypeVariableElement(variableName, element, typeNode, variableType); |
+ variableType.element = variableElement; |
+ } |
+ return arguments.toLink(); |
+} |
+ |
+/** |
+ * Looks up [name] within the type variables declared in [element]. |
+ */ |
+Element lookupTypeVariable(TypeDeclarationElement element, |
+ SourceString name) { |
+ Link<TypeVariableType> typeVariableLink = element.typeVariables; |
+ while (!typeVariableLink.isEmpty()) { |
+ TypeVariableType typeVariable = typeVariableLink.head; |
+ if (typeVariable.name == name) { |
+ return typeVariable.element; |
+ } |
+ typeVariableLink = typeVariableLink.tail; |
+ } |
+ return null; |
+} |
+ |
ahe
2012/08/02 06:43:14
Extra line.
|
+ |
+class ClassElement extends ContainerElement |
+ implements TypeDeclarationElement { |
final int id; |
- Type type; |
- Type supertype; |
- Type defaultClass; |
+ InterfaceType type; |
+ InterfaceType supertype; |
ahe
2012/08/02 06:43:14
Eventually an interface may extend a typedef. So I
|
+ InterfaceType defaultClass; |
Link<Element> members = const EmptyLink<Element>(); |
Map<SourceString, Element> localMembers; |
Map<SourceString, Element> constructors; |
- Link<Type> interfaces = const EmptyLink<Type>(); |
- LinkedHashMap<SourceString, TypeVariableElement> typeParameters; |
+ Link<InterfaceType> interfaces = const EmptyLink<InterfaceType>(); |
bool isResolved = false; |
bool isBeingResolved = false; |
// backendMembers are members that have been added by the backend to simplify |
// compilation. They don't have any user-side counter-part. |
Link<Element> backendMembers = const EmptyLink<Element>(); |
- Link<Type> allSupertypes; |
+ Link<InterfaceType> allSupertypes; |
ClassElement patch = null; |
Node defaultClause; // Only for interfaces. |
ClassElement(SourceString name, CompilationUnitElement enclosing, this.id) |
: localMembers = new Map<SourceString, Element>(), |
constructors = new Map<SourceString, Element>(), |
- typeParameters = new LinkedHashMap<SourceString, TypeVariableElement>(), |
super(name, ElementKind.CLASS, enclosing); |
void addMember(Element element, DiagnosticListener listener) { |
@@ -850,23 +940,23 @@ class ClassElement extends ContainerElement { |
} |
} |
- Type computeType(compiler) { |
- if (type === null) { |
- type = new InterfaceType(this); |
+ InterfaceType computeType(compiler) { |
+ if (type == null) { |
+ ClassNode node = parseNode(compiler); |
+ Link<TypeVariableType> parameters = |
+ createTypeVariables(this, node.typeParameters); |
+ type = new InterfaceType(this, parameters); |
} |
return type; |
} |
+ Link<TypeVariableType> get typeVariables() => type.typeArguments; |
ahe
2012/08/02 06:43:14
Same applies here, so I would prefer Link<Type>.
|
+ |
ClassElement ensureResolved(Compiler compiler) { |
compiler.resolveClass(this); |
return this; |
} |
- Element lookupTypeParameter(SourceString parameterName) { |
- Element result = typeParameters[parameterName]; |
- return result; |
- } |
- |
Element lookupLocalMember(SourceString memberName) { |
return localMembers[memberName]; |
} |
@@ -1002,6 +1092,9 @@ class ClassElement extends ContainerElement { |
bool isNative() => nativeName != null; |
SourceString nativeName; |
int hashCode() => id; |
+ |
+ Scope buildScope() => |
+ new ClassScope(enclosingElement.buildScope(), this); |
} |
class Elements { |
@@ -1180,13 +1273,17 @@ class TargetElement extends Element { |
} |
class TypeVariableElement extends Element { |
- final Node node; |
+ final Node cachedNode; |
Type bound; |
- Type type; |
- TypeVariableElement(name, Element enclosing, this.node, this.type, |
+ TypeVariableType type; |
+ |
+ TypeVariableElement(name, Element enclosing, this.cachedNode, this.type, |
[this.bound]) |
: super(name, ElementKind.TYPE_VARIABLE, enclosing); |
- Type computeType(compiler) => type; |
- Node parseNode(compiler) => node; |
- toString() => "${enclosingElement.toString()}.${name.slowToString()}"; |
+ |
+ TypeVariableType computeType(compiler) => type; |
+ |
+ Node parseNode(compiler) => cachedNode; |
+ |
+ String toString() => "${enclosingElement.toString()}.${name.slowToString()}"; |
ahe
2012/08/02 06:43:14
This change is fine, but am I the only one thinkin
|
} |