Index: pkg/kernel/lib/ast.dart |
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart |
index d93b704191debdf92ea41a532e35422977e1b13e..daa5427e83ab2e3d8af16aec6b0c292b3b547747 100644 |
--- a/pkg/kernel/lib/ast.dart |
+++ b/pkg/kernel/lib/ast.dart |
@@ -228,6 +228,13 @@ class Reference { |
} |
return node as Procedure; |
} |
+ |
+ Typedef get asTypedef { |
+ if (node == null) { |
+ throw '$this is not bound to an AST node. A typedef was expected'; |
+ } |
+ return node as Typedef; |
+ } |
} |
// ------------------------------------------------------------------------ |
@@ -258,6 +265,7 @@ class Library extends NamedNode implements Comparable<Library> { |
String name; |
final List<DeferredImport> deferredImports; |
+ final List<Typedef> typedefs; |
final List<Class> classes; |
final List<Procedure> procedures; |
final List<Field> fields; |
@@ -266,16 +274,20 @@ class Library extends NamedNode implements Comparable<Library> { |
{this.name, |
this.isExternal: false, |
List<DeferredImport> imports, |
+ List<Typedef> typedefs, |
List<Class> classes, |
List<Procedure> procedures, |
List<Field> fields, |
this.fileUri, |
Reference reference}) |
: this.deferredImports = imports ?? <DeferredImport>[], |
+ this.typedefs = typedefs ?? <Typedef>[], |
this.classes = classes ?? <Class>[], |
this.procedures = procedures ?? <Procedure>[], |
this.fields = fields ?? <Field>[], |
super(reference) { |
+ setParents(this.deferredImports, this); |
+ setParents(this.typedefs, this); |
setParents(this.classes, this); |
setParents(this.procedures, this); |
setParents(this.fields, this); |
@@ -304,8 +316,16 @@ class Library extends NamedNode implements Comparable<Library> { |
classes.add(class_); |
} |
+ void addTypedef(Typedef typedef_) { |
+ typedef_.parent = this; |
+ typedefs.add(typedef_); |
+ } |
+ |
void computeCanonicalNames() { |
assert(canonicalName != null); |
+ for (var typedef_ in typedefs) { |
+ canonicalName.getChildFromTypedef(typedef_).bindTo(typedef_.reference); |
+ } |
for (var field in fields) { |
canonicalName.getChildFromMember(field).bindTo(field.reference); |
} |
@@ -321,12 +341,16 @@ class Library extends NamedNode implements Comparable<Library> { |
accept(TreeVisitor v) => v.visitLibrary(this); |
visitChildren(Visitor v) { |
+ visitList(deferredImports, v); |
+ visitList(typedefs, v); |
visitList(classes, v); |
visitList(procedures, v); |
visitList(fields, v); |
} |
transformChildren(Transformer v) { |
+ transformList(deferredImports, v, this); |
+ transformList(typedefs, v, this); |
transformList(classes, v, this); |
transformList(procedures, v, this); |
transformList(fields, v, this); |
@@ -366,6 +390,51 @@ class DeferredImport extends TreeNode { |
transformChildren(Transformer v) {} |
} |
+/// Declaration of a type alias. |
+class Typedef extends NamedNode { |
+ /// The uri of the source file that contains the declaration of this typedef. |
+ String fileUri; |
+ List<Expression> annotations = const <Expression>[]; |
+ String name; |
+ final List<TypeParameter> typeParameters; |
+ DartType type; |
+ |
+ Typedef(this.name, this.type, |
+ {Reference reference, this.fileUri, List<TypeParameter> typeParameters}) |
+ : this.typeParameters = typeParameters ?? <TypeParameter>[], |
+ super(reference) { |
+ setParents(this.typeParameters, this); |
+ } |
+ |
+ Library get enclosingLibrary => parent; |
+ |
+ accept(TreeVisitor v) { |
+ return v.visitTypedef(this); |
+ } |
+ |
+ transformChildren(Transformer v) { |
+ transformList(annotations, v, this); |
+ transformList(typeParameters, v, this); |
+ if (type != null) { |
+ type = v.visitDartType(type); |
+ } |
+ } |
+ |
+ visitChildren(Visitor v) { |
+ visitList(annotations, v); |
+ visitList(typeParameters, v); |
+ type?.accept(v); |
+ } |
+ |
+ void addAnnotation(Expression node) { |
+ if (annotations.isEmpty) { |
+ annotations = <Expression>[]; |
+ } |
+ annotations.add(node); |
+ node.parent = this; |
+ } |
+} |
+ |
/// The degree to which the contents of a class have been loaded into memory. |
/// |
/// Each level imply the requirements of the previous ones. |
@@ -3695,6 +3764,16 @@ abstract class DartType extends Node { |
accept(DartTypeVisitor v); |
bool operator ==(Object other); |
+ |
+ /// If this is a typedef type, repeatedly unfolds its type definition until |
+ /// the root term is not a typedef type, otherwise returns the type itself. |
+ /// |
+ /// Will never return a typedef type. |
+ DartType get unalias => this; |
+ |
+ /// If this is a typedef type, unfolds its type definition once, otherwise |
+ /// returns the type itself. |
+ DartType get unaliasOnce => this; |
} |
/// The type arising from invalid type annotations. |
@@ -3924,6 +4003,60 @@ class FunctionType extends DartType { |
} |
} |
+/// A use of a [Typedef] as a type. |
+/// |
+/// The underlying type can be extracted using [unalias]. |
+class TypedefType extends DartType { |
+ final Reference typedefReference; |
+ final List<DartType> typeArguments; |
+ |
+ TypedefType(Typedef typedefNode, [List<DartType> typeArguments]) |
+ : this.byReference( |
+ typedefNode.reference, typeArguments ?? const <DartType>[]); |
+ |
+ TypedefType.byReference(this.typedefReference, this.typeArguments); |
+ |
+ Typedef get typedefNode => typedefReference.asTypedef; |
+ |
+ accept(DartTypeVisitor v) => v.visitTypedefType(this); |
+ |
+ visitChildren(Visitor v) { |
+ visitList(typeArguments, v); |
+ v.visitTypedefReference(typedefNode); |
+ } |
+ |
+ DartType get unaliasOnce { |
+ return Substitution.fromTypedefType(this).substituteType(typedefNode.type); |
+ } |
+ |
+ DartType get unalias { |
+ return unaliasOnce.unalias; |
+ } |
+ |
+ bool operator ==(Object other) { |
+ if (identical(this, other)) return true; |
+ if (other is TypedefType) { |
+ if (typedefReference != other.typedefReference || |
+ typeArguments.length != other.typeArguments.length) { |
+ return false; |
+ } |
+ for (int i = 0; i < typeArguments.length; ++i) { |
+ if (typeArguments[i] != other.typeArguments[i]) return false; |
+ } |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ int get hashCode { |
+ int hash = 0x3fffffff & typedefNode.hashCode; |
+ for (int i = 0; i < typeArguments.length; ++i) { |
+ hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode)); |
+ } |
+ return hash; |
+ } |
+} |
+ |
/// A named parameter in [FunctionType]. |
class NamedType extends Node implements Comparable<NamedType> { |
final String name; |
@@ -4323,3 +4456,15 @@ CanonicalName getCanonicalNameOfLibrary(Library library) { |
} |
return library.canonicalName; |
} |
+ |
+/// Returns the canonical name of [typedef_], or throws an exception if the |
+/// typedef has not been assigned a canonical name yet. |
+/// |
+/// Returns `null` if the typedef is `null`. |
+CanonicalName getCanonicalNameOfTypedef(Typedef typedef_) { |
+ if (typedef_ == null) return null; |
+ if (typedef_.canonicalName == null) { |
+ throw '$typedef_ has no canonical name'; |
+ } |
+ return typedef_.canonicalName; |
+} |