Skip to content

Commit 9f99400

Browse files
authored
Fix crash overriding partial-type attribute with method (#12943)
Attributes can still be partially typed (e.g. `<partial list[?]>`) after a parent-class definition if the block they are declared in is deferred. The first pass for child classes might then encounter this type when considering method overrides, which could cause a crash when attempting to determine subtype compatibility. Fixes #11686 Fixes #11981
1 parent 49b4b3d commit 9f99400

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

mypy/checker.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1579,7 +1579,9 @@ def check_method_override_for_base_with_name(
15791579
# it can be checked for compatibility.
15801580
original_type = get_proper_type(base_attr.type)
15811581
original_node = base_attr.node
1582-
if original_type is None:
1582+
# `original_type` can be partial if (e.g.) it is originally an
1583+
# instance variable from an `__init__` block that becomes deferred.
1584+
if original_type is None or isinstance(original_type, PartialType):
15831585
if self.pass_num < self.last_pass:
15841586
# If there are passes left, defer this node until next pass,
15851587
# otherwise try reconstructing the method type from available information.

test-data/unit/check-classes.test

+18
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,24 @@ class Derived(Base):
151151
__hash__ = 1 # E: Incompatible types in assignment (expression has type "int", base class "Base" defined the type as "Callable[[Base], int]")
152152

153153

154+
[case testOverridePartialAttributeWithMethod]
155+
# This was crashing: https://github.com/python/mypy/issues/11686.
156+
class Base:
157+
def __init__(self, arg: int):
158+
self.partial_type = [] # E: Need type annotation for "partial_type" (hint: "partial_type: List[<type>] = ...")
159+
self.force_deferral = []
160+
161+
# Force inference of the `force_deferral` attribute in `__init__` to be
162+
# deferred to a later pass by providing a definition in another context,
163+
# which means `partial_type` remains only partially inferred.
164+
force_deferral = [] # E: Need type annotation for "force_deferral" (hint: "force_deferral: List[<type>] = ...")
165+
166+
167+
class Derived(Base):
168+
def partial_type(self) -> int: # E: Signature of "partial_type" incompatible with supertype "Base"
169+
...
170+
171+
154172
-- Attributes
155173
-- ----------
156174

0 commit comments

Comments
 (0)