mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-31 15:47:41 +00:00
[ty] Pass down specialization to generic dataclass bases (#19472)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary closes https://github.com/astral-sh/ty/issues/853 ## Test Plan Regression test
This commit is contained in:
parent
88de5727df
commit
fcdffe4ac9
2 changed files with 47 additions and 6 deletions
|
@ -640,6 +640,8 @@ reveal_type(C.__init__) # revealed: (self: C, normal: int, conditionally_presen
|
||||||
python-version = "3.12"
|
python-version = "3.12"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@ -658,6 +660,34 @@ reveal_type(d_int.description) # revealed: str
|
||||||
DataWithDescription[int](None, "description")
|
DataWithDescription[int](None, "description")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Deriving from generic dataclasses
|
||||||
|
|
||||||
|
This is a regression test for <https://github.com/astral-sh/ty/issues/853>.
|
||||||
|
|
||||||
|
```py
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Wrap[T]:
|
||||||
|
data: T
|
||||||
|
|
||||||
|
reveal_type(Wrap[int].__init__) # revealed: (self: Wrap[int], data: int) -> None
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WrappedInt(Wrap[int]):
|
||||||
|
other_field: str
|
||||||
|
|
||||||
|
reveal_type(WrappedInt.__init__) # revealed: (self: WrappedInt, data: int, other_field: str) -> None
|
||||||
|
|
||||||
|
# Make sure that another generic type parameter does not affect the `data` field
|
||||||
|
@dataclass
|
||||||
|
class WrappedIntAndExtraData[T](Wrap[int]):
|
||||||
|
extra_data: T
|
||||||
|
|
||||||
|
# revealed: (self: WrappedIntAndExtraData[bytes], data: int, extra_data: bytes) -> None
|
||||||
|
reveal_type(WrappedIntAndExtraData[bytes].__init__)
|
||||||
|
```
|
||||||
|
|
||||||
## Descriptor-typed fields
|
## Descriptor-typed fields
|
||||||
|
|
||||||
### Same type in `__get__` and `__set__`
|
### Same type in `__get__` and `__set__`
|
||||||
|
|
|
@ -1668,16 +1668,16 @@ impl<'db> ClassLiteral<'db> {
|
||||||
if field_policy == CodeGeneratorKind::NamedTuple {
|
if field_policy == CodeGeneratorKind::NamedTuple {
|
||||||
// NamedTuples do not allow multiple inheritance, so it is sufficient to enumerate the
|
// NamedTuples do not allow multiple inheritance, so it is sufficient to enumerate the
|
||||||
// fields of this class only.
|
// fields of this class only.
|
||||||
return self.own_fields(db);
|
return self.own_fields(db, specialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
let matching_classes_in_mro: Vec<_> = self
|
let matching_classes_in_mro: Vec<_> = self
|
||||||
.iter_mro(db, specialization)
|
.iter_mro(db, specialization)
|
||||||
.filter_map(|superclass| {
|
.filter_map(|superclass| {
|
||||||
if let Some(class) = superclass.into_class() {
|
if let Some(class) = superclass.into_class() {
|
||||||
let class_literal = class.class_literal(db).0;
|
let (class_literal, specialization) = class.class_literal(db);
|
||||||
if field_policy.matches(db, class_literal) {
|
if field_policy.matches(db, class_literal) {
|
||||||
Some(class_literal)
|
Some((class_literal, specialization))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1691,7 +1691,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
matching_classes_in_mro
|
matching_classes_in_mro
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.rev()
|
.rev()
|
||||||
.flat_map(|class| class.own_fields(db))
|
.flat_map(|(class, specialization)| class.own_fields(db, specialization))
|
||||||
// We collect into a FxOrderMap here to deduplicate attributes
|
// We collect into a FxOrderMap here to deduplicate attributes
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -1707,7 +1707,11 @@ impl<'db> ClassLiteral<'db> {
|
||||||
/// y: str = "a"
|
/// y: str = "a"
|
||||||
/// ```
|
/// ```
|
||||||
/// we return a map `{"x": (int, None), "y": (str, Some(Literal["a"]))}`.
|
/// we return a map `{"x": (int, None), "y": (str, Some(Literal["a"]))}`.
|
||||||
fn own_fields(self, db: &'db dyn Db) -> FxOrderMap<Name, (Type<'db>, Option<Type<'db>>)> {
|
fn own_fields(
|
||||||
|
self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
specialization: Option<Specialization<'db>>,
|
||||||
|
) -> FxOrderMap<Name, (Type<'db>, Option<Type<'db>>)> {
|
||||||
let mut attributes = FxOrderMap::default();
|
let mut attributes = FxOrderMap::default();
|
||||||
|
|
||||||
let class_body_scope = self.body_scope(db);
|
let class_body_scope = self.body_scope(db);
|
||||||
|
@ -1747,7 +1751,14 @@ impl<'db> ClassLiteral<'db> {
|
||||||
let bindings = use_def.end_of_scope_bindings(place_id);
|
let bindings = use_def.end_of_scope_bindings(place_id);
|
||||||
let default_ty = place_from_bindings(db, bindings).ignore_possibly_unbound();
|
let default_ty = place_from_bindings(db, bindings).ignore_possibly_unbound();
|
||||||
|
|
||||||
attributes.insert(place_expr.expect_name().clone(), (attr_ty, default_ty));
|
attributes.insert(
|
||||||
|
place_expr.expect_name().clone(),
|
||||||
|
(
|
||||||
|
attr_ty.apply_optional_specialization(db, specialization),
|
||||||
|
default_ty
|
||||||
|
.map(|ty| ty.apply_optional_specialization(db, specialization)),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue