I'm not a fan of `Tensor[T, ...]` because it has confusing semantics.
Tensors will usually be typed as:
class Tensor(Generic[DType, *Shape]): ...
where `Tensor[np.float64, Literal, Literal]` represents a 10x20 Tensor where each element has datatype `np.float64`. Let's say we want to represent a Tensor that has arbitrary shape.
+ `Tensor[np.float64, ...]` looks like it represents a Tensor of datatype np.float64 and arbitrary shape. But by analogy with the similar `Tuple[float, ...]`, it would have to represent any Tensor where all the *dimensions* are `np.float64`: `Tensor[np.float64, np.float64, np.float64]`, etc. That's not what we would expect for a Tensor.
+ To counter that, we might change the semantics of `Tensor[T, ...]`, to mean datatype T with arbitrary shape (i.e., `Tensor[T, Any, Any, Any]`, etc.), but that will be ambiguous for a class that has multiple unary generics like:
class Transformer(Generic[T_in, T_out, *Shape]): ...
# Is `T_out` int or Any?
x: Transformer[int, ...]
New syntax like Transformer[int, str, ...] seems even more confusing.
+ The only remaining use afaik would be `Tensor[Any, ...]` to represent a Tensor where all parameters are Any. Given that `x: Tensor` already represents this, it doesn't feel worth adding fresh syntax to express the same.
In contrast, `Tensor[np.float64, *Tuple[Any, ...]]` expresses the fact that the datatype is `np.float64` but the shape can be anything. `Transformer[A, B, *Tuple[Any, ...]]` works for the other case. We can also state that the dimension types have to be int: `Tensor[np.float64, *Tuple[int, ...]]` to represent `Tensor[np.float64, int, int, int]`, etc.
I completely agree that the syntax is verbose and frankly not very pretty :) (TypeScript has a nicer `Tensor[float, ...any]` syntax.) That seems fine given that we don't really want to encourage this.
Overall, I see two options:
+ No explicit syntax for unbounded Tensors: We just have `x: Tensor` to support gradual typing as of PEP 646 and we can add unbounded Tensors in follow-up PEPs. Typecheckers would be free to treat `Float32Array = Array[np.float32, *Shape]; x: Float32Array` as `x: Array`, thereby making all parameters `Any`. This seems like the simplest option right now.
+ Explicit syntax where we substitute `Tuple[Any, ...]` for `Ts`: This would complicate an already heavy PEP, but would allow us to precisely express the fact that the shape can be anything.