mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-07 09:00:31 +00:00

## Summary Simplifies literal `True` and `False` conditions to `ALWAYS_TRUE` / `ALWAYS_FALSE` during semantic index building. This allows us to eagerly evaluate more constraints, which should help with performance (looks like there is a tiny 1% improvement in instrumented benchmarks), but also allows us to eliminate definitely-unreachable branches in control-flow merging. This can lead to better type inference in some cases because it allows us to retain narrowing constraints without solving https://github.com/astral-sh/ty/issues/690 first: ```py def _(c: int | None): if c is None: assert False reveal_type(c) # int, previously: int | None ``` closes https://github.com/astral-sh/ty/issues/713 ## Test Plan * Regression test for https://github.com/astral-sh/ty/issues/713 * Made sure that all ecosystem diffs trace back to removed false positives
1.4 KiB
1.4 KiB
Narrowing in while
loops
We only make sure that narrowing works for while
loops in general, we do not exhaustively test all
narrowing forms here, as they are covered in other tests.
Note how type narrowing works subtly different from if
... else
, because the negated constraint
is retained after the loop.
Basic while
loop
def next_item() -> int | None:
return 1
x = next_item()
while x is not None:
reveal_type(x) # revealed: int
x = next_item()
reveal_type(x) # revealed: None
while
loop with else
def next_item() -> int | None:
return 1
x = next_item()
while x is not None:
reveal_type(x) # revealed: int
x = next_item()
else:
reveal_type(x) # revealed: None
reveal_type(x) # revealed: None
Nested while
loops
from typing import Literal
def next_item() -> Literal[1, 2, 3]:
raise NotImplementedError
x = next_item()
while x != 1:
reveal_type(x) # revealed: Literal[2, 3]
while x != 2:
# TODO: this should be Literal[1, 3]; Literal[3] is only correct
# in the first loop iteration
reveal_type(x) # revealed: Literal[3]
x = next_item()
x = next_item()
With break
statements
def next_item() -> int | None:
return 1
while True:
x = next_item()
if x is not None:
break
reveal_type(x) # revealed: int