mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
[red-knot] fix detecting a metaclass on a not-explicitly-specialized generic base (#17621)
## Summary After https://github.com/astral-sh/ruff/pull/17620 (which this PR is based on), I was looking at other call sites of `Type::into_class_type`, and I began to feel that _all_ of them were currently buggy due to silently skipping unspecialized generic class literal types (though in some cases the bug hadn't shown up yet because we don't understand legacy generic classes from typeshed), and in every case they would be better off if an unspecialized generic class literal were implicitly specialized with the default specialization (which is the usual Python typing semantics for an unspecialized reference to a generic class), instead of silently skipped. So I changed the method to implicitly apply the default specialization, and added a test that previously failed for detecting metaclasses on an unspecialized generic base. I also renamed the method to `to_class_type`, because I feel we have a strong naming convention where `Type::into_foo` is always a trivial `const fn` that simply returns `Some()` if the type is of variant `Foo` and `None` otherwise. Even the existing method (with it handling both `GenericAlias` and `ClassLiteral`, and distinguishing kinds of `ClassLiteral`) was stretching this convention, and the new version definitely breaks that envelope. ## Test Plan Added a test that failed before this PR.
This commit is contained in:
parent
4c3f389598
commit
fa88989ef0
4 changed files with 35 additions and 14 deletions
|
@ -53,6 +53,25 @@ class B(A): ...
|
|||
reveal_type(B.__class__) # revealed: Literal[M]
|
||||
```
|
||||
|
||||
## Linear inheritance with PEP 695 generic class
|
||||
|
||||
The same is true if the base with the metaclass is a generic class.
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.13"
|
||||
```
|
||||
|
||||
```py
|
||||
class M(type): ...
|
||||
class A[T](metaclass=M): ...
|
||||
class B(A): ...
|
||||
class C(A[int]): ...
|
||||
|
||||
reveal_type(B.__class__) # revealed: Literal[M]
|
||||
reveal_type(C.__class__) # revealed: Literal[M]
|
||||
```
|
||||
|
||||
## Conflict (1)
|
||||
|
||||
The metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue