Skip to content

Type-narrowing in a union sometimes fails #19265

Description

@bzoracler

Possibly related: #10680

Bug Report, To Reproduce, & Actual Behaviour

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

fromtypingimportProtocol
type StaticCallback[**P, R] =Callback[P, R] |staticmethod[P, R]
classCallback[**P, R](Protocol):
def__call__(self, /, *args: P.args, **kwargs: P.kwargs) ->R: ...
deftry_return_type(val: StaticCallback[[str], str], /) ->type[str]:
ifisinstance(val, type) andissubclass(val, str):
returnval# 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]assertFalse

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