Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(935)

Unified Diff: pkg/analyzer/lib/src/generated/element.dart

Issue 1143003007: Fix handling of nested typedefs (for real this time). (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/testing/element_factory.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
}
/**
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/testing/element_factory.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698