Chromium Code Reviews| 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
|
| } |