private boolean isSubtypeOf(InterfaceType type, HashSet<ClassElement> visitedClasses,
Set<TypePair> visitedTypePairs) {
InterfaceType typeT = this;
InterfaceType typeS = type;
ClassElement elementT = getElement();
if (elementT == null || visitedClasses.contains(elementT)) {
return false;
}
visitedClasses.add(elementT);
if (typeT.equals(typeS)) {
return true;
} else if (ObjectUtilities.equals(elementT, typeS.getElement())) {
// For each of the type arguments return true if all type args from T is a subtype of all
// types from S.
Type[] typeTArgs = typeT.getTypeArguments();
Type[] typeSArgs = typeS.getTypeArguments();
if (typeTArgs.length != typeSArgs.length) {
// This case covers the case where two objects are being compared that have a different
// number of parameterized types.
return false;
}
for (int i = 0; i < typeTArgs.length; i++) {
// Recursively call isSubtypeOf the type arguments and return false if the T argument is not
// a subtype of the S argument.
if (!((TypeImpl) typeTArgs[i]).isSubtypeOf(typeSArgs[i], visitedTypePairs)) {
return false;
}
}
return true;
} else if (typeS.isDartCoreFunction() && elementT.getMethod("call") != null) {
return true;
}
InterfaceType supertype = getSuperclass();
// The type is Object, return false.