mirror of https://github.com/python/cpython
gh-119933: Improve ``SyntaxError`` message for invalid type parameters expressions (#119976)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
parent
274f844830
commit
4bf17c381f
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -13,8 +13,9 @@ from _symtable import (
|
|||
)
|
||||
|
||||
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 @@ class SymbolTableFactory:
|
|||
_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 @@ class SymbolTable:
|
|||
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):
|
||||
|
|
|
@ -49,7 +49,7 @@ type GenericAlias[T] = list[T]
|
|||
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 @@ class SymtableTest(unittest.TestCase):
|
|||
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)
|
||||
|
|
|
@ -2046,16 +2046,91 @@ Invalid expressions in type scopes:
|
|||
...
|
||||
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 @@ Invalid expressions in type scopes:
|
|||
...
|
||||
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):
|
||||
...
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue