Skip to content

Type-narrowing in a union sometimes fails #19265

Open
@bzoracler

Description

@bzoracler

Possibly related: #10680

Bug Report, To Reproduce, & Actual Behaviour

The following snippet doesn't type-narrow properly (see mypy Playground):

from typing import Protocol

type StaticCallback[**P, R] = Callback[P, R] | staticmethod[P, R]

class Callback[**P, R](Protocol):
    def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> R: ...

def try_return_type(val: StaticCallback[[str], str], /) -> type[str]:
    if isinstance(val, type) and issubclass(val, str):
        return val  # E: Incompatible return value type (got "<subclass of "__main__.Callback[[builtins.str], builtins.str]" and "builtins.type"> | <subclass of "builtins.staticmethod[[builtins.str], builtins.str]" and "builtins.type">", expected "type[str]")  [return-value]
    assert False

This has something to do with the second member of the StaticCallback union. I've tried with these other random examples of <T> in type StaticCallback[**P, R] = Callback[P, R] | <T>, but the reason for failure still isn't obvious to me:

Narrowing succeeds:

  • <T> = int
  • <T> = None
  • <T> = dict[str, object]
  • <T> = dict[R, R]

Narrowing fails:

  • <T> = staticmethod[P, R] (same as the snippet)
  • <T> = bytes (fails regardless of whether --strict-bytes is on)
  • <T> = list[object]
  • <T> = list[R]

Expected Behavior

No errors

Your Environment

  • Mypy version used: 1.13—1.16
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.9, 3.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-type-narrowingConditional type narrowing / binder

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions