| Index: pkg/compiler/lib/src/dart_types.dart
|
| diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
|
| deleted file mode 100644
|
| index 32acb8871d16783a3ea8d8d2c03dddcc8d2064c7..0000000000000000000000000000000000000000
|
| --- a/pkg/compiler/lib/src/dart_types.dart
|
| +++ /dev/null
|
| @@ -1,1808 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -library dart_types;
|
| -
|
| -import 'dart:math' show min;
|
| -
|
| -import 'dart2jslib.dart' show Compiler, invariant, Script, Message;
|
| -import 'elements/modelx.dart'
|
| - show VoidElementX,
|
| - LibraryElementX,
|
| - BaseClassElementX,
|
| - TypeDeclarationElementX,
|
| - TypedefElementX;
|
| -import 'elements/elements.dart';
|
| -import 'helpers/helpers.dart'; // Included for debug helpers.
|
| -import 'ordered_typeset.dart' show OrderedTypeSet;
|
| -import 'util/util.dart' show CURRENT_ELEMENT_SPANNABLE, equalElements;
|
| -
|
| -class TypeKind {
|
| - final String id;
|
| -
|
| - const TypeKind(String this.id);
|
| -
|
| - static const TypeKind FUNCTION = const TypeKind('function');
|
| - static const TypeKind INTERFACE = const TypeKind('interface');
|
| - static const TypeKind STATEMENT = const TypeKind('statement');
|
| - static const TypeKind TYPEDEF = const TypeKind('typedef');
|
| - static const TypeKind TYPE_VARIABLE = const TypeKind('type variable');
|
| - static const TypeKind MALFORMED_TYPE = const TypeKind('malformed');
|
| - static const TypeKind DYNAMIC = const TypeKind('dynamic');
|
| - static const TypeKind VOID = const TypeKind('void');
|
| -
|
| - String toString() => id;
|
| -}
|
| -
|
| -abstract class DartType {
|
| - String get name;
|
| -
|
| - TypeKind get kind;
|
| -
|
| - const DartType();
|
| -
|
| - /**
|
| - * Returns the [Element] which declared this type.
|
| - *
|
| - * This can be [ClassElement] for classes, [TypedefElement] for typedefs,
|
| - * [TypeVariableElement] for type variables and [FunctionElement] for
|
| - * function types.
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - Element get element;
|
| -
|
| - /**
|
| - * Performs the substitution [: [arguments[i]/parameters[i]]this :].
|
| - *
|
| - * The notation is known from this lambda calculus rule:
|
| - *
|
| - * (lambda x.e0)e1 -> [e1/x]e0.
|
| - *
|
| - * See [TypeVariableType] for a motivation for this method.
|
| - *
|
| - * Invariant: There must be the same number of [arguments] and [parameters].
|
| - */
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters);
|
| -
|
| - /// Performs the substitution of the type arguments of [type] for their
|
| - /// corresponding type variables in this type.
|
| - DartType substByContext(GenericType type) {
|
| - return subst(type.typeArguments, type.element.typeVariables);
|
| - }
|
| -
|
| - /**
|
| - * 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 :].
|
| - */
|
| - DartType unalias(Compiler compiler);
|
| -
|
| - /**
|
| - * If this type is malformed or a generic type created with the wrong number
|
| - * of type arguments then [userProvidedBadType] holds the bad type provided
|
| - * by the user.
|
| - */
|
| - DartType get userProvidedBadType => null;
|
| -
|
| - /// Is [: true :] if this type has no explict type arguments.
|
| - bool get isRaw => true;
|
| -
|
| - /// Returns the raw version of this type.
|
| - DartType asRaw() => this;
|
| -
|
| - /// Is [: true :] if this type has no non-dynamic type arguments.
|
| - bool get treatAsRaw => isRaw;
|
| -
|
| - /// Is [: true :] if this type should be treated as the dynamic type.
|
| - bool get treatAsDynamic => false;
|
| -
|
| - /// Is [: true :] if this type is the dynamic type.
|
| - bool get isDynamic => kind == TypeKind.DYNAMIC;
|
| -
|
| - /// Is [: true :] if this type is the void type.
|
| - bool get isVoid => kind == TypeKind.VOID;
|
| -
|
| - /// Is [: true :] if this is the type of `Object` from dart:core.
|
| - bool get isObject => false;
|
| -
|
| - /// Is [: true :] if this type is an interface type.
|
| - bool get isInterfaceType => kind == TypeKind.INTERFACE;
|
| -
|
| - /// Is [: true :] if this type is a typedef.
|
| - bool get isTypedef => kind == TypeKind.TYPEDEF;
|
| -
|
| - /// Is [: true :] if this type is a function type.
|
| - bool get isFunctionType => kind == TypeKind.FUNCTION;
|
| -
|
| - /// Is [: true :] if this type is a type variable.
|
| - bool get isTypeVariable => kind == TypeKind.TYPE_VARIABLE;
|
| -
|
| - /// Is [: true :] if this type is a malformed type.
|
| - bool get isMalformed => kind == TypeKind.MALFORMED_TYPE;
|
| -
|
| - /// Returns an occurrence of a type variable within this type, if any.
|
| - TypeVariableType get typeVariableOccurrence => null;
|
| -
|
| - /// Applies [f] to each occurence of a [TypeVariableType] within this type.
|
| - void forEachTypeVariable(f(TypeVariableType variable)) {}
|
| -
|
| - TypeVariableType _findTypeVariableOccurrence(List<DartType> types) {
|
| - for (DartType type in types) {
|
| - TypeVariableType typeVariable = type.typeVariableOccurrence;
|
| - if (typeVariable != null) {
|
| - return typeVariable;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /// Is [: true :] if this type contains any type variables.
|
| - bool get containsTypeVariables => typeVariableOccurrence != null;
|
| -
|
| - /// Returns a textual representation of this type as if it was the type
|
| - /// of a member named [name].
|
| - String getStringAsDeclared(String name) {
|
| - return new TypeDeclarationFormatter().format(this, name);
|
| - }
|
| -
|
| - accept(DartTypeVisitor visitor, var argument);
|
| -
|
| - void visitChildren(DartTypeVisitor visitor, var argument) {}
|
| -
|
| - static void visitList(List<DartType> types,
|
| - DartTypeVisitor visitor, var argument) {
|
| - for (DartType type in types) {
|
| - type.accept(visitor, argument);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Represents a type variable, that is the type parameters of a class type.
|
| - *
|
| - * For example, in [: class Array<E> { ... } :], E is a type variable.
|
| - *
|
| - * Each class should have its own unique type variables, one for each type
|
| - * parameter. A class with type parameters is said to be parameterized or
|
| - * generic.
|
| - *
|
| - * Non-static members, constructors, and factories of generic
|
| - * class/interface can refer to type variables of the current class
|
| - * (not of supertypes).
|
| - *
|
| - * When using a generic type, also known as an application or
|
| - * instantiation of the type, the actual type arguments should be
|
| - * substituted for the type variables in the class declaration.
|
| - *
|
| - * For example, given a box, [: class Box<T> { T value; } :], the
|
| - * type of the expression [: new Box<String>().value :] is
|
| - * [: String :] because we must substitute [: String :] for the
|
| - * the type variable [: T :].
|
| - */
|
| -class TypeVariableType extends DartType {
|
| - final TypeVariableElement element;
|
| -
|
| - TypeVariableType(this.element);
|
| -
|
| - TypeKind get kind => TypeKind.TYPE_VARIABLE;
|
| -
|
| - String get name => element.name;
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| - assert(arguments.length == parameters.length);
|
| - if (parameters.isEmpty) {
|
| - // Return fast on empty substitutions.
|
| - return this;
|
| - }
|
| - for (int index = 0; index < arguments.length; index++) {
|
| - TypeVariableType parameter = parameters[index];
|
| - DartType argument = arguments[index];
|
| - if (parameter == this) {
|
| - return argument;
|
| - }
|
| - }
|
| - // The type variable was not substituted.
|
| - return this;
|
| - }
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - DartType get typeVariableOccurrence => this;
|
| -
|
| - void forEachTypeVariable(f(TypeVariableType variable)) {
|
| - f(this);
|
| - }
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitTypeVariableType(this, argument);
|
| - }
|
| -
|
| - int get hashCode => 17 * element.hashCode;
|
| -
|
| - bool operator ==(other) {
|
| - if (other is !TypeVariableType) return false;
|
| - return identical(other.element, element);
|
| - }
|
| -
|
| - String toString() => name;
|
| -}
|
| -
|
| -/// Internal type representing the result of analyzing a statement.
|
| -class StatementType extends DartType {
|
| - Element get element => null;
|
| -
|
| - TypeKind get kind => TypeKind.STATEMENT;
|
| -
|
| - String get name => 'statement';
|
| -
|
| - const StatementType();
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitStatementType(this, argument);
|
| - }
|
| -}
|
| -
|
| -class VoidType extends DartType {
|
| - const VoidType();
|
| -
|
| - TypeKind get kind => TypeKind.VOID;
|
| -
|
| - String get name => 'void';
|
| -
|
| - Element get element => null;
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| - // Void cannot be substituted.
|
| - return this;
|
| - }
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitVoidType(this, argument);
|
| - }
|
| -
|
| - String toString() => name;
|
| -}
|
| -
|
| -class MalformedType extends DartType {
|
| - final ErroneousElement element;
|
| -
|
| - /**
|
| - * [declaredType] holds the type which the user wrote in code.
|
| - *
|
| - * For instance, for a resolved but malformed type like [: Map<String> :] the
|
| - * [declaredType] is [: Map<String> :] whereas for an unresolved type
|
| - * [userProvidedBadType] is [: null :].
|
| - */
|
| - final DartType userProvidedBadType;
|
| -
|
| - /**
|
| - * Type arguments for the malformed typed, if these cannot fit in the
|
| - * [declaredType].
|
| - *
|
| - * This field is for instance used for [: dynamic<int> :] and [: T<int> :]
|
| - * where [: T :] is a type variable, in which case [declaredType] holds
|
| - * [: dynamic :] and [: T :], respectively, or for [: X<int> :] where [: X :]
|
| - * is not resolved or does not imply a type.
|
| - */
|
| - final List<DartType> typeArguments;
|
| -
|
| - final int hashCode = (nextHash++) & 0x3fffffff;
|
| - static int nextHash = 43765;
|
| -
|
| - MalformedType(this.element, this.userProvidedBadType,
|
| - [this.typeArguments = null]);
|
| -
|
| - TypeKind get kind => TypeKind.MALFORMED_TYPE;
|
| -
|
| - String get name => element.name;
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| - // Malformed types are not substitutable.
|
| - return this;
|
| - }
|
| -
|
| - // Malformed types are treated as dynamic.
|
| - bool get treatAsDynamic => true;
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitMalformedType(this, argument);
|
| - }
|
| -
|
| - String toString() {
|
| - var sb = new StringBuffer();
|
| - if (typeArguments != null) {
|
| - if (userProvidedBadType != null) {
|
| - sb.write(userProvidedBadType.name);
|
| - } else {
|
| - sb.write(element.name);
|
| - }
|
| - if (!typeArguments.isEmpty) {
|
| - sb.write('<');
|
| - sb.write(typeArguments.join(', '));
|
| - sb.write('>');
|
| - }
|
| - } else {
|
| - sb.write(userProvidedBadType.toString());
|
| - }
|
| - return sb.toString();
|
| - }
|
| -}
|
| -
|
| -abstract class GenericType extends DartType {
|
| - final TypeDeclarationElement element;
|
| - final List<DartType> typeArguments;
|
| -
|
| - GenericType(TypeDeclarationElement element,
|
| - this.typeArguments,
|
| - {bool checkTypeArgumentCount: true})
|
| - : this.element = element {
|
| - assert(invariant(element, () {
|
| - if (!checkTypeArgumentCount) return true;
|
| - if (element is TypeDeclarationElementX) {
|
| - return element.thisTypeCache == null ||
|
| - typeArguments.length == element.typeVariables.length;
|
| - }
|
| - return true;
|
| - }, message: () => 'Invalid type argument count on ${element.thisType}. '
|
| - 'Provided type arguments: $typeArguments.'));
|
| - }
|
| -
|
| - /// Creates a new instance of this type using the provided type arguments.
|
| - GenericType createInstantiation(List<DartType> newTypeArguments);
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| - if (typeArguments.isEmpty) {
|
| - // Return fast on non-generic types.
|
| - return this;
|
| - }
|
| - if (parameters.isEmpty) {
|
| - assert(arguments.isEmpty);
|
| - // Return fast on empty substitutions.
|
| - return this;
|
| - }
|
| - List<DartType> newTypeArguments =
|
| - Types.substTypes(typeArguments, arguments, parameters);
|
| - if (!identical(typeArguments, newTypeArguments)) {
|
| - // Create a new type only if necessary.
|
| - return createInstantiation(newTypeArguments);
|
| - }
|
| - return this;
|
| - }
|
| -
|
| - TypeVariableType get typeVariableOccurrence {
|
| - return _findTypeVariableOccurrence(typeArguments);
|
| - }
|
| -
|
| - void forEachTypeVariable(f(TypeVariableType variable)) {
|
| - for (DartType type in typeArguments) {
|
| - type.forEachTypeVariable(f);
|
| - }
|
| - }
|
| -
|
| - void visitChildren(DartTypeVisitor visitor, var argument) {
|
| - DartType.visitList(typeArguments, visitor, argument);
|
| - }
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - sb.write(name);
|
| - if (!isRaw) {
|
| - sb.write('<');
|
| - sb.write(typeArguments.join(', '));
|
| - sb.write('>');
|
| - }
|
| - return sb.toString();
|
| - }
|
| -
|
| - int get hashCode {
|
| - int hash = element.hashCode;
|
| - for (DartType argument in typeArguments) {
|
| - int argumentHash = argument != null ? argument.hashCode : 0;
|
| - hash = 17 * hash + 3 * argumentHash;
|
| - }
|
| - return hash;
|
| - }
|
| -
|
| - bool operator ==(other) {
|
| - if (other is !GenericType) return false;
|
| - return kind == other.kind
|
| - && element == other.element
|
| - && equalElements(typeArguments, other.typeArguments);
|
| - }
|
| -
|
| - /// Returns `true` if the declaration of this type has type variables.
|
| - bool get isGeneric => !typeArguments.isEmpty;
|
| -
|
| - bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
|
| -
|
| - GenericType asRaw() => element.rawType;
|
| -
|
| - bool get treatAsRaw {
|
| - if (isRaw) return true;
|
| - for (DartType type in typeArguments) {
|
| - if (!type.treatAsDynamic) return false;
|
| - }
|
| - return true;
|
| - }
|
| -}
|
| -
|
| -class InterfaceType extends GenericType {
|
| - InterfaceType(ClassElement element,
|
| - [List<DartType> typeArguments = const <DartType>[]])
|
| - : super(element, typeArguments) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - }
|
| -
|
| - InterfaceType.forUserProvidedBadType(BaseClassElementX element,
|
| - [List<DartType> typeArguments =
|
| - const <DartType>[]])
|
| - : super(element, typeArguments, checkTypeArgumentCount: false);
|
| -
|
| - ClassElement get element => super.element;
|
| -
|
| - TypeKind get kind => TypeKind.INTERFACE;
|
| -
|
| - String get name => element.name;
|
| -
|
| - bool get isObject => element.isObject;
|
| -
|
| - InterfaceType createInstantiation(List<DartType> newTypeArguments) {
|
| - return new InterfaceType(element, newTypeArguments);
|
| - }
|
| -
|
| - /**
|
| - * Returns the type as an instance of class [other], if possible, null
|
| - * otherwise.
|
| - */
|
| - DartType asInstanceOf(ClassElement other) {
|
| - other = other.declaration;
|
| - if (element == other) return this;
|
| - InterfaceType supertype = element.asInstanceOf(other);
|
| - if (supertype != null) {
|
| - List<DartType> arguments = Types.substTypes(supertype.typeArguments,
|
| - typeArguments,
|
| - element.typeVariables);
|
| - return new InterfaceType(supertype.element, arguments);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - MemberSignature lookupInterfaceMember(Name name) {
|
| - MemberSignature member = element.lookupInterfaceMember(name);
|
| - if (member != null && isGeneric) {
|
| - return new InterfaceMember(this, member);
|
| - }
|
| - return member;
|
| - }
|
| -
|
| - MemberSignature lookupClassMember(Name name) {
|
| - MemberSignature member = element.lookupClassMember(name);
|
| - if (member != null && isGeneric) {
|
| - return new InterfaceMember(this, member);
|
| - }
|
| - return member;
|
| - }
|
| -
|
| - int get hashCode => super.hashCode;
|
| -
|
| - InterfaceType asRaw() => super.asRaw();
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitInterfaceType(this, argument);
|
| - }
|
| -
|
| - /// Returns the type of the 'call' method in this interface type, or
|
| - /// `null` if the interface type has no 'call' method.
|
| - FunctionType get callType {
|
| - FunctionType type = element.callType;
|
| - return type != null && isGeneric ? type.substByContext(this) : type;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Special subclass of [InterfaceType] used for generic interface types created
|
| - * with the wrong number of type arguments.
|
| - *
|
| - * The type uses [:dynamic:] for all it s type arguments.
|
| - */
|
| -class BadInterfaceType extends InterfaceType {
|
| - final InterfaceType userProvidedBadType;
|
| -
|
| - BadInterfaceType(ClassElement element,
|
| - InterfaceType this.userProvidedBadType)
|
| - : super(element, element.rawType.typeArguments);
|
| -
|
| - String toString() {
|
| - return userProvidedBadType.toString();
|
| - }
|
| -}
|
| -
|
| -
|
| -/**
|
| - * Special subclass of [TypedefType] used for generic typedef types created
|
| - * with the wrong number of type arguments.
|
| - *
|
| - * The type uses [:dynamic:] for all it s type arguments.
|
| - */
|
| -class BadTypedefType extends TypedefType {
|
| - final TypedefType userProvidedBadType;
|
| -
|
| - BadTypedefType(TypedefElement element,
|
| - TypedefType this.userProvidedBadType)
|
| - : super(element, element.rawType.typeArguments);
|
| -
|
| - String toString() {
|
| - return userProvidedBadType.toString();
|
| - }
|
| -}
|
| -
|
| -class FunctionType extends DartType {
|
| - final FunctionTypedElement element;
|
| - final DartType returnType;
|
| - final List<DartType> parameterTypes;
|
| - final List<DartType> optionalParameterTypes;
|
| -
|
| - /**
|
| - * The names of the named parameters ordered lexicographically.
|
| - */
|
| - final List<String> namedParameters;
|
| -
|
| - /**
|
| - * The types of the named parameters in the order corresponding to the
|
| - * [namedParameters].
|
| - */
|
| - final List<DartType> namedParameterTypes;
|
| -
|
| - factory FunctionType(
|
| - FunctionTypedElement element,
|
| - [DartType returnType = const DynamicType(),
|
| - List<DartType> parameterTypes = const <DartType>[],
|
| - List<DartType> optionalParameterTypes = const <DartType>[],
|
| - List<String> namedParameters = const <String>[],
|
| - List<DartType> namedParameterTypes = const <DartType>[]]) {
|
| - assert(invariant(CURRENT_ELEMENT_SPANNABLE, element != null));
|
| - assert(invariant(element, element.isDeclaration));
|
| - return new FunctionType.internal(element,
|
| - returnType, parameterTypes, optionalParameterTypes,
|
| - namedParameters, namedParameterTypes);
|
| - }
|
| -
|
| - factory FunctionType.synthesized(
|
| - [DartType returnType = const DynamicType(),
|
| - List<DartType> parameterTypes = const <DartType>[],
|
| - List<DartType> optionalParameterTypes = const <DartType>[],
|
| - List<String> namedParameters = const <String>[],
|
| - List<DartType> namedParameterTypes = const <DartType>[]]) {
|
| - return new FunctionType.internal(null,
|
| - returnType, parameterTypes, optionalParameterTypes,
|
| - namedParameters, namedParameterTypes);
|
| - }
|
| -
|
| - FunctionType.internal(FunctionTypedElement this.element,
|
| - [DartType this.returnType = const DynamicType(),
|
| - this.parameterTypes = const <DartType>[],
|
| - this.optionalParameterTypes = const <DartType>[],
|
| - this.namedParameters = const <String>[],
|
| - this.namedParameterTypes = const <DartType>[]]) {
|
| - assert(invariant(CURRENT_ELEMENT_SPANNABLE,
|
| - element == null || element.isDeclaration));
|
| - // Assert that optional and named parameters are not used at the same time.
|
| - assert(optionalParameterTypes.isEmpty || namedParameterTypes.isEmpty);
|
| - assert(namedParameters.length == namedParameterTypes.length);
|
| - }
|
| -
|
| -
|
| -
|
| - TypeKind get kind => TypeKind.FUNCTION;
|
| -
|
| - DartType getNamedParameterType(String name) {
|
| - for (int i = 0; i < namedParameters.length; i++) {
|
| - if (namedParameters[i] == name) {
|
| - return namedParameterTypes[i];
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| - if (parameters.isEmpty) {
|
| - assert(arguments.isEmpty);
|
| - // Return fast on empty substitutions.
|
| - return this;
|
| - }
|
| - DartType newReturnType = returnType.subst(arguments, parameters);
|
| - bool changed = !identical(newReturnType, returnType);
|
| - List<DartType> newParameterTypes =
|
| - Types.substTypes(parameterTypes, arguments, parameters);
|
| - List<DartType> newOptionalParameterTypes =
|
| - Types.substTypes(optionalParameterTypes, arguments, parameters);
|
| - List<DartType> newNamedParameterTypes =
|
| - Types.substTypes(namedParameterTypes, arguments, parameters);
|
| - if (!changed &&
|
| - (!identical(parameterTypes, newParameterTypes) ||
|
| - !identical(optionalParameterTypes, newOptionalParameterTypes) ||
|
| - !identical(namedParameterTypes, newNamedParameterTypes))) {
|
| - changed = true;
|
| - }
|
| - if (changed) {
|
| - // Create a new type only if necessary.
|
| - return new FunctionType.internal(element,
|
| - newReturnType,
|
| - newParameterTypes,
|
| - newOptionalParameterTypes,
|
| - namedParameters,
|
| - newNamedParameterTypes);
|
| - }
|
| - return this;
|
| - }
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - DartType get typeVariableOccurrence {
|
| - TypeVariableType typeVariableType = returnType.typeVariableOccurrence;
|
| - if (typeVariableType != null) return typeVariableType;
|
| -
|
| - typeVariableType = _findTypeVariableOccurrence(parameterTypes);
|
| - if (typeVariableType != null) return typeVariableType;
|
| -
|
| - typeVariableType = _findTypeVariableOccurrence(optionalParameterTypes);
|
| - if (typeVariableType != null) return typeVariableType;
|
| -
|
| - return _findTypeVariableOccurrence(namedParameterTypes);
|
| - }
|
| -
|
| - void forEachTypeVariable(f(TypeVariableType variable)) {
|
| - returnType.forEachTypeVariable(f);
|
| - parameterTypes.forEach((DartType type) {
|
| - type.forEachTypeVariable(f);
|
| - });
|
| - optionalParameterTypes.forEach((DartType type) {
|
| - type.forEachTypeVariable(f);
|
| - });
|
| - namedParameterTypes.forEach((DartType type) {
|
| - type.forEachTypeVariable(f);
|
| - });
|
| - }
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitFunctionType(this, argument);
|
| - }
|
| -
|
| - void visitChildren(DartTypeVisitor visitor, var argument) {
|
| - returnType.accept(visitor, argument);
|
| - DartType.visitList(parameterTypes, visitor, argument);
|
| - DartType.visitList(optionalParameterTypes, visitor, argument);
|
| - DartType.visitList(namedParameterTypes, visitor, argument);
|
| - }
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - sb.write('(');
|
| - sb.write(parameterTypes.join(', '));
|
| - bool first = parameterTypes.isEmpty;
|
| - if (!optionalParameterTypes.isEmpty) {
|
| - if (!first) {
|
| - sb.write(', ');
|
| - }
|
| - sb.write('[');
|
| - sb.write(optionalParameterTypes.join(', '));
|
| - sb.write(']');
|
| - first = false;
|
| - }
|
| - if (!namedParameterTypes.isEmpty) {
|
| - if (!first) {
|
| - sb.write(', ');
|
| - }
|
| - sb.write('{');
|
| - first = true;
|
| - for (int i = 0; i < namedParameters.length; i++) {
|
| - if (!first) {
|
| - sb.write(', ');
|
| - }
|
| - sb.write(namedParameterTypes[i]);
|
| - sb.write(' ');
|
| - sb.write(namedParameters[i]);
|
| - first = false;
|
| - }
|
| - sb.write('}');
|
| - }
|
| - sb.write(') -> ${returnType}');
|
| - return sb.toString();
|
| - }
|
| -
|
| - String get name => 'Function';
|
| -
|
| - int computeArity() {
|
| - int arity = 0;
|
| - parameterTypes.forEach((_) { arity++; });
|
| - return arity;
|
| - }
|
| -
|
| - int get hashCode {
|
| - int hash = 3 * returnType.hashCode;
|
| - for (DartType parameter in parameterTypes) {
|
| - hash = 17 * hash + 5 * parameter.hashCode;
|
| - }
|
| - for (DartType parameter in optionalParameterTypes) {
|
| - hash = 19 * hash + 7 * parameter.hashCode;
|
| - }
|
| - for (String name in namedParameters) {
|
| - hash = 23 * hash + 11 * name.hashCode;
|
| - }
|
| - for (DartType parameter in namedParameterTypes) {
|
| - hash = 29 * hash + 13 * parameter.hashCode;
|
| - }
|
| - return hash;
|
| - }
|
| -
|
| - bool operator ==(other) {
|
| - if (other is !FunctionType) return false;
|
| - return returnType == other.returnType &&
|
| - equalElements(parameterTypes, other.parameterTypes) &&
|
| - equalElements(optionalParameterTypes, other.optionalParameterTypes) &&
|
| - equalElements(namedParameters, other.namedParameters) &&
|
| - equalElements(namedParameterTypes, other.namedParameterTypes);
|
| - }
|
| -}
|
| -
|
| -class TypedefType extends GenericType {
|
| - TypedefType(TypedefElement element,
|
| - [List<DartType> typeArguments = const <DartType>[]])
|
| - : super(element, typeArguments);
|
| -
|
| - TypedefType.forUserProvidedBadType(TypedefElement element,
|
| - [List<DartType> typeArguments =
|
| - const <DartType>[]])
|
| - : super(element, typeArguments, checkTypeArgumentCount: false);
|
| -
|
| - TypedefElement get element => super.element;
|
| -
|
| - TypeKind get kind => TypeKind.TYPEDEF;
|
| -
|
| - String get name => element.name;
|
| -
|
| - TypedefType createInstantiation(List<DartType> newTypeArguments) {
|
| - return new TypedefType(element, newTypeArguments);
|
| - }
|
| -
|
| - DartType unalias(Compiler compiler) {
|
| - element.ensureResolved(compiler);
|
| - element.checkCyclicReference(compiler);
|
| - DartType definition = element.alias.unalias(compiler);
|
| - return definition.substByContext(this);
|
| - }
|
| -
|
| - int get hashCode => super.hashCode;
|
| -
|
| - TypedefType asRaw() => super.asRaw();
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitTypedefType(this, argument);
|
| - }
|
| -}
|
| -
|
| -/// A typedef which has already been resolved to its alias.
|
| -class ResolvedTypedefType extends TypedefType {
|
| - FunctionType alias;
|
| -
|
| - ResolvedTypedefType(TypedefElement element,
|
| - List<DartType> typeArguments,
|
| - this.alias)
|
| - : super(element, typeArguments) {
|
| - assert(invariant(element, alias != null,
|
| - message: 'Alias must be non-null on $element.'));
|
| - }
|
| -
|
| - FunctionType unalias(Compiler compiler) => alias;
|
| -}
|
| -
|
| -/**
|
| - * Special type for the `dynamic` type.
|
| - */
|
| -class DynamicType extends DartType {
|
| - const DynamicType();
|
| -
|
| - Element get element => null;
|
| -
|
| - String get name => 'dynamic';
|
| -
|
| - bool get treatAsDynamic => true;
|
| -
|
| - TypeKind get kind => TypeKind.DYNAMIC;
|
| -
|
| - DartType unalias(Compiler compiler) => this;
|
| -
|
| - DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
|
| -
|
| - accept(DartTypeVisitor visitor, var argument) {
|
| - return visitor.visitDynamicType(this, argument);
|
| - }
|
| -
|
| - String toString() => name;
|
| -}
|
| -
|
| -/**
|
| - * [InterfaceMember] encapsulates a member (method, field, property) with
|
| - * the types of the declarer and receiver in order to do substitution on the
|
| - * member type.
|
| - *
|
| - * Consider for instance these classes and the variable `B<String> b`:
|
| - *
|
| - * class A<E> {
|
| - * E field;
|
| - * }
|
| - * class B<F> extends A<F> {}
|
| - *
|
| - * In an [InterfaceMember] for `b.field` the [receiver] is the type
|
| - * `B<String>` and the declarer is the type `A<F>`, which is the supertype of
|
| - * `B<F>` from which `field` has been inherited. To compute the type of
|
| - * `b.field` we must first substitute `E` by `F` using the relation between
|
| - * `A<E>` and `A<F>`, and then `F` by `String` using the relation between
|
| - * `B<F>` and `B<String>`.
|
| - */
|
| -class InterfaceMember implements MemberSignature {
|
| - final InterfaceType instance;
|
| - final MemberSignature member;
|
| -
|
| - InterfaceMember(this.instance, this.member);
|
| -
|
| - Name get name => member.name;
|
| -
|
| - DartType get type => member.type.substByContext(instance);
|
| -
|
| - FunctionType get functionType => member.functionType.substByContext(instance);
|
| -
|
| - bool get isGetter => member.isGetter;
|
| -
|
| - bool get isSetter => member.isSetter;
|
| -
|
| - bool get isMethod => member.isMethod;
|
| -
|
| - Iterable<Member> get declarations => member.declarations;
|
| -}
|
| -
|
| -abstract class DartTypeVisitor<R, A> {
|
| - const DartTypeVisitor();
|
| -
|
| - R visitType(DartType type, A argument);
|
| -
|
| - R visitVoidType(VoidType type, A argument) =>
|
| - visitType(type, argument);
|
| -
|
| - R visitTypeVariableType(TypeVariableType type, A argument) =>
|
| - visitType(type, argument);
|
| -
|
| - R visitFunctionType(FunctionType type, A argument) =>
|
| - visitType(type, argument);
|
| -
|
| - R visitMalformedType(MalformedType type, A argument) =>
|
| - visitType(type, argument);
|
| -
|
| - R visitStatementType(StatementType type, A argument) =>
|
| - visitType(type, argument);
|
| -
|
| - R visitGenericType(GenericType type, A argument) =>
|
| - visitType(type, argument);
|
| -
|
| - R visitInterfaceType(InterfaceType type, A argument) =>
|
| - visitGenericType(type, argument);
|
| -
|
| - R visitTypedefType(TypedefType type, A argument) =>
|
| - visitGenericType(type, argument);
|
| -
|
| - R visitDynamicType(DynamicType type, A argument) =>
|
| - visitType(type, argument);
|
| -}
|
| -
|
| -/**
|
| - * Abstract visitor for determining relations between types.
|
| - */
|
| -abstract class AbstractTypeRelation extends DartTypeVisitor<bool, DartType> {
|
| - final Compiler compiler;
|
| -
|
| - AbstractTypeRelation(Compiler this.compiler);
|
| -
|
| - bool visitType(DartType t, DartType s) {
|
| - throw 'internal error: unknown type kind ${t.kind}';
|
| - }
|
| -
|
| - bool visitVoidType(VoidType t, DartType s) {
|
| - assert(s is! VoidType);
|
| - return false;
|
| - }
|
| -
|
| - bool invalidTypeArguments(DartType t, DartType s);
|
| -
|
| - bool invalidFunctionReturnTypes(DartType t, DartType s);
|
| -
|
| - bool invalidFunctionParameterTypes(DartType t, DartType s);
|
| -
|
| - bool invalidTypeVariableBounds(DartType bound, DartType s);
|
| -
|
| - /// Handle as dynamic for both subtype and more specific relation to avoid
|
| - /// spurious errors from malformed types.
|
| - bool visitMalformedType(MalformedType t, DartType s) => true;
|
| -
|
| - bool visitInterfaceType(InterfaceType t, DartType s) {
|
| -
|
| - // TODO(johnniwinther): Currently needed since literal types like int,
|
| - // double, bool etc. might not have been resolved yet.
|
| - t.element.ensureResolved(compiler);
|
| -
|
| - bool checkTypeArguments(InterfaceType instance, InterfaceType other) {
|
| - List<DartType> tTypeArgs = instance.typeArguments;
|
| - List<DartType> sTypeArgs = other.typeArguments;
|
| - assert(tTypeArgs.length == sTypeArgs.length);
|
| - for (int i = 0; i < tTypeArgs.length; i++) {
|
| - if (invalidTypeArguments(tTypeArgs[i], sTypeArgs[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - if (s is InterfaceType) {
|
| - InterfaceType instance = t.asInstanceOf(s.element);
|
| - return instance != null && checkTypeArguments(instance, s);
|
| - } else {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - bool visitFunctionType(FunctionType t, DartType s) {
|
| - if (s is InterfaceType && identical(s.element, compiler.functionClass)) {
|
| - return true;
|
| - }
|
| - if (s is !FunctionType) return false;
|
| - FunctionType tf = t;
|
| - FunctionType sf = s;
|
| - if (invalidFunctionReturnTypes(tf.returnType, sf.returnType)) {
|
| - return false;
|
| - }
|
| -
|
| - // TODO(johnniwinther): Rewrite the function subtyping to be more readable
|
| - // but still as efficient.
|
| -
|
| - // For the comments we use the following abbreviations:
|
| - // x.p : parameterTypes on [:x:],
|
| - // x.o : optionalParameterTypes on [:x:], and
|
| - // len(xs) : length of list [:xs:].
|
| -
|
| - Iterator<DartType> tps = tf.parameterTypes.iterator;
|
| - Iterator<DartType> sps = sf.parameterTypes.iterator;
|
| - bool sNotEmpty = sps.moveNext();
|
| - bool tNotEmpty = tps.moveNext();
|
| - tNext() => (tNotEmpty = tps.moveNext());
|
| - sNext() => (sNotEmpty = sps.moveNext());
|
| -
|
| - bool incompatibleParameters() {
|
| - while (tNotEmpty && sNotEmpty) {
|
| - if (invalidFunctionParameterTypes(tps.current, sps.current)) {
|
| - return true;
|
| - }
|
| - tNext();
|
| - sNext();
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - if (incompatibleParameters()) return false;
|
| - if (tNotEmpty) {
|
| - // We must have [: len(t.p) <= len(s.p) :].
|
| - return false;
|
| - }
|
| - if (!sf.namedParameters.isEmpty) {
|
| - // We must have [: len(t.p) == len(s.p) :].
|
| - if (sNotEmpty) {
|
| - return false;
|
| - }
|
| - // Since named parameters are globally ordered we can determine the
|
| - // subset relation with a linear search for [:sf.namedParameters:]
|
| - // within [:tf.namedParameters:].
|
| - List<String> tNames = tf.namedParameters;
|
| - List<DartType> tTypes = tf.namedParameterTypes;
|
| - List<String> sNames = sf.namedParameters;
|
| - List<DartType> sTypes = sf.namedParameterTypes;
|
| - int tIndex = 0;
|
| - int sIndex = 0;
|
| - while (tIndex < tNames.length && sIndex < sNames.length) {
|
| - if (tNames[tIndex] == sNames[sIndex]) {
|
| - if (invalidFunctionParameterTypes(tTypes[tIndex], sTypes[sIndex])) {
|
| - return false;
|
| - }
|
| - sIndex++;
|
| - }
|
| - tIndex++;
|
| - }
|
| - if (sIndex < sNames.length) {
|
| - // We didn't find all names.
|
| - return false;
|
| - }
|
| - } else {
|
| - // Check the remaining [: s.p :] against [: t.o :].
|
| - tps = tf.optionalParameterTypes.iterator;
|
| - tNext();
|
| - if (incompatibleParameters()) return false;
|
| - if (sNotEmpty) {
|
| - // We must have [: len(t.p) + len(t.o) >= len(s.p) :].
|
| - return false;
|
| - }
|
| - if (!sf.optionalParameterTypes.isEmpty) {
|
| - // Check the remaining [: s.o :] against the remaining [: t.o :].
|
| - sps = sf.optionalParameterTypes.iterator;
|
| - sNext();
|
| - if (incompatibleParameters()) return false;
|
| - if (sNotEmpty) {
|
| - // We didn't find enough parameters:
|
| - // We must have [: len(t.p) + len(t.o) <= len(s.p) + len(s.o) :].
|
| - return false;
|
| - }
|
| - } else {
|
| - if (sNotEmpty) {
|
| - // We must have [: len(t.p) + len(t.o) >= len(s.p) :].
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - bool visitTypeVariableType(TypeVariableType t, DartType s) {
|
| - // Identity check is handled in [isSubtype].
|
| - DartType bound = t.element.bound;
|
| - if (bound.isTypeVariable) {
|
| - // The bound is potentially cyclic so we need to be extra careful.
|
| - Set<TypeVariableElement> seenTypeVariables =
|
| - new Set<TypeVariableElement>();
|
| - seenTypeVariables.add(t.element);
|
| - while (bound.isTypeVariable) {
|
| - TypeVariableElement element = bound.element;
|
| - if (identical(bound.element, s.element)) {
|
| - // [t] extends [s].
|
| - return true;
|
| - }
|
| - if (seenTypeVariables.contains(element)) {
|
| - // We have a cycle and have already checked all bounds in the cycle
|
| - // against [s] and can therefore conclude that [t] is not a subtype
|
| - // of [s].
|
| - return false;
|
| - }
|
| - seenTypeVariables.add(element);
|
| - bound = element.bound;
|
| - }
|
| - }
|
| - if (invalidTypeVariableBounds(bound, s)) return false;
|
| - return true;
|
| - }
|
| -}
|
| -
|
| -class MoreSpecificVisitor extends AbstractTypeRelation {
|
| - MoreSpecificVisitor(Compiler compiler) : super(compiler);
|
| -
|
| - bool isMoreSpecific(DartType t, DartType s) {
|
| - if (identical(t, s) || s.treatAsDynamic ||
|
| - identical(t.element, compiler.nullClass)) {
|
| - return true;
|
| - }
|
| - if (t.isVoid || s.isVoid) {
|
| - return false;
|
| - }
|
| - if (t.treatAsDynamic) {
|
| - return false;
|
| - }
|
| - if (identical(s.element, compiler.objectClass)) {
|
| - return true;
|
| - }
|
| - t = t.unalias(compiler);
|
| - s = s.unalias(compiler);
|
| -
|
| - return t.accept(this, s);
|
| - }
|
| -
|
| - bool invalidTypeArguments(DartType t, DartType s) {
|
| - return !isMoreSpecific(t, s);
|
| - }
|
| -
|
| - bool invalidFunctionReturnTypes(DartType t, DartType s) {
|
| - if (s.treatAsDynamic && t.isVoid) return true;
|
| - return !s.isVoid && !isMoreSpecific(t, s);
|
| - }
|
| -
|
| - bool invalidFunctionParameterTypes(DartType t, DartType s) {
|
| - return !isMoreSpecific(t, s);
|
| - }
|
| -
|
| - bool invalidTypeVariableBounds(DartType bound, DartType s) {
|
| - return !isMoreSpecific(bound, s);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Type visitor that determines the subtype relation two types.
|
| - */
|
| -class SubtypeVisitor extends MoreSpecificVisitor {
|
| -
|
| - SubtypeVisitor(Compiler compiler) : super(compiler);
|
| -
|
| - bool isSubtype(DartType t, DartType s) {
|
| - return t.treatAsDynamic || isMoreSpecific(t, s);
|
| - }
|
| -
|
| - bool isAssignable(DartType t, DartType s) {
|
| - return isSubtype(t, s) || isSubtype(s, t);
|
| - }
|
| -
|
| - bool invalidTypeArguments(DartType t, DartType s) {
|
| - return !isSubtype(t, s);
|
| - }
|
| -
|
| - bool invalidFunctionReturnTypes(DartType t, DartType s) {
|
| - return !s.isVoid && !isAssignable(t, s);
|
| - }
|
| -
|
| - bool invalidFunctionParameterTypes(DartType t, DartType s) {
|
| - return !isAssignable(t, s);
|
| - }
|
| -
|
| - bool invalidTypeVariableBounds(DartType bound, DartType s) {
|
| - return !isSubtype(bound, s);
|
| - }
|
| -
|
| - bool visitInterfaceType(InterfaceType t, DartType s) {
|
| - if (super.visitInterfaceType(t, s)) return true;
|
| -
|
| - if (s is InterfaceType &&
|
| - s.element == compiler.functionClass &&
|
| - t.element.callType != null) {
|
| - return true;
|
| - } else if (s is FunctionType) {
|
| - FunctionType callType = t.callType;
|
| - return callType != null && isSubtype(callType, s);
|
| - }
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Callback used to check whether the [typeArgument] of [type] is a valid
|
| - * substitute for the bound of [typeVariable]. [bound] holds the bound against
|
| - * which [typeArgument] should be checked.
|
| - */
|
| -typedef void CheckTypeVariableBound(GenericType type,
|
| - DartType typeArgument,
|
| - TypeVariableType typeVariable,
|
| - DartType bound);
|
| -
|
| -class Types {
|
| - final Compiler compiler;
|
| - final MoreSpecificVisitor moreSpecificVisitor;
|
| - final SubtypeVisitor subtypeVisitor;
|
| - final PotentialSubtypeVisitor potentialSubtypeVisitor;
|
| -
|
| - Types(Compiler compiler)
|
| - : this.compiler = compiler,
|
| - this.moreSpecificVisitor = new MoreSpecificVisitor(compiler),
|
| - this.subtypeVisitor = new SubtypeVisitor(compiler),
|
| - this.potentialSubtypeVisitor = new PotentialSubtypeVisitor(compiler);
|
| -
|
| - Types copy(Compiler compiler) {
|
| - return new Types(compiler);
|
| - }
|
| -
|
| - /** Returns true if [t] is more specific than [s]. */
|
| - bool isMoreSpecific(DartType t, DartType s) {
|
| - return moreSpecificVisitor.isMoreSpecific(t, s);
|
| - }
|
| -
|
| - /**
|
| - * Returns the most specific type of [t] and [s] or `null` if neither is more
|
| - * specific than the other.
|
| - */
|
| - DartType getMostSpecific(DartType t, DartType s) {
|
| - if (isMoreSpecific(t, s)) {
|
| - return t;
|
| - } else if (isMoreSpecific(s, t)) {
|
| - return s;
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - /** Returns true if t is a subtype of s */
|
| - bool isSubtype(DartType t, DartType s) {
|
| - return subtypeVisitor.isSubtype(t, s);
|
| - }
|
| -
|
| - bool isAssignable(DartType r, DartType s) {
|
| - return subtypeVisitor.isAssignable(r, s);
|
| - }
|
| -
|
| - static const int IS_SUBTYPE = 1;
|
| - static const int MAYBE_SUBTYPE = 0;
|
| - static const int NOT_SUBTYPE = -1;
|
| -
|
| - int computeSubtypeRelation(DartType t, DartType s) {
|
| - // TODO(johnniwinther): Compute this directly in [isPotentialSubtype].
|
| - if (isSubtype(t, s)) return IS_SUBTYPE;
|
| - return isPotentialSubtype(t, s) ? MAYBE_SUBTYPE : NOT_SUBTYPE;
|
| - }
|
| -
|
| - bool isPotentialSubtype(DartType t, DartType s) {
|
| - // TODO(johnniwinther): Return a set of variable points in the positive
|
| - // cases.
|
| - return potentialSubtypeVisitor.isSubtype(t, s);
|
| - }
|
| -
|
| - /**
|
| - * Checks the type arguments of [type] against the type variable bounds
|
| - * declared on [element]. Calls [checkTypeVariableBound] on each type
|
| - * argument and bound.
|
| - */
|
| - void checkTypeVariableBounds(GenericType type,
|
| - CheckTypeVariableBound checkTypeVariableBound) {
|
| - TypeDeclarationElement element = type.element;
|
| - List<DartType> typeArguments = type.typeArguments;
|
| - List<DartType> typeVariables = element.typeVariables;
|
| - assert(typeVariables.length == typeArguments.length);
|
| - for (int index = 0; index < typeArguments.length; index++) {
|
| - TypeVariableType typeVariable = typeVariables[index];
|
| - DartType bound = typeVariable.element.bound.substByContext(type);
|
| - DartType typeArgument = typeArguments[index];
|
| - checkTypeVariableBound(type, typeArgument, typeVariable, bound);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Helper method for performing substitution of a list of types.
|
| - *
|
| - * If no types are changed by the substitution, the [types] is returned
|
| - * instead of a newly created list.
|
| - */
|
| - static List<DartType> substTypes(List<DartType> types,
|
| - List<DartType> arguments,
|
| - List<DartType> parameters) {
|
| - bool changed = false;
|
| - List<DartType> result = new List<DartType>.generate(types.length, (index) {
|
| - DartType type = types[index];
|
| - DartType argument = type.subst(arguments, parameters);
|
| - if (!changed && !identical(argument, type)) {
|
| - changed = true;
|
| - }
|
| - return argument;
|
| - });
|
| - // Use the new List only if necessary.
|
| - return changed ? result : types;
|
| - }
|
| -
|
| - /**
|
| - * Returns the [ClassElement] which declares the type variables occurring in
|
| - * [type], or [:null:] if [type] does not contain type variables.
|
| - */
|
| - static ClassElement getClassContext(DartType type) {
|
| - TypeVariableType typeVariable = type.typeVariableOccurrence;
|
| - if (typeVariable == null) return null;
|
| - return typeVariable.element.typeDeclaration;
|
| - }
|
| -
|
| - /**
|
| - * A `compareTo` function that globally orders types using
|
| - * [Elements.compareByPosition] to order types defined by a declaration.
|
| - *
|
| - * The order is:
|
| - * * void
|
| - * * dynamic
|
| - * * interface, typedef, type variables ordered by element order
|
| - * - interface and typedef of the same element are ordered by
|
| - * the order of their type arguments
|
| - * * function types, ordered by
|
| - * - return type
|
| - * - required parameter types
|
| - * - optional parameter types
|
| - * - named parameter names
|
| - * - named parameter types
|
| - * * malformed types
|
| - * * statement types
|
| - */
|
| - static int compare(DartType a, DartType b) {
|
| - if (a == b) return 0;
|
| - if (a.isVoid) {
|
| - // [b] is not void => a < b.
|
| - return -1;
|
| - } else if (b.isVoid) {
|
| - // [a] is not void => a > b.
|
| - return 1;
|
| - }
|
| - if (a.isDynamic) {
|
| - // [b] is not dynamic => a < b.
|
| - return -1;
|
| - } else if (b.isDynamic) {
|
| - // [a] is not dynamic => a > b.
|
| - return 1;
|
| - }
|
| - bool isDefinedByDeclaration(DartType type) {
|
| - return type.isInterfaceType ||
|
| - type.isTypedef ||
|
| - type.isTypeVariable;
|
| - }
|
| -
|
| - if (isDefinedByDeclaration(a)) {
|
| - if (isDefinedByDeclaration(b)) {
|
| - int result = Elements.compareByPosition(a.element, b.element);
|
| - if (result != 0) return result;
|
| - if (a.isTypeVariable) {
|
| - return b.isTypeVariable
|
| - ? 0
|
| - : 1; // [b] is not a type variable => a > b.
|
| - } else {
|
| - if (b.isTypeVariable) {
|
| - // [a] is not a type variable => a < b.
|
| - return -1;
|
| - } else {
|
| - return compareList((a as GenericType).typeArguments,
|
| - (b as GenericType).typeArguments);
|
| - }
|
| - }
|
| - } else {
|
| - // [b] is neither an interface, typedef, type variable, dynamic,
|
| - // nor void => a < b.
|
| - return -1;
|
| - }
|
| - } else if (isDefinedByDeclaration(b)) {
|
| - // [a] is neither an interface, typedef, type variable, dynamic,
|
| - // nor void => a > b.
|
| - return 1;
|
| - }
|
| - if (a.isFunctionType) {
|
| - if (b.isFunctionType) {
|
| - FunctionType aFunc = a;
|
| - FunctionType bFunc = b;
|
| - int result = compare(aFunc.returnType, bFunc.returnType);
|
| - if (result != 0) return result;
|
| - result = compareList(aFunc.parameterTypes, bFunc.parameterTypes);
|
| - if (result != 0) return result;
|
| - result = compareList(aFunc.optionalParameterTypes,
|
| - bFunc.optionalParameterTypes);
|
| - if (result != 0) return result;
|
| - // TODO(karlklose): reuse [compareList].
|
| - Iterator<String> aNames = aFunc.namedParameters.iterator;
|
| - Iterator<String> bNames = bFunc.namedParameters.iterator;
|
| - while (aNames.moveNext() && bNames.moveNext()) {
|
| - int result = aNames.current.compareTo(bNames.current);
|
| - if (result != 0) return result;
|
| - }
|
| - if (aNames.moveNext()) {
|
| - // [aNames] is longer that [bNames] => a > b.
|
| - return 1;
|
| - } else if (bNames.moveNext()) {
|
| - // [bNames] is longer that [aNames] => a < b.
|
| - return -1;
|
| - }
|
| - return compareList(aFunc.namedParameterTypes,
|
| - bFunc.namedParameterTypes);
|
| - } else {
|
| - // [b] is a malformed or statement type => a < b.
|
| - return -1;
|
| - }
|
| - } else if (b.isFunctionType) {
|
| - // [b] is a malformed or statement type => a > b.
|
| - return 1;
|
| - }
|
| - if (a.kind == TypeKind.STATEMENT) {
|
| - if (b.kind == TypeKind.STATEMENT) {
|
| - return 0;
|
| - } else {
|
| - // [b] is a malformed type => a > b.
|
| - return 1;
|
| - }
|
| - } else if (b.kind == TypeKind.STATEMENT) {
|
| - // [a] is a malformed type => a < b.
|
| - return -1;
|
| - }
|
| - assert (a.isMalformed);
|
| - assert (b.isMalformed);
|
| - // TODO(johnniwinther): Can we do this better?
|
| - return Elements.compareByPosition(a.element, b.element);
|
| - }
|
| -
|
| - static int compareList(List<DartType> a, List<DartType> b) {
|
| - for (int index = 0; index < min(a.length, b.length); index++) {
|
| - int result = compare(a[index], b[index]);
|
| - if (result != 0) return result;
|
| - }
|
| - if (a.length > b.length) {
|
| - return 1;
|
| - } else if (a.length < b.length) {
|
| - return -1;
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - static List<DartType> sorted(Iterable<DartType> types) {
|
| - return types.toList()..sort(compare);
|
| - }
|
| -
|
| - /// Computes the least upper bound of two interface types [a] and [b].
|
| - InterfaceType computeLeastUpperBoundInterfaces(InterfaceType a,
|
| - InterfaceType b) {
|
| -
|
| - /// Returns the set of supertypes of [type] at depth [depth].
|
| - Set<DartType> getSupertypesAtDepth(InterfaceType type, int depth) {
|
| - OrderedTypeSet types = type.element.allSupertypesAndSelf;
|
| - Set<DartType> set = new Set<DartType>();
|
| - types.forEach(depth, (DartType supertype) {
|
| - set.add(supertype.substByContext(type));
|
| - });
|
| - return set;
|
| - }
|
| -
|
| - ClassElement aClass = a.element;
|
| - ClassElement bClass = b.element;
|
| - int maxCommonDepth = min(aClass.hierarchyDepth, bClass.hierarchyDepth);
|
| - for (int depth = maxCommonDepth; depth >= 0; depth--) {
|
| - Set<DartType> aTypeSet = getSupertypesAtDepth(a, depth);
|
| - Set<DartType> bTypeSet = getSupertypesAtDepth(b, depth);
|
| - Set<DartType> intersection = aTypeSet..retainAll(bTypeSet);
|
| - if (intersection.length == 1) {
|
| - return intersection.first;
|
| - }
|
| - }
|
| - invariant(CURRENT_ELEMENT_SPANNABLE, false,
|
| - message: 'No least upper bound computed for $a and $b.');
|
| - return null;
|
| - }
|
| -
|
| - /// Computes the least upper bound of the types in the longest prefix of [a]
|
| - /// and [b].
|
| - List<DartType> computeLeastUpperBoundsTypes(List<DartType> a,
|
| - List<DartType> b) {
|
| - if (a.isEmpty || b.isEmpty) return const <DartType>[];
|
| - int prefixLength = min(a.length, b.length);
|
| - List<DartType> types = new List<DartType>(prefixLength);
|
| - for (int index = 0; index < prefixLength; index++) {
|
| - types[index] = computeLeastUpperBound(a[index], b[index]);
|
| - }
|
| - return types;
|
| - }
|
| -
|
| - /// Computes the least upper bound of two function types [a] and [b].
|
| - ///
|
| - /// If the required parameter count of [a] and [b] does not match, `Function`
|
| - /// is returned.
|
| - ///
|
| - /// Otherwise, a function type is returned whose return type and
|
| - /// parameter types are the least upper bound of those of [a] and [b],
|
| - /// respectively. In addition, the optional parameters are the least upper
|
| - /// bound of the longest common prefix of the optional parameters of [a] and
|
| - /// [b], and the named parameters are the least upper bound of those common to
|
| - /// [a] and [b].
|
| - DartType computeLeastUpperBoundFunctionTypes(FunctionType a,
|
| - FunctionType b) {
|
| - if (a.parameterTypes.length != b.parameterTypes.length) {
|
| - return compiler.functionClass.rawType;
|
| - }
|
| - DartType returnType = computeLeastUpperBound(a.returnType, b.returnType);
|
| - List<DartType> parameterTypes =
|
| - computeLeastUpperBoundsTypes(a.parameterTypes, b.parameterTypes);
|
| - List<DartType> optionalParameterTypes =
|
| - computeLeastUpperBoundsTypes(a.optionalParameterTypes,
|
| - b.optionalParameterTypes);
|
| - List<String> namedParameters = <String>[];
|
| - List<String> aNamedParameters = a.namedParameters;
|
| - List<String> bNamedParameters = b.namedParameters;
|
| - List<DartType> namedParameterTypes = <DartType>[];
|
| - List<DartType> aNamedParameterTypes = a.namedParameterTypes;
|
| - List<DartType> bNamedParameterTypes = b.namedParameterTypes;
|
| - int aIndex = 0;
|
| - int bIndex = 0;
|
| - int prefixLength =
|
| - min(aNamedParameterTypes.length, bNamedParameterTypes.length);
|
| - while (aIndex < aNamedParameters.length &&
|
| - bIndex < bNamedParameters.length) {
|
| - String aNamedParameter = aNamedParameters[aIndex];
|
| - String bNamedParameter = bNamedParameters[bIndex];
|
| - int result = aNamedParameter.compareTo(bNamedParameter);
|
| - if (result == 0) {
|
| - namedParameters.add(aNamedParameter);
|
| - namedParameterTypes.add(computeLeastUpperBound(
|
| - aNamedParameterTypes[aIndex], bNamedParameterTypes[bIndex]));
|
| - }
|
| - if (result <= 0) {
|
| - aIndex++;
|
| - }
|
| - if (result >= 0) {
|
| - bIndex++;
|
| - }
|
| - }
|
| - return new FunctionType.synthesized(
|
| - returnType,
|
| - parameterTypes, optionalParameterTypes,
|
| - namedParameters, namedParameterTypes);
|
| - }
|
| -
|
| - /// Computes the least upper bound of two types of which at least one is a
|
| - /// type variable. The least upper bound of a type variable is defined in
|
| - /// terms of its bound, but to ensure reflexivity we need to check for common
|
| - /// bounds transitively.
|
| - DartType computeLeastUpperBoundTypeVariableTypes(DartType a,
|
| - DartType b) {
|
| - Set<DartType> typeVariableBounds = new Set<DartType>();
|
| - while (a.isTypeVariable) {
|
| - if (a == b) return a;
|
| - typeVariableBounds.add(a);
|
| - TypeVariableElement element = a.element;
|
| - a = element.bound;
|
| - }
|
| - while (b.isTypeVariable) {
|
| - if (typeVariableBounds.contains(b)) return b;
|
| - TypeVariableElement element = b.element;
|
| - b = element.bound;
|
| - }
|
| - return computeLeastUpperBound(a, b);
|
| - }
|
| -
|
| - /// Computes the least upper bound for [a] and [b].
|
| - DartType computeLeastUpperBound(DartType a, DartType b) {
|
| - if (a == b) return a;
|
| -
|
| - if (a.isTypeVariable ||
|
| - b.isTypeVariable) {
|
| - return computeLeastUpperBoundTypeVariableTypes(a, b);
|
| - }
|
| -
|
| - a = a.unalias(compiler);
|
| - b = b.unalias(compiler);
|
| -
|
| - if (a.treatAsDynamic || b.treatAsDynamic) return const DynamicType();
|
| - if (a.isVoid || b.isVoid) return const VoidType();
|
| -
|
| - if (a.isFunctionType && b.isFunctionType) {
|
| - return computeLeastUpperBoundFunctionTypes(a, b);
|
| - }
|
| -
|
| - if (a.isFunctionType) {
|
| - a = compiler.functionClass.rawType;
|
| - }
|
| - if (b.isFunctionType) {
|
| - b = compiler.functionClass.rawType;
|
| - }
|
| -
|
| - if (a.isInterfaceType && b.isInterfaceType) {
|
| - return computeLeastUpperBoundInterfaces(a, b);
|
| - }
|
| - return const DynamicType();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Type visitor that determines one type could a subtype of another given the
|
| - * right type variable substitution. The computation is approximate and returns
|
| - * [:false:] only if we are sure no such substitution exists.
|
| - */
|
| -class PotentialSubtypeVisitor extends SubtypeVisitor {
|
| - PotentialSubtypeVisitor(Compiler compiler) : super(compiler);
|
| -
|
| - bool isSubtype(DartType t, DartType s) {
|
| - if (t is TypeVariableType || s is TypeVariableType) {
|
| - return true;
|
| - }
|
| - return super.isSubtype(t, s);
|
| - }
|
| -}
|
| -
|
| -/// Visitor used to compute an instantiation of a generic type that is more
|
| -/// specific than a given type.
|
| -///
|
| -/// The visitor tries to compute constraints for all type variables in the
|
| -/// visited type by structurally matching it with the argument type. If the
|
| -/// constraints are too complex or the two types are too different, `false`
|
| -/// is returned. Otherwise, the [constraintMap] holds the valid constraints.
|
| -class MoreSpecificSubtypeVisitor extends DartTypeVisitor<bool, DartType> {
|
| - final Compiler compiler;
|
| - Map<TypeVariableType, DartType> constraintMap;
|
| -
|
| - MoreSpecificSubtypeVisitor(Compiler this.compiler);
|
| -
|
| - /// Compute an instance of [element] which is more specific than [supertype].
|
| - /// If no instance is found, `null` is returned.
|
| - ///
|
| - /// Note that this computation is a heuristic. It does not find a suggestion
|
| - /// in all possible cases.
|
| - InterfaceType computeMoreSpecific(ClassElement element,
|
| - InterfaceType supertype) {
|
| - InterfaceType supertypeInstance =
|
| - element.thisType.asInstanceOf(supertype.element);
|
| - if (supertypeInstance == null) return null;
|
| -
|
| - constraintMap = new Map<TypeVariableType, DartType>();
|
| - element.typeVariables.forEach((TypeVariableType typeVariable) {
|
| - constraintMap[typeVariable] = const DynamicType();
|
| - });
|
| - if (supertypeInstance.accept(this, supertype)) {
|
| - List<DartType> variables = element.typeVariables;
|
| - List<DartType> typeArguments = new List<DartType>.generate(
|
| - variables.length, (int index) => constraintMap[variables[index]]);
|
| - return element.thisType.createInstantiation(typeArguments);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - bool visitType(DartType type, DartType argument) {
|
| - return compiler.types.isMoreSpecific(type, argument);
|
| - }
|
| -
|
| - bool visitTypes(List<DartType> a, List<DartType> b) {
|
| - int prefixLength = min(a.length, b.length);
|
| - for (int index = 0; index < prefixLength; index++) {
|
| - if (!a[index].accept(this, b[index])) return false;
|
| - }
|
| - return prefixLength == a.length && a.length == b.length;
|
| - }
|
| -
|
| - bool visitTypeVariableType(TypeVariableType type, DartType argument) {
|
| - DartType constraint =
|
| - compiler.types.getMostSpecific(constraintMap[type], argument);
|
| - constraintMap[type] = constraint;
|
| - return constraint != null;
|
| - }
|
| -
|
| - bool visitFunctionType(FunctionType type, DartType argument) {
|
| - if (argument is FunctionType) {
|
| - if (type.parameterTypes.length !=
|
| - argument.parameterTypes.length) {
|
| - return false;
|
| - }
|
| - if (type.optionalParameterTypes.length !=
|
| - argument.optionalParameterTypes.length) {
|
| - return false;
|
| - }
|
| - if (type.namedParameters != argument.namedParameters) {
|
| - return false;
|
| - }
|
| -
|
| - if (!type.returnType.accept(this, argument.returnType)) return false;
|
| - if (visitTypes(type.parameterTypes, argument.parameterTypes)) {
|
| - return false;
|
| - }
|
| - if (visitTypes(type.optionalParameterTypes,
|
| - argument.optionalParameterTypes)) {
|
| - return false;
|
| - }
|
| - return visitTypes(type.namedParameterTypes, argument.namedParameterTypes);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - bool visitGenericType(GenericType type, DartType argument) {
|
| - if (argument is GenericType) {
|
| - if (type.element != argument.element) return false;
|
| - return visitTypes(type.typeArguments, argument.typeArguments);
|
| - }
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -/// Visitor used to print type annotation like they used in the source code.
|
| -/// The visitor is especially for printing a function type like
|
| -/// `(Foo,[Bar])->Baz` as `Baz m(Foo a1, [Bar a2])`.
|
| -class TypeDeclarationFormatter extends DartTypeVisitor<dynamic, String> {
|
| - Set<String> usedNames;
|
| - StringBuffer sb;
|
| -
|
| - /// Creates textual representation of [type] as if a member by the [name] were
|
| - /// declared. For instance 'String foo' for `format(String, 'foo')`.
|
| - String format(DartType type, String name) {
|
| - sb = new StringBuffer();
|
| - usedNames = new Set<String>();
|
| - type.accept(this, name);
|
| - usedNames = null;
|
| - return sb.toString();
|
| - }
|
| -
|
| - String createName(String name) {
|
| - if (name != null && !usedNames.contains(name)) {
|
| - usedNames.add(name);
|
| - return name;
|
| - }
|
| - int index = usedNames.length;
|
| - String proposal;
|
| - do {
|
| - proposal = '${name}${index++}';
|
| - } while (usedNames.contains(proposal));
|
| - usedNames.add(proposal);
|
| - return proposal;
|
| - }
|
| -
|
| - void visit(DartType type) {
|
| - type.accept(this, null);
|
| - }
|
| -
|
| - void visitTypes(List<DartType> types, String prefix) {
|
| - bool needsComma = false;
|
| - for (DartType type in types) {
|
| - if (needsComma) {
|
| - sb.write(', ');
|
| - }
|
| - type.accept(this, prefix);
|
| - needsComma = true;
|
| - }
|
| - }
|
| -
|
| - void visitType(DartType type, String name) {
|
| - if (name == null) {
|
| - sb.write(type);
|
| - } else {
|
| - sb.write('$type ${createName(name)}');
|
| - }
|
| - }
|
| -
|
| - void visitGenericType(GenericType type, String name) {
|
| - sb.write(type.name);
|
| - if (!type.treatAsRaw) {
|
| - sb.write('<');
|
| - visitTypes(type.typeArguments, null);
|
| - sb.write('>');
|
| - }
|
| - if (name != null) {
|
| - sb.write(' ');
|
| - sb.write(createName(name));
|
| - }
|
| - }
|
| -
|
| - void visitFunctionType(FunctionType type, String name) {
|
| - visit(type.returnType);
|
| - sb.write(' ');
|
| - if (name != null) {
|
| - sb.write(name);
|
| - } else {
|
| - sb.write(createName('f'));
|
| - }
|
| - sb.write('(');
|
| - visitTypes(type.parameterTypes, 'a');
|
| - bool needsComma = !type.parameterTypes.isEmpty;
|
| - if (!type.optionalParameterTypes.isEmpty) {
|
| - if (needsComma) {
|
| - sb.write(', ');
|
| - }
|
| - sb.write('[');
|
| - visitTypes(type.optionalParameterTypes, 'a');
|
| - sb.write(']');
|
| - needsComma = true;
|
| - }
|
| - if (!type.namedParameterTypes.isEmpty) {
|
| - if (needsComma) {
|
| - sb.write(', ');
|
| - }
|
| - sb.write('{');
|
| - List<String> namedParameters = type.namedParameters;
|
| - List<DartType> namedParameterTypes = type.namedParameterTypes;
|
| - needsComma = false;
|
| - for (int index = 0; index < namedParameters.length; index++) {
|
| - if (needsComma) {
|
| - sb.write(', ');
|
| - }
|
| - namedParameterTypes[index].accept(this, namedParameters[index]);
|
| - needsComma = true;
|
| - }
|
| - sb.write('}');
|
| - }
|
| - sb.write(')');
|
| - }
|
| -}
|
| -
|
|
|