Skip to content

Commit

Permalink
Fix crash overriding partial-type attribute with method (#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 #11686
Fixes #11981
  • Loading branch information
jakelishman committed Jul 8, 2022
1 parent 49b4b3d commit 9f99400
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
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
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 9f99400

Please sign in to comment.