Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions mypy/semanal_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from __future__ import annotations

from collections import Counter
from collections.abc import Callable, Iterator
from contextlib import nullcontext
from itertools import groupby
Expand Down Expand Up @@ -222,10 +223,9 @@ def order_by_subclassing(targets: list[FullTargetInfo]) -> Iterator[FullTargetIn
that are already almost correctly ordered.
"""

# First, group the targets by their TypeInfo (since targets are sorted by line,
# we know that each TypeInfo will appear as group key only once).
# A nested class can split its enclosing class's methods into multiple groups.
grouped = [(k, list(g)) for k, g in groupby(targets, key=lambda x: x[3])]
remaining_infos = {info for info, _ in grouped if info is not None}
remaining_infos = Counter(info for info, _ in grouped if info is not None)

next_group = 0
while grouped:
Expand All @@ -245,7 +245,9 @@ def order_by_subclassing(targets: list[FullTargetInfo]) -> Iterator[FullTargetIn
continue
yield from group
grouped.pop(next_group)
remaining_infos.discard(next_info)
remaining_infos[next_info] -= 1
if not remaining_infos[next_info]:
del remaining_infos[next_info]
# Each time after processing a method group we should retry from start,
# since there may be some groups that are not blocked on parents anymore.
next_group = 0
Expand Down
12 changes: 12 additions & 0 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -7322,6 +7322,18 @@ class E(C):

[targets __main__, __main__, __main__.C.__init__, __main__.D.g, __main__.D.f, __main__.E.g, __main__.E.f]

[case testAttributeDefOrderNestedClass]
class E(D):
def e(self) -> None:
self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")

class D:
def d(self) -> None: pass
class N:
def n(self) -> None: pass
def d2(self) -> None:
self.x = 0

[case testNewReturnType1]
class A:
def __new__(cls) -> B:
Expand Down
Loading