mirror of
https://github.com/python/cpython.git
synced 2025-08-22 09:45:06 +00:00
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:
parent
fdafdc235e
commit
24d8b88420
56 changed files with 11405 additions and 5469 deletions
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue