mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 03:55:09 +00:00 
			
		
		
		
	 db3dcd8ad6
			
		
	
	
		db3dcd8ad6
		
			
		
	
	
	
	
		
			
			## 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