Skip to content

Commit

Permalink
Fix crash overriding partial-type attribute with method (python#12943)
Browse files Browse the repository at this point in the history
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 python#11686
Fixes python#11981
  • Loading branch information
jakelishman authored and Gobot1234 committed Aug 12, 2022
1 parent 63e95f3 commit 81d082c
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 1 deletion.
4 changes: 3 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1579,7 +1579,9 @@ def check_method_override_for_base_with_name(
# it can be checked for compatibility.
original_type = get_proper_type(base_attr.type)
original_node = base_attr.node
if original_type is None:
# `original_type` can be partial if (e.g.) it is originally an
# instance variable from an `__init__` block that becomes deferred.
if original_type is None or isinstance(original_type, PartialType):
if self.pass_num < self.last_pass:
# If there are passes left, defer this node until next pass,
# otherwise try reconstructing the method type from available information.
Expand Down
18 changes: 18 additions & 0 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,24 @@ class Derived(Base):
__hash__ = 1 # E: Incompatible types in assignment (expression has type "int", base class "Base" defined the type as "Callable[[Base], int]")


[case testOverridePartialAttributeWithMethod]
# This was crashing: https://github.com/python/mypy/issues/11686.
class Base:
def __init__(self, arg: int):
self.partial_type = [] # E: Need type annotation for "partial_type" (hint: "partial_type: List[<type>] = ...")
self.force_deferral = []

# Force inference of the `force_deferral` attribute in `__init__` to be
# deferred to a later pass by providing a definition in another context,
# which means `partial_type` remains only partially inferred.
force_deferral = [] # E: Need type annotation for "force_deferral" (hint: "force_deferral: List[<type>] = ...")


class Derived(Base):
def partial_type(self) -> int: # E: Signature of "partial_type" incompatible with supertype "Base"
...


-- Attributes
-- ----------

Expand Down

0 comments on commit 81d082c

Please sign in to comment.