@@ -1799,6 +1799,24 @@ _Py_make_typevartuple(PyThreadState *Py_UNUSED(ignored), PyObject *v)
1799
1799
return (PyObject * )typevartuple_alloc (v , NULL , NULL );
1800
1800
}
1801
1801
1802
+ static PyObject *
1803
+ get_type_param_default (PyThreadState * ts , PyObject * typeparam ) {
1804
+ // Does not modify refcount of existing objects.
1805
+ if (Py_IS_TYPE (typeparam , ts -> interp -> cached_objects .typevar_type )) {
1806
+ return typevar_default ((typevarobject * )typeparam , NULL );
1807
+ }
1808
+ else if (Py_IS_TYPE (typeparam , ts -> interp -> cached_objects .paramspec_type )) {
1809
+ return paramspec_default ((paramspecobject * )typeparam , NULL );
1810
+ }
1811
+ else if (Py_IS_TYPE (typeparam , ts -> interp -> cached_objects .typevartuple_type )) {
1812
+ return typevartuple_default ((typevartupleobject * )typeparam , NULL );
1813
+ }
1814
+ else {
1815
+ PyErr_Format (PyExc_TypeError , "Expected a type param, got %R" , typeparam );
1816
+ return NULL ;
1817
+ }
1818
+ }
1819
+
1802
1820
static void
1803
1821
typealias_dealloc (PyObject * self )
1804
1822
{
@@ -1906,25 +1924,75 @@ static PyGetSetDef typealias_getset[] = {
1906
1924
{0 }
1907
1925
};
1908
1926
1909
- static typealiasobject *
1910
- typealias_alloc (PyObject * name , PyObject * type_params , PyObject * compute_value ,
1911
- PyObject * value , PyObject * module )
1912
- {
1913
- typealiasobject * ta = PyObject_GC_New (typealiasobject , & _PyTypeAlias_Type );
1914
- if (ta == NULL ) {
1927
+ static PyObject *
1928
+ typealias_check_type_params (PyObject * type_params , int * err ) {
1929
+ // Can return type_params or NULL without exception set.
1930
+ // Does not change the reference count of type_params,
1931
+ // sets `*err` to 1 when error happens and sets an exception,
1932
+ // otherwise `*err` is set to 0.
1933
+ * err = 0 ;
1934
+ if (type_params == NULL ) {
1915
1935
return NULL ;
1916
1936
}
1917
- ta -> name = Py_NewRef (name );
1937
+
1938
+ assert (PyTuple_Check (type_params ));
1939
+ Py_ssize_t length = PyTuple_GET_SIZE (type_params );
1940
+ if (!length ) { // 0-length tuples are the same as `NULL`.
1941
+ return NULL ;
1942
+ }
1943
+
1944
+ PyThreadState * ts = _PyThreadState_GET ();
1945
+ int default_seen = 0 ;
1946
+ for (Py_ssize_t index = 0 ; index < length ; index ++ ) {
1947
+ PyObject * type_param = PyTuple_GET_ITEM (type_params , index );
1948
+ PyObject * dflt = get_type_param_default (ts , type_param );
1949
+ if (dflt == NULL ) {
1950
+ * err = 1 ;
1951
+ return NULL ;
1952
+ }
1953
+ if (dflt == & _Py_NoDefaultStruct ) {
1954
+ if (default_seen ) {
1955
+ * err = 1 ;
1956
+ PyErr_Format (PyExc_TypeError ,
1957
+ "non-default type parameter '%R' "
1958
+ "follows default type parameter" ,
1959
+ type_param );
1960
+ return NULL ;
1961
+ }
1962
+ } else {
1963
+ default_seen = 1 ;
1964
+ Py_DECREF (dflt );
1965
+ }
1966
+ }
1967
+
1968
+ return type_params ;
1969
+ }
1970
+
1971
+ static PyObject *
1972
+ typelias_convert_type_params (PyObject * type_params )
1973
+ {
1918
1974
if (
1919
1975
type_params == NULL
1920
1976
|| Py_IsNone (type_params )
1921
1977
|| (PyTuple_Check (type_params ) && PyTuple_GET_SIZE (type_params ) == 0 )
1922
1978
) {
1923
- ta -> type_params = NULL ;
1979
+ return NULL ;
1924
1980
}
1925
1981
else {
1926
- ta -> type_params = Py_NewRef ( type_params ) ;
1982
+ return type_params ;
1927
1983
}
1984
+ }
1985
+
1986
+ static typealiasobject *
1987
+ typealias_alloc (PyObject * name , PyObject * type_params , PyObject * compute_value ,
1988
+ PyObject * value , PyObject * module )
1989
+ {
1990
+ typealiasobject * ta = PyObject_GC_New (typealiasobject , & _PyTypeAlias_Type );
1991
+ if (ta == NULL ) {
1992
+ return NULL ;
1993
+ }
1994
+ ta -> name = Py_NewRef (name );
1995
+ ta -> type_params = Py_XNewRef (type_params );
1928
1996
ta -> compute_value = Py_XNewRef (compute_value );
1929
1997
ta -> value = Py_XNewRef (value );
1930
1998
ta -> module = Py_XNewRef (module );
@@ -2002,11 +2070,18 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
2002
2070
PyErr_SetString (PyExc_TypeError , "type_params must be a tuple" );
2003
2071
return NULL ;
2004
2072
}
2073
+
2074
+ int err = 0 ;
2075
+ PyObject * checked_params = typealias_check_type_params (type_params , & err );
2076
+ if (err ) {
2077
+ return NULL ;
2078
+ }
2079
+
2005
2080
PyObject * module = caller ();
2006
2081
if (module == NULL ) {
2007
2082
return NULL ;
2008
2083
}
2009
- PyObject * ta = (PyObject * )typealias_alloc (name , type_params , NULL , value ,
2084
+ PyObject * ta = (PyObject * )typealias_alloc (name , checked_params , NULL , value ,
2010
2085
module );
2011
2086
Py_DECREF (module );
2012
2087
return ta ;
@@ -2072,7 +2147,7 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args)
2072
2147
assert (PyTuple_GET_SIZE (args ) == 3 );
2073
2148
PyObject * name = PyTuple_GET_ITEM (args , 0 );
2074
2149
assert (PyUnicode_Check (name ));
2075
- PyObject * type_params = PyTuple_GET_ITEM (args , 1 );
2150
+ PyObject * type_params = typelias_convert_type_params ( PyTuple_GET_ITEM (args , 1 ) );
2076
2151
PyObject * compute_value = PyTuple_GET_ITEM (args , 2 );
2077
2152
assert (PyFunction_Check (compute_value ));
2078
2153
return (PyObject * )typealias_alloc (name , type_params , compute_value , NULL , NULL );
0 commit comments