Skip to content

Commit ee1d2b6

Browse files
committed
improve MROs for classes that inherit from generic protocols
1 parent cd4afac commit ee1d2b6

File tree

4 files changed

+27
-19
lines changed

4 files changed

+27
-19
lines changed

crates/red_knot_python_semantic/resources/mdtest/annotations/stdlib_typing_aliases.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,24 @@ import typing
6767

6868
####################
6969
### Built-ins
70+
####################
7071

7172
class ListSubclass(typing.List): ...
7273

73-
# revealed: tuple[Literal[ListSubclass], Literal[list], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), Literal[object]]
74+
# TODO: generic protocols
75+
# revealed: tuple[Literal[ListSubclass], Literal[list], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), @Todo(`Generic[]` subscript), Literal[object]]
7476
reveal_type(ListSubclass.__mro__)
7577

7678
class DictSubclass(typing.Dict): ...
7779

78-
# TODO
80+
# TODO: generic protocols
7981
# revealed: tuple[Literal[DictSubclass], Literal[dict], Literal[MutableMapping], Literal[Mapping], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), @Todo(`Generic[]` subscript), Literal[object]]
8082
reveal_type(DictSubclass.__mro__)
8183

8284
class SetSubclass(typing.Set): ...
8385

84-
# revealed: tuple[Literal[SetSubclass], Literal[set], Literal[MutableSet], Literal[AbstractSet], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), Literal[object]]
86+
# TODO: generic protocols
87+
# revealed: tuple[Literal[SetSubclass], Literal[set], Literal[MutableSet], Literal[AbstractSet], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), @Todo(`Generic[]` subscript), Literal[object]]
8588
reveal_type(SetSubclass.__mro__)
8689

8790
class FrozenSetSubclass(typing.FrozenSet): ...
@@ -92,10 +95,11 @@ reveal_type(FrozenSetSubclass.__mro__)
9295

9396
####################
9497
### `collections`
98+
####################
9599

96100
class ChainMapSubclass(typing.ChainMap): ...
97101

98-
# TODO
102+
# TODO: generic protocols
99103
# revealed: tuple[Literal[ChainMapSubclass], Literal[ChainMap], Literal[MutableMapping], Literal[Mapping], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), @Todo(`Generic[]` subscript), Literal[object]]
100104
reveal_type(ChainMapSubclass.__mro__)
101105

@@ -113,7 +117,8 @@ reveal_type(DefaultDictSubclass.__mro__)
113117

114118
class DequeSubclass(typing.Deque): ...
115119

116-
# revealed: tuple[Literal[DequeSubclass], Literal[deque], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), Literal[object]]
120+
# TODO: generic protocols
121+
# revealed: tuple[Literal[DequeSubclass], Literal[deque], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), @Todo(`Generic[]` subscript), Literal[object]]
117122
reveal_type(DequeSubclass.__mro__)
118123

119124
class OrderedDictSubclass(typing.OrderedDict): ...

crates/red_knot_python_semantic/resources/mdtest/subscript/tuple.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ from typing import Tuple
117117

118118
class C(Tuple): ...
119119

120-
# revealed: tuple[Literal[C], Literal[tuple], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), Literal[object]]
120+
# TODO: generic protocols
121+
# revealed: tuple[Literal[C], Literal[tuple], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), @Todo(`Generic[]` subscript), Literal[object]]
121122
reveal_type(C.__mro__)
122123
```

crates/red_knot_python_semantic/src/types/class_base.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,20 @@ impl<'db> ClassBase<'db> {
178178
/// Iterate over the MRO of this base
179179
pub(super) fn mro(self, db: &'db dyn Db) -> impl Iterator<Item = ClassBase<'db>> {
180180
match self {
181-
ClassBase::Dynamic(_) | ClassBase::Generic => {
182-
Either::Left(Either::Left([self, ClassBase::object(db)].into_iter()))
183-
}
184-
ClassBase::Protocol => Either::Left(Either::Right(
181+
ClassBase::Protocol => Either::Left(Either::Left(
185182
[self, ClassBase::Generic, ClassBase::object(db)].into_iter(),
186183
)),
184+
ClassBase::Dynamic(DynamicType::SubscriptedProtocol) => Either::Left(Either::Left(
185+
[
186+
self,
187+
ClassBase::Dynamic(DynamicType::SubscriptedGeneric),
188+
ClassBase::object(db),
189+
]
190+
.into_iter(),
191+
)),
192+
ClassBase::Dynamic(_) | ClassBase::Generic => {
193+
Either::Left(Either::Right([self, ClassBase::object(db)].into_iter()))
194+
}
187195
ClassBase::Class(class) => Either::Right(class.iter_mro(db)),
188196
}
189197
}

crates/red_knot_python_semantic/src/types/infer.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6358,15 +6358,9 @@ impl<'db> TypeInferenceBuilder<'db> {
63586358

63596359
// TODO: properly handle old-style generics; get rid of this temporary hack
63606360
if !value_ty.into_class_literal().is_some_and(|class| {
6361-
class.iter_mro(self.db(), None).any(|base| {
6362-
matches!(
6363-
base,
6364-
ClassBase::Dynamic(
6365-
DynamicType::SubscriptedGeneric
6366-
| DynamicType::SubscriptedProtocol,
6367-
)
6368-
)
6369-
})
6361+
class
6362+
.iter_mro(self.db(), None)
6363+
.any(|base| base == ClassBase::Dynamic(DynamicType::SubscriptedGeneric))
63706364
}) {
63716365
report_non_subscriptable(
63726366
&self.context,

0 commit comments

Comments
 (0)