[red-knot] is_subtype_of fix for KnownInstance types (#14750)

## Summary

`KnownInstance::instance_fallback` may return instances of supertypes.
For example, it returns an instance of `_SpecialForm` for `Literal`.
This means it can't be used on the right-hand side of `is_subtype_of`
relationships, because it might lead to false positives.

I can lead to false negatives on the left hand side of `is_subtype_of`,
but this is at least a known limitation. False negatives are fine for
most applications, but false positives can lead to wrong results in
intersection-simplification, for example.

closes #14731

## Test Plan

Added regression test
This commit is contained in:
David Peter 2024-12-03 12:03:26 +01:00 committed by GitHub
parent 70bd10614f
commit a255d79087
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -722,9 +722,6 @@ impl<'db> Type<'db> {
(Type::KnownInstance(left), right) => {
left.instance_fallback(db).is_subtype_of(db, right)
}
(left, Type::KnownInstance(right)) => {
left.is_subtype_of(db, right.instance_fallback(db))
}
(Type::Instance(left), Type::Instance(right)) => left.is_instance_of(db, right.class),
// TODO
_ => false,
@ -3270,6 +3267,7 @@ pub(crate) mod tests {
#[test_case(Ty::IntLiteral(1), Ty::Intersection{pos: vec![Ty::BuiltinInstance("int")], neg: vec![Ty::IntLiteral(1)]})]
#[test_case(Ty::BuiltinClassLiteral("int"), Ty::BuiltinClassLiteral("object"))]
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinClassLiteral("int"))]
#[test_case(Ty::TypingInstance("_SpecialForm"), Ty::TypingLiteral)]
fn is_not_subtype_of(from: Ty, to: Ty) {
let db = setup_db();
assert!(!from.into_type(&db).is_subtype_of(&db, to.into_type(&db)));