Skip to content

spec: expand Never/NoReturn with precise subtyping rules#2309

Open
ashishpatel26 wants to merge 5 commits into
python:mainfrom
ashishpatel26:fix/1458-never-noreturn-spec
Open

spec: expand Never/NoReturn with precise subtyping rules#2309
ashishpatel26 wants to merge 5 commits into
python:mainfrom
ashishpatel26:fix/1458-never-noreturn-spec

Conversation

@ashishpatel26

Copy link
Copy Markdown

Summary

Resolves #1458.

The Never section in the spec was four lines with no subtyping rules. Type checkers (mypy, pyright, pyrefly, zuban) all converge on a consistent set of behaviours, but none were written down, making the spec unexecutable for implementers and leaving the community guessing.

This PR codifies what the implementations already agree on:

  • Never is a subtype of every fully static type (bottom type property)
  • No type other than Never (and Any) is a subtype of Never
  • Never | T is equivalent to T for any T
  • In covariant type parameter positions, Container[Never] is assignable to Container[T] for any T; in invariant positions, the normal invariance rules apply
  • type[Never] is a valid annotation representing an uninhabitable class
  • Clarify that NoReturn may appear in non-return-type positions (the old restriction was removed)

Changes

File Change
docs/spec/special-types.rst Expand Never from 4 lines to a full subtyping specification
conformance/tests/specialtypes_never.py Add 6 new test cases covering union collapse, type[Never], and invariance
conformance/results/*/specialtypes_never.toml Updated results for mypy, pyright, pyrefly, zuban (all Pass); ty marked Partial (misses two of the new error cases)

Conformance results snapshot

Checker Result Notes
mypy Pass All 5 expected errors flagged
pyright Pass All 5 expected errors flagged
pyrefly Pass All 5 expected errors flagged
zuban Pass All 5 expected errors flagged
ty Partial Misses object → Never and list[Never] → list[int] errors

Out of scope

The LSP/mutable-attribute debate from #1458 (whether class B(A): foo: Never should be an error) is left for a separate issue. That requires formalising mutable attribute override rules — a larger change that should not block landing the uncontroversial subtyping rules documented here.

…hon#1458)

The previous spec described Never in four lines without defining any of
its subtyping behaviour. Type checkers converge on a consistent set of
rules, but none were written down. This commit codifies them.

Spec changes (docs/spec/special-types.rst):
- Never is a subtype of every fully static type (bottom type property)
- No type other than Never (and Any) is a subtype of Never
- Never | T collapses to T for any type T
- Never as a type argument: covariant containers accept it,
  invariant containers do not
- type[Never] represents an uninhabitable class object
- Clarify that NoReturn may appear in non-return positions

Conformance test changes (conformance/tests/specialtypes_never.py):
- Add func11: Never | int collapses to int
- Add func12: object is not assignable to Never (E)
- Add func13: raise in Never-returning function is OK
- Add func14: type[Never] is a valid annotation
- Add func15: list[Never] return is valid
- Add func16: list[Never] is not assignable to list[int] (E)

Result TOMLs updated for mypy, pyright, pyrefly, zuban (Pass).
ty marked Partial: does not flag func12 and func16 errors.

Closes python#1458
@srittau srittau added the topic: typing spec For improving the typing spec label Jun 22, 2026

@JelleZijlstra JelleZijlstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this verbiage is necessary. This isn't the kind of issue that can be fixed by adding some text without much understanding.

Comment thread docs/spec/special-types.rst Outdated
Comment thread docs/spec/special-types.rst Outdated
Comment thread docs/spec/special-types.rst Outdated
Comment thread docs/spec/special-types.rst Outdated
Comment thread docs/spec/special-types.rst Outdated
Comment thread docs/spec/special-types.rst
- Use int instead of object as the non-Never witness (object is already
  expected to not be a subtype of most things; int is more illuminating)
- Rephrase to avoid the too-strong 'No type other than Never' claim
  (uninhabitable types like tuple[Never, int] are also subtypes of Never)
- Qualify all 'every type T' as 'every fully static type T' throughout
  (the subtype relation is undefined for gradual types like Any)
- Replace list[Never] with Sequence[Never] in the covariant example
  (list is invariant, so list[Never] is not assignable to list[int];
  Sequence is covariant and correctly demonstrates the bottom-type behaviour)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic: typing spec For improving the typing spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NoReturn and Never are underspecified in the spec

4 participants