https://github.com/python/cpython/commit/4bf17c381fb7b465f0f26aecb94a6c54cf9be2d3
commit: 4bf17c381fb7b465f0f26aecb94a6c54cf9be2d3
branch: main
author: Bénédikt Tran <10796600+picn...@users.noreply.github.com>
committer: JelleZijlstra <jelle.zijls...@gmail.com>
date: 2024-06-17T06:51:03-07:00
summary:

gh-119933: Improve ``SyntaxError`` message for invalid type parameters 
expressions (#119976)

Co-authored-by: Jelle Zijlstra <jelle.zijls...@gmail.com>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst
A Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst
M Doc/library/symtable.rst
M Include/internal/pycore_symtable.h
M Lib/symtable.py
M Lib/test/test_symtable.py
M Lib/test/test_syntax.py
M Modules/symtablemodule.c
M Python/symtable.c

diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst
index 050a941d9d0516..a33263796ee53d 100644
--- a/Doc/library/symtable.rst
+++ b/Doc/library/symtable.rst
@@ -31,21 +31,74 @@ Generating Symbol Tables
 Examining Symbol Tables
 -----------------------
 
+.. class:: SymbolTableType
+
+   An enumeration indicating the type of a :class:`SymbolTable` object.
+
+   .. attribute:: MODULE
+      :value: "module"
+
+      Used for the symbol table of a module.
+
+   .. attribute:: FUNCTION
+      :value: "function"
+
+      Used for the symbol table of a function.
+
+   .. attribute:: CLASS
+      :value: "class"
+
+      Used for the symbol table of a class.
+
+   The following members refer to different flavors of
+   :ref:`annotation scopes <annotation-scopes>`.
+
+   .. attribute:: ANNOTATION
+      :value: "annotation"
+
+      Used for annotations if ``from __future__ import annotations`` is active.
+
+   .. attribute:: TYPE_ALIAS
+      :value: "type alias"
+
+      Used for the symbol table of :keyword:`type` constructions.
+
+   .. attribute:: TYPE_PARAMETERS
+      :value: "type parameters"
+
+      Used for the symbol table of :ref:`generic functions <generic-functions>`
+      or :ref:`generic classes <generic-classes>`.
+
+   .. attribute:: TYPE_VARIABLE
+      :value: "type variable"
+
+      Used for the symbol table of the bound, the constraint tuple or the
+      default value of a single type variable in the formal sense, i.e.,
+      a TypeVar, a TypeVarTuple or a ParamSpec object (the latter two do
+      not support a bound or a constraint tuple).
+
+   .. versionadded:: 3.13
+
 .. class:: SymbolTable
 
    A namespace table for a block.  The constructor is not public.
 
    .. method:: get_type()
 
-      Return the type of the symbol table.  Possible values are ``'class'``,
-      ``'module'``, ``'function'``, ``'annotation'``, ``'TypeVar bound'``,
-      ``'type alias'``, and ``'type parameter'``. The latter four refer to
-      different flavors of :ref:`annotation scopes <annotation-scopes>`.
+      Return the type of the symbol table.  Possible values are members
+      of the :class:`SymbolTableType` enumeration.
 
       .. versionchanged:: 3.12
          Added ``'annotation'``,  ``'TypeVar bound'``, ``'type alias'``,
          and ``'type parameter'`` as possible return values.
 
+      .. versionchanged:: 3.13
+         Return values are members of the :class:`SymbolTableType` enumeration.
+
+         The exact values of the returned string may change in the future,
+         and thus, it is recommended to use :class:`SymbolTableType` members
+         instead of hard-coded strings.
+
    .. method:: get_id()
 
       Return the table's identifier.
diff --git a/Include/internal/pycore_symtable.h 
b/Include/internal/pycore_symtable.h
index 519505c0edf52a..4cfdf92459c70a 100644
--- a/Include/internal/pycore_symtable.h
+++ b/Include/internal/pycore_symtable.h
@@ -16,11 +16,23 @@ typedef enum _block_type {
     // annotation blocks cannot bind names and are not evaluated. Otherwise, 
they
     // are lazily evaluated (see PEP 649).
     AnnotationBlock,
-    // Used for generics and type aliases. These work mostly like functions
-    // (see PEP 695 for details). The three different blocks function 
identically;
-    // they are different enum entries only so that error messages can be more
-    // precise.
-    TypeVarBoundBlock, TypeAliasBlock, TypeParamBlock
+
+    // The following blocks are used for generics and type aliases. These work
+    // mostly like functions (see PEP 695 for details). The three different
+    // blocks function identically; they are different enum entries only so
+    // that error messages can be more precise.
+
+    // The block to enter when processing a "type" (PEP 695) construction,
+    // e.g., "type MyGeneric[T] = list[T]".
+    TypeAliasBlock,
+    // The block to enter when processing a "generic" (PEP 695) object,
+    // e.g., "def foo[T](): pass" or "class A[T]: pass".
+    TypeParametersBlock,
+    // The block to enter when processing the bound, the constraint tuple
+    // or the default value of a single "type variable" in the formal sense,
+    // i.e., a TypeVar, a TypeVarTuple or a ParamSpec object (the latter two
+    // do not support a bound or a constraint tuple).
+    TypeVariableBlock,
 } _Py_block_ty;
 
 typedef enum _comprehension_type {
@@ -83,7 +95,16 @@ typedef struct _symtable_entry {
     PyObject *ste_children;  /* list of child blocks */
     PyObject *ste_directives;/* locations of global and nonlocal statements */
     PyObject *ste_mangled_names; /* set of names for which mangling should be 
applied */
+
     _Py_block_ty ste_type;
+    // Optional string set by symtable.c and used when reporting errors.
+    // The content of that string is a description of the current "context".
+    //
+    // For instance, if we are processing the default value of the type
+    // variable "T" in "def foo[T = int](): pass", `ste_scope_info` is
+    // set to "a TypeVar default".
+    const char *ste_scope_info;
+
     int ste_nested;      /* true if block is nested */
     unsigned ste_free : 1;        /* true if block has free variables */
     unsigned ste_child_free : 1;  /* true if a child block has free vars,
diff --git a/Lib/symtable.py b/Lib/symtable.py
index f8ba3496439535..2522cf44de20bd 100644
--- a/Lib/symtable.py
+++ b/Lib/symtable.py
@@ -13,8 +13,9 @@
 )
 
 import weakref
+from enum import StrEnum
 
-__all__ = ["symtable", "SymbolTable", "Class", "Function", "Symbol"]
+__all__ = ["symtable", "SymbolTableType", "SymbolTable", "Class", "Function", 
"Symbol"]
 
 def symtable(code, filename, compile_type):
     """ Return the toplevel *SymbolTable* for the source code.
@@ -46,6 +47,16 @@ def __call__(self, table, filename):
 _newSymbolTable = SymbolTableFactory()
 
 
+class SymbolTableType(StrEnum):
+    MODULE = "module"
+    FUNCTION = "function"
+    CLASS = "class"
+    ANNOTATION = "annotation"
+    TYPE_ALIAS = "type alias"
+    TYPE_PARAMETERS = "type parameters"
+    TYPE_VARIABLE = "type variable"
+
+
 class SymbolTable:
 
     def __init__(self, raw_table, filename):
@@ -69,23 +80,23 @@ def __repr__(self):
     def get_type(self):
         """Return the type of the symbol table.
 
-        The values returned are 'class', 'module', 'function',
-        'annotation', 'TypeVar bound', 'type alias', and 'type parameter'.
+        The value returned is one of the values in
+        the ``SymbolTableType`` enumeration.
         """
         if self._table.type == _symtable.TYPE_MODULE:
-            return "module"
+            return SymbolTableType.MODULE
         if self._table.type == _symtable.TYPE_FUNCTION:
-            return "function"
+            return SymbolTableType.FUNCTION
         if self._table.type == _symtable.TYPE_CLASS:
-            return "class"
+            return SymbolTableType.CLASS
         if self._table.type == _symtable.TYPE_ANNOTATION:
-            return "annotation"
-        if self._table.type == _symtable.TYPE_TYPE_VAR_BOUND:
-            return "TypeVar bound"
+            return SymbolTableType.ANNOTATION
         if self._table.type == _symtable.TYPE_TYPE_ALIAS:
-            return "type alias"
-        if self._table.type == _symtable.TYPE_TYPE_PARAM:
-            return "type parameter"
+            return SymbolTableType.TYPE_ALIAS
+        if self._table.type == _symtable.TYPE_TYPE_PARAMETERS:
+            return SymbolTableType.TYPE_PARAMETERS
+        if self._table.type == _symtable.TYPE_TYPE_VARIABLE:
+            return SymbolTableType.TYPE_VARIABLE
         assert False, f"unexpected type: {self._table.type}"
 
     def get_id(self):
diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py
index 903c6d66f50964..175f453447bab9 100644
--- a/Lib/test/test_symtable.py
+++ b/Lib/test/test_symtable.py
@@ -49,7 +49,7 @@ def namespace_test(): pass
 def generic_spam[T](a):
     pass
 
-class GenericMine[T: int]:
+class GenericMine[T: int, U: (int, str) = int]:
     pass
 """
 
@@ -78,6 +78,7 @@ class SymtableTest(unittest.TestCase):
     GenericMine = find_block(top, "GenericMine")
     GenericMine_inner = find_block(GenericMine, "GenericMine")
     T = find_block(GenericMine, "T")
+    U = find_block(GenericMine, "U")
 
     def test_type(self):
         self.assertEqual(self.top.get_type(), "module")
@@ -87,13 +88,14 @@ def test_type(self):
         self.assertEqual(self.internal.get_type(), "function")
         self.assertEqual(self.foo.get_type(), "function")
         self.assertEqual(self.Alias.get_type(), "type alias")
-        self.assertEqual(self.GenericAlias.get_type(), "type parameter")
+        self.assertEqual(self.GenericAlias.get_type(), "type parameters")
         self.assertEqual(self.GenericAlias_inner.get_type(), "type alias")
-        self.assertEqual(self.generic_spam.get_type(), "type parameter")
+        self.assertEqual(self.generic_spam.get_type(), "type parameters")
         self.assertEqual(self.generic_spam_inner.get_type(), "function")
-        self.assertEqual(self.GenericMine.get_type(), "type parameter")
+        self.assertEqual(self.GenericMine.get_type(), "type parameters")
         self.assertEqual(self.GenericMine_inner.get_type(), "class")
-        self.assertEqual(self.T.get_type(), "TypeVar bound")
+        self.assertEqual(self.T.get_type(), "type variable")
+        self.assertEqual(self.U.get_type(), "type variable")
 
     def test_id(self):
         self.assertGreater(self.top.get_id(), 0)
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 491f7fd7908e97..cdeb26adf34d89 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -2046,16 +2046,91 @@ def f(x: *b)
    ...
    SyntaxError: Type parameter list cannot be empty
 
+   >>> def f[T: (x:=3)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar bound
+
+   >>> def f[T: ((x:= 3), int)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar constraint
+
+   >>> def f[T = ((x:=3))](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar default
+
+   >>> async def f[T: (x:=3)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar bound
+
+   >>> async def f[T: ((x:= 3), int)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar constraint
+
+   >>> async def f[T = ((x:=3))](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar default
+
    >>> type A[T: (x:=3)] = int
    Traceback (most recent call last):
       ...
    SyntaxError: named expression cannot be used within a TypeVar bound
 
+   >>> type A[T: ((x:= 3), int)] = int
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar constraint
+
+   >>> type A[T = ((x:=3))] = int
+   Traceback (most recent call last):
+      ...
+   SyntaxError: named expression cannot be used within a TypeVar default
+
+   >>> def f[T: (yield)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar bound
+
+   >>> def f[T: (int, (yield))](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar constraint
+
+   >>> def f[T = (yield)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar default
+
+   >>> def f[*Ts = (yield)](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVarTuple default
+
+   >>> def f[**P = [(yield), int]](): pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a ParamSpec default
+
    >>> type A[T: (yield 3)] = int
    Traceback (most recent call last):
       ...
    SyntaxError: yield expression cannot be used within a TypeVar bound
 
+   >>> type A[T: (int, (yield 3))] = int
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar constraint
+
+   >>> type A[T = (yield 3)] = int
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar default
+
    >>> type A[T: (await 3)] = int
    Traceback (most recent call last):
       ...
@@ -2066,6 +2141,31 @@ def f(x: *b)
       ...
    SyntaxError: yield expression cannot be used within a TypeVar bound
 
+   >>> class A[T: (yield 3)]: pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar bound
+
+   >>> class A[T: (int, (yield 3))]: pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar constraint
+
+   >>> class A[T = (yield)]: pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVar default
+
+   >>> class A[*Ts = (yield)]: pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a TypeVarTuple default
+
+   >>> class A[**P = [(yield), int]]: pass
+   Traceback (most recent call last):
+      ...
+   SyntaxError: yield expression cannot be used within a ParamSpec default
+
    >>> type A = (x := 3)
    Traceback (most recent call last):
       ...
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst
new file mode 100644
index 00000000000000..513a0200dcc48a
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst 
@@ -0,0 +1,4 @@
+Improve :exc:`SyntaxError` messages for invalid expressions in a type
+parameters bound, a type parameter constraint tuple or a default type
+parameter.
+Patch by Bénédikt Tran.
diff --git 
a/Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst 
b/Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst
new file mode 100644
index 00000000000000..475da88914bde3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst
@@ -0,0 +1,3 @@
+Add the :class:`symtable.SymbolTableType` enumeration to represent the
+possible outputs of the :class:`symtable.SymbolTable.get_type` method. Patch
+by Bénédikt Tran.
diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c
index 618465536e7851..d0d5223e5acea8 100644
--- a/Modules/symtablemodule.c
+++ b/Modules/symtablemodule.c
@@ -91,11 +91,11 @@ symtable_init_constants(PyObject *m)
         return -1;
     if (PyModule_AddIntConstant(m, "TYPE_ANNOTATION", AnnotationBlock) < 0)
         return -1;
-    if (PyModule_AddIntConstant(m, "TYPE_TYPE_VAR_BOUND", TypeVarBoundBlock) < 
0)
-        return -1;
     if (PyModule_AddIntConstant(m, "TYPE_TYPE_ALIAS", TypeAliasBlock) < 0)
         return -1;
-    if (PyModule_AddIntConstant(m, "TYPE_TYPE_PARAM", TypeParamBlock) < 0)
+    if (PyModule_AddIntConstant(m, "TYPE_TYPE_PARAMETERS", 
TypeParametersBlock) < 0)
+        return -1;
+    if (PyModule_AddIntConstant(m, "TYPE_TYPE_VARIABLE", TypeVariableBlock) < 
0)
         return -1;
 
     if (PyModule_AddIntMacro(m, LOCAL) < 0) return -1;
diff --git a/Python/symtable.c b/Python/symtable.c
index 0490014166e65c..a8e4ba331f4fd8 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -58,13 +58,13 @@
 #define ANNOTATION_NOT_ALLOWED \
 "%s cannot be used within an annotation"
 
-#define TYPEVAR_BOUND_NOT_ALLOWED \
-"%s cannot be used within a TypeVar bound"
+#define EXPR_NOT_ALLOWED_IN_TYPE_VARIABLE \
+"%s cannot be used within %s"
 
-#define TYPEALIAS_NOT_ALLOWED \
+#define EXPR_NOT_ALLOWED_IN_TYPE_ALIAS \
 "%s cannot be used within a type alias"
 
-#define TYPEPARAM_NOT_ALLOWED \
+#define EXPR_NOT_ALLOWED_IN_TYPE_PARAMETERS \
 "%s cannot be used within the definition of a generic"
 
 #define DUPLICATE_TYPE_PARAM \
@@ -106,6 +106,8 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty 
block,
     ste->ste_mangled_names = NULL;
 
     ste->ste_type = block;
+    ste->ste_scope_info = NULL;
+
     ste->ste_nested = 0;
     ste->ste_free = 0;
     ste->ste_varargs = 0;
@@ -269,9 +271,9 @@ static void _dump_symtable(PySTEntryObject* ste, PyObject* 
prefix)
         case ClassBlock: blocktype = "ClassBlock"; break;
         case ModuleBlock: blocktype = "ModuleBlock"; break;
         case AnnotationBlock: blocktype = "AnnotationBlock"; break;
-        case TypeVarBoundBlock: blocktype = "TypeVarBoundBlock"; break;
+        case TypeVariableBlock: blocktype = "TypeVariableBlock"; break;
         case TypeAliasBlock: blocktype = "TypeAliasBlock"; break;
-        case TypeParamBlock: blocktype = "TypeParamBlock"; break;
+        case TypeParametersBlock: blocktype = "TypeParametersBlock"; break;
     }
     const char *comptype = "";
     switch (ste->ste_comprehension) {
@@ -544,9 +546,9 @@ _PyST_IsFunctionLike(PySTEntryObject *ste)
 {
     return ste->ste_type == FunctionBlock
         || ste->ste_type == AnnotationBlock
-        || ste->ste_type == TypeVarBoundBlock
+        || ste->ste_type == TypeVariableBlock
         || ste->ste_type == TypeAliasBlock
-        || ste->ste_type == TypeParamBlock;
+        || ste->ste_type == TypeParametersBlock;
 }
 
 static int
@@ -1519,7 +1521,7 @@ symtable_enter_type_param_block(struct symtable *st, 
identifier name,
                                int end_lineno, int end_col_offset)
 {
     _Py_block_ty current_type = st->st_cur->ste_type;
-    if(!symtable_enter_block(st, name, TypeParamBlock, ast, lineno,
+    if(!symtable_enter_block(st, name, TypeParametersBlock, ast, lineno,
                              col_offset, end_lineno, end_col_offset)) {
         return 0;
     }
@@ -2122,20 +2124,20 @@ symtable_extend_namedexpr_scope(struct symtable *st, 
expr_ty e)
         }
         /* Disallow usage in ClassBlock and type scopes */
         if (ste->ste_type == ClassBlock ||
-            ste->ste_type == TypeParamBlock ||
+            ste->ste_type == TypeParametersBlock ||
             ste->ste_type == TypeAliasBlock ||
-            ste->ste_type == TypeVarBoundBlock) {
+            ste->ste_type == TypeVariableBlock) {
             switch (ste->ste_type) {
                 case ClassBlock:
                     PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_CLASS);
                     break;
-                case TypeParamBlock:
+                case TypeParametersBlock:
                     PyErr_Format(PyExc_SyntaxError, 
NAMED_EXPR_COMP_IN_TYPEPARAM);
                     break;
                 case TypeAliasBlock:
                     PyErr_Format(PyExc_SyntaxError, 
NAMED_EXPR_COMP_IN_TYPEALIAS);
                     break;
-                case TypeVarBoundBlock:
+                case TypeVariableBlock:
                     PyErr_Format(PyExc_SyntaxError, 
NAMED_EXPR_COMP_IN_TYPEVAR_BOUND);
                     break;
                 default:
@@ -2341,19 +2343,27 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
 }
 
 static int
-symtable_visit_type_param_bound_or_default(struct symtable *st, expr_ty e, 
identifier name, void *key)
+symtable_visit_type_param_bound_or_default(
+    struct symtable *st, expr_ty e, identifier name,
+    void *key, const char *ste_scope_info)
 {
     if (e) {
         int is_in_class = st->st_cur->ste_can_see_class_scope;
-        if (!symtable_enter_block(st, name, TypeVarBoundBlock, key, 
LOCATION(e)))
+        if (!symtable_enter_block(st, name, TypeVariableBlock, key, 
LOCATION(e)))
             return 0;
+
         st->st_cur->ste_can_see_class_scope = is_in_class;
         if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, 
LOCATION(e))) {
             VISIT_QUIT(st, 0);
         }
+
+        assert(ste_scope_info != NULL);
+        st->st_cur->ste_scope_info = ste_scope_info;
         VISIT(st, expr, e);
-        if (!symtable_exit_block(st))
+
+        if (!symtable_exit_block(st)) {
             return 0;
+        }
     }
     return 1;
 }
@@ -2371,6 +2381,12 @@ symtable_visit_type_param(struct symtable *st, 
type_param_ty tp)
         if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | 
DEF_LOCAL, LOCATION(tp)))
             VISIT_QUIT(st, 0);
 
