| 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;
|
| +}
|
|
|