gh-103763: Implement PEP 695 (#103764)

This implements PEP 695, Type Parameter Syntax. It adds support for:

- Generic functions (def func[T](): ...)
- Generic classes (class X[T](): ...)
- Type aliases (type X = ...)
- New scoping when the new syntax is used within a class body
- Compiler and interpreter changes to support the new syntax and scoping rules 

Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
Co-authored-by: Eric Traut <eric@traut.com>
Co-authored-by: Larry Hastings <larry@hastings.org>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Jelle Zijlstra 2023-05-15 20:36:23 -07:00 committed by GitHub
parent fdafdc235e
commit 24d8b88420
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 11405 additions and 5469 deletions

View file

@ -47,6 +47,18 @@
#define ANNOTATION_NOT_ALLOWED \
"'%s' can not be used within an annotation"
#define TYPEVAR_BOUND_NOT_ALLOWED \
"'%s' can not be used within a TypeVar bound"
#define TYPEALIAS_NOT_ALLOWED \
"'%s' can not be used within a type alias"
#define TYPEPARAM_NOT_ALLOWED \
"'%s' can not be used within the definition of a generic"
#define DUPLICATE_TYPE_PARAM \
"duplicate type parameter '%U'"
#define LOCATION(x) \
(x)->lineno, (x)->col_offset, (x)->end_lineno, (x)->end_col_offset
@ -95,7 +107,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
if (st->st_cur != NULL &&
(st->st_cur->ste_nested ||
st->st_cur->ste_type == FunctionBlock))
_PyST_IsFunctionLike(st->st_cur)))
ste->ste_nested = 1;
ste->ste_child_free = 0;
ste->ste_generator = 0;
@ -105,7 +117,9 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
ste->ste_needs_class_closure = 0;
ste->ste_comp_inlined = 0;
ste->ste_comp_iter_target = 0;
ste->ste_can_see_class_scope = 0;
ste->ste_comp_iter_expr = 0;
ste->ste_needs_classdict = 0;
ste->ste_symbols = PyDict_New();
ste->ste_varnames = PyList_New(0);
@ -208,6 +222,7 @@ static int symtable_enter_block(struct symtable *st, identifier name,
static int symtable_exit_block(struct symtable *st);
static int symtable_visit_stmt(struct symtable *st, stmt_ty s);
static int symtable_visit_expr(struct symtable *st, expr_ty s);
static int symtable_visit_typeparam(struct symtable *st, typeparam_ty s);
static int symtable_visit_genexp(struct symtable *st, expr_ty s);
static int symtable_visit_listcomp(struct symtable *st, expr_ty s);
static int symtable_visit_setcomp(struct symtable *st, expr_ty s);
@ -403,6 +418,15 @@ _PyST_GetScope(PySTEntryObject *ste, PyObject *name)
return (symbol >> SCOPE_OFFSET) & SCOPE_MASK;
}
int
_PyST_IsFunctionLike(PySTEntryObject *ste)
{
return ste->ste_type == FunctionBlock
|| ste->ste_type == TypeVarBoundBlock
|| ste->ste_type == TypeAliasBlock
|| ste->ste_type == TypeParamBlock;
}
static int
error_at_directive(PySTEntryObject *ste, PyObject *name)
{
@ -495,7 +519,7 @@ error_at_directive(PySTEntryObject *ste, PyObject *name)
static int
analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
PyObject *bound, PyObject *local, PyObject *free,
PyObject *global)
PyObject *global, PyObject *typeparams, PySTEntryObject *class_entry)
{
if (flags & DEF_GLOBAL) {
if (flags & DEF_NONLOCAL) {
@ -524,6 +548,12 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
return error_at_directive(ste, name);
}
if (PySet_Contains(typeparams, name)) {
PyErr_Format(PyExc_SyntaxError,
"nonlocal binding not allowed for type parameter '%U'",
name);
return error_at_directive(ste, name);
}
SET_SCOPE(scopes, name, FREE);
ste->ste_free = 1;
return PySet_Add(free, name) >= 0;
@ -534,8 +564,34 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
return 0;
if (PySet_Discard(global, name) < 0)
return 0;
if (flags & DEF_TYPE_PARAM) {
if (PySet_Add(typeparams, name) < 0)
return 0;
}
else {
if (PySet_Discard(typeparams, name) < 0)
return 0;
}
return 1;
}
// If we were passed class_entry (i.e., we're in an ste_can_see_class_scope scope)
// and the bound name is in that set, then the name is potentially bound both by
// the immediately enclosing class namespace, and also by an outer function namespace.
// In that case, we want the runtime name resolution to look at only the class
// namespace and the globals (not the namespace providing the bound).
// Similarly, if the name is explicitly global in the class namespace (through the
// global statement), we want to also treat it as a global in this scope.
if (class_entry != NULL) {
long class_flags = _PyST_GetSymbol(class_entry, name);
if (class_flags & DEF_GLOBAL) {
SET_SCOPE(scopes, name, GLOBAL_EXPLICIT);
return 1;
}
else if (class_flags & DEF_BOUND && !(class_flags & DEF_NONLOCAL)) {
SET_SCOPE(scopes, name, GLOBAL_IMPLICIT);
return 1;
}
}
/* If an enclosing block has a binding for this name, it
is a free variable rather than a global variable.
Note that having a non-NULL bound implies that the block
@ -611,7 +667,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
if (PyLong_AsLong(existing) & DEF_BOUND) {
// cell vars in comprehension that are locals in outer scope
// must be promoted to cell so u_cellvars isn't wrong
if (scope == CELL && ste->ste_type == FunctionBlock) {
if (scope == CELL && _PyST_IsFunctionLike(ste)) {
if (PySet_Add(promote_to_cell, k) < 0) {
return 0;
}
@ -682,6 +738,11 @@ drop_class_free(PySTEntryObject *ste, PyObject *free)
return 0;
if (res)
ste->ste_needs_class_closure = 1;
res = PySet_Discard(free, &_Py_ID(__classdict__));
if (res < 0)
return 0;
if (res)
ste->ste_needs_classdict = 1;
return 1;
}
@ -799,11 +860,13 @@ error:
static int
analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
PyObject *global, PyObject **child_free);
PyObject *global, PyObject *typeparams,
PySTEntryObject *class_entry, PyObject **child_free);
static int
analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
PyObject *global)
PyObject *global, PyObject *typeparams,
PySTEntryObject *class_entry)
{
PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL;
PyObject *newglobal = NULL, *newfree = NULL, *promote_to_cell = NULL;
@ -865,14 +928,14 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
long flags = PyLong_AS_LONG(v);
if (!analyze_name(ste, scopes, name, flags,
bound, local, free, global))
bound, local, free, global, typeparams, class_entry))
goto error;
}
/* Populate global and bound sets to be passed to children. */
if (ste->ste_type != ClassBlock) {
/* Add function locals to bound set */
if (ste->ste_type == FunctionBlock) {
if (_PyST_IsFunctionLike(ste)) {
temp = PyNumber_InPlaceOr(newbound, local);
if (!temp)
goto error;
@ -892,9 +955,11 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
Py_DECREF(temp);
}
else {
/* Special-case __class__ */
/* Special-case __class__ and __classdict__ */
if (PySet_Add(newbound, &_Py_ID(__class__)) < 0)
goto error;
if (PySet_Add(newbound, &_Py_ID(__classdict__)) < 0)
goto error;
}
/* Recursively call analyze_child_block() on each child block.
@ -910,13 +975,23 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
assert(c && PySTEntry_Check(c));
entry = (PySTEntryObject*)c;
PySTEntryObject *new_class_entry = NULL;
if (entry->ste_can_see_class_scope) {
if (ste->ste_type == ClassBlock) {
new_class_entry = ste;
}
else if (class_entry) {
new_class_entry = class_entry;
}
}
// we inline all non-generator-expression comprehensions
int inline_comp =
entry->ste_comprehension &&
!entry->ste_generator;
if (!analyze_child_block(entry, newbound, newfree, newglobal,
&child_free))
typeparams, new_class_entry, &child_free))
{
goto error;
}
@ -952,7 +1027,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
}
/* Check if any local variables must be converted to cell variables */
if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree, promote_to_cell))
if (_PyST_IsFunctionLike(ste) && !analyze_cells(scopes, newfree, promote_to_cell))
goto error;
else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree))
goto error;
@ -980,9 +1055,11 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
static int
analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
PyObject *global, PyObject** child_free)
PyObject *global, PyObject *typeparams,
PySTEntryObject *class_entry, PyObject** child_free)
{
PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL;
PyObject *temp_typeparams = NULL;
/* Copy the bound/global/free sets.
@ -1000,24 +1077,30 @@ analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
temp_global = PySet_New(global);
if (!temp_global)
goto error;
temp_typeparams = PySet_New(typeparams);
if (!temp_typeparams)
goto error;
if (!analyze_block(entry, temp_bound, temp_free, temp_global))
if (!analyze_block(entry, temp_bound, temp_free, temp_global,
temp_typeparams, class_entry))
goto error;
*child_free = temp_free;
Py_DECREF(temp_bound);
Py_DECREF(temp_global);
Py_DECREF(temp_typeparams);
return 1;
error:
Py_XDECREF(temp_bound);
Py_XDECREF(temp_free);
Py_XDECREF(temp_global);
Py_XDECREF(temp_typeparams);
return 0;
}
static int
symtable_analyze(struct symtable *st)
{
PyObject *free, *global;
PyObject *free, *global, *typeparams;
int r;
free = PySet_New(NULL);
@ -1028,9 +1111,16 @@ symtable_analyze(struct symtable *st)
Py_DECREF(free);
return 0;
}
r = analyze_block(st->st_top, NULL, free, global);
typeparams = PySet_New(NULL);
if (!typeparams) {
Py_DECREF(free);
Py_DECREF(global);
return 0;
}
r = analyze_block(st->st_top, NULL, free, global, typeparams, NULL);
Py_DECREF(free);
Py_DECREF(global);
Py_DECREF(typeparams);
return r;
}
@ -1133,6 +1223,13 @@ symtable_add_def_helper(struct symtable *st, PyObject *name, int flag, struct _s
end_lineno, end_col_offset + 1);
goto error;
}
if ((flag & DEF_TYPE_PARAM) && (val & DEF_TYPE_PARAM)) {
PyErr_Format(PyExc_SyntaxError, DUPLICATE_TYPE_PARAM, name);
PyErr_RangedSyntaxLocationObject(st->st_filename,
lineno, col_offset + 1,
end_lineno, end_col_offset + 1);
goto error;
}
val |= flag;
}
else if (PyErr_Occurred()) {
@ -1204,6 +1301,65 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag,
lineno, col_offset, end_lineno, end_col_offset);
}
static int
symtable_enter_typeparam_block(struct symtable *st, identifier name,
void *ast, int has_defaults, int has_kwdefaults,
enum _stmt_kind kind,
int lineno, int col_offset,
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,
col_offset, end_lineno, end_col_offset)) {
return 0;
}
if (current_type == ClassBlock) {
st->st_cur->ste_can_see_class_scope = 1;
if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
}
if (kind == ClassDef_kind) {
_Py_DECLARE_STR(type_params, ".type_params");
// It gets "set" when we create the type params tuple and
// "used" when we build up the bases.
if (!symtable_add_def(st, &_Py_STR(type_params), DEF_LOCAL,
lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
if (!symtable_add_def(st, &_Py_STR(type_params), USE,
lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
st->st_private = name;
// This is used for setting the generic base
_Py_DECLARE_STR(generic_base, ".generic_base");
if (!symtable_add_def(st, &_Py_STR(generic_base), DEF_LOCAL,
lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
if (!symtable_add_def(st, &_Py_STR(generic_base), USE,
lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
}
if (has_defaults) {
_Py_DECLARE_STR(defaults, ".defaults");
if (!symtable_add_def(st, &_Py_STR(defaults), DEF_PARAM,
lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
}
if (has_kwdefaults) {
_Py_DECLARE_STR(kwdefaults, ".kwdefaults");
if (!symtable_add_def(st, &_Py_STR(kwdefaults), DEF_PARAM,
lineno, col_offset, end_lineno, end_col_offset)) {
return 0;
}
}
return 1;
}
/* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument.
They use the ASDL name to synthesize the name of the C type and the visit
function.
@ -1275,6 +1431,17 @@ symtable_record_directive(struct symtable *st, identifier name, int lineno,
return res == 0;
}
static int
has_kwonlydefaults(asdl_arg_seq *kwonlyargs, asdl_expr_seq *kw_defaults)
{
for (int i = 0; i < asdl_seq_LEN(kwonlyargs); i++) {
expr_ty default_ = asdl_seq_GET(kw_defaults, i);
if (default_) {
return 1;
}
}
return 0;
}
static int
symtable_visit_stmt(struct symtable *st, stmt_ty s)
@ -1292,11 +1459,24 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults);
if (s->v.FunctionDef.args->kw_defaults)
VISIT_SEQ_WITH_NULL(st, expr, s->v.FunctionDef.args->kw_defaults);
if (s->v.FunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list);
if (asdl_seq_LEN(s->v.FunctionDef.typeparams) > 0) {
if (!symtable_enter_typeparam_block(
st, s->v.FunctionDef.name,
(void *)s->v.FunctionDef.typeparams,
s->v.FunctionDef.args->defaults != NULL,
has_kwonlydefaults(s->v.FunctionDef.args->kwonlyargs,
s->v.FunctionDef.args->kw_defaults),
s->kind,
LOCATION(s))) {
VISIT_QUIT(st, 0);
}
VISIT_SEQ(st, typeparam, s->v.FunctionDef.typeparams);
}
if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args,
s->v.FunctionDef.returns))
VISIT_QUIT(st, 0);
if (s->v.FunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list);
if (!symtable_enter_block(st, s->v.FunctionDef.name,
FunctionBlock, (void *)s,
LOCATION(s)))
@ -1305,25 +1485,85 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, stmt, s->v.FunctionDef.body);
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
if (asdl_seq_LEN(s->v.FunctionDef.typeparams) > 0) {
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
break;
case ClassDef_kind: {
PyObject *tmp;
if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL, LOCATION(s)))
VISIT_QUIT(st, 0);
VISIT_SEQ(st, expr, s->v.ClassDef.bases);
VISIT_SEQ(st, keyword, s->v.ClassDef.keywords);
if (s->v.ClassDef.decorator_list)
VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list);
if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) {
if (!symtable_enter_typeparam_block(st, s->v.ClassDef.name,
(void *)s->v.ClassDef.typeparams,
false, false, s->kind,
LOCATION(s))) {
VISIT_QUIT(st, 0);
}
VISIT_SEQ(st, typeparam, s->v.ClassDef.typeparams);
}
VISIT_SEQ(st, expr, s->v.ClassDef.bases);
VISIT_SEQ(st, keyword, s->v.ClassDef.keywords);
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
(void *)s, s->lineno, s->col_offset,
s->end_lineno, s->end_col_offset))
VISIT_QUIT(st, 0);
tmp = st->st_private;
st->st_private = s->v.ClassDef.name;
if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) {
if (!symtable_add_def(st, &_Py_ID(__type_params__),
DEF_LOCAL, LOCATION(s))) {
VISIT_QUIT(st, 0);
}
_Py_DECLARE_STR(type_params, ".type_params");
if (!symtable_add_def(st, &_Py_STR(type_params),
USE, LOCATION(s))) {
VISIT_QUIT(st, 0);
}
}
VISIT_SEQ(st, stmt, s->v.ClassDef.body);
st->st_private = tmp;
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) {
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
break;
}
case TypeAlias_kind: {
VISIT(st, expr, s->v.TypeAlias.name);
assert(s->v.TypeAlias.name->kind == Name_kind);
PyObject *name = s->v.TypeAlias.name->v.Name.id;
int is_in_class = st->st_cur->ste_type == ClassBlock;
int is_generic = asdl_seq_LEN(s->v.TypeAlias.typeparams) > 0;
if (is_generic) {
if (!symtable_enter_typeparam_block(
st, name,
(void *)s->v.TypeAlias.typeparams,
false, false, s->kind,
LOCATION(s))) {
VISIT_QUIT(st, 0);
}
VISIT_SEQ(st, typeparam, s->v.TypeAlias.typeparams);
}
if (!symtable_enter_block(st, name, TypeAliasBlock,
(void *)s, LOCATION(s)))
VISIT_QUIT(st, 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(s->v.TypeAlias.value))) {
VISIT_QUIT(st, 0);
}
VISIT(st, expr, s->v.TypeAlias.value);
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
if (is_generic) {
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
break;
}
case Return_kind:
@ -1532,11 +1772,24 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
if (s->v.AsyncFunctionDef.args->kw_defaults)
VISIT_SEQ_WITH_NULL(st, expr,
s->v.AsyncFunctionDef.args->kw_defaults);
if (s->v.AsyncFunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list);
if (asdl_seq_LEN(s->v.AsyncFunctionDef.typeparams) > 0) {
if (!symtable_enter_typeparam_block(
st, s->v.AsyncFunctionDef.name,
(void *)s->v.AsyncFunctionDef.typeparams,
s->v.AsyncFunctionDef.args->defaults != NULL,
has_kwonlydefaults(s->v.AsyncFunctionDef.args->kwonlyargs,
s->v.AsyncFunctionDef.args->kw_defaults),
s->kind,
LOCATION(s))) {
VISIT_QUIT(st, 0);
}
VISIT_SEQ(st, typeparam, s->v.AsyncFunctionDef.typeparams);
}
if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args,
s->v.AsyncFunctionDef.returns))
VISIT_QUIT(st, 0);
if (s->v.AsyncFunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list);
if (!symtable_enter_block(st, s->v.AsyncFunctionDef.name,
FunctionBlock, (void *)s,
s->lineno, s->col_offset,
@ -1547,6 +1800,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body);
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
if (asdl_seq_LEN(s->v.AsyncFunctionDef.typeparams) > 0) {
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
break;
case AsyncWith_kind:
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
@ -1598,7 +1855,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)
}
/* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */
if (ste->ste_type == FunctionBlock) {
if (_PyST_IsFunctionLike(ste)) {
long target_in_scope = _PyST_GetSymbol(ste, target_name);
if (target_in_scope & DEF_GLOBAL) {
if (!symtable_add_def(st, target_name, DEF_GLOBAL, LOCATION(e)))
@ -1633,7 +1890,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)
}
}
/* We should always find either a FunctionBlock, ModuleBlock or ClassBlock
/* We should always find either a function-like block, ModuleBlock or ClassBlock
and should never fall to this case
*/
Py_UNREACHABLE();
@ -1806,7 +2063,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_QUIT(st, 0);
/* Special-case super: it counts as a use of __class__ */
if (e->v.Name.ctx == Load &&
st->st_cur->ste_type == FunctionBlock &&
_PyST_IsFunctionLike(st->st_cur) &&
_PyUnicode_EqualToASCIIString(e->v.Name.id, "super")) {
if (!symtable_add_def(st, &_Py_ID(__class__), USE, LOCATION(e)))
VISIT_QUIT(st, 0);
@ -1823,6 +2080,45 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_QUIT(st, 1);
}
static int
symtable_visit_typeparam(struct symtable *st, typeparam_ty tp)
{
if (++st->recursion_depth > st->recursion_limit) {
PyErr_SetString(PyExc_RecursionError,
"maximum recursion depth exceeded during compilation");
VISIT_QUIT(st, 0);
}
switch(tp->kind) {
case TypeVar_kind:
if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
VISIT_QUIT(st, 0);
if (tp->v.TypeVar.bound) {
int is_in_class = st->st_cur->ste_can_see_class_scope;
if (!symtable_enter_block(st, tp->v.TypeVar.name,
TypeVarBoundBlock, (void *)tp,
LOCATION(tp)))
VISIT_QUIT(st, 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(tp->v.TypeVar.bound))) {
VISIT_QUIT(st, 0);
}
VISIT(st, expr, tp->v.TypeVar.bound);
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
break;
case TypeVarTuple_kind:
if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
VISIT_QUIT(st, 0);
break;
case ParamSpec_kind:
if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
VISIT_QUIT(st, 0);
break;
}
VISIT_QUIT(st, 1);
}
static int
symtable_visit_pattern(struct symtable *st, pattern_ty p)
{
@ -2194,11 +2490,18 @@ symtable_visit_dictcomp(struct symtable *st, expr_ty e)
static int
symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_ty e)
{
if (st->st_cur->ste_type != AnnotationBlock) {
enum _block_type 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
return 1;
}
PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name);
PyErr_RangedSyntaxLocationObject(st->st_filename,
e->lineno,
e->col_offset + 1,