Skip to content

Incorrect type narrowing for select class hierarchies  #16379

Closed

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

Activity

  1. added and removed
    bugmypy got something wrong
    on Oct 31, 2023
  2. erictraut commented on Oct 31, 2023

    @erictraut

    This is because mypy uses a join operator rather than unions when combining types from different code paths. join(B, D, E, F) is A. If it used unions instead, the resulting type of obj would be B | D | E | F, and no type error would result.

  3. hauntsaninja commented on Dec 30, 2025

    @hauntsaninja
    Collaborator

    Fixed in #18538

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions