summaryrefslogtreecommitdiffstats
path: root/Python/symtable.c
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2023-05-16 03:36:23 (GMT)
committerGitHub <noreply@github.com>2023-05-16 03:36:23 (GMT)
commit24d8b88420b81fc60aeb0cbcacef1e72d633824a (patch)
tree1b06e157ddc7d1066fd41a28d2c27270ccf2e278 /Python/symtable.c
parentfdafdc235e74f2f4fedc1f745bf8b90141daa162 (diff)
downloadcpython-24d8b88420b81fc60aeb0cbcacef1e72d633824a.zip
cpython-24d8b88420b81fc60aeb0cbcacef1e72d633824a.tar.gz
cpython-24d8b88420b81fc60aeb0cbcacef1e72d633824a.tar.bz2
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>
Diffstat (limited to 'Python/symtable.c')
-rw-r--r--Python/symtable.c355
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,