diff options
Diffstat (limited to 'Python/symtable.c')
-rw-r--r-- | Python/symtable.c | 355 |
1 files changed, 329 insertions, 26 deletions
diff --git a/Python/symtable.c b/Python/symtable.c index 2c29f60..3451f6c 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -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); @@ -1824,6 +2081,45 @@ symtable_visit_expr(struct symtable *st, expr_ty e) } 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) { if (++st->recursion_depth > st->recursion_limit) { @@ -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, |