mirror of
https://github.com/python/cpython.git
synced 2025-07-19 09:15:34 +00:00
gh-116126: Implement PEP 696 (#116129)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
This commit is contained in:
parent
852263e108
commit
ca269e58c2
28 changed files with 1924 additions and 623 deletions
178
Python/Python-ast.c
generated
178
Python/Python-ast.c
generated
|
@ -203,6 +203,7 @@ void _PyAST_Fini(PyInterpreterState *interp)
|
|||
Py_CLEAR(state->conversion);
|
||||
Py_CLEAR(state->ctx);
|
||||
Py_CLEAR(state->decorator_list);
|
||||
Py_CLEAR(state->default_value);
|
||||
Py_CLEAR(state->defaults);
|
||||
Py_CLEAR(state->elt);
|
||||
Py_CLEAR(state->elts);
|
||||
|
@ -311,6 +312,7 @@ static int init_identifiers(struct ast_state *state)
|
|||
if ((state->conversion = PyUnicode_InternFromString("conversion")) == NULL) return -1;
|
||||
if ((state->ctx = PyUnicode_InternFromString("ctx")) == NULL) return -1;
|
||||
if ((state->decorator_list = PyUnicode_InternFromString("decorator_list")) == NULL) return -1;
|
||||
if ((state->default_value = PyUnicode_InternFromString("default_value")) == NULL) return -1;
|
||||
if ((state->defaults = PyUnicode_InternFromString("defaults")) == NULL) return -1;
|
||||
if ((state->elt = PyUnicode_InternFromString("elt")) == NULL) return -1;
|
||||
if ((state->elts = PyUnicode_InternFromString("elts")) == NULL) return -1;
|
||||
|
@ -809,12 +811,15 @@ static PyObject* ast2obj_type_param(struct ast_state *state, struct validator
|
|||
static const char * const TypeVar_fields[]={
|
||||
"name",
|
||||
"bound",
|
||||
"default_value",
|
||||
};
|
||||
static const char * const ParamSpec_fields[]={
|
||||
"name",
|
||||
"default_value",
|
||||
};
|
||||
static const char * const TypeVarTuple_fields[]={
|
||||
"name",
|
||||
"default_value",
|
||||
};
|
||||
|
||||
|
||||
|
@ -4913,6 +4918,22 @@ add_ast_annotations(struct ast_state *state)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
PyObject *type = state->expr_type;
|
||||
type = _Py_union_type_or(type, Py_None);
|
||||
cond = type != NULL;
|
||||
if (!cond) {
|
||||
Py_DECREF(TypeVar_annotations);
|
||||
return 0;
|
||||
}
|
||||
cond = PyDict_SetItemString(TypeVar_annotations, "default_value", type)
|
||||
== 0;
|
||||
Py_DECREF(type);
|
||||
if (!cond) {
|
||||
Py_DECREF(TypeVar_annotations);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cond = PyObject_SetAttrString(state->TypeVar_type, "_field_types",
|
||||
TypeVar_annotations) == 0;
|
||||
if (!cond) {
|
||||
|
@ -4938,6 +4959,22 @@ add_ast_annotations(struct ast_state *state)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
PyObject *type = state->expr_type;
|
||||
type = _Py_union_type_or(type, Py_None);
|
||||
cond = type != NULL;
|
||||
if (!cond) {
|
||||
Py_DECREF(ParamSpec_annotations);
|
||||
return 0;
|
||||
}
|
||||
cond = PyDict_SetItemString(ParamSpec_annotations, "default_value",
|
||||
type) == 0;
|
||||
Py_DECREF(type);
|
||||
if (!cond) {
|
||||
Py_DECREF(ParamSpec_annotations);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cond = PyObject_SetAttrString(state->ParamSpec_type, "_field_types",
|
||||
ParamSpec_annotations) == 0;
|
||||
if (!cond) {
|
||||
|
@ -4964,6 +5001,22 @@ add_ast_annotations(struct ast_state *state)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
PyObject *type = state->expr_type;
|
||||
type = _Py_union_type_or(type, Py_None);
|
||||
cond = type != NULL;
|
||||
if (!cond) {
|
||||
Py_DECREF(TypeVarTuple_annotations);
|
||||
return 0;
|
||||
}
|
||||
cond = PyDict_SetItemString(TypeVarTuple_annotations, "default_value",
|
||||
type) == 0;
|
||||
Py_DECREF(type);
|
||||
if (!cond) {
|
||||
Py_DECREF(TypeVarTuple_annotations);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cond = PyObject_SetAttrString(state->TypeVarTuple_type, "_field_types",
|
||||
TypeVarTuple_annotations) == 0;
|
||||
if (!cond) {
|
||||
|
@ -6243,28 +6296,37 @@ init_types(struct ast_state *state)
|
|||
if (!state->TypeIgnore_type) return -1;
|
||||
state->type_param_type = make_type(state, "type_param", state->AST_type,
|
||||
NULL, 0,
|
||||
"type_param = TypeVar(identifier name, expr? bound)\n"
|
||||
" | ParamSpec(identifier name)\n"
|
||||
" | TypeVarTuple(identifier name)");
|
||||
"type_param = TypeVar(identifier name, expr? bound, expr? default_value)\n"
|
||||
" | ParamSpec(identifier name, expr? default_value)\n"
|
||||
" | TypeVarTuple(identifier name, expr? default_value)");
|
||||
if (!state->type_param_type) return -1;
|
||||
if (add_attributes(state, state->type_param_type, type_param_attributes, 4)
|
||||
< 0) return -1;
|
||||
state->TypeVar_type = make_type(state, "TypeVar", state->type_param_type,
|
||||
TypeVar_fields, 2,
|
||||
"TypeVar(identifier name, expr? bound)");
|
||||
TypeVar_fields, 3,
|
||||
"TypeVar(identifier name, expr? bound, expr? default_value)");
|
||||
if (!state->TypeVar_type) return -1;
|
||||
if (PyObject_SetAttr(state->TypeVar_type, state->bound, Py_None) == -1)
|
||||
return -1;
|
||||
if (PyObject_SetAttr(state->TypeVar_type, state->default_value, Py_None) ==
|
||||
-1)
|
||||
return -1;
|
||||
state->ParamSpec_type = make_type(state, "ParamSpec",
|
||||
state->type_param_type, ParamSpec_fields,
|
||||
1,
|
||||
"ParamSpec(identifier name)");
|
||||
2,
|
||||
"ParamSpec(identifier name, expr? default_value)");
|
||||
if (!state->ParamSpec_type) return -1;
|
||||
if (PyObject_SetAttr(state->ParamSpec_type, state->default_value, Py_None)
|
||||
== -1)
|
||||
return -1;
|
||||
state->TypeVarTuple_type = make_type(state, "TypeVarTuple",
|
||||
state->type_param_type,
|
||||
TypeVarTuple_fields, 1,
|
||||
"TypeVarTuple(identifier name)");
|
||||
TypeVarTuple_fields, 2,
|
||||
"TypeVarTuple(identifier name, expr? default_value)");
|
||||
if (!state->TypeVarTuple_type) return -1;
|
||||
if (PyObject_SetAttr(state->TypeVarTuple_type, state->default_value,
|
||||
Py_None) == -1)
|
||||
return -1;
|
||||
|
||||
if (!add_ast_annotations(state)) {
|
||||
return -1;
|
||||
|
@ -8055,8 +8117,9 @@ _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena)
|
|||
}
|
||||
|
||||
type_param_ty
|
||||
_PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int
|
||||
end_lineno, int end_col_offset, PyArena *arena)
|
||||
_PyAST_TypeVar(identifier name, expr_ty bound, expr_ty default_value, int
|
||||
lineno, int col_offset, int end_lineno, int end_col_offset,
|
||||
PyArena *arena)
|
||||
{
|
||||
type_param_ty p;
|
||||
if (!name) {
|
||||
|
@ -8070,6 +8133,7 @@ _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int
|
|||
p->kind = TypeVar_kind;
|
||||
p->v.TypeVar.name = name;
|
||||
p->v.TypeVar.bound = bound;
|
||||
p->v.TypeVar.default_value = default_value;
|
||||
p->lineno = lineno;
|
||||
p->col_offset = col_offset;
|
||||
p->end_lineno = end_lineno;
|
||||
|
@ -8078,8 +8142,8 @@ _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int
|
|||
}
|
||||
|
||||
type_param_ty
|
||||
_PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno,
|
||||
int end_col_offset, PyArena *arena)
|
||||
_PyAST_ParamSpec(identifier name, expr_ty default_value, int lineno, int
|
||||
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
|
||||
{
|
||||
type_param_ty p;
|
||||
if (!name) {
|
||||
|
@ -8092,6 +8156,7 @@ _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno,
|
|||
return NULL;
|
||||
p->kind = ParamSpec_kind;
|
||||
p->v.ParamSpec.name = name;
|
||||
p->v.ParamSpec.default_value = default_value;
|
||||
p->lineno = lineno;
|
||||
p->col_offset = col_offset;
|
||||
p->end_lineno = end_lineno;
|
||||
|
@ -8100,8 +8165,9 @@ _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno,
|
|||
}
|
||||
|
||||
type_param_ty
|
||||
_PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int
|
||||
end_lineno, int end_col_offset, PyArena *arena)
|
||||
_PyAST_TypeVarTuple(identifier name, expr_ty default_value, int lineno, int
|
||||
col_offset, int end_lineno, int end_col_offset, PyArena
|
||||
*arena)
|
||||
{
|
||||
type_param_ty p;
|
||||
if (!name) {
|
||||
|
@ -8114,6 +8180,7 @@ _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int
|
|||
return NULL;
|
||||
p->kind = TypeVarTuple_kind;
|
||||
p->v.TypeVarTuple.name = name;
|
||||
p->v.TypeVarTuple.default_value = default_value;
|
||||
p->lineno = lineno;
|
||||
p->col_offset = col_offset;
|
||||
p->end_lineno = end_lineno;
|
||||
|
@ -10079,6 +10146,11 @@ ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
|
|||
if (PyObject_SetAttr(result, state->bound, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_expr(state, vstate, o->v.TypeVar.default_value);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->default_value, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case ParamSpec_kind:
|
||||
tp = (PyTypeObject *)state->ParamSpec_type;
|
||||
|
@ -10089,6 +10161,11 @@ ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
|
|||
if (PyObject_SetAttr(result, state->name, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_expr(state, vstate, o->v.ParamSpec.default_value);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->default_value, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case TypeVarTuple_kind:
|
||||
tp = (PyTypeObject *)state->TypeVarTuple_type;
|
||||
|
@ -10099,6 +10176,11 @@ ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
|
|||
if (PyObject_SetAttr(result, state->name, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_expr(state, vstate, o->v.TypeVarTuple.default_value);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->default_value, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
}
|
||||
value = ast2obj_int(state, vstate, o->lineno);
|
||||
|
@ -16935,6 +17017,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
|
|||
if (isinstance) {
|
||||
identifier name;
|
||||
expr_ty bound;
|
||||
expr_ty default_value;
|
||||
|
||||
if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) {
|
||||
return -1;
|
||||
|
@ -16970,8 +17053,25 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
|
|||
if (res != 0) goto failed;
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_TypeVar(name, bound, lineno, col_offset, end_lineno,
|
||||
end_col_offset, arena);
|
||||
if (PyObject_GetOptionalAttr(obj, state->default_value, &tmp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (tmp == NULL || tmp == Py_None) {
|
||||
Py_CLEAR(tmp);
|
||||
default_value = NULL;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
if (_Py_EnterRecursiveCall(" while traversing 'TypeVar' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_expr(state, tmp, &default_value, arena);
|
||||
_Py_LeaveRecursiveCall();
|
||||
if (res != 0) goto failed;
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_TypeVar(name, bound, default_value, lineno, col_offset,
|
||||
end_lineno, end_col_offset, arena);
|
||||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
|
@ -16982,6 +17082,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
|
|||
}
|
||||
if (isinstance) {
|
||||
identifier name;
|
||||
expr_ty default_value;
|
||||
|
||||
if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) {
|
||||
return -1;
|
||||
|
@ -17000,8 +17101,25 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
|
|||
if (res != 0) goto failed;
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_ParamSpec(name, lineno, col_offset, end_lineno,
|
||||
end_col_offset, arena);
|
||||
if (PyObject_GetOptionalAttr(obj, state->default_value, &tmp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (tmp == NULL || tmp == Py_None) {
|
||||
Py_CLEAR(tmp);
|
||||
default_value = NULL;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
if (_Py_EnterRecursiveCall(" while traversing 'ParamSpec' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_expr(state, tmp, &default_value, arena);
|
||||
_Py_LeaveRecursiveCall();
|
||||
if (res != 0) goto failed;
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_ParamSpec(name, default_value, lineno, col_offset,
|
||||
end_lineno, end_col_offset, arena);
|
||||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
|
@ -17012,6 +17130,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
|
|||
}
|
||||
if (isinstance) {
|
||||
identifier name;
|
||||
expr_ty default_value;
|
||||
|
||||
if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) {
|
||||
return -1;
|
||||
|
@ -17030,8 +17149,25 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
|
|||
if (res != 0) goto failed;
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_TypeVarTuple(name, lineno, col_offset, end_lineno,
|
||||
end_col_offset, arena);
|
||||
if (PyObject_GetOptionalAttr(obj, state->default_value, &tmp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (tmp == NULL || tmp == Py_None) {
|
||||
Py_CLEAR(tmp);
|
||||
default_value = NULL;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
if (_Py_EnterRecursiveCall(" while traversing 'TypeVarTuple' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_expr(state, tmp, &default_value, arena);
|
||||
_Py_LeaveRecursiveCall();
|
||||
if (res != 0) goto failed;
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_TypeVarTuple(name, default_value, lineno, col_offset,
|
||||
end_lineno, end_col_offset, arena);
|
||||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
|
|
12
Python/ast.c
12
Python/ast.c
|
@ -1011,13 +1011,19 @@ validate_typeparam(struct validator *state, type_param_ty tp)
|
|||
case TypeVar_kind:
|
||||
ret = validate_name(tp->v.TypeVar.name) &&
|
||||
(!tp->v.TypeVar.bound ||
|
||||
validate_expr(state, tp->v.TypeVar.bound, Load));
|
||||
validate_expr(state, tp->v.TypeVar.bound, Load)) &&
|
||||
(!tp->v.TypeVar.default_value ||
|
||||
validate_expr(state, tp->v.TypeVar.default_value, Load));
|
||||
break;
|
||||
case ParamSpec_kind:
|
||||
ret = validate_name(tp->v.ParamSpec.name);
|
||||
ret = validate_name(tp->v.ParamSpec.name) &&
|
||||
(!tp->v.ParamSpec.default_value ||
|
||||
validate_expr(state, tp->v.ParamSpec.default_value, Load));
|
||||
break;
|
||||
case TypeVarTuple_kind:
|
||||
ret = validate_name(tp->v.TypeVarTuple.name);
|
||||
ret = validate_name(tp->v.TypeVarTuple.name) &&
|
||||
(!tp->v.TypeVarTuple.default_value ||
|
||||
validate_expr(state, tp->v.TypeVarTuple.default_value, Load));
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -2116,6 +2116,36 @@ wrap_in_stopiteration_handler(struct compiler *c)
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
|
||||
identifier name, void *key,
|
||||
bool allow_starred)
|
||||
{
|
||||
if (compiler_enter_scope(c, name, COMPILER_SCOPE_TYPEPARAMS,
|
||||
key, e->lineno) == -1) {
|
||||
return ERROR;
|
||||
}
|
||||
if (allow_starred && e->kind == Starred_kind) {
|
||||
VISIT(c, expr, e->v.Starred.value);
|
||||
ADDOP_I(c, LOC(e), UNPACK_SEQUENCE, (Py_ssize_t)1);
|
||||
}
|
||||
else {
|
||||
VISIT(c, expr, e);
|
||||
}
|
||||
ADDOP_IN_SCOPE(c, LOC(e), RETURN_VALUE);
|
||||
PyCodeObject *co = optimize_and_assemble(c, 1);
|
||||
compiler_exit_scope(c);
|
||||
if (co == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
if (compiler_make_closure(c, LOC(e), co, 0) < 0) {
|
||||
Py_DECREF(co);
|
||||
return ERROR;
|
||||
}
|
||||
Py_DECREF(co);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
|
||||
{
|
||||
|
@ -2123,6 +2153,7 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
|
|||
return SUCCESS;
|
||||
}
|
||||
Py_ssize_t n = asdl_seq_LEN(type_params);
|
||||
bool seen_default = false;
|
||||
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
type_param_ty typeparam = asdl_seq_GET(type_params, i);
|
||||
|
@ -2132,22 +2163,10 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
|
|||
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) {
|
||||
if (compiler_type_param_bound_or_default(c, bound, typeparam->v.TypeVar.name,
|
||||
(void *)typeparam, false) < 0) {
|
||||
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
|
||||
|
@ -2157,18 +2176,60 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
|
|||
else {
|
||||
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVAR);
|
||||
}
|
||||
if (typeparam->v.TypeVar.default_value) {
|
||||
seen_default = true;
|
||||
expr_ty default_ = typeparam->v.TypeVar.default_value;
|
||||
if (compiler_type_param_bound_or_default(c, default_, typeparam->v.TypeVar.name,
|
||||
(void *)((uintptr_t)typeparam + 1), false) < 0) {
|
||||
return ERROR;
|
||||
}
|
||||
ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT);
|
||||
}
|
||||
else if (seen_default) {
|
||||
return compiler_error(c, loc, "non-default type parameter '%U' "
|
||||
"follows default type parameter",
|
||||
typeparam->v.TypeVar.name);
|
||||
}
|
||||
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);
|
||||
if (typeparam->v.TypeVarTuple.default_value) {
|
||||
expr_ty default_ = typeparam->v.TypeVarTuple.default_value;
|
||||
if (compiler_type_param_bound_or_default(c, default_, typeparam->v.TypeVarTuple.name,
|
||||
(void *)typeparam, true) < 0) {
|
||||
return ERROR;
|
||||
}
|
||||
ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT);
|
||||
seen_default = true;
|
||||
}
|
||||
else if (seen_default) {
|
||||
return compiler_error(c, loc, "non-default type parameter '%U' "
|
||||
"follows default type parameter",
|
||||
typeparam->v.TypeVarTuple.name);
|
||||
}
|
||||
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);
|
||||
if (typeparam->v.ParamSpec.default_value) {
|
||||
expr_ty default_ = typeparam->v.ParamSpec.default_value;
|
||||
if (compiler_type_param_bound_or_default(c, default_, typeparam->v.ParamSpec.name,
|
||||
(void *)typeparam, false) < 0) {
|
||||
return ERROR;
|
||||
}
|
||||
ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT);
|
||||
seen_default = true;
|
||||
}
|
||||
else if (seen_default) {
|
||||
return compiler_error(c, loc, "non-default type parameter '%U' "
|
||||
"follows default type parameter",
|
||||
typeparam->v.ParamSpec.name);
|
||||
}
|
||||
ADDOP_I(c, loc, COPY, 1);
|
||||
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.ParamSpec.name, Store));
|
||||
break;
|
||||
|
|
|
@ -265,6 +265,7 @@ _PyIntrinsics_BinaryFunctions[] = {
|
|||
INTRINSIC_FUNC_ENTRY(INTRINSIC_TYPEVAR_WITH_BOUND, make_typevar_with_bound)
|
||||
INTRINSIC_FUNC_ENTRY(INTRINSIC_TYPEVAR_WITH_CONSTRAINTS, make_typevar_with_constraints)
|
||||
INTRINSIC_FUNC_ENTRY(INTRINSIC_SET_FUNCTION_TYPE_PARAMS, _Py_set_function_type_params)
|
||||
INTRINSIC_FUNC_ENTRY(INTRINSIC_SET_TYPEPARAM_DEFAULT, _Py_set_typeparam_default)
|
||||
};
|
||||
|
||||
#undef INTRINSIC_FUNC_ENTRY
|
||||
|
|
|
@ -2275,6 +2275,24 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
|
|||
VISIT_QUIT(st, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
symtable_visit_type_param_bound_or_default(struct symtable *st, expr_ty e, identifier name, void *key)
|
||||
{
|
||||
if (e) {
|
||||
int is_in_class = st->st_cur->ste_can_see_class_scope;
|
||||
if (!symtable_enter_block(st, name, TypeVarBoundBlock, key, LOCATION(e)))
|
||||
return 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(e))) {
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
VISIT(st, expr, e);
|
||||
if (!symtable_exit_block(st))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
symtable_visit_type_param(struct symtable *st, type_param_ty tp)
|
||||
{
|
||||
|
@ -2287,28 +2305,39 @@ symtable_visit_type_param(struct symtable *st, type_param_ty tp)
|
|||
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);
|
||||
|
||||
// We must use a different key for the bound and default. The obvious choice would be to
|
||||
// use the .bound and .default_value pointers, but that fails when the expression immediately
|
||||
// inside the bound or default is a comprehension: we would reuse the same key for
|
||||
// the comprehension scope. Therefore, use the address + 1 as the second key.
|
||||
// The only requirement for the key is that it is unique and it matches the logic in
|
||||
// compile.c where the scope is retrieved.
|
||||
if (!symtable_visit_type_param_bound_or_default(st, tp->v.TypeVar.bound, tp->v.TypeVar.name,
|
||||
(void *)tp)) {
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
if (!symtable_visit_type_param_bound_or_default(st, tp->v.TypeVar.default_value, tp->v.TypeVar.name,
|
||||
(void *)((uintptr_t)tp + 1))) {
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
break;
|
||||
case TypeVarTuple_kind:
|
||||
if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
|
||||
if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) {
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
if (!symtable_visit_type_param_bound_or_default(st, tp->v.TypeVarTuple.default_value, tp->v.TypeVarTuple.name,
|
||||
(void *)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)))
|
||||
if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) {
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
if (!symtable_visit_type_param_bound_or_default(st, tp->v.ParamSpec.default_value, tp->v.ParamSpec.name,
|
||||
(void *)tp)) {
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
VISIT_QUIT(st, 1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue