The extra complication as you put it has to either exist in the type system or in user code. Placing it in the type system is the only thing I can see as the correct call until the type system has a way to accurately express this.
This harkens back to the same ideas I brought up in A more useful and less divisive future for typing?. I see no reason that the type system should enforce something more than it actually has the means to express at the cost of ergonomics. The line should be “check what can be expressed, make it ergonomic to defer to the programmer when the type system cannot express something, work on making the type system able to express more things ergonomically”
The problem with asking this as “what should the subtyping rules be”, is the question itself somewhat limits itself to an audience of typing experts and doesn’t actually consider the ergonomics of use for non-typing experts.
And since this is proposing formalizing it to one or the other, this should probably explicitly require feedback from each of the type checkers on their rationale for the current state.
Why should they return less type information than can be correctly expressed? The decision to do so makes this less safe without an actual reason to do so. In the case of treating a tuple as a gradual type, it could be narrowed in multiple ways. tuple[T, ...] for a non-Any T, can become tuple[T] with just a length check against a literal.
That really is just an arbitrary decision of where to place the gradualness and not place it where it actually exists though to say we should have more, but not the builtin types, even when appropriate.
Additionally, the PEP itself actually does indicate tuples should be treated as a Gradual type in multiple ways, if not directly.
This rule also applies to
Tuple, in annotation context it is equivalent toTuple[Any, ...]and, in turn, totuple. As well, a bareCallablein an annotation is equivalent toCallable[..., Any]and, in turn, tocollections.abc.Callable
def foo(*args: str, **kwds: int): ...…
In the body of functionfoo, the type of variableargsis deduced asTuple[str, ...]
and in acknowledging that tuple is a special construct
Type hints may be built-in classes (including those defined in standard library or third-party extension modules), abstract base classes, types available in the
typesmodule, and user-defined classes (including those defined in the standard library or third-party modules).
[…]
In addition to the above, the following special constructs defined below may be used:None,Any,Union,Tuple,Callable
All indications in the PEP itself is that the authors were aware that tuple needed special behavior and (possibly) the underlying theory also suggesting this.