+        const char *ste_scope_info = NULL;
+        const expr_ty bound = tp->v.TypeVar.bound;
+        if (bound != NULL) {
+            ste_scope_info = bound->kind == Tuple_kind ? "a TypeVar 
constraint" : "a TypeVar bound";
+        }
+
         // We must use a different key for the bound and default. The obvious 
choice would be to
         // use the .bound and .default_value pointers, but that fails when the 
expression immediately
         // inside the bound or default is a comprehension: we would reuse the 
same key for
@@ -2378,11 +2394,12 @@ symtable_visit_type_param(struct symtable *st, 
type_param_ty tp)
         // The only requirement for the key is that it is unique and it 
matches the logic in
         // compile.c where the scope is retrieved.
         if (!symtable_visit_type_param_bound_or_default(st, 
tp->v.TypeVar.bound, tp->v.TypeVar.name,
-                                                        (void *)tp)) {
+                                                        (void *)tp, 
ste_scope_info)) {
             VISIT_QUIT(st, 0);
         }
+
         if (!symtable_visit_type_param_bound_or_default(st, 
tp->v.TypeVar.default_value, tp->v.TypeVar.name,
-                                                        (void *)((uintptr_t)tp 
+ 1))) {
+                                                        (void *)((uintptr_t)tp 
+ 1), "a TypeVar default")) {
             VISIT_QUIT(st, 0);
         }
         break;
