| Index: pkg/analyzer/lib/src/generated/element.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
|
| index f7b2c0b53985201d2fa90b4dcc2f542036ed8727..c59fc32d23b2540ab5d2e26b512ff848a4d2cf07 100644
|
| --- a/pkg/analyzer/lib/src/generated/element.dart
|
| +++ b/pkg/analyzer/lib/src/generated/element.dart
|
| @@ -84,27 +84,45 @@ class BottomTypeImpl extends TypeImpl {
|
| bool operator ==(Object object) => identical(object, this);
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) =>
|
| - identical(object, this);
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) => true;
|
|
|
| @override
|
| - int internalHashCode(List<DartType> visitedTypes) => hashCode;
|
| + bool isSubtypeOf(DartType type) => true;
|
|
|
| @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) => true;
|
| + bool isSupertypeOf(DartType type) => false;
|
|
|
| @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) => true;
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
|
|
|
| @override
|
| - bool isSupertypeOf(DartType type) => false;
|
| + BottomTypeImpl substitute2(
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) => this;
|
| +}
|
| +
|
| +/**
|
| + * Type created internally if a circular reference is ever detected. Behaves
|
| + * like `dynamic`, except that when converted to a string it is displayed as
|
| + * `...`.
|
| + */
|
| +class CircularTypeImpl extends DynamicTypeImpl {
|
| + CircularTypeImpl() : super._circular();
|
|
|
| @override
|
| - BottomTypeImpl substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) => this;
|
| + int get hashCode => 1;
|
| +
|
| + @override
|
| + bool operator ==(Object object) => object is CircularTypeImpl;
|
| +
|
| + @override
|
| + void appendTo(StringBuffer buffer) {
|
| + buffer.write('...');
|
| + }
|
| +
|
| + @override
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
|
| }
|
|
|
| /**
|
| @@ -2079,7 +2097,7 @@ abstract class DartType {
|
| * type directly.
|
| *
|
| * Note too that the current implementation of this method is only guaranteed
|
| - * to work when the argument types are type variables.
|
| + * to work when the parameter types are type variables.
|
| */
|
| DartType substitute2(
|
| List<DartType> argumentTypes, List<DartType> parameterTypes);
|
| @@ -2191,6 +2209,12 @@ class DynamicTypeImpl extends TypeImpl {
|
| (element as DynamicElementImpl).type = this;
|
| }
|
|
|
| + /**
|
| + * Constructor used by [CircularTypeImpl].
|
| + */
|
| + DynamicTypeImpl._circular()
|
| + : super(_INSTANCE.element, Keyword.DYNAMIC.syntax);
|
| +
|
| @override
|
| int get hashCode => 1;
|
|
|
| @@ -2201,16 +2225,8 @@ class DynamicTypeImpl extends TypeImpl {
|
| bool operator ==(Object object) => identical(object, this);
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) =>
|
| - identical(object, this);
|
| -
|
| - @override
|
| - int internalHashCode(List<DartType> visitedTypes) => hashCode;
|
| -
|
| - @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) {
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) {
|
| // T is S
|
| if (identical(this, type)) {
|
| return true;
|
| @@ -2220,15 +2236,18 @@ class DynamicTypeImpl extends TypeImpl {
|
| }
|
|
|
| @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) => true;
|
| + bool isSubtypeOf(DartType type) => true;
|
|
|
| @override
|
| bool isSupertypeOf(DartType type) => true;
|
|
|
| @override
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
|
| +
|
| + @override
|
| DartType substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) {
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) {
|
| int length = parameterTypes.length;
|
| for (int i = 0; i < length; i++) {
|
| if (parameterTypes[i] == this) {
|
| @@ -3237,60 +3256,6 @@ class ElementLocationImpl implements ElementLocation {
|
| }
|
|
|
| /**
|
| - * A pair of [Element]s. [Object.==] and
|
| - * [Object.hashCode] so this class can be used in hashed data structures.
|
| - */
|
| -class ElementPair {
|
| - /**
|
| - * The first [Element].
|
| - */
|
| - final Element _first;
|
| -
|
| - /**
|
| - * The second [Element].
|
| - */
|
| - final Element _second;
|
| -
|
| - /**
|
| - * A cached copy of the calculated hashCode for this element.
|
| - */
|
| - int _cachedHashCode;
|
| -
|
| - /**
|
| - * Initialize a newly created pair of elements consisting of the [_first] and
|
| - * [_second] elements.
|
| - */
|
| - ElementPair(this._first, this._second) {
|
| - _cachedHashCode = JenkinsSmiHash.hash2(_first.hashCode, _second.hashCode);
|
| - }
|
| -
|
| - /**
|
| - * Return the first element.
|
| - */
|
| - Element get firstElt => _first;
|
| -
|
| - @override
|
| - int get hashCode {
|
| - return _cachedHashCode;
|
| - }
|
| -
|
| - /**
|
| - * Return the second element
|
| - */
|
| - Element get secondElt => _second;
|
| -
|
| - @override
|
| - bool operator ==(Object object) {
|
| - if (identical(object, this)) {
|
| - return true;
|
| - }
|
| - return object is ElementPair &&
|
| - _first == object._first &&
|
| - _second == object._second;
|
| - }
|
| -}
|
| -
|
| -/**
|
| * An object that can be used to visit an element structure.
|
| */
|
| abstract class ElementVisitor<R> {
|
| @@ -4608,17 +4573,26 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| List<DartType> typeArguments = DartType.EMPTY_LIST;
|
|
|
| /**
|
| + * The set of typedefs which should not be expanded when exploring this type,
|
| + * to avoid creating infinite types in response to self-referential typedefs.
|
| + */
|
| + final List<FunctionTypeAliasElement> prunedTypedefs;
|
| +
|
| + /**
|
| * Initialize a newly created function type to be declared by the given
|
| * [element].
|
| */
|
| - FunctionTypeImpl(ExecutableElement element) : super(element, null);
|
| + FunctionTypeImpl(ExecutableElement element, [this.prunedTypedefs])
|
| + : super(element, null);
|
|
|
| /**
|
| * Initialize a newly created function type to be declared by the given
|
| * [element].
|
| */
|
| @deprecated // Use new FunctionTypeImpl(element)
|
| - FunctionTypeImpl.con1(ExecutableElement element) : super(element, null);
|
| + FunctionTypeImpl.con1(ExecutableElement element)
|
| + : prunedTypedefs = null,
|
| + super(element, null);
|
|
|
| /**
|
| * Initialize a newly created function type to be declared by the given
|
| @@ -4626,16 +4600,24 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| */
|
| @deprecated // Use new FunctionTypeImpl.forTypedef(element)
|
| FunctionTypeImpl.con2(FunctionTypeAliasElement element)
|
| - : super(element, element == null ? null : element.name);
|
| + : prunedTypedefs = null,
|
| + super(element, element == null ? null : element.name);
|
|
|
| /**
|
| * Initialize a newly created function type to be declared by the given
|
| * [element].
|
| */
|
| - FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element)
|
| + FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element,
|
| + [this.prunedTypedefs])
|
| : super(element, element == null ? null : element.name);
|
|
|
| /**
|
| + * Private constructor.
|
| + */
|
| + FunctionTypeImpl._(Element element, String name, this.prunedTypedefs)
|
| + : super(element, name);
|
| +
|
| + /**
|
| * Return the base parameter elements of this function element.
|
| */
|
| List<ParameterElement> get baseParameters {
|
| @@ -4731,7 +4713,27 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| }
|
|
|
| @override
|
| - int get hashCode => internalHashCode(<DartType>[]);
|
| + int get hashCode {
|
| + if (element == null) {
|
| + return 0;
|
| + }
|
| + // Reference the arrays of parameters
|
| + List<DartType> normalParameterTypes = this.normalParameterTypes;
|
| + List<DartType> optionalParameterTypes = this.optionalParameterTypes;
|
| + Iterable<DartType> namedParameterTypes = this.namedParameterTypes.values;
|
| + // Generate the hashCode
|
| + int code = (returnType as TypeImpl).hashCode;
|
| + for (int i = 0; i < normalParameterTypes.length; i++) {
|
| + code = (code << 1) + (normalParameterTypes[i] as TypeImpl).hashCode;
|
| + }
|
| + for (int i = 0; i < optionalParameterTypes.length; i++) {
|
| + code = (code << 1) + (optionalParameterTypes[i] as TypeImpl).hashCode;
|
| + }
|
| + for (DartType type in namedParameterTypes) {
|
| + code = (code << 1) + (type as TypeImpl).hashCode;
|
| + }
|
| + return code;
|
| + }
|
|
|
| @override
|
| Map<String, DartType> get namedParameterTypes {
|
| @@ -4748,7 +4750,10 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| DartType type = parameter.type;
|
| if (typeArguments.length != 0 &&
|
| typeArguments.length == typeParameters.length) {
|
| - type = type.substitute2(typeArguments, typeParameters);
|
| + type = (type as TypeImpl).substitute2(
|
| + typeArguments, typeParameters, newPrune);
|
| + } else {
|
| + type = (type as TypeImpl).pruned(newPrune);
|
| }
|
| namedParameterTypes[parameter.name] = type;
|
| }
|
| @@ -4756,6 +4761,27 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| return namedParameterTypes;
|
| }
|
|
|
| + /**
|
| + * Determine the new set of typedefs which should be pruned when expanding
|
| + * this function type.
|
| + */
|
| + List<FunctionTypeAliasElement> get newPrune {
|
| + Element element = this.element;
|
| + if (element is FunctionTypeAliasElement && !element.isSynthetic) {
|
| + // This typedef should be pruned, along with anything that was previously
|
| + // pruned.
|
| + if (prunedTypedefs == null) {
|
| + return <FunctionTypeAliasElement>[element];
|
| + } else {
|
| + return new List<FunctionTypeAliasElement>.from(prunedTypedefs)
|
| + ..add(element);
|
| + }
|
| + } else {
|
| + // This is not a typedef, so nothing additional needs to be pruned.
|
| + return prunedTypedefs;
|
| + }
|
| + }
|
| +
|
| @override
|
| List<DartType> get normalParameterTypes {
|
| List<ParameterElement> parameters = baseParameters;
|
| @@ -4770,7 +4796,10 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| DartType type = parameter.type;
|
| if (typeArguments.length != 0 &&
|
| typeArguments.length == typeParameters.length) {
|
| - type = type.substitute2(typeArguments, typeParameters);
|
| + type = (type as TypeImpl).substitute2(
|
| + typeArguments, typeParameters, newPrune);
|
| + } else {
|
| + type = (type as TypeImpl).pruned(newPrune);
|
| }
|
| types.add(type);
|
| }
|
| @@ -4792,7 +4821,10 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| DartType type = parameter.type;
|
| if (typeArguments.length != 0 &&
|
| typeArguments.length == typeParameters.length) {
|
| - type = type.substitute2(typeArguments, typeParameters);
|
| + type = (type as TypeImpl).substitute2(
|
| + typeArguments, typeParameters, newPrune);
|
| + } else {
|
| + type = (type as TypeImpl).pruned(newPrune);
|
| }
|
| types.add(type);
|
| }
|
| @@ -4829,10 +4861,10 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| // match the parameter size, return the base return type.
|
| if (typeArguments.length == 0 ||
|
| typeArguments.length != typeParameters.length) {
|
| - return baseReturnType;
|
| + return (baseReturnType as TypeImpl).pruned(newPrune);
|
| }
|
| - return baseReturnType.substitute2(
|
| - typeArguments, TypeParameterTypeImpl.getTypes(typeParameters));
|
| + return (baseReturnType as TypeImpl).substitute2(typeArguments,
|
| + TypeParameterTypeImpl.getTypes(typeParameters), newPrune);
|
| }
|
|
|
| @override
|
| @@ -4850,15 +4882,21 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| }
|
|
|
| @override
|
| - bool operator ==(Object object) =>
|
| - internalEquals(object, new HashSet<ElementPair>());
|
| + bool operator ==(Object object) {
|
| + if (object is! FunctionTypeImpl) {
|
| + return false;
|
| + }
|
| + FunctionTypeImpl otherType = object as FunctionTypeImpl;
|
| + return TypeImpl.equalArrays(
|
| + normalParameterTypes, otherType.normalParameterTypes) &&
|
| + TypeImpl.equalArrays(
|
| + optionalParameterTypes, otherType.optionalParameterTypes) &&
|
| + _equals(namedParameterTypes, otherType.namedParameterTypes) &&
|
| + returnType == otherType.returnType;
|
| + }
|
|
|
| @override
|
| - void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
|
| - if (!visitedTypes.add(this)) {
|
| - buffer.write(name == null ? '...' : name);
|
| - return;
|
| - }
|
| + void appendTo(StringBuffer buffer) {
|
| List<DartType> normalParameterTypes = this.normalParameterTypes;
|
| List<DartType> optionalParameterTypes = this.optionalParameterTypes;
|
| Map<String, DartType> namedParameterTypes = this.namedParameterTypes;
|
| @@ -4872,7 +4910,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| } else {
|
| needsComma = true;
|
| }
|
| - (type as TypeImpl).appendTo(buffer, visitedTypes);
|
| + (type as TypeImpl).appendTo(buffer);
|
| }
|
| }
|
| if (optionalParameterTypes.length > 0) {
|
| @@ -4887,7 +4925,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| } else {
|
| needsComma = true;
|
| }
|
| - (type as TypeImpl).appendTo(buffer, visitedTypes);
|
| + (type as TypeImpl).appendTo(buffer);
|
| }
|
| buffer.write("]");
|
| needsComma = true;
|
| @@ -4906,7 +4944,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| }
|
| buffer.write(name);
|
| buffer.write(": ");
|
| - (type as TypeImpl).appendTo(buffer, visitedTypes);
|
| + (type as TypeImpl).appendTo(buffer);
|
| });
|
| buffer.write("}");
|
| needsComma = true;
|
| @@ -4916,78 +4954,20 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| if (returnType == null) {
|
| buffer.write("null");
|
| } else {
|
| - (returnType as TypeImpl).appendTo(buffer, visitedTypes);
|
| + (returnType as TypeImpl).appendTo(buffer);
|
| }
|
| }
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) {
|
| - if (object is! FunctionTypeImpl) {
|
| - return false;
|
| - }
|
| - FunctionTypeImpl otherType = object as FunctionTypeImpl;
|
| - // If the visitedTypePairs already has the pair (this, type),
|
| - // use the elements to determine equality
|
| - ElementPair elementPair = new ElementPair(element, otherType.element);
|
| - if (!visitedElementPairs.add(elementPair)) {
|
| - return elementPair.firstElt == elementPair.secondElt;
|
| - }
|
| - // Compute the result
|
| - bool result = TypeImpl.equalArrays(normalParameterTypes,
|
| - otherType.normalParameterTypes, visitedElementPairs) &&
|
| - TypeImpl.equalArrays(optionalParameterTypes,
|
| - otherType.optionalParameterTypes, visitedElementPairs) &&
|
| - _equals(namedParameterTypes, otherType.namedParameterTypes,
|
| - visitedElementPairs) &&
|
| - (returnType as TypeImpl).internalEquals(
|
| - otherType.returnType, visitedElementPairs);
|
| - // Remove the pair from our visited pairs list
|
| - visitedElementPairs.remove(elementPair);
|
| - // Return the result
|
| - return result;
|
| - }
|
| -
|
| - @override
|
| - int internalHashCode(List<DartType> visitedTypes) {
|
| - if (element == null) {
|
| - return 0;
|
| - } else if (visitedTypes.contains(this)) {
|
| - return 3;
|
| - }
|
| - visitedTypes.add(this);
|
| - // Reference the arrays of parameters
|
| - List<DartType> normalParameterTypes = this.normalParameterTypes;
|
| - List<DartType> optionalParameterTypes = this.optionalParameterTypes;
|
| - Iterable<DartType> namedParameterTypes = this.namedParameterTypes.values;
|
| - // Generate the hashCode
|
| - int code = (returnType as TypeImpl).internalHashCode(visitedTypes);
|
| - for (int i = 0; i < normalParameterTypes.length; i++) {
|
| - code = (code << 1) +
|
| - (normalParameterTypes[i] as TypeImpl).internalHashCode(visitedTypes);
|
| - }
|
| - for (int i = 0; i < optionalParameterTypes.length; i++) {
|
| - code = (code << 1) +
|
| - (optionalParameterTypes[i] as TypeImpl)
|
| - .internalHashCode(visitedTypes);
|
| - }
|
| - for (DartType type in namedParameterTypes) {
|
| - code = (code << 1) + (type as TypeImpl).internalHashCode(visitedTypes);
|
| - }
|
| - return code;
|
| - }
|
| -
|
| - @override
|
| - bool isAssignableTo(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
|
| + bool isAssignableTo(DartType type) {
|
| // A function type T may be assigned to a function type S, written T <=> S,
|
| // iff T <: S.
|
| - return isSubtypeOf(type, thisExpansions, typeExpansions);
|
| + return isSubtypeOf(type);
|
| }
|
|
|
| @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) {
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) {
|
| // Note: visitedElements is only used for breaking recursion in the type
|
| // hierarchy; we don't use it when recursing into the function type.
|
|
|
| @@ -5006,129 +4986,104 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| }
|
| FunctionType t = this;
|
| FunctionType s = type as FunctionType;
|
| - if (thisExpansions == null) {
|
| - thisExpansions = new HashSet<Element>();
|
| - } else if (thisExpansions.contains(this.element)) {
|
| - // [this] contains a reference to itself, which is illegal (and is
|
| - // checked elsewhere). To avoid cascading errors, consider T to be a
|
| - // subtype of S.
|
| - return true;
|
| - }
|
| - if (typeExpansions == null) {
|
| - typeExpansions = new HashSet<Element>();
|
| - } else if (typeExpansions.contains(type.element)) {
|
| - // [type] contains a reference to itself, which is illegal (and is
|
| - // checked elsewhere). To avoid cascading errors, consider T to be a
|
| - // subtype of S.
|
| - return true;
|
| + List<DartType> tTypes = t.normalParameterTypes;
|
| + List<DartType> tOpTypes = t.optionalParameterTypes;
|
| + List<DartType> sTypes = s.normalParameterTypes;
|
| + List<DartType> sOpTypes = s.optionalParameterTypes;
|
| + // If one function has positional and the other has named parameters,
|
| + // return false.
|
| + if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
|
| + (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
|
| + return false;
|
| }
|
| - thisExpansions.add(this.element);
|
| - typeExpansions.add(type.element);
|
| - try {
|
| - List<DartType> tTypes = t.normalParameterTypes;
|
| - List<DartType> tOpTypes = t.optionalParameterTypes;
|
| - List<DartType> sTypes = s.normalParameterTypes;
|
| - List<DartType> sOpTypes = s.optionalParameterTypes;
|
| - // If one function has positional and the other has named parameters,
|
| - // return false.
|
| - if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
|
| - (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
|
| + // named parameters case
|
| + if (t.namedParameterTypes.length > 0) {
|
| + // check that the number of required parameters are equal, and check that
|
| + // every t_i is more specific than every s_i
|
| + if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
|
| + return false;
|
| + } else if (t.normalParameterTypes.length > 0) {
|
| + for (int i = 0; i < tTypes.length; i++) {
|
| + if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
|
| + sTypes[i], withDynamic)) {
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + Map<String, DartType> namedTypesT = t.namedParameterTypes;
|
| + Map<String, DartType> namedTypesS = s.namedParameterTypes;
|
| + // if k >= m is false, return false: the passed function type has more
|
| + // named parameter types than this
|
| + if (namedTypesT.length < namedTypesS.length) {
|
| return false;
|
| }
|
| - // named parameters case
|
| - if (t.namedParameterTypes.length > 0) {
|
| - // check that the number of required parameters are equal, and check that
|
| - // every t_i is more specific than every s_i
|
| - if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
|
| + // Loop through each element in S verifying that T has a matching
|
| + // parameter name and that the corresponding type is more specific then
|
| + // the type in S.
|
| + for (String keyS in namedTypesS.keys) {
|
| + DartType typeT = namedTypesT[keyS];
|
| + if (typeT == null) {
|
| return false;
|
| - } else if (t.normalParameterTypes.length > 0) {
|
| - for (int i = 0; i < tTypes.length; i++) {
|
| - if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
|
| - sTypes[i], thisExpansions, typeExpansions, withDynamic)) {
|
| - return false;
|
| - }
|
| - }
|
| }
|
| - Map<String, DartType> namedTypesT = t.namedParameterTypes;
|
| - Map<String, DartType> namedTypesS = s.namedParameterTypes;
|
| - // if k >= m is false, return false: the passed function type has more
|
| - // named parameter types than this
|
| - if (namedTypesT.length < namedTypesS.length) {
|
| + if (!(typeT as TypeImpl).isMoreSpecificThan(
|
| + namedTypesS[keyS], withDynamic)) {
|
| return false;
|
| }
|
| - // Loop through each element in S verifying that T has a matching
|
| - // parameter name and that the corresponding type is more specific then
|
| - // the type in S.
|
| - for (String keyS in namedTypesS.keys) {
|
| - DartType typeT = namedTypesT[keyS];
|
| - if (typeT == null) {
|
| - return false;
|
| - }
|
| - if (!(typeT as TypeImpl).isMoreSpecificThan(
|
| - namedTypesS[keyS], thisExpansions, typeExpansions, withDynamic)) {
|
| + }
|
| + } else if (s.namedParameterTypes.length > 0) {
|
| + return false;
|
| + } else {
|
| + // positional parameter case
|
| + int tArgLength = tTypes.length + tOpTypes.length;
|
| + int sArgLength = sTypes.length + sOpTypes.length;
|
| + // Check that the total number of parameters in t is greater than or equal
|
| + // to the number of parameters in s and that the number of required
|
| + // parameters in s is greater than or equal to the number of required
|
| + // parameters in t.
|
| + if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
|
| + return false;
|
| + }
|
| + if (tOpTypes.length == 0 && sOpTypes.length == 0) {
|
| + // No positional arguments, don't copy contents to new array
|
| + for (int i = 0; i < sTypes.length; i++) {
|
| + if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
|
| + sTypes[i], withDynamic)) {
|
| return false;
|
| }
|
| }
|
| - } else if (s.namedParameterTypes.length > 0) {
|
| - return false;
|
| } else {
|
| - // positional parameter case
|
| - int tArgLength = tTypes.length + tOpTypes.length;
|
| - int sArgLength = sTypes.length + sOpTypes.length;
|
| - // Check that the total number of parameters in t is greater than or equal
|
| - // to the number of parameters in s and that the number of required
|
| - // parameters in s is greater than or equal to the number of required
|
| - // parameters in t.
|
| - if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
|
| - return false;
|
| + // Else, we do have positional parameters, copy required and positional
|
| + // parameter types into arrays to do the compare (for loop below).
|
| + List<DartType> tAllTypes = new List<DartType>(sArgLength);
|
| + for (int i = 0; i < tTypes.length; i++) {
|
| + tAllTypes[i] = tTypes[i];
|
| }
|
| - if (tOpTypes.length == 0 && sOpTypes.length == 0) {
|
| - // No positional arguments, don't copy contents to new array
|
| - for (int i = 0; i < sTypes.length; i++) {
|
| - if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
|
| - sTypes[i], thisExpansions, typeExpansions, withDynamic)) {
|
| - return false;
|
| - }
|
| - }
|
| - } else {
|
| - // Else, we do have positional parameters, copy required and positional
|
| - // parameter types into arrays to do the compare (for loop below).
|
| - List<DartType> tAllTypes = new List<DartType>(sArgLength);
|
| - for (int i = 0; i < tTypes.length; i++) {
|
| - tAllTypes[i] = tTypes[i];
|
| - }
|
| - for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| - tAllTypes[i] = tOpTypes[j];
|
| - }
|
| - List<DartType> sAllTypes = new List<DartType>(sArgLength);
|
| - for (int i = 0; i < sTypes.length; i++) {
|
| - sAllTypes[i] = sTypes[i];
|
| - }
|
| - for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| - sAllTypes[i] = sOpTypes[j];
|
| - }
|
| - for (int i = 0; i < sAllTypes.length; i++) {
|
| - if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan(
|
| - sAllTypes[i], thisExpansions, typeExpansions, withDynamic)) {
|
| - return false;
|
| - }
|
| + for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| + tAllTypes[i] = tOpTypes[j];
|
| + }
|
| + List<DartType> sAllTypes = new List<DartType>(sArgLength);
|
| + for (int i = 0; i < sTypes.length; i++) {
|
| + sAllTypes[i] = sTypes[i];
|
| + }
|
| + for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| + sAllTypes[i] = sOpTypes[j];
|
| + }
|
| + for (int i = 0; i < sAllTypes.length; i++) {
|
| + if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan(
|
| + sAllTypes[i], withDynamic)) {
|
| + return false;
|
| }
|
| }
|
| }
|
| - DartType tRetType = t.returnType;
|
| - DartType sRetType = s.returnType;
|
| - return sRetType.isVoid ||
|
| - (tRetType as TypeImpl).isMoreSpecificThan(
|
| - sRetType, thisExpansions, typeExpansions, withDynamic);
|
| - } finally {
|
| - thisExpansions.remove(this.element);
|
| - typeExpansions.remove(type.element);
|
| }
|
| + DartType tRetType = t.returnType;
|
| + DartType sRetType = s.returnType;
|
| + return sRetType.isVoid ||
|
| + (tRetType as TypeImpl).isMoreSpecificThan(sRetType, withDynamic);
|
| }
|
|
|
| @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
|
| + bool isSubtypeOf(DartType type) {
|
| // trivial base cases
|
| if (type == null) {
|
| return false;
|
| @@ -5144,141 +5099,142 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| }
|
| FunctionType t = this;
|
| FunctionType s = type as FunctionType;
|
| - if (thisExpansions == null) {
|
| - thisExpansions = new HashSet<Element>();
|
| - } else if (thisExpansions.contains(this.element)) {
|
| - // [this] contains a reference to itself, which is illegal (and is
|
| - // checked elsewhere). To avoid cascading errors, consider T to be a
|
| - // subtype of S.
|
| - return true;
|
| - }
|
| - if (typeExpansions == null) {
|
| - typeExpansions = new HashSet<Element>();
|
| - } else if (typeExpansions.contains(type.element)) {
|
| - // [type] contains a reference to itself, which is illegal (and is
|
| - // checked elsewhere). To avoid cascading errors, consider T to be a
|
| - // subtype of S.
|
| - return true;
|
| + List<DartType> tTypes = t.normalParameterTypes;
|
| + List<DartType> tOpTypes = t.optionalParameterTypes;
|
| + List<DartType> sTypes = s.normalParameterTypes;
|
| + List<DartType> sOpTypes = s.optionalParameterTypes;
|
| + // If one function has positional and the other has named parameters,
|
| + // return false.
|
| + if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
|
| + (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
|
| + return false;
|
| }
|
| - thisExpansions.add(this.element);
|
| - typeExpansions.add(type.element);
|
| - try {
|
| - List<DartType> tTypes = t.normalParameterTypes;
|
| - List<DartType> tOpTypes = t.optionalParameterTypes;
|
| - List<DartType> sTypes = s.normalParameterTypes;
|
| - List<DartType> sOpTypes = s.optionalParameterTypes;
|
| - // If one function has positional and the other has named parameters,
|
| - // return false.
|
| - if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
|
| - (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
|
| + // named parameters case
|
| + if (t.namedParameterTypes.length > 0) {
|
| + // check that the number of required parameters are equal,
|
| + // and check that every t_i is assignable to every s_i
|
| + if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
|
| + return false;
|
| + } else if (t.normalParameterTypes.length > 0) {
|
| + for (int i = 0; i < tTypes.length; i++) {
|
| + if (!(tTypes[i] as TypeImpl).isAssignableTo(sTypes[i])) {
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + Map<String, DartType> namedTypesT = t.namedParameterTypes;
|
| + Map<String, DartType> namedTypesS = s.namedParameterTypes;
|
| + // if k >= m is false, return false: the passed function type has more
|
| + // named parameter types than this
|
| + if (namedTypesT.length < namedTypesS.length) {
|
| return false;
|
| }
|
| - // named parameters case
|
| - if (t.namedParameterTypes.length > 0) {
|
| - // check that the number of required parameters are equal,
|
| - // and check that every t_i is assignable to every s_i
|
| - if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
|
| + // Loop through each element in S verifying that T has a matching
|
| + // parameter name and that the corresponding type is assignable to the
|
| + // type in S.
|
| + for (String keyS in namedTypesS.keys) {
|
| + DartType typeT = namedTypesT[keyS];
|
| + if (typeT == null) {
|
| return false;
|
| - } else if (t.normalParameterTypes.length > 0) {
|
| - for (int i = 0; i < tTypes.length; i++) {
|
| - if (!(tTypes[i] as TypeImpl).isAssignableTo(
|
| - sTypes[i], thisExpansions, typeExpansions)) {
|
| - return false;
|
| - }
|
| - }
|
| }
|
| - Map<String, DartType> namedTypesT = t.namedParameterTypes;
|
| - Map<String, DartType> namedTypesS = s.namedParameterTypes;
|
| - // if k >= m is false, return false: the passed function type has more
|
| - // named parameter types than this
|
| - if (namedTypesT.length < namedTypesS.length) {
|
| + if (!(typeT as TypeImpl).isAssignableTo(namedTypesS[keyS])) {
|
| return false;
|
| }
|
| - // Loop through each element in S verifying that T has a matching
|
| - // parameter name and that the corresponding type is assignable to the
|
| - // type in S.
|
| - for (String keyS in namedTypesS.keys) {
|
| - DartType typeT = namedTypesT[keyS];
|
| - if (typeT == null) {
|
| - return false;
|
| - }
|
| - if (!(typeT as TypeImpl).isAssignableTo(
|
| - namedTypesS[keyS], thisExpansions, typeExpansions)) {
|
| + }
|
| + } else if (s.namedParameterTypes.length > 0) {
|
| + return false;
|
| + } else {
|
| + // positional parameter case
|
| + int tArgLength = tTypes.length + tOpTypes.length;
|
| + int sArgLength = sTypes.length + sOpTypes.length;
|
| + // Check that the total number of parameters in t is greater than or
|
| + // equal to the number of parameters in s and that the number of
|
| + // required parameters in s is greater than or equal to the number of
|
| + // required parameters in t.
|
| + if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
|
| + return false;
|
| + }
|
| + if (tOpTypes.length == 0 && sOpTypes.length == 0) {
|
| + // No positional arguments, don't copy contents to new array
|
| + for (int i = 0; i < sTypes.length; i++) {
|
| + if (!(tTypes[i] as TypeImpl).isAssignableTo(sTypes[i])) {
|
| return false;
|
| }
|
| }
|
| - } else if (s.namedParameterTypes.length > 0) {
|
| - return false;
|
| } else {
|
| - // positional parameter case
|
| - int tArgLength = tTypes.length + tOpTypes.length;
|
| - int sArgLength = sTypes.length + sOpTypes.length;
|
| - // Check that the total number of parameters in t is greater than or
|
| - // equal to the number of parameters in s and that the number of
|
| - // required parameters in s is greater than or equal to the number of
|
| - // required parameters in t.
|
| - if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
|
| - return false;
|
| + // Else, we do have positional parameters, copy required and
|
| + // positional parameter types into arrays to do the compare (for loop
|
| + // below).
|
| + List<DartType> tAllTypes = new List<DartType>(sArgLength);
|
| + for (int i = 0; i < tTypes.length; i++) {
|
| + tAllTypes[i] = tTypes[i];
|
| }
|
| - if (tOpTypes.length == 0 && sOpTypes.length == 0) {
|
| - // No positional arguments, don't copy contents to new array
|
| - for (int i = 0; i < sTypes.length; i++) {
|
| - if (!(tTypes[i] as TypeImpl).isAssignableTo(
|
| - sTypes[i], thisExpansions, typeExpansions)) {
|
| - return false;
|
| - }
|
| - }
|
| - } else {
|
| - // Else, we do have positional parameters, copy required and
|
| - // positional parameter types into arrays to do the compare (for loop
|
| - // below).
|
| - List<DartType> tAllTypes = new List<DartType>(sArgLength);
|
| - for (int i = 0; i < tTypes.length; i++) {
|
| - tAllTypes[i] = tTypes[i];
|
| - }
|
| - for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| - tAllTypes[i] = tOpTypes[j];
|
| - }
|
| - List<DartType> sAllTypes = new List<DartType>(sArgLength);
|
| - for (int i = 0; i < sTypes.length; i++) {
|
| - sAllTypes[i] = sTypes[i];
|
| - }
|
| - for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| - sAllTypes[i] = sOpTypes[j];
|
| - }
|
| - for (int i = 0; i < sAllTypes.length; i++) {
|
| - if (!(tAllTypes[i] as TypeImpl).isAssignableTo(
|
| - sAllTypes[i], thisExpansions, typeExpansions)) {
|
| - return false;
|
| - }
|
| + for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| + tAllTypes[i] = tOpTypes[j];
|
| + }
|
| + List<DartType> sAllTypes = new List<DartType>(sArgLength);
|
| + for (int i = 0; i < sTypes.length; i++) {
|
| + sAllTypes[i] = sTypes[i];
|
| + }
|
| + for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
|
| + sAllTypes[i] = sOpTypes[j];
|
| + }
|
| + for (int i = 0; i < sAllTypes.length; i++) {
|
| + if (!(tAllTypes[i] as TypeImpl).isAssignableTo(sAllTypes[i])) {
|
| + return false;
|
| }
|
| }
|
| }
|
| - DartType tRetType = t.returnType;
|
| - DartType sRetType = s.returnType;
|
| - return sRetType.isVoid ||
|
| - (tRetType as TypeImpl).isAssignableTo(
|
| - sRetType, thisExpansions, typeExpansions);
|
| - } finally {
|
| - thisExpansions.remove(this.element);
|
| - typeExpansions.remove(type.element);
|
| + }
|
| + DartType tRetType = t.returnType;
|
| + DartType sRetType = s.returnType;
|
| + return sRetType.isVoid || (tRetType as TypeImpl).isAssignableTo(sRetType);
|
| + }
|
| +
|
| + @override
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) {
|
| + if (prune == null) {
|
| + return this;
|
| + } else if (prune.contains(element)) {
|
| + // Circularity found. Prune the type declaration.
|
| + return new CircularTypeImpl();
|
| + } else {
|
| + // There should never be a reason to prune a type that has already been
|
| + // pruned, since pruning is only done when expanding a function type
|
| + // alias, and function type aliases are always expanded by starting with
|
| + // base types.
|
| + assert(this.prunedTypedefs == null);
|
| + FunctionTypeImpl result = new FunctionTypeImpl._(element, name, prune);
|
| + result.typeArguments =
|
| + typeArguments.map((TypeImpl t) => t.pruned(prune)).toList();
|
| + return result;
|
| }
|
| }
|
|
|
| @override
|
| - FunctionTypeImpl substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) {
|
| + DartType substitute2(
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) {
|
| + // Pruned types should only ever result from peforming type variable
|
| + // substitution, and it doesn't make sense to substitute again after
|
| + // substituting once.
|
| + assert(this.prunedTypedefs == null);
|
| if (argumentTypes.length != parameterTypes.length) {
|
| throw new IllegalArgumentException(
|
| "argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})");
|
| }
|
| + Element element = this.element;
|
| + if (prune != null && prune.contains(element)) {
|
| + // Circularity found. Prune the type declaration.
|
| + return new CircularTypeImpl();
|
| + }
|
| if (argumentTypes.length == 0) {
|
| - return this;
|
| + return this.pruned(prune);
|
| }
|
| - Element element = this.element;
|
| FunctionTypeImpl newType = (element is ExecutableElement)
|
| - ? new FunctionTypeImpl(element)
|
| - : new FunctionTypeImpl.forTypedef(element as FunctionTypeAliasElement);
|
| + ? new FunctionTypeImpl(element, prune)
|
| + : new FunctionTypeImpl.forTypedef(
|
| + element as FunctionTypeAliasElement, prune);
|
| newType.typeArguments =
|
| TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes);
|
| return newType;
|
| @@ -5292,12 +5248,10 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| * Return `true` if all of the name/type pairs in the first map ([firstTypes])
|
| * are equal to the corresponding name/type pairs in the second map
|
| * ([secondTypes]). The maps are expected to iterate over their entries in the
|
| - * same order in which those entries were added to the map. The set of
|
| - * [visitedElementPairs] is used to prevent infinite recursion in the case of
|
| - * cyclic type structures.
|
| + * same order in which those entries were added to the map.
|
| */
|
| - static bool _equals(Map<String, DartType> firstTypes,
|
| - Map<String, DartType> secondTypes, Set<ElementPair> visitedElementPairs) {
|
| + static bool _equals(
|
| + Map<String, DartType> firstTypes, Map<String, DartType> secondTypes) {
|
| if (secondTypes.length != firstTypes.length) {
|
| return false;
|
| }
|
| @@ -5308,8 +5262,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
|
| String secondKey = secondKeys.current;
|
| TypeImpl firstType = firstTypes[firstKey];
|
| TypeImpl secondType = secondTypes[secondKey];
|
| - if (firstKey != secondKey ||
|
| - !firstType.internalEquals(secondType, visitedElementPairs)) {
|
| + if (firstKey != secondKey || firstType != secondType) {
|
| return false;
|
| }
|
| }
|
| @@ -6113,29 +6066,47 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| List<DartType> typeArguments = DartType.EMPTY_LIST;
|
|
|
| /**
|
| + * The set of typedefs which should not be expanded when exploring this type,
|
| + * to avoid creating infinite types in response to self-referential typedefs.
|
| + */
|
| + final List<FunctionTypeAliasElement> prunedTypedefs;
|
| +
|
| + /**
|
| * Initialize a newly created type to be declared by the given [element].
|
| */
|
| - InterfaceTypeImpl(ClassElement element) : super(element, element.displayName);
|
| + InterfaceTypeImpl(ClassElement element, [this.prunedTypedefs])
|
| + : super(element, element.displayName);
|
|
|
| /**
|
| * Initialize a newly created type to be declared by the given [element].
|
| */
|
| @deprecated // Use new InterfaceTypeImpl(element)
|
| InterfaceTypeImpl.con1(ClassElement element)
|
| - : super(element, element.displayName);
|
| + : prunedTypedefs = null,
|
| + super(element, element.displayName);
|
|
|
| /**
|
| * Initialize a newly created type to have the given [name]. This constructor
|
| * should only be used in cases where there is no declaration of the type.
|
| */
|
| @deprecated // Use new InterfaceTypeImpl.named(name)
|
| - InterfaceTypeImpl.con2(String name) : super(null, name);
|
| + InterfaceTypeImpl.con2(String name)
|
| + : prunedTypedefs = null,
|
| + super(null, name);
|
|
|
| /**
|
| * Initialize a newly created type to have the given [name]. This constructor
|
| * should only be used in cases where there is no declaration of the type.
|
| */
|
| - InterfaceTypeImpl.named(String name) : super(null, name);
|
| + InterfaceTypeImpl.named(String name)
|
| + : prunedTypedefs = null,
|
| + super(null, name);
|
| +
|
| + /**
|
| + * Private constructor.
|
| + */
|
| + InterfaceTypeImpl._(Element element, String name, this.prunedTypedefs)
|
| + : super(element, name);
|
|
|
| @override
|
| List<PropertyAccessorElement> get accessors {
|
| @@ -6280,15 +6251,16 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| if (identical(object, this)) {
|
| return true;
|
| }
|
| - return internalEquals(object, new HashSet<ElementPair>());
|
| + if (object is! InterfaceTypeImpl) {
|
| + return false;
|
| + }
|
| + InterfaceTypeImpl otherType = object as InterfaceTypeImpl;
|
| + return (element == otherType.element) &&
|
| + TypeImpl.equalArrays(typeArguments, otherType.typeArguments);
|
| }
|
|
|
| @override
|
| - void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
|
| - if (!visitedTypes.add(this)) {
|
| - buffer.write(name == null ? '...' : name);
|
| - return;
|
| - }
|
| + void appendTo(StringBuffer buffer) {
|
| buffer.write(name);
|
| int argumentCount = typeArguments.length;
|
| if (argumentCount > 0) {
|
| @@ -6297,7 +6269,7 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| if (i > 0) {
|
| buffer.write(", ");
|
| }
|
| - (typeArguments[i] as TypeImpl).appendTo(buffer, visitedTypes);
|
| + (typeArguments[i] as TypeImpl).appendTo(buffer);
|
| }
|
| buffer.write(">");
|
| }
|
| @@ -6373,23 +6345,6 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| .from((element as ClassElementImpl).getSetter(setterName), this);
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) {
|
| - if (identical(object, this)) {
|
| - return true;
|
| - }
|
| - if (object is! InterfaceTypeImpl) {
|
| - return false;
|
| - }
|
| - InterfaceTypeImpl otherType = object as InterfaceTypeImpl;
|
| - return (element == otherType.element) &&
|
| - TypeImpl.equalArrays(
|
| - typeArguments, otherType.typeArguments, visitedElementPairs);
|
| - }
|
| -
|
| - @override
|
| - int internalHashCode(List<DartType> visitedTypes) => hashCode;
|
| -
|
| - @override
|
| bool isDirectSupertypeOf(InterfaceType type) {
|
| InterfaceType i = this;
|
| InterfaceType j = type;
|
| @@ -6438,9 +6393,8 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| }
|
|
|
| @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) {
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) {
|
| //
|
| // S is dynamic.
|
| // The test to determine whether S is dynamic is done here because dynamic
|
| @@ -6481,7 +6435,7 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| }
|
| for (int i = 0; i < tArguments.length; i++) {
|
| if (!(tArguments[i] as TypeImpl).isMoreSpecificThan(
|
| - sArguments[i], thisExpansions, typeExpansions, withDynamic)) {
|
| + sArguments[i], withDynamic)) {
|
| return false;
|
| }
|
| }
|
| @@ -6507,19 +6461,18 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| // specific than S.
|
| InterfaceTypeImpl supertype = superclass;
|
| if (supertype != null &&
|
| - supertype.isMoreSpecificThan(type, thisExpansions, typeExpansions,
|
| - withDynamic, visitedElements)) {
|
| + supertype.isMoreSpecificThan(type, withDynamic, visitedElements)) {
|
| return true;
|
| }
|
| for (InterfaceType interfaceType in interfaces) {
|
| - if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan(type,
|
| - thisExpansions, typeExpansions, withDynamic, visitedElements)) {
|
| + if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan(
|
| + type, withDynamic, visitedElements)) {
|
| return true;
|
| }
|
| }
|
| for (InterfaceType mixinType in mixins) {
|
| - if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan(type,
|
| - thisExpansions, typeExpansions, withDynamic, visitedElements)) {
|
| + if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan(
|
| + type, withDynamic, visitedElements)) {
|
| return true;
|
| }
|
| }
|
| @@ -6529,8 +6482,7 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| MethodElement callMethod = getMethod('call');
|
| if (callMethod != null && !callMethod.isStatic) {
|
| FunctionTypeImpl callType = callMethod.type;
|
| - if (callType.isMoreSpecificThan(type, thisExpansions, typeExpansions,
|
| - withDynamic, visitedElements)) {
|
| + if (callType.isMoreSpecificThan(type, withDynamic, visitedElements)) {
|
| return true;
|
| }
|
| }
|
| @@ -6682,21 +6634,43 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
| }
|
|
|
| @override
|
| + InterfaceTypeImpl pruned(List<FunctionTypeAliasElement> prune) {
|
| + if (prune == null) {
|
| + return this;
|
| + } else {
|
| + // There should never be a reason to prune a type that has already been
|
| + // pruned, since pruning is only done when expanding a function type
|
| + // alias, and function type aliases are always expanded by starting with
|
| + // base types.
|
| + assert(this.prunedTypedefs == null);
|
| + InterfaceTypeImpl result = new InterfaceTypeImpl._(element, name, prune);
|
| + result.typeArguments =
|
| + typeArguments.map((TypeImpl t) => t.pruned(prune)).toList();
|
| + return result;
|
| + }
|
| + }
|
| +
|
| + @override
|
| InterfaceTypeImpl substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) {
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) {
|
| + // Pruned types should only ever result from performing type variable
|
| + // substitution, and it doesn't make sense to substitute again after
|
| + // substituting once.
|
| + assert(this.prunedTypedefs == null);
|
| if (argumentTypes.length != parameterTypes.length) {
|
| throw new IllegalArgumentException(
|
| "argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})");
|
| }
|
| if (argumentTypes.length == 0 || typeArguments.length == 0) {
|
| - return this;
|
| + return this.pruned(prune);
|
| }
|
| - List<DartType> newTypeArguments =
|
| - TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes);
|
| + List<DartType> newTypeArguments = TypeImpl.substitute(
|
| + typeArguments, argumentTypes, parameterTypes, prune);
|
| if (JavaArrays.equals(newTypeArguments, typeArguments)) {
|
| return this;
|
| }
|
| - InterfaceTypeImpl newType = new InterfaceTypeImpl(element);
|
| + InterfaceTypeImpl newType = new InterfaceTypeImpl(element, prune);
|
| newType.typeArguments = newTypeArguments;
|
| return newType;
|
| }
|
| @@ -9690,11 +9664,7 @@ abstract class TypeImpl implements DartType {
|
| * Append a textual representation of this type to the given [buffer]. The set
|
| * of [visitedTypes] is used to prevent infinite recusion.
|
| */
|
| - void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
|
| - if (!visitedTypes.add(this)) {
|
| - buffer.write(name == null ? '...' : name);
|
| - return;
|
| - }
|
| + void appendTo(StringBuffer buffer) {
|
| if (name == null) {
|
| buffer.write("<unnamed type>");
|
| } else {
|
| @@ -9705,10 +9675,6 @@ abstract class TypeImpl implements DartType {
|
| @override
|
| DartType getLeastUpperBound(DartType type) => null;
|
|
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs);
|
| -
|
| - int internalHashCode(List<DartType> visitedTypes);
|
| -
|
| /**
|
| * Return `true` if this type is assignable to the given [type] (written in
|
| * the spec as "T <=> S", where T=[this] and S=[type]).
|
| @@ -9721,25 +9687,16 @@ abstract class TypeImpl implements DartType {
|
| * use these as sets of function type aliases that don't need to be expanded.
|
| */
|
| @override
|
| - bool isAssignableTo(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
|
| + bool isAssignableTo(DartType type) {
|
| // An interface type T may be assigned to a type S, written T <=> S, iff
|
| // either T <: S or S <: T.
|
| - return isSubtypeOf(type, thisExpansions, typeExpansions) ||
|
| - (type as TypeImpl).isSubtypeOf(this, typeExpansions, thisExpansions);
|
| + return isSubtypeOf(type) || (type as TypeImpl).isSubtypeOf(this);
|
| }
|
|
|
| /**
|
| * Return `true` if this type is more specific than the given [type] (written
|
| * in the spec as "T << S", where T=[this] and S=[type]).
|
| *
|
| - * The sets [thisExpansions] and [typeExpansions], if given, are the sets of
|
| - * function type aliases that have been expanded so far in the process of
|
| - * reaching [this] and [type], respectively. These are used to avoid
|
| - * infinite regress when analyzing invalid code; since the language spec
|
| - * forbids a typedef from referring to itself directly or indirectly, we can
|
| - * use these as sets of function type aliases that don't need to be expanded.
|
| - *
|
| * If [withDynamic] is `true`, then "dynamic" should be considered as a
|
| * subtype of any type (as though "dynamic" had been replaced with bottom).
|
| *
|
| @@ -9751,9 +9708,8 @@ abstract class TypeImpl implements DartType {
|
| * examined when walking the class hierarchy.
|
| */
|
| @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]);
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]);
|
|
|
| /**
|
| * Return `true` if this type is a subtype of the given [type] (written in
|
| @@ -9767,29 +9723,53 @@ abstract class TypeImpl implements DartType {
|
| * use these as sets of function type aliases that don't need to be expanded.
|
| */
|
| @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
|
| + bool isSubtypeOf(DartType type) {
|
| // For non-function types, T <: S iff [_|_/dynamic]T << S.
|
| - return isMoreSpecificThan(type, thisExpansions, typeExpansions, true);
|
| + return isMoreSpecificThan(type, true);
|
| }
|
|
|
| @override
|
| bool isSupertypeOf(DartType type) => type.isSubtypeOf(this);
|
|
|
| + /**
|
| + * Create a new [TypeImpl] that is identical to [this] except that when
|
| + * visiting type parameters, function parameter types, and function return
|
| + * types, function types listed in [prune] will not be expanded. This is
|
| + * used to avoid creating infinite types in the presence of circular
|
| + * typedefs.
|
| + *
|
| + * If [prune] is null, then [this] is returned unchanged.
|
| + *
|
| + * Only legal to call on a [TypeImpl] that is not already subject to pruning.
|
| + */
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune);
|
| +
|
| + /**
|
| + * Return the type resulting from substituting the given [argumentTypes] for
|
| + * the given [parameterTypes] in this type.
|
| + *
|
| + * In all classes derived from [TypeImpl], a new optional argument
|
| + * [prune] is added. If specified, it is a list of function typdefs
|
| + * which should not be expanded. This is used to avoid creating infinite
|
| + * types in response to self-referential typedefs.
|
| + */
|
| + @override
|
| + DartType substitute2(
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]);
|
| +
|
| @override
|
| String toString() {
|
| StringBuffer buffer = new StringBuffer();
|
| - appendTo(buffer, new HashSet<DartType>());
|
| + appendTo(buffer);
|
| return buffer.toString();
|
| }
|
|
|
| /**
|
| * Return `true` if corresponding elements of the [first] and [second] lists
|
| - * of type arguments are all equal. Use the set of [visitedElementPairs] to
|
| - * prevent infinite loops when the types are recursively defined.
|
| + * of type arguments are all equal.
|
| */
|
| - static bool equalArrays(List<DartType> first, List<DartType> second,
|
| - Set<ElementPair> visitedElementPairs) {
|
| + static bool equalArrays(List<DartType> first, List<DartType> second) {
|
| if (first.length != second.length) {
|
| return false;
|
| }
|
| @@ -9803,8 +9783,7 @@ abstract class TypeImpl implements DartType {
|
| .logInformation('Found null type argument in TypeImpl.equalArrays');
|
| return false;
|
| }
|
| - if (!(first[i] as TypeImpl).internalEquals(
|
| - second[i], visitedElementPairs)) {
|
| + if (first[i] != second[i]) {
|
| return false;
|
| }
|
| }
|
| @@ -9814,16 +9793,22 @@ abstract class TypeImpl implements DartType {
|
| /**
|
| * Return a list containing the results of using the given [argumentTypes] and
|
| * [parameterTypes] to perform a substitution on all of the given [types].
|
| + *
|
| + * If [prune] is specified, it is a list of function typdefs which should not
|
| + * be expanded. This is used to avoid creating infinite types in response to
|
| + * self-referential typedefs.
|
| */
|
| static List<DartType> substitute(List<DartType> types,
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) {
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) {
|
| int length = types.length;
|
| if (length == 0) {
|
| return types;
|
| }
|
| List<DartType> newTypes = new List<DartType>(length);
|
| for (int i = 0; i < length; i++) {
|
| - newTypes[i] = types[i].substitute2(argumentTypes, parameterTypes);
|
| + newTypes[i] = (types[i] as TypeImpl).substitute2(
|
| + argumentTypes, parameterTypes, prune);
|
| }
|
| return newTypes;
|
| }
|
| @@ -9943,16 +9928,8 @@ class TypeParameterTypeImpl extends TypeImpl implements TypeParameterType {
|
| object is TypeParameterTypeImpl && (element == object.element);
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) =>
|
| - this == object;
|
| -
|
| - @override
|
| - int internalHashCode(List<DartType> visitedTypes) => hashCode;
|
| -
|
| - @override
|
| - bool isMoreSpecificThan(DartType s, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) {
|
| + bool isMoreSpecificThan(DartType s,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) {
|
| //
|
| // A type T is more specific than a type S, written T << S,
|
| // if one of the following conditions is met:
|
| @@ -9998,21 +9975,22 @@ class TypeParameterTypeImpl extends TypeImpl implements TypeParameterType {
|
| }
|
| visitedElements.add(element);
|
| try {
|
| - return bound.isMoreSpecificThan(
|
| - s, thisExpansions, typeExpansions, withDynamic, visitedElements);
|
| + return bound.isMoreSpecificThan(s, withDynamic, visitedElements);
|
| } finally {
|
| visitedElements.remove(element);
|
| }
|
| }
|
|
|
| @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) =>
|
| - isMoreSpecificThan(type, thisExpansions, typeExpansions, true);
|
| + bool isSubtypeOf(DartType type) => isMoreSpecificThan(type, true);
|
| +
|
| + @override
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
|
|
|
| @override
|
| DartType substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) {
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) {
|
| int length = parameterTypes.length;
|
| for (int i = 0; i < length; i++) {
|
| if (parameterTypes[i] == this) {
|
| @@ -10085,16 +10063,8 @@ class UndefinedTypeImpl extends TypeImpl {
|
| bool operator ==(Object object) => identical(object, this);
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) =>
|
| - identical(object, this);
|
| -
|
| - @override
|
| - int internalHashCode(List<DartType> visitedTypes) => hashCode;
|
| -
|
| - @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) {
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) {
|
| // T is S
|
| if (identical(this, type)) {
|
| return true;
|
| @@ -10104,15 +10074,18 @@ class UndefinedTypeImpl extends TypeImpl {
|
| }
|
|
|
| @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) => true;
|
| + bool isSubtypeOf(DartType type) => true;
|
|
|
| @override
|
| bool isSupertypeOf(DartType type) => true;
|
|
|
| @override
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
|
| +
|
| + @override
|
| DartType substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) {
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) {
|
| int length = parameterTypes.length;
|
| for (int i = 0; i < length; i++) {
|
| if (parameterTypes[i] == this) {
|
| @@ -10420,20 +10393,12 @@ class VoidTypeImpl extends TypeImpl implements VoidType {
|
| bool operator ==(Object object) => identical(object, this);
|
|
|
| @override
|
| - bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) =>
|
| - identical(object, this);
|
| -
|
| - @override
|
| - int internalHashCode(List<DartType> visitedTypes) => hashCode;
|
| + bool isMoreSpecificThan(DartType type,
|
| + [bool withDynamic = false, Set<Element> visitedElements]) =>
|
| + isSubtypeOf(type);
|
|
|
| @override
|
| - bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
|
| - Set<Element> typeExpansions, bool withDynamic = false,
|
| - Set<Element> visitedElements]) => isSubtypeOf(type);
|
| -
|
| - @override
|
| - bool isSubtypeOf(DartType type,
|
| - [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
|
| + bool isSubtypeOf(DartType type) {
|
| // The only subtype relations that pertain to void are therefore:
|
| // void <: void (by reflexivity)
|
| // bottom <: void (as bottom is a subtype of all types).
|
| @@ -10442,8 +10407,12 @@ class VoidTypeImpl extends TypeImpl implements VoidType {
|
| }
|
|
|
| @override
|
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
|
| +
|
| + @override
|
| VoidTypeImpl substitute2(
|
| - List<DartType> argumentTypes, List<DartType> parameterTypes) => this;
|
| + List<DartType> argumentTypes, List<DartType> parameterTypes,
|
| + [List<FunctionTypeAliasElement> prune]) => this;
|
| }
|
|
|
| /**
|
|
|