python / python/mypy

Mypy does not narrow class type when a `→ NoReturn` (`→ Never`) member method is called

Open
#14,989 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

feature topic-type-narrowing
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

This is easier to explain with the minimal example:

To Reproduce

Gist: https://mypy-play.net/?mypy=latest&python=3.11&gist=ee98d7589e833e85b60faabacb777c33

from typing import NoReturn, assert_type


class Ok:
    def validate(self) -> None:
        pass


class Error:
    def validate(self) -> NoReturn:
        raise Exception


response: Ok | Error
assert_type(response, Ok | Error)

response.validate()
assert_type(response, Ok)

Expected Behavior

I expect the last assertion to pass: Error.validate() is annotated with NoReturn, so by the last line, response can only be Ok. An Error would already have caused a NoReturn result, and so get ruled out.

Actual Behavior

scratch.py:18: error: Expression is of type "Union[Ok, Error]", not "Ok"  [assert-type]
    assert_type(response, Ok)
    ^

Environment

  • Mypy version used: mypy 1.1.1 (compiled: yes)
  • Mypy command-line flags: none
  • Python version used: 3.11.2
[tool.mypy]
allow_redefinition = true
allow_untyped_globals = true
check_untyped_defs = true
pretty = true

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal Python example in the issue or its linked mypy-play gist, and reproduce the failed final assert_type. Trace how mypy narrows unions after member methods annotated NoReturn or Never. Done means the final assertion is accepted while existing narrowing behavior remains correct; the payload does not name an implementation file or test.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.