Index: lib/compiler/implementation/typechecker.dart |
diff --git a/lib/compiler/implementation/typechecker.dart b/lib/compiler/implementation/typechecker.dart |
index aa6891976f43dcf3c4b610b6a68172a6a3a6b6b5..8c36f1f797c130ca126d8835e49d6f1753b77471 100644 |
--- a/lib/compiler/implementation/typechecker.dart |
+++ b/lib/compiler/implementation/typechecker.dart |
@@ -27,6 +27,18 @@ class TypeCheckerTask extends CompilerTask { |
interface Type { |
SourceString get name(); |
Element get element(); |
+ |
+ /** |
+ * Returns the unaliased type of this type. |
+ * |
+ * The unaliased type of a typedef'd type is the unaliased type to which its |
+ * name is bound. The unaliased version of any other type is the type itself. |
+ * |
+ * For example, the unaliased type of [: typedef A Func<A,B>(B b) :] is the |
+ * function type [: (B) -> A :] and the unaliased type of |
+ * [: Func<int,String> :] is the function type [: (String) -> int :]. |
+ */ |
+ Type unalias(Compiler compiler); |
} |
class TypeVariableType implements Type { |
@@ -36,7 +48,9 @@ class TypeVariableType implements Type { |
SourceString get name() => element.name; |
- toString() => name.slowToString(); |
+ Type unalias(Compiler compiler) => this; |
+ |
+ String toString() => name.slowToString(); |
} |
/** |
@@ -59,6 +73,8 @@ class StatementType implements Type { |
return (this === other) ? this : MAYBE_RETURNING; |
} |
+ Type unalias(Compiler compiler) => this; |
+ |
String toString() => stringName; |
} |
@@ -67,7 +83,9 @@ class VoidType implements Type { |
SourceString get name() => element.name; |
final VoidElement element; |
- toString() => name.slowToString(); |
+ Type unalias(Compiler compiler) => this; |
+ |
+ String toString() => name.slowToString(); |
} |
class InterfaceType implements Type { |
@@ -79,7 +97,9 @@ class InterfaceType implements Type { |
SourceString get name() => element.name; |
- toString() { |
+ Type unalias(Compiler compiler) => this; |
+ |
+ String toString() { |
StringBuffer sb = new StringBuffer(); |
sb.add(name.slowToString()); |
if (!arguments.isEmpty()) { |
@@ -99,7 +119,9 @@ class FunctionType implements Type { |
FunctionType(Type this.returnType, Link<Type> this.parameterTypes, |
Element this.element); |
- toString() { |
+ Type unalias(Compiler compiler) => this; |
+ |
+ String toString() { |
StringBuffer sb = new StringBuffer(); |
bool first = true; |
sb.add('('); |
@@ -124,23 +146,60 @@ class FunctionType implements Type { |
} |
} |
+class TypedefType implements Type { |
+ final TypedefElement element; |
+ final Link<Type> typeArguments; |
+ |
+ const TypedefType(this.element, |
+ [this.typeArguments = const EmptyLink<Type>()]); |
+ |
+ SourceString get name() => element.name; |
+ |
+ Type unalias(Compiler compiler) { |
+ // TODO(ahe): This should be [ensureResolved]. |
+ compiler.resolveTypedef(element); |
+ return element.alias.unalias(compiler); |
+ } |
+ |
+ String toString() { |
+ StringBuffer sb = new StringBuffer(); |
+ sb.add(name.slowToString()); |
+ if (!typeArguments.isEmpty()) { |
+ sb.add('<'); |
+ typeArguments.printOn(sb, ', '); |
+ sb.add('>'); |
+ } |
+ return sb.toString(); |
+ } |
+} |
+ |
class Types { |
+ final Compiler compiler; |
+ // TODO(karlklose): should we have a class Void? |
final VoidType voidType; |
final InterfaceType dynamicType; |
- Types(Element dynamicElement) |
- : this.with(dynamicElement, new LibraryElement(new Script(null, null))); |
+ Types(Compiler compiler, Element dynamicElement) |
+ : this.with(compiler, dynamicElement, |
+ new LibraryElement(new Script(null, null))); |
- // TODO(karlklose): should we have a class Void? |
- Types.with(Element dynamicElement, LibraryElement library) |
- : voidType = new VoidType(new VoidElement(library.entryCompilationUnit)), |
+ Types.with(Compiler this.compiler, |
+ Element dynamicElement, |
+ LibraryElement library) |
+ : voidType = new VoidType(new VoidElement(library)), |
dynamicType = new InterfaceType(dynamicElement); |
/** Returns true if t is a subtype of s */ |
bool isSubtype(Type t, Type s) { |
- if (t === s || t === dynamicType || s === dynamicType || |
- // TODO(karlklose): Test for s.element === compiler.objectClass. |
- s.name == const SourceString('Object')) return true; |
+ if (t === s || |
+ t === dynamicType || |
+ s === dynamicType || |
+ s.element === compiler.objectClass) { |
+ return true; |
+ } |
+ t = t.unalias(compiler); |
+ s = s.unalias(compiler); |
+ |
if (t is VoidType) { |
return false; |
} else if (t is InterfaceType) { |
@@ -155,6 +214,7 @@ class Types { |
} |
return false; |
} else if (t is FunctionType) { |
+ if (s.element === compiler.functionClass) return true; |
if (s is !FunctionType) return false; |
FunctionType tf = t; |
FunctionType sf = s; |