@@ -2390,8 +2407,9 @@ symtable_visit_type_param(struct symtable *st, 
type_param_ty tp)
         if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | 
DEF_LOCAL, LOCATION(tp))) {
             VISIT_QUIT(st, 0);
         }
+
         if (!symtable_visit_type_param_bound_or_default(st, 
tp->v.TypeVarTuple.default_value, tp->v.TypeVarTuple.name,
-                                                        (void *)tp)) {
+                                                        (void *)tp, "a 
TypeVarTuple default")) {
             VISIT_QUIT(st, 0);
         }
         break;
@@ -2399,8 +2417,9 @@ symtable_visit_type_param(struct symtable *st, 
type_param_ty tp)
         if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | 
DEF_LOCAL, LOCATION(tp))) {
             VISIT_QUIT(st, 0);
         }
+
         if (!symtable_visit_type_param_bound_or_default(st, 
tp->v.ParamSpec.default_value, tp->v.ParamSpec.name,
-                                                        (void *)tp)) {
+                                                        (void *)tp, "a 
ParamSpec default")) {
             VISIT_QUIT(st, 0);
         }
         break;
@@ -2829,12 +2848,21 @@ symtable_raise_if_annotation_block(struct symtable *st, 
const char *name, expr_t
     _Py_block_ty type = st->st_cur->ste_type;
     if (type == AnnotationBlock)
         PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name);
