astral-sh/ruff

[red-knot] Infer precise types for `len()` calls

Closed this issue · 0 comments

Sometimes, it is useful to know the precise length of a type:

reveal_type(len((0, 1, 2)))  # revealed: Literal[3]

This might help with narrowing:

a: tuple[Literal[1], int] | tuple[Literal[2], str, str]

if len(a) == 2:
	reveal_type(a[0])  # revealed: Literal[1]

Current behaviour of Mypy and Pyright:

def f(a: tuple[Literal[1], int] | tuple[Literal[2], str, str]) -> None:
    if len(a) == 2:
        reveal_type(a[0])  # mypy    => Literal[1]
                           # pyright => Literal[1]
    
    l1 = len(a)
    reveal_type(l1)        # mypy    => int
                           # pyright => int

    if (l2 := len(a)) == 2:
        reveal_type(l2)    # mypy    => int
                           # pyright => Literal[2]
        reveal_type(a[0])  # mypy    => Literal[1]
                           # pyright => Literal[1, 2]