python / cpython

The Python programming language
https://www.python.org
Other
63.55k stars 30.45k forks source link

TypeAliasType with should also raise an error if non-default type parameter follows default type parameter #124787

Open Daraan opened 1 month ago

Daraan commented 1 month ago

Bug report

Bug description:

The following statement is invalid:

type X[T_default=int, T] = (T_default, U) 
# SyntaxError: non-default type parameter 'T' follows default type parameter

However, writing it as a TypeAliasType is possible. The following should likely raise an error as well to mimic this behavior:

from typing import TypeAliasType, TypeVar
T = TypeVar('T')
T_default = TypeVar("T_default", default=int)
TypeAliasType("TupleT_default_reversed", tuple[T_default, T], type_params=(T_default, T))
print("OK")

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

sobolevn commented 1 month ago

I would like to work on this, if no one else has already started. We need to check both Python API and our internal _Py_make_typealias C-API. I think that raising TypeError here is appropriate for the invalid input.

JelleZijlstra commented 1 month ago

_Py_make_typealias is only used for creating type aliases from the type statement in the interpreter. Because we already validate ordering in the parser, we don't strictly need to validate again in that case.

sobolevn commented 1 month ago

There's one more problem that I've noticed. This is allowed: TypeAliasType('a', int, type_params=(1, 2))

Was allowed :)

Daraan commented 1 month ago

There's one more problem that I've noticed. This is allowed: TypeAliasType('a', int, type_params=(1, 2))

Was allowed :)

👀

I have the suspicion that everything(?) can be passed as long as it is packed in a tuple. One could argue that this is a job for type-checkers to detect. But, where does one draw the line 😅? I have no opinion here btw.


I found another case that is invalid, a repeated type parameter, see https://peps.python.org/pep-0695/#specification.

type A[T, T] = ... # SyntaxError
type B[T, *T] = ... # SyntaxError
type C[T, **T] = ... # SyntaxError
Daraan commented 1 month ago

A question PEP 696 states

The compiler would enforce [...] that TypeVars with defaults cannot immediately follow TypeVarTuples.

class G[*Ts, T=int]: ...
TypeError: Type parameter with a default follows TypeVarTuple

but

type Foo[*Ts, T=int] = tuple[*Ts] | list[T]

is okay.

Is this an oversight, or an exception?

JelleZijlstra commented 1 month ago

That's a runtime error, not a compile-time error. I think it's fine for the type statement (as well as generic functions) to be a bit more permissive at runtime here.