-    else if (type == TypeVarBoundBlock)
-        PyErr_Format(PyExc_SyntaxError, TYPEVAR_BOUND_NOT_ALLOWED, name);
-    else if (type == TypeAliasBlock)
-        PyErr_Format(PyExc_SyntaxError, TYPEALIAS_NOT_ALLOWED, name);
-    else if (type == TypeParamBlock)
-        PyErr_Format(PyExc_SyntaxError, TYPEPARAM_NOT_ALLOWED, name);
+    else if (type == TypeVariableBlock) {
+        const char *info = st->st_cur->ste_scope_info;
+        assert(info != NULL); // e.g., info == "a ParamSpec default"
+        PyErr_Format(PyExc_SyntaxError, EXPR_NOT_ALLOWED_IN_TYPE_VARIABLE, 
name, info);
+    }
+    else if (type == TypeAliasBlock) {
+        // for now, we do not have any extra information
+        assert(st->st_cur->ste_scope_info == NULL);
+        PyErr_Format(PyExc_SyntaxError, EXPR_NOT_ALLOWED_IN_TYPE_ALIAS, name);
+    }
+    else if (type == TypeParametersBlock) {
+        // for now, we do not have any extra information
+        assert(st->st_cur->ste_scope_info == NULL);
+        PyErr_Format(PyExc_SyntaxError, EXPR_NOT_ALLOWED_IN_TYPE_PARAMETERS, 
name);
+    }
     else
         return 1;
 

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to