[ty] Do not carry the generic context of Protocol or Generic in the ClassBase enum (#17989)
## Summary It doesn't seem to be necessary for our generics implementation to carry the `GenericContext` in the `ClassBase` variants. Removing it simplifies the code, fixes many TODOs about `Generic` or `Protocol` appearing multiple times in MROs when each should only appear at most once, and allows us to more accurately detect runtime errors that occur due to `Generic` or `Protocol` appearing multiple times in a class's bases. In order to remove the `GenericContext` from the `ClassBase` variant, it turns out to be necessary to emulate `typing._GenericAlias.__mro_entries__`, or we end up with a large number of false-positive `inconsistent-mro` errors. This PR therefore also does that. Lastly, this PR fixes the inferred MROs of PEP-695 generic classes, which implicitly inherit from `Generic` even if they have no explicit bases. ## Test Plan mdtests
This commit is contained in:
@@ -527,6 +527,45 @@ reveal_type(unknown_object) # revealed: Unknown
|
||||
reveal_type(unknown_object.__mro__) # revealed: Unknown
|
||||
```
|
||||
|
||||
## MROs of classes that use multiple inheritance with generic aliases and subscripted `Generic`
|
||||
|
||||
```py
|
||||
from typing import Generic, TypeVar, Iterator
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class peekable(Generic[T], Iterator[T]): ...
|
||||
|
||||
# revealed: tuple[<class 'peekable[Unknown]'>, <class 'Iterator[T]'>, <class 'Iterable[T]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(peekable.__mro__)
|
||||
|
||||
class peekable2(Iterator[T], Generic[T]): ...
|
||||
|
||||
# revealed: tuple[<class 'peekable2[Unknown]'>, <class 'Iterator[T]'>, <class 'Iterable[T]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(peekable2.__mro__)
|
||||
|
||||
class Base: ...
|
||||
class Intermediate(Base, Generic[T]): ...
|
||||
class Sub(Intermediate[T], Base): ...
|
||||
|
||||
# revealed: tuple[<class 'Sub[Unknown]'>, <class 'Intermediate[T]'>, <class 'Base'>, typing.Generic, <class 'object'>]
|
||||
reveal_type(Sub.__mro__)
|
||||
```
|
||||
|
||||
## Unresolvable MROs involving generics have the original bases reported in the error message, not the resolved bases
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
from typing_extensions import Protocol, TypeVar, Generic
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class Foo(Protocol): ...
|
||||
class Bar(Protocol[T]): ...
|
||||
class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||
```
|
||||
|
||||
## Classes that inherit from themselves
|
||||
|
||||
These are invalid, but we need to be able to handle them gracefully without panicking.
|
||||
|
||||
Reference in New Issue
Block a user