isSubtypeOf method
Checks if this type is a subtype of other.
Implementation
@override
bool isSubtypeOf(RuntimeType other, {Object? value}) {
// Any concrete type is a subtype of a type parameter (T)
if (other is TypeParameter) return true;
if (other is BridgedClass) {
if (isSubtypeOfFunc != null) {
return isSubtypeOfFunc!.call(other, value: value);
}
if (name == 'num') {
// DFUB7: `num` is a subtype of `num` (and, below, of `Object`), but NOT
// of its own subtypes `int`/`double`. The downward direction
// (int/double <: num) is handled separately further down. Returning
// true for int/double here made num a subtype of its subtypes.
final isSubtype = switch (other.name) {
'num' => true,
_ => false,
};
return isSubtype;
}
if (nativeType == other.nativeType) return true;
// Common Dart type hierarchy relationships
// Object is a supertype of everything
if (other.name == 'Object') return true;
// List, Set implement Iterable
if (other.name == 'Iterable' && (name == 'List' || name == 'Set')) {
return true;
}
// int, double are subtypes of num
if (other.name == 'num' && (name == 'int' || name == 'double')) {
return true;
}
// GEN-075: Check native type hierarchy via isAssignable
// When the value's native object satisfies the target class's isAssignable,
// the native type IS a subtype (e.g., Row is a subtype of Widget).
if (value != null && other.isAssignable != null) {
final nativeValue = value is BridgedInstance
? value.nativeObject
: value;
if (other.isAssignable!(nativeValue)) return true;
}
// RC-7b: Check static supertype registry for native class hierarchy.
// This handles cases like StatelessWidget→Widget where BridgedClass
// objects don't have parent references.
//
// SCC19: consult the FULL closure. This used to check the direct
// supertypes and one further hop and then stop — the comment here said
// "walk the registry chain", but it walked exactly one extra link — so a
// chain three levels deep answered false, while the member walk, reading
// the same registry through [transitiveSupertypeNames], went all the way
// down. A bridge could therefore resolve its inherited members correctly
// and deny being a subtype of its own root, and every hierarchy block in
// the stdlib was written with its closure flattened by hand to work
// around it.
//
// The direct hit is kept as a short circuit: it answers most queries
// without allocating the walk at all.
final supertypes = _supertypeRegistry[name];
if (supertypes == null) return false;
if (supertypes.contains(other.name)) return true;
return transitiveSupertypeNames(name).contains(other.name);
}
return false;
}