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

767
Python/Python-ast.c generated

File diff suppressed because it is too large Load diff

View file

@ -17,10 +17,12 @@ struct validator {
static int validate_stmts(struct validator *, asdl_stmt_seq *);
static int validate_exprs(struct validator *, asdl_expr_seq *, expr_context_ty, int);
static int validate_patterns(struct validator *, asdl_pattern_seq *, int);
static int validate_typeparams(struct validator *, asdl_typeparam_seq *);
static int _validate_nonempty_seq(asdl_seq *, const char *, const char *);
static int validate_stmt(struct validator *, stmt_ty);
static int validate_expr(struct validator *, expr_ty, expr_context_ty);
static int validate_pattern(struct validator *, pattern_ty, int);
static int validate_typeparam(struct validator *, typeparam_ty);
#define VALIDATE_POSITIONS(node) \
if (node->lineno > node->end_lineno) { \
@ -726,6 +728,7 @@ validate_stmt(struct validator *state, stmt_ty stmt)
switch (stmt->kind) {
case FunctionDef_kind:
ret = validate_body(state, stmt->v.FunctionDef.body, "FunctionDef") &&
validate_typeparams(state, stmt->v.FunctionDef.typeparams) &&
validate_arguments(state, stmt->v.FunctionDef.args) &&
validate_exprs(state, stmt->v.FunctionDef.decorator_list, Load, 0) &&
(!stmt->v.FunctionDef.returns ||
@ -733,6 +736,7 @@ validate_stmt(struct validator *state, stmt_ty stmt)
break;
case ClassDef_kind:
ret = validate_body(state, stmt->v.ClassDef.body, "ClassDef") &&
validate_typeparams(state, stmt->v.ClassDef.typeparams) &&
validate_exprs(state, stmt->v.ClassDef.bases, Load, 0) &&
validate_keywords(state, stmt->v.ClassDef.keywords) &&
validate_exprs(state, stmt->v.ClassDef.decorator_list, Load, 0);
@ -763,6 +767,11 @@ validate_stmt(struct validator *state, stmt_ty stmt)
validate_expr(state, stmt->v.AnnAssign.value, Load)) &&
validate_expr(state, stmt->v.AnnAssign.annotation, Load);
break;
case TypeAlias_kind:
ret = validate_expr(state, stmt->v.TypeAlias.name, Store) &&
validate_typeparams(state, stmt->v.TypeAlias.typeparams) &&
validate_expr(state, stmt->v.TypeAlias.value, Load);
break;
case For_kind:
ret = validate_expr(state, stmt->v.For.target, Store) &&
validate_expr(state, stmt->v.For.iter, Load) &&
@ -910,6 +919,7 @@ validate_stmt(struct validator *state, stmt_ty stmt)
break;
case AsyncFunctionDef_kind:
ret = validate_body(state, stmt->v.AsyncFunctionDef.body, "AsyncFunctionDef") &&
validate_typeparams(state, stmt->v.AsyncFunctionDef.typeparams) &&
validate_arguments(state, stmt->v.AsyncFunctionDef.args) &&
validate_exprs(state, stmt->v.AsyncFunctionDef.decorator_list, Load, 0) &&
(!stmt->v.AsyncFunctionDef.returns ||
@ -982,6 +992,41 @@ validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_
return 1;
}
static int
validate_typeparam(struct validator *state, typeparam_ty tp)
{
VALIDATE_POSITIONS(tp);
int ret = -1;
switch (tp->kind) {
case TypeVar_kind:
ret = validate_name(tp->v.TypeVar.name) &&
(!tp->v.TypeVar.bound ||
validate_expr(state, tp->v.TypeVar.bound, Load));
break;
case ParamSpec_kind:
ret = validate_name(tp->v.ParamSpec.name);
break;
case TypeVarTuple_kind:
ret = validate_name(tp->v.TypeVarTuple.name);
break;
}
return ret;
}
static int
validate_typeparams(struct validator *state, asdl_typeparam_seq *tps)
{
Py_ssize_t i;
for (i = 0; i < asdl_seq_LEN(tps); i++) {
typeparam_ty tp = asdl_seq_GET(tps, i);
if (tp) {
if (!validate_typeparam(state, tp))
return 0;
}
}
return 1;
}
/* See comments in symtable.c. */
#define COMPILER_STACK_FRAME_SCALE 3

View file

@ -642,6 +642,7 @@ static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeStat
static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
static int astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
static int astfold_typeparam(typeparam_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
#define CALL(FUNC, TYPE, ARG) \
if (!FUNC((ARG), ctx_, state)) \
@ -880,6 +881,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
}
switch (node_->kind) {
case FunctionDef_kind:
CALL_SEQ(astfold_typeparam, typeparam, node_->v.FunctionDef.typeparams);
CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args);
CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body);
CALL_SEQ(astfold_expr, expr, node_->v.FunctionDef.decorator_list);
@ -888,6 +890,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
}
break;
case AsyncFunctionDef_kind:
CALL_SEQ(astfold_typeparam, typeparam, node_->v.AsyncFunctionDef.typeparams);
CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args);
CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body);
CALL_SEQ(astfold_expr, expr, node_->v.AsyncFunctionDef.decorator_list);
@ -896,6 +899,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
}
break;
case ClassDef_kind:
CALL_SEQ(astfold_typeparam, typeparam, node_->v.ClassDef.typeparams);
CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.bases);
CALL_SEQ(astfold_keyword, keyword, node_->v.ClassDef.keywords);
CALL(astfold_body, asdl_seq, node_->v.ClassDef.body);
@ -922,6 +926,11 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
}
CALL_OPT(astfold_expr, expr_ty, node_->v.AnnAssign.value);
break;
case TypeAlias_kind:
CALL(astfold_expr, expr_ty, node_->v.TypeAlias.name);
CALL_SEQ(astfold_typeparam, typeparam, node_->v.TypeAlias.typeparams);
CALL(astfold_expr, expr_ty, node_->v.TypeAlias.value);
break;
case For_kind:
CALL(astfold_expr, expr_ty, node_->v.For.target);
CALL(astfold_expr, expr_ty, node_->v.For.iter);
@ -1074,6 +1083,21 @@ astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *stat
return 1;
}
static int
astfold_typeparam(typeparam_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
{
switch (node_->kind) {
case TypeVar_kind:
CALL_OPT(astfold_expr, expr_ty, node_->v.TypeVar.bound);
break;
case ParamSpec_kind:
break;
case TypeVarTuple_kind:
break;
}
return 1;
}
#undef CALL
#undef CALL_OPT
#undef CALL_SEQ

View file

@ -56,7 +56,7 @@ static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub
static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2;
static PyObject *list, *tuple, *dict, *owner, *set, *str, *tup, *map, *keys;
static PyObject *exit_func, *lasti, *val, *retval, *obj, *iter;
static PyObject *aiter, *awaitable, *iterable, *w, *exc_value, *bc;
static PyObject *aiter, *awaitable, *iterable, *w, *exc_value, *bc, *locals;
static PyObject *orig, *excs, *update, *b, *fromlist, *level, *from;
static PyObject **pieces, **values;
static size_t jump;
@ -125,6 +125,7 @@ dummy_func(
PyObject *subject;
PyObject *top;
PyObject *type;
PyObject *typevars;
int values_or_none;
switch (opcode) {
@ -1002,6 +1003,7 @@ dummy_func(
}
}
inst(STORE_NAME, (v -- )) {
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
PyObject *ns = LOCALS();
@ -1158,31 +1160,41 @@ dummy_func(
}
}
inst(LOAD_NAME, ( -- v)) {
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
PyObject *locals = LOCALS();
op(_LOAD_LOCALS, ( -- locals)) {
locals = LOCALS();
if (locals == NULL) {
_PyErr_Format(tstate, PyExc_SystemError,
"no locals when loading %R", name);
goto error;
_PyErr_SetString(tstate, PyExc_SystemError,
"no locals found");
ERROR_IF(true, error);
}
if (PyDict_CheckExact(locals)) {
v = PyDict_GetItemWithError(locals, name);
Py_INCREF(locals);
}
macro(LOAD_LOCALS) = _LOAD_LOCALS;
op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) {
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
if (PyDict_CheckExact(mod_or_class_dict)) {
v = PyDict_GetItemWithError(mod_or_class_dict, name);
if (v != NULL) {
Py_INCREF(v);
}
else if (_PyErr_Occurred(tstate)) {
Py_DECREF(mod_or_class_dict);
goto error;
}
}
else {
v = PyObject_GetItem(locals, name);
v = PyObject_GetItem(mod_or_class_dict, name);
if (v == NULL) {
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError))
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
Py_DECREF(mod_or_class_dict);
goto error;
}
_PyErr_Clear(tstate);
}
}
Py_DECREF(mod_or_class_dict);
if (v == NULL) {
v = PyDict_GetItemWithError(GLOBALS(), name);
if (v != NULL) {
@ -1219,6 +1231,10 @@ dummy_func(
}
}
macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS;
macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS;
family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = {
LOAD_GLOBAL,
LOAD_GLOBAL_MODULE,
@ -1339,29 +1355,32 @@ dummy_func(
Py_DECREF(oldobj);
}
inst(LOAD_CLASSDEREF, ( -- value)) {
PyObject *name, *locals = LOCALS();
assert(locals);
inst(LOAD_FROM_DICT_OR_DEREF, (class_dict -- value)) {
PyObject *name;
assert(class_dict);
assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus);
name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg);
if (PyDict_CheckExact(locals)) {
value = PyDict_GetItemWithError(locals, name);
if (PyDict_CheckExact(class_dict)) {
value = PyDict_GetItemWithError(class_dict, name);
if (value != NULL) {
Py_INCREF(value);
}
else if (_PyErr_Occurred(tstate)) {
Py_DECREF(class_dict);
goto error;
}
}
else {
value = PyObject_GetItem(locals, name);
value = PyObject_GetItem(class_dict, name);
if (value == NULL) {
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
Py_DECREF(class_dict);
goto error;
}
_PyErr_Clear(tstate);
}
}
Py_DECREF(class_dict);
if (!value) {
PyObject *cell = GETLOCAL(oparg);
value = PyCell_GET(cell);

View file

@ -147,6 +147,7 @@ enum {
COMPILER_SCOPE_ASYNC_FUNCTION,
COMPILER_SCOPE_LAMBDA,
COMPILER_SCOPE_COMPREHENSION,
COMPILER_SCOPE_TYPEPARAMS,
};
@ -231,6 +232,7 @@ instr_sequence_next_inst(instr_sequence *seq) {
&seq->s_allocated,
INITIAL_INSTR_SEQUENCE_SIZE,
sizeof(instruction)));
assert(seq->s_allocated >= 0);
assert(seq->s_used < seq->s_allocated);
return seq->s_used++;
}
@ -714,6 +716,19 @@ compiler_set_qualname(struct compiler *c)
capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME);
assert(parent);
if (parent->u_scope_type == COMPILER_SCOPE_TYPEPARAMS) {
/* The parent is a type parameter scope, so we need to
look at the grandparent. */
if (stack_size == 2) {
// If we're immediately within the module, we can skip
// the rest and just set the qualname to be the same as name.
u->u_metadata.u_qualname = Py_NewRef(u->u_metadata.u_name);
return SUCCESS;
}
capsule = PyList_GET_ITEM(c->c_stack, stack_size - 2);
parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME);
assert(parent);
}
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION
|| u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION
@ -1114,16 +1129,18 @@ codegen_addop_j(instr_sequence *seq, location loc,
return instr_sequence_addop(seq, opcode, target.id, loc);
}
#define ADDOP(C, LOC, OP) \
RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)))
#define ADDOP_IN_SCOPE(C, LOC, OP) { \
if (codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)) < 0) { \
compiler_exit_scope(C); \
#define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \
if ((CALL) < 0) { \
compiler_exit_scope((C)); \
return ERROR; \
} \
}
#define ADDOP(C, LOC, OP) \
RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)))
#define ADDOP_IN_SCOPE(C, LOC, OP) RETURN_IF_ERROR_IN_SCOPE((C), codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)))
#define ADDOP_LOAD_CONST(C, LOC, O) \
RETURN_IF_ERROR(compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), (O)))
@ -1183,12 +1200,8 @@ codegen_addop_j(instr_sequence *seq, location loc,
#define VISIT(C, TYPE, V) \
RETURN_IF_ERROR(compiler_visit_ ## TYPE((C), (V)));
#define VISIT_IN_SCOPE(C, TYPE, V) {\
if (compiler_visit_ ## TYPE((C), (V)) < 0) { \
compiler_exit_scope(C); \
return ERROR; \
} \
}
#define VISIT_IN_SCOPE(C, TYPE, V) \
RETURN_IF_ERROR_IN_SCOPE((C), compiler_visit_ ## TYPE((C), (V)))
#define VISIT_SEQ(C, TYPE, SEQ) { \
int _i; \
@ -1252,6 +1265,16 @@ compiler_enter_scope(struct compiler *c, identifier name,
return ERROR;
}
}
if (u->u_ste->ste_needs_classdict) {
/* Cook up an implicit __classdict__ cell. */
Py_ssize_t res;
assert(u->u_scope_type == COMPILER_SCOPE_CLASS);
res = dict_add_o(u->u_metadata.u_cellvars, &_Py_ID(__classdict__));
if (res < 0) {
compiler_unit_free(u);
return ERROR;
}
}
u->u_metadata.u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS,
PyDict_GET_SIZE(u->u_metadata.u_cellvars));
@ -1718,8 +1741,10 @@ get_ref_type(struct compiler *c, PyObject *name)
{
int scope;
if (c->u->u_scope_type == COMPILER_SCOPE_CLASS &&
_PyUnicode_EqualToASCIIString(name, "__class__"))
(_PyUnicode_EqualToASCIIString(name, "__class__") ||
_PyUnicode_EqualToASCIIString(name, "__classdict__"))) {
return CELL;
}
scope = _PyST_GetScope(c->u->u_ste, name);
if (scope == 0) {
PyErr_Format(PyExc_SystemError,
@ -2085,26 +2110,81 @@ wrap_in_stopiteration_handler(struct compiler *c)
}
static int
compiler_function(struct compiler *c, stmt_ty s, int is_async)
compiler_type_params(struct compiler *c, asdl_typeparam_seq *typeparams)
{
if (!typeparams) {
return SUCCESS;
}
Py_ssize_t n = asdl_seq_LEN(typeparams);
for (Py_ssize_t i = 0; i < n; i++) {
typeparam_ty typeparam = asdl_seq_GET(typeparams, i);
location loc = LOC(typeparam);
switch(typeparam->kind) {
case TypeVar_kind:
ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVar.name);
if (typeparam->v.TypeVar.bound) {
expr_ty bound = typeparam->v.TypeVar.bound;
if (compiler_enter_scope(c, typeparam->v.TypeVar.name, COMPILER_SCOPE_TYPEPARAMS,
(void *)typeparam, bound->lineno) == -1) {
return ERROR;
}
VISIT_IN_SCOPE(c, expr, bound);
ADDOP_IN_SCOPE(c, loc, RETURN_VALUE);
PyCodeObject *co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
int intrinsic = bound->kind == Tuple_kind
? INTRINSIC_TYPEVAR_WITH_CONSTRAINTS
: INTRINSIC_TYPEVAR_WITH_BOUND;
ADDOP_I(c, loc, CALL_INTRINSIC_2, intrinsic);
}
else {
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVAR);
}
ADDOP_I(c, loc, COPY, 1);
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVar.name, Store));
break;
case TypeVarTuple_kind:
ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVarTuple.name);
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVARTUPLE);
ADDOP_I(c, loc, COPY, 1);
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVarTuple.name, Store));
break;
case ParamSpec_kind:
ADDOP_LOAD_CONST(c, loc, typeparam->v.ParamSpec.name);
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_PARAMSPEC);
ADDOP_I(c, loc, COPY, 1);
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.ParamSpec.name, Store));
break;
}
}
ADDOP_I(c, LOC(asdl_seq_GET(typeparams, 0)), BUILD_TUPLE, n);
return SUCCESS;
}
static int
compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t funcflags,
int firstlineno)
{
PyCodeObject *co;
PyObject *docstring = NULL;
arguments_ty args;
expr_ty returns;
identifier name;
asdl_expr_seq* decos;
asdl_stmt_seq *body;
Py_ssize_t i, funcflags;
int annotations;
int scope_type;
int firstlineno;
if (is_async) {
assert(s->kind == AsyncFunctionDef_kind);
args = s->v.AsyncFunctionDef.args;
returns = s->v.AsyncFunctionDef.returns;
decos = s->v.AsyncFunctionDef.decorator_list;
name = s->v.AsyncFunctionDef.name;
body = s->v.AsyncFunctionDef.body;
@ -2113,33 +2193,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
assert(s->kind == FunctionDef_kind);
args = s->v.FunctionDef.args;
returns = s->v.FunctionDef.returns;
decos = s->v.FunctionDef.decorator_list;
name = s->v.FunctionDef.name;
body = s->v.FunctionDef.body;
scope_type = COMPILER_SCOPE_FUNCTION;
}
RETURN_IF_ERROR(compiler_check_debug_args(c, args));
RETURN_IF_ERROR(compiler_decorators(c, decos));
firstlineno = s->lineno;
if (asdl_seq_LEN(decos)) {
firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno;
}
location loc = LOC(s);
funcflags = compiler_default_arguments(c, loc, args);
if (funcflags == -1) {
return ERROR;
}
annotations = compiler_visit_annotations(c, loc, args, returns);
RETURN_IF_ERROR(annotations);
if (annotations > 0) {
funcflags |= 0x04;
}
RETURN_IF_ERROR(
compiler_enter_scope(c, name, scope_type, (void *)s, firstlineno));
@ -2155,7 +2214,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args);
c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
for (i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) {
for (Py_ssize_t i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) {
VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i));
}
if (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator) {
@ -2164,29 +2223,52 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
return ERROR;
}
}
co = optimize_and_assemble(c, 1);
PyCodeObject *co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL) {
Py_XDECREF(co);
return ERROR;
}
location loc = LOC(s);
if (compiler_make_closure(c, loc, co, funcflags) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
RETURN_IF_ERROR(compiler_apply_decorators(c, decos));
return compiler_nameop(c, loc, name, Store);
return SUCCESS;
}
static int
compiler_class(struct compiler *c, stmt_ty s)
compiler_function(struct compiler *c, stmt_ty s, int is_async)
{
PyCodeObject *co;
int i, firstlineno;
asdl_expr_seq *decos = s->v.ClassDef.decorator_list;
arguments_ty args;
expr_ty returns;
identifier name;
asdl_expr_seq *decos;
asdl_typeparam_seq *typeparams;
Py_ssize_t funcflags;
int annotations;
int firstlineno;
if (is_async) {
assert(s->kind == AsyncFunctionDef_kind);
args = s->v.AsyncFunctionDef.args;
returns = s->v.AsyncFunctionDef.returns;
decos = s->v.AsyncFunctionDef.decorator_list;
name = s->v.AsyncFunctionDef.name;
typeparams = s->v.AsyncFunctionDef.typeparams;
} else {
assert(s->kind == FunctionDef_kind);
args = s->v.FunctionDef.args;
returns = s->v.FunctionDef.returns;
decos = s->v.FunctionDef.decorator_list;
name = s->v.FunctionDef.name;
typeparams = s->v.FunctionDef.typeparams;
}
RETURN_IF_ERROR(compiler_check_debug_args(c, args));
RETURN_IF_ERROR(compiler_decorators(c, decos));
firstlineno = s->lineno;
@ -2194,6 +2276,108 @@ compiler_class(struct compiler *c, stmt_ty s)
firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno;
}
location loc = LOC(s);
int is_generic = asdl_seq_LEN(typeparams) > 0;
if (is_generic) {
// Used by the CALL to the type parameters function.
ADDOP(c, loc, PUSH_NULL);
}
funcflags = compiler_default_arguments(c, loc, args);
if (funcflags == -1) {
return ERROR;
}
int num_typeparam_args = 0;
if (is_generic) {
if (funcflags & 0x01) {
num_typeparam_args += 1;
}
if (funcflags & 0x02) {
num_typeparam_args += 1;
}
if (num_typeparam_args == 2) {
ADDOP_I(c, loc, SWAP, 2);
}
PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", name);
if (!typeparams_name) {
return ERROR;
}
if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS,
(void *)typeparams, firstlineno) == -1) {
Py_DECREF(typeparams_name);
return ERROR;
}
Py_DECREF(typeparams_name);
RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams));
if ((funcflags & 0x01) || (funcflags & 0x02)) {
RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 0, loc));
}
if ((funcflags & 0x01) && (funcflags & 0x02)) {
RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 1, loc));
}
}
annotations = compiler_visit_annotations(c, loc, args, returns);
if (annotations < 0) {
if (is_generic) {
compiler_exit_scope(c);
}
return ERROR;
}
if (annotations > 0) {
funcflags |= 0x04;
}
if (compiler_function_body(c, s, is_async, funcflags, firstlineno) < 0) {
if (is_generic) {
compiler_exit_scope(c);
}
return ERROR;
}
if (is_generic) {
RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(
INSTR_SEQUENCE(c), SWAP, 2, loc));
RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(
INSTR_SEQUENCE(c), CALL_INTRINSIC_2, INTRINSIC_SET_FUNCTION_TYPE_PARAMS, loc));
c->u->u_metadata.u_argcount = num_typeparam_args;
PyCodeObject *co = optimize_and_assemble(c, 0);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
if (num_typeparam_args > 0) {
ADDOP_I(c, loc, SWAP, num_typeparam_args + 1);
}
ADDOP_I(c, loc, CALL, num_typeparam_args);
}
RETURN_IF_ERROR(compiler_apply_decorators(c, decos));
return compiler_nameop(c, loc, name, Store);
}
static int
compiler_set_type_params_in_class(struct compiler *c, location loc)
{
_Py_DECLARE_STR(type_params, ".type_params");
RETURN_IF_ERROR(compiler_nameop(c, loc, &_Py_STR(type_params), Load));
RETURN_IF_ERROR(compiler_nameop(c, loc, &_Py_ID(__type_params__), Store));
return 1;
}
static int
compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno)
{
/* ultimately generate code for:
<name> = __build_class__(<func>, <name>, *<bases>, **<keywords>)
where:
@ -2204,68 +2388,100 @@ compiler_class(struct compiler *c, stmt_ty s)
<keywords> is the keyword arguments and **kwds argument
This borrows from compiler_call.
*/
/* 1. compile the class body into a code object */
RETURN_IF_ERROR(
compiler_enter_scope(c, s->v.ClassDef.name,
COMPILER_SCOPE_CLASS, (void *)s, firstlineno));
/* this block represents what we do in the new scope */
{
location loc = LOCATION(firstlineno, firstlineno, 0, 0);
/* use the class name for name mangling */
Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name));
/* load (global) __name__ ... */
if (compiler_nameop(c, loc, &_Py_ID(__name__), Load) < 0) {
compiler_exit_scope(c);
return ERROR;
}
/* ... and store it as __module__ */
if (compiler_nameop(c, loc, &_Py_ID(__module__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
assert(c->u->u_metadata.u_qualname);
ADDOP_LOAD_CONST(c, loc, c->u->u_metadata.u_qualname);
if (compiler_nameop(c, loc, &_Py_ID(__qualname__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
/* compile the body proper */
if (compiler_body(c, loc, s->v.ClassDef.body) < 0) {
compiler_exit_scope(c);
return ERROR;
}
/* The following code is artificial */
/* Return __classcell__ if it is referenced, otherwise return None */
if (c->u->u_ste->ste_needs_class_closure) {
/* Store __classcell__ into class namespace & return it */
i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
if (i < 0) {
compiler_exit_scope(c);
return ERROR;
}
ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i);
ADDOP_I(c, NO_LOCATION, COPY, 1);
if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
}
else {
/* No methods referenced __class__, so just return None */
ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
}
ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE);
/* create the code object */
co = optimize_and_assemble(c, 1);
location loc = LOCATION(firstlineno, firstlineno, 0, 0);
/* use the class name for name mangling */
Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name));
/* load (global) __name__ ... */
if (compiler_nameop(c, loc, &_Py_ID(__name__), Load) < 0) {
compiler_exit_scope(c);
return ERROR;
}
/* ... and store it as __module__ */
if (compiler_nameop(c, loc, &_Py_ID(__module__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
assert(c->u->u_metadata.u_qualname);
ADDOP_LOAD_CONST(c, loc, c->u->u_metadata.u_qualname);
if (compiler_nameop(c, loc, &_Py_ID(__qualname__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
asdl_typeparam_seq *typeparams = s->v.ClassDef.typeparams;
if (asdl_seq_LEN(typeparams) > 0) {
if (!compiler_set_type_params_in_class(c, loc)) {
compiler_exit_scope(c);
return ERROR;
}
}
if (c->u->u_ste->ste_needs_classdict) {
ADDOP(c, loc, LOAD_LOCALS);
// We can't use compiler_nameop here because we need to generate a
// STORE_DEREF in a class namespace, and compiler_nameop() won't do
// that by default.
PyObject *cellvars = c->u->u_metadata.u_cellvars;
if (compiler_addop_o(c->u, loc, STORE_DEREF, cellvars,
&_Py_ID(__classdict__)) < 0) {
compiler_exit_scope(c);
return ERROR;
}
}
/* compile the body proper */
if (compiler_body(c, loc, s->v.ClassDef.body) < 0) {
compiler_exit_scope(c);
return ERROR;
}
/* The following code is artificial */
/* Set __classdictcell__ if necessary */
if (c->u->u_ste->ste_needs_classdict) {
/* Store __classdictcell__ into class namespace */
int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__));
if (i < 0) {
compiler_exit_scope(c);
return ERROR;
}
ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i);
if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classdictcell__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
}
/* Return __classcell__ if it is referenced, otherwise return None */
if (c->u->u_ste->ste_needs_class_closure) {
/* Store __classcell__ into class namespace & return it */
int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
if (i < 0) {
compiler_exit_scope(c);
return ERROR;
}
ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i);
ADDOP_I(c, NO_LOCATION, COPY, 1);
if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
}
}
else {
/* No methods referenced __class__, so just return None */
ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
}
ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE);
/* create the code object */
PyCodeObject *co = optimize_and_assemble(c, 1);
/* leave the new scope */
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
location loc = LOC(s);
/* 2. load the 'build_class' function */
ADDOP(c, loc, PUSH_NULL);
ADDOP(c, loc, LOAD_BUILD_CLASS);
@ -2280,10 +2496,100 @@ compiler_class(struct compiler *c, stmt_ty s)
/* 4. load class name */
ADDOP_LOAD_CONST(c, loc, s->v.ClassDef.name);
/* 5. generate the rest of the code for the call */
RETURN_IF_ERROR(compiler_call_helper(c, loc, 2,
s->v.ClassDef.bases,
s->v.ClassDef.keywords));
return SUCCESS;
}
static int
compiler_class(struct compiler *c, stmt_ty s)
{
asdl_expr_seq *decos = s->v.ClassDef.decorator_list;
RETURN_IF_ERROR(compiler_decorators(c, decos));
int firstlineno = s->lineno;
if (asdl_seq_LEN(decos)) {
firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno;
}
location loc = LOC(s);
asdl_typeparam_seq *typeparams = s->v.ClassDef.typeparams;
int is_generic = asdl_seq_LEN(typeparams) > 0;
if (is_generic) {
Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name));
ADDOP(c, loc, PUSH_NULL);
PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>",
s->v.ClassDef.name);
if (!typeparams_name) {
return ERROR;
}
if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS,
(void *)typeparams, firstlineno) == -1) {
Py_DECREF(typeparams_name);
return ERROR;
}
Py_DECREF(typeparams_name);
RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams));
_Py_DECLARE_STR(type_params, ".type_params");
RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Store));
}
if (compiler_class_body(c, s, firstlineno) < 0) {
if (is_generic) {
compiler_exit_scope(c);
}
return ERROR;
}
/* generate the rest of the code for the call */
if (is_generic) {
_Py_DECLARE_STR(type_params, ".type_params");
_Py_DECLARE_STR(generic_base, ".generic_base");
RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Load));
RETURN_IF_ERROR_IN_SCOPE(
c, codegen_addop_i(INSTR_SEQUENCE(c), CALL_INTRINSIC_1, INTRINSIC_SUBSCRIPT_GENERIC, loc)
)
RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(generic_base), Store));
Py_ssize_t original_len = asdl_seq_LEN(s->v.ClassDef.bases);
asdl_expr_seq *bases = _Py_asdl_expr_seq_new(
original_len + 1, c->c_arena);
if (bases == NULL) {
compiler_exit_scope(c);
return ERROR;
}
for (Py_ssize_t i = 0; i < original_len; i++) {
asdl_seq_SET(bases, i, asdl_seq_GET(s->v.ClassDef.bases, i));
}
expr_ty name_node = _PyAST_Name(
&_Py_STR(generic_base), Load,
loc.lineno, loc.col_offset, loc.end_lineno, loc.end_col_offset, c->c_arena
);
if (name_node == NULL) {
compiler_exit_scope(c);
return ERROR;
}
asdl_seq_SET(bases, original_len, name_node);
RETURN_IF_ERROR_IN_SCOPE(c, compiler_call_helper(c, loc, 2,
bases,
s->v.ClassDef.keywords));
PyCodeObject *co = optimize_and_assemble(c, 0);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
ADDOP_I(c, loc, CALL, 0);
} else {
RETURN_IF_ERROR(compiler_call_helper(c, loc, 2,
s->v.ClassDef.bases,
s->v.ClassDef.keywords));
}
/* 6. apply decorators */
RETURN_IF_ERROR(compiler_apply_decorators(c, decos));
@ -2293,6 +2599,87 @@ compiler_class(struct compiler *c, stmt_ty s)
return SUCCESS;
}
static int
compiler_typealias_body(struct compiler *c, stmt_ty s)
{
location loc = LOC(s);
PyObject *name = s->v.TypeAlias.name->v.Name.id;
RETURN_IF_ERROR(
compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION, s, loc.lineno));
/* Make None the first constant, so the evaluate function can't have a
docstring. */
RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None));
VISIT_IN_SCOPE(c, expr, s->v.TypeAlias.value);
ADDOP_IN_SCOPE(c, loc, RETURN_VALUE);
PyCodeObject *co = optimize_and_assemble(c, 0);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
ADDOP_I(c, loc, BUILD_TUPLE, 3);
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEALIAS);
return SUCCESS;
}
static int
compiler_typealias(struct compiler *c, stmt_ty s)
{
location loc = LOC(s);
asdl_typeparam_seq *typeparams = s->v.TypeAlias.typeparams;
int is_generic = asdl_seq_LEN(typeparams) > 0;
PyObject *name = s->v.TypeAlias.name->v.Name.id;
if (is_generic) {
ADDOP(c, loc, PUSH_NULL);
PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>",
name);
if (!typeparams_name) {
return ERROR;
}
if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS,
(void *)typeparams, loc.lineno) == -1) {
Py_DECREF(typeparams_name);
return ERROR;
}
Py_DECREF(typeparams_name);
RETURN_IF_ERROR_IN_SCOPE(
c, compiler_addop_load_const(c->c_const_cache, c->u, loc, name)
);
RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams));
}
else {
ADDOP_LOAD_CONST(c, loc, name);
ADDOP_LOAD_CONST(c, loc, Py_None);
}
if (compiler_typealias_body(c, s) < 0) {
if (is_generic) {
compiler_exit_scope(c);
}
return ERROR;
}
if (is_generic) {
PyCodeObject *co = optimize_and_assemble(c, 0);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
ADDOP_I(c, loc, CALL, 0);
}
RETURN_IF_ERROR(compiler_nameop(c, loc, name, Store));
return SUCCESS;
}
/* Return false if the expression is a constant value except named singletons.
Return true otherwise. */
static bool
@ -2705,7 +3092,7 @@ compiler_return(struct compiler *c, stmt_ty s)
location loc = LOC(s);
int preserve_tos = ((s->v.Return.value != NULL) &&
(s->v.Return.value->kind != Constant_kind));
if (c->u->u_ste->ste_type != FunctionBlock) {
if (!_PyST_IsFunctionLike(c->u->u_ste)) {
return compiler_error(c, loc, "'return' outside function");
}
if (s->v.Return.value != NULL &&
@ -3519,6 +3906,8 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
return compiler_function(c, s, 0);
case ClassDef_kind:
return compiler_class(c, s);
case TypeAlias_kind:
return compiler_typealias(c, s);
case Return_kind:
return compiler_return(c, s);
case Delete_kind:
@ -3725,12 +4114,12 @@ compiler_nameop(struct compiler *c, location loc,
optype = OP_DEREF;
break;
case LOCAL:
if (c->u->u_ste->ste_type == FunctionBlock ||
if (_PyST_IsFunctionLike(c->u->u_ste) ||
(PyDict_GetItem(c->u->u_metadata.u_fasthidden, mangled) == Py_True))
optype = OP_FAST;
break;
case GLOBAL_IMPLICIT:
if (c->u->u_ste->ste_type == FunctionBlock)
if (_PyST_IsFunctionLike(c->u->u_ste))
optype = OP_GLOBAL;
break;
case GLOBAL_EXPLICIT:
@ -3748,7 +4137,24 @@ compiler_nameop(struct compiler *c, location loc,
case OP_DEREF:
switch (ctx) {
case Load:
op = (c->u->u_ste->ste_type == ClassBlock) ? LOAD_CLASSDEREF : LOAD_DEREF;
if (c->u->u_ste->ste_type == ClassBlock) {
op = LOAD_FROM_DICT_OR_DEREF;
// First load the locals
if (codegen_addop_noarg(INSTR_SEQUENCE(c), LOAD_LOCALS, loc) < 0) {
return ERROR;
}
}
else if (c->u->u_ste->ste_can_see_class_scope) {
op = LOAD_FROM_DICT_OR_DEREF;
// First load the classdict
if (compiler_addop_o(c->u, loc, LOAD_DEREF,
c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) {
return ERROR;
}
}
else {
op = LOAD_DEREF;
}
break;
case Store: op = STORE_DEREF; break;
case Del: op = DELETE_DEREF; break;
@ -3764,7 +4170,18 @@ compiler_nameop(struct compiler *c, location loc,
return SUCCESS;
case OP_GLOBAL:
switch (ctx) {
case Load: op = LOAD_GLOBAL; break;
case Load:
if (c->u->u_ste->ste_can_see_class_scope && scope == GLOBAL_IMPLICIT) {
op = LOAD_FROM_DICT_OR_GLOBALS;
// First load the classdict
if (compiler_addop_o(c->u, loc, LOAD_DEREF,
c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) {
return ERROR;
}
} else {
op = LOAD_GLOBAL;
}
break;
case Store: op = STORE_GLOBAL; break;
case Del: op = DELETE_GLOBAL; break;
}
@ -5008,7 +5425,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
// assignment expression to a nonlocal in the comprehension, these don't
// need handling here since they shouldn't be isolated
if (symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) {
if (c->u->u_ste->ste_type != FunctionBlock) {
if (!_PyST_IsFunctionLike(c->u->u_ste)) {
// non-function scope: override this name to use fast locals
PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k);
if (orig != Py_True) {
@ -5604,7 +6021,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
case DictComp_kind:
return compiler_dictcomp(c, e);
case Yield_kind:
if (c->u->u_ste->ste_type != FunctionBlock) {
if (!_PyST_IsFunctionLike(c->u->u_ste)) {
return compiler_error(c, loc, "'yield' outside function");
}
if (e->v.Yield.value) {
@ -5616,7 +6033,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
ADDOP_YIELD(c, loc);
break;
case YieldFrom_kind:
if (c->u->u_ste->ste_type != FunctionBlock) {
if (!_PyST_IsFunctionLike(c->u->u_ste)) {
return compiler_error(c, loc, "'yield' outside function");
}
if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION) {
@ -5629,7 +6046,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
break;
case Await_kind:
if (!IS_TOP_LEVEL_AWAIT(c)){
if (c->u->u_ste->ste_type != FunctionBlock){
if (!_PyST_IsFunctionLike(c->u->u_ste)) {
return compiler_error(c, loc, "'await' outside function");
}
@ -6916,7 +7333,7 @@ compute_code_flags(struct compiler *c)
{
PySTEntryObject *ste = c->u->u_ste;
int flags = 0;
if (ste->ste_type == FunctionBlock) {
if (_PyST_IsFunctionLike(c->u->u_ste)) {
flags |= CO_NEWLOCALS | CO_OPTIMIZED;
if (ste->ste_nested)
flags |= CO_NESTED;
@ -7114,7 +7531,7 @@ fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *
case LOAD_DEREF:
case STORE_DEREF:
case DELETE_DEREF:
case LOAD_CLASSDEREF:
case LOAD_FROM_DICT_OR_DEREF:
assert(oldoffset >= 0);
assert(oldoffset < noffsets);
assert(fixedmap[oldoffset] >= 0);

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,12 @@
#include "Python.h"
#include "pycore_frame.h"
#include "pycore_function.h"
#include "pycore_runtime.h"
#include "pycore_global_objects.h"
#include "pycore_intrinsics.h"
#include "pycore_pyerrors.h"
#include "pycore_typevarobject.h"
/******** Unary functions ********/
@ -199,6 +201,13 @@ list_to_tuple(PyThreadState* unused, PyObject *v)
return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v));
}
static PyObject *
make_typevar(PyThreadState* Py_UNUSED(ignored), PyObject *v)
{
assert(PyUnicode_Check(v));
return _Py_make_typevar(v, NULL, NULL);
}
const instrinsic_func1
_PyIntrinsics_UnaryFunctions[] = {
[0] = no_intrinsic,
@ -208,6 +217,11 @@ _PyIntrinsics_UnaryFunctions[] = {
[INTRINSIC_ASYNC_GEN_WRAP] = _PyAsyncGenValueWrapperNew,
[INTRINSIC_UNARY_POSITIVE] = unary_pos,
[INTRINSIC_LIST_TO_TUPLE] = list_to_tuple,
[INTRINSIC_TYPEVAR] = make_typevar,
[INTRINSIC_PARAMSPEC] = _Py_make_paramspec,
[INTRINSIC_TYPEVARTUPLE] = _Py_make_typevartuple,
[INTRINSIC_SUBSCRIPT_GENERIC] = _Py_subscript_generic,
[INTRINSIC_TYPEALIAS] = _Py_make_typealias,
};
@ -221,8 +235,26 @@ prep_reraise_star(PyThreadState* unused, PyObject *orig, PyObject *excs)
return _PyExc_PrepReraiseStar(orig, excs);
}
static PyObject *
make_typevar_with_bound(PyThreadState* Py_UNUSED(ignored), PyObject *name,
PyObject *evaluate_bound)
{
assert(PyUnicode_Check(name));
return _Py_make_typevar(name, evaluate_bound, NULL);
}
static PyObject *
make_typevar_with_constraints(PyThreadState* Py_UNUSED(ignored), PyObject *name,
PyObject *evaluate_constraints)
{
assert(PyUnicode_Check(name));
return _Py_make_typevar(name, NULL, evaluate_constraints);
}
const instrinsic_func2
_PyIntrinsics_BinaryFunctions[] = {
[INTRINSIC_PREP_RERAISE_STAR] = prep_reraise_star,
[INTRINSIC_TYPEVAR_WITH_BOUND] = make_typevar_with_bound,
[INTRINSIC_TYPEVAR_WITH_CONSTRAINTS] = make_typevar_with_constraints,
[INTRINSIC_SET_FUNCTION_TYPE_PARAMS] = _Py_set_function_type_params,
};

View file

@ -161,8 +161,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case DELETE_GLOBAL:
return 0;
case LOAD_NAME:
case LOAD_LOCALS:
return 0;
case LOAD_NAME:
return 0+1;
case LOAD_FROM_DICT_OR_GLOBALS:
return 1;
case LOAD_GLOBAL:
return 0;
case LOAD_GLOBAL_MODULE:
@ -175,8 +179,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0;
case DELETE_DEREF:
return 0;
case LOAD_CLASSDEREF:
return 0;
case LOAD_FROM_DICT_OR_DEREF:
return 1;
case LOAD_DEREF:
return 0;
case STORE_DEREF:
@ -551,7 +555,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case DELETE_GLOBAL:
return 0;
case LOAD_LOCALS:
return 1;
case LOAD_NAME:
return 1+1;
case LOAD_FROM_DICT_OR_GLOBALS:
return 1;
case LOAD_GLOBAL:
return ((oparg & 1) ? 1 : 0) + 1;
@ -565,7 +573,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case DELETE_DEREF:
return 0;
case LOAD_CLASSDEREF:
case LOAD_FROM_DICT_OR_DEREF:
return 1;
case LOAD_DEREF:
return 1;
@ -869,14 +877,16 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[DELETE_ATTR] = { true, INSTR_FMT_IB },
[STORE_GLOBAL] = { true, INSTR_FMT_IB },
[DELETE_GLOBAL] = { true, INSTR_FMT_IB },
[LOAD_LOCALS] = { true, INSTR_FMT_IB },
[LOAD_NAME] = { true, INSTR_FMT_IB },
[LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB },
[LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 },
[LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 },
[LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 },
[DELETE_FAST] = { true, INSTR_FMT_IB },
[MAKE_CELL] = { true, INSTR_FMT_IB },
[DELETE_DEREF] = { true, INSTR_FMT_IB },
[LOAD_CLASSDEREF] = { true, INSTR_FMT_IB },
[LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB },
[LOAD_DEREF] = { true, INSTR_FMT_IB },
[STORE_DEREF] = { true, INSTR_FMT_IB },
[COPY_FREE_VARS] = { true, INSTR_FMT_IB },

View file

@ -86,8 +86,8 @@ static void *opcode_targets[256] = {
&&TARGET_LOAD_CONST__LOAD_FAST,
&&TARGET_SETUP_ANNOTATIONS,
&&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_LOAD_LOCALS,
&&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_POP_EXCEPT,
&&TARGET_STORE_NAME,
&&TARGET_DELETE_NAME,
@ -110,9 +110,9 @@ static void *opcode_targets[256] = {
&&TARGET_IMPORT_NAME,
&&TARGET_IMPORT_FROM,
&&TARGET_JUMP_FORWARD,
&&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT,
&&TARGET_POP_JUMP_IF_FALSE,
&&TARGET_POP_JUMP_IF_TRUE,
&&TARGET_LOAD_GLOBAL,
@ -147,7 +147,7 @@ static void *opcode_targets[256] = {
&&TARGET_LIST_APPEND,
&&TARGET_SET_ADD,
&&TARGET_MAP_ADD,
&&TARGET_LOAD_CLASSDEREF,
&&TARGET_STORE_ATTR_SLOT,
&&TARGET_COPY_FREE_VARS,
&&TARGET_YIELD_VALUE,
&&TARGET_RESUME,
@ -174,8 +174,8 @@ static void *opcode_targets[256] = {
&&TARGET_KW_NAMES,
&&TARGET_CALL_INTRINSIC_1,
&&TARGET_CALL_INTRINSIC_2,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_LOAD_FROM_DICT_OR_GLOBALS,
&&TARGET_LOAD_FROM_DICT_OR_DEREF,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,

View file

@ -26,6 +26,7 @@
#include "pycore_sysmodule.h" // _PySys_ClearAuditHooks()
#include "pycore_traceback.h" // _Py_DumpTracebackThreads()
#include "pycore_typeobject.h" // _PyTypes_InitTypes()
#include "pycore_typevarobject.h" // _Py_clear_generic_types()
#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
#include "opcode.h"
@ -1698,6 +1699,7 @@ finalize_interp_clear(PyThreadState *tstate)
int is_main_interp = _Py_IsMainInterpreter(tstate->interp);
_PyExc_ClearExceptionGroupType(tstate->interp);
_Py_clear_generic_types(tstate->interp);
/* Clear interpreter state and all thread states */
_PyInterpreterState_Clear(tstate);

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,