Skip to content

Conversation

@sharkdp
Copy link
Contributor

@sharkdp sharkdp commented Oct 29, 2025

Summary

Adds proper type narrowing and reachability analysis for matching on non-inferable type variables bound to enums. For example:

from enum import Enum

class Answer(Enum):
    NO = 0
    YES = 1

    def is_yes(self) -> bool:  # no error here!
        match self:
            case Answer.YES:
                return True
            case Answer.NO:
                return False

closes astral-sh/ty#1404

Test Plan

Added regression tests

@sharkdp sharkdp added ty Multi-file analysis & type inference ecosystem-analyzer labels Oct 29, 2025
@sharkdp sharkdp force-pushed the david/narrowing-for-enum-methods branch from 4d39b75 to 2946e79 Compare October 29, 2025 20:30
@github-actions
Copy link
Contributor

github-actions bot commented Oct 29, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@github-actions
Copy link
Contributor

github-actions bot commented Oct 29, 2025

mypy_primer results

Changes were detected when running on open source projects
mitmproxy (https://github.com/mitmproxy/mitmproxy)
- mitmproxy/proxy/layers/http/_events.py:127:17: error[type-assertion-failure] Argument does not have asserted type `Never`
- Found 1890 diagnostics
+ Found 1889 diagnostics

jax (https://github.com/google/jax)
- jax/_src/pallas/mosaic_gpu/core.py:1527:24: error[invalid-return-type] Function can implicitly return `None`, which is not assignable to return type `TMEMLayout`
- Found 2545 diagnostics
+ Found 2544 diagnostics
No memory usage changes detected ✅

@sharkdp sharkdp force-pushed the david/narrowing-for-enum-methods branch from 2946e79 to 6a9bc2e Compare October 30, 2025 13:15
@sharkdp sharkdp marked this pull request as ready for review October 30, 2025 13:19
@github-actions
Copy link
Contributor

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-return-type 0 1 0
type-assertion-failure 0 1 0
Total 0 2 0

Full report with detailed diff (timing results)

@sharkdp sharkdp force-pushed the david/narrowing-for-enum-methods branch from 6a9bc2e to 236427f Compare October 30, 2025 13:36
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

This fixes the issue for methods on enums, but there appear to be lots of other cases where you can have a TypeVar bound to a union (or type equivalent to a union) where we also exhibit similar issues with reachability and narrowing. These are all on this branch:

from typing import assert_never, Literal

def f[T: bool](x: T) -> T:
    match x:
        case True:
            return x
        case False:
            return x
        case _:
            reveal_type(x) # T@f & ~Literal[True] & ~Literal[False]
            assert_never(x)  # false-positive error

def g[T: Literal["foo", "bar"]](x: T) -> T:
    match x:
        case "foo":
            return x
        case "bar":
            return x
        case _:
            reveal_type(x)  # T@g & ~Literal["foo"] & ~Literal["bar"]
            assert_never(x)  # false-positive error

def h[T: int | str](x: T) -> T:
    if isinstance(x, int):
        return x
    elif isinstance(x, str):
        return x
    else:
        reveal_type(x)  # T@h & ~int & ~str
        assert_never(x)  # false-positive error

@sharkdp sharkdp force-pushed the david/narrowing-for-enum-methods branch from 236427f to 53b79d8 Compare October 30, 2025 14:16
@sharkdp sharkdp merged commit e55bc94 into main Oct 30, 2025
41 checks passed
@sharkdp sharkdp deleted the david/narrowing-for-enum-methods branch October 30, 2025 14:38
dcreager added a commit that referenced this pull request Oct 30, 2025
* origin/main: (21 commits)
  [ty] Update "constraint implication" relation to work on constraints between two typevars (#21068)
  [`flake8-type-checking`] Fix `TC003` false positive with `future-annotations` (#21125)
  [ty] Fix lookup of `__new__` on instances (#21147)
  Fix syntax error false positive on nested alternative patterns (#21104)
  [`pyupgrade`] Fix false positive for `TypeVar` with default on Python <3.13 (`UP046`,`UP047`) (#21045)
  [ty] Reachability and narrowing for enum methods (#21130)
  [ty] Use `range` instead of custom `IntIterable` (#21138)
  [`ruff`] Add support for additional eager conversion patterns (`RUF065`) (#20657)
  [`ruff-ecosystem`] Fix CLI crash on Python 3.14 (#21092)
  [ty] Infer type of `self` for decorated methods and properties (#21123)
  [`flake8-bandit`] Fix correct example for `S308` (#21128)
  [ty] Dont provide goto definition for definitions which are not reexported in builtins (#21127)
  [`airflow`] warning `airflow....DAG.create_dagrun` has been removed (`AIR301`) (#21093)
  [ty] follow the breaking API changes made in salsa-rs/salsa#1015 (#21117)
  [ty] Rename `Type::into_nominal_instance` (#21124)
  [ty] Filter out "unimported" from the current module
  [ty] Add evaluation test for auto-import including symbols in current module
  [ty] Refactor `ty_ide` completion tests
  [ty] Render `import <...>` in completions when "label details" isn't supported
  [`refurb`] Preserve digit separators in `Decimal` constructor (`FURB157`) (#20588)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed exhaustiveness matching on type variable

3 participants