Skip to content

Incorrect type narrowing for select class hierarchies  #16379

Open
@Redoubts

Description

@Redoubts

Bug Report

I've found that in an exhaustive isinstance if block, mypy still leaves a more general type resolution than it should. In the snippet of code, mypy should be able to understand that there is no attr-defined error.

To Reproduce

from __future__ import annotations


class A:
    pass


class B(A):
    def get_x(self):
        pass


class C(A):
    def get_x(self):
        pass


class D(C):
    pass


class E(C):
    pass


class F(C):
    pass


def x(obj: A):
    value = ""
    if isinstance(obj, B):
        value = obj.__class__.__name__
    elif isinstance(obj, D):
        value = obj.__class__.__name__
    elif isinstance(obj, E):
        value = obj.__class__.__name__
    elif isinstance(obj, F):
        value = obj.__class__.__name__
    else:
        raise RuntimeError("unhandled type")

    reveal_type(obj)
    obj.get_x()

Expected Behavior

x.py:43: note: Revealed type is "B | D | E | F"

Actual Behavior

x.py:43: note: Revealed type is "x.A"
x.py:44: error: "A" has no attribute "get_x"  [attr-defined]

Your Environment

  • Mypy version used: mypy 1.6.1 (compiled: yes)
  • Mypy command-line flags: default
  • Mypy configuration options from mypy.ini (and other config files): default
  • Python version used: 3.10.13

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions