Skip to content

false positive "Tuple index out of range" when indexing tuple[Any, *tuple[Any, ...]] #19858

Closed as not planned

Description

@jorenham
from typing import Any

def f0n(xs: tuple[Any, ...]) -> int:
    return xs[42]  # ✔️ 

def f1n(xs: tuple[int, *tuple[Any, ...]]) -> int:
    return xs[42]  # ❌ 
main.py:7: error: Tuple index out of range  [misc]
main.py:7: note: Variadic tuple can have length 1

https://mypy-play.net/?mypy=latest&python=3.13&gist=9dc847117579110c1406d6b1cf3f2b35

this occurs with 1.17.1, 1.18.1, and master

possibly related to #19109

Activity

  1. ilevkivskyi commented on Sep 16, 2025

    @ilevkivskyi
    Member

    As you can see from the note this is intentional. For historical reasons plain tuple[X, ...] is handled in unsafe manner. But types that can be only expressed with unpack syntax are handled strictly.

  2. ilevkivskyi commented on Sep 16, 2025

    @ilevkivskyi
    Member

    Oh, I guess you want Any to be special-cased, if yes, then we already have an issue for this IIRC.

  3. ilevkivskyi commented on Sep 16, 2025

    @ilevkivskyi
    Member
  4. jorenham commented on Sep 16, 2025

    @jorenham
    ContributorAuthor

    Hm no that's not what I meant. You see, the issue here is that tuple[Any, ...] is the "gradual tuple", which is not only "any-isch" in value, but also in size. That is, tuple[Any, ...] is assignable to every other tuple type and vice-versa. That's why mypy correctly (as can be seen in the example) accepts indexing it for any index.

    A restricted form of the gradual tuple is tuple[int, *tuple[Any, ...]], which has the additional requirement that 1) the type at index 0 is int and 2) that the size must be at least 1 (not 0). Just like before, it should be allowed to arbitrarily index it, since it's gradual in size. So it's length is a a hypothetical gradual positive int of at least 1, i.e. Literal[1] | (PosInt & Any).
    But mypy does not behave that way here. Instead, it reports that indexing it beyond 1 can be type-unsafe. Technically this is true. But by gradual construction, we have indicated that it should be treated as if it has any size.

    The issue you linked is certainly related, but I don't think its the same thing here. This is about the special-cased tuple type itself, not about user-defined variadically-gradual types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions