[ty] Callable types are disjoint from non-callable @final nominal instance types (#18368)

## Summary

Resolves [#513](https://github.com/astral-sh/ty/issues/513).

Callable types are now considered to be disjoint from nominal instance
types where:

* The class is `@final`, and
* Its `__call__` either does not exist or is not assignable to `(...) ->
Unknown`.

## Test Plan

Markdown tests.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
InSync 2025-05-30 06:27:27 +07:00 committed by GitHub
parent 695de4f27f
commit 9b0dfc505f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 0 deletions

View file

@ -2177,6 +2177,26 @@ impl<'db> Type<'db> {
true
}
(
Type::Callable(_) | Type::DataclassDecorator(_) | Type::DataclassTransformer(_),
Type::NominalInstance(instance),
)
| (
Type::NominalInstance(instance),
Type::Callable(_) | Type::DataclassDecorator(_) | Type::DataclassTransformer(_),
) if instance.class.is_final(db) => {
let member = self.member_lookup_with_policy(
db,
Name::new_static("__call__"),
MemberLookupPolicy::NO_INSTANCE_FALLBACK,
);
match member.symbol {
// TODO: ideally this would check disjointness of the `__call__` signature and the callable signature
Symbol::Type(ty, _) => !ty.is_assignable_to(db, CallableType::unknown(db)),
Symbol::Unbound => true,
}
}
(
Type::Callable(_) | Type::DataclassDecorator(_) | Type::DataclassTransformer(_),
_,