mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:51:30 +00:00
[ty] Fix ClassLiteral.into_callable
for dataclasses (#19192)
## Summary Change `ClassLiteral.into_callable` to also look for `__init__` functions of type `Type::Callable` (such as synthesized `__init__` functions of dataclasses). Fixes https://github.com/astral-sh/ty/issues/760 ## Test Plan Add subtype test --------- Co-authored-by: David Peter <mail@david-peter.de>
This commit is contained in:
parent
68106dd631
commit
f32f7a3b48
2 changed files with 44 additions and 19 deletions
|
@ -1774,6 +1774,25 @@ static_assert(is_subtype_of(type[B], Callable[[str], B]))
|
|||
static_assert(not is_subtype_of(type[B], Callable[[int], B]))
|
||||
```
|
||||
|
||||
### Dataclasses
|
||||
|
||||
Dataclasses synthesize a `__init__` method.
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
from ty_extensions import TypeOf, static_assert, is_subtype_of
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class A:
|
||||
x: "A" | None
|
||||
|
||||
static_assert(is_subtype_of(type[A], Callable[[A], A]))
|
||||
static_assert(is_subtype_of(type[A], Callable[[None], A]))
|
||||
static_assert(is_subtype_of(type[A], Callable[[A | None], A]))
|
||||
static_assert(not is_subtype_of(type[A], Callable[[int], A]))
|
||||
```
|
||||
|
||||
### Bound methods
|
||||
|
||||
```py
|
||||
|
|
|
@ -661,27 +661,33 @@ impl<'db> ClassType<'db> {
|
|||
// same parameters as the `__init__` method after it is bound, and with the return type of
|
||||
// the concrete type of `Self`.
|
||||
let synthesized_dunder_init_callable =
|
||||
if let Place::Type(Type::FunctionLiteral(dunder_init_function), _) =
|
||||
dunder_init_function_symbol
|
||||
{
|
||||
let synthesized_signature = |signature: Signature<'db>| {
|
||||
Signature::new(signature.parameters().clone(), Some(correct_return_type))
|
||||
.bind_self()
|
||||
if let Place::Type(ty, _) = dunder_init_function_symbol {
|
||||
let signature = match ty {
|
||||
Type::FunctionLiteral(dunder_init_function) => {
|
||||
Some(dunder_init_function.signature(db))
|
||||
}
|
||||
Type::Callable(callable) => Some(callable.signatures(db)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let synthesized_dunder_init_signature = CallableSignature::from_overloads(
|
||||
dunder_init_function
|
||||
.signature(db)
|
||||
.overloads
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(synthesized_signature),
|
||||
);
|
||||
Some(Type::Callable(CallableType::new(
|
||||
db,
|
||||
synthesized_dunder_init_signature,
|
||||
true,
|
||||
)))
|
||||
if let Some(signature) = signature {
|
||||
let synthesized_signature = |signature: &Signature<'db>| {
|
||||
Signature::new(signature.parameters().clone(), Some(correct_return_type))
|
||||
.bind_self()
|
||||
};
|
||||
|
||||
let synthesized_dunder_init_signature = CallableSignature::from_overloads(
|
||||
signature.overloads.iter().map(synthesized_signature),
|
||||
);
|
||||
|
||||
Some(Type::Callable(CallableType::new(
|
||||
db,
|
||||
synthesized_dunder_init_signature,
|
||||
true,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue