summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2024-05-03 13:17:32 (GMT)
committerGitHub <noreply@github.com>2024-05-03 13:17:32 (GMT)
commitca269e58c290be8ca11bb728004ea842d9f85e3a (patch)
tree7af6ddffd5195536343780ef7aeb338ef460501e /Python
parent852263e1086748492602a90347ecc0a3925e1dda (diff)
downloadcpython-ca269e58c290be8ca11bb728004ea842d9f85e3a.zip
cpython-ca269e58c290be8ca11bb728004ea842d9f85e3a.tar.gz
cpython-ca269e58c290be8ca11bb728004ea842d9f85e3a.tar.bz2
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>
Diffstat (limited to 'Python')
-rw-r--r--Python/Python-ast.c178
-rw-r--r--Python/ast.c12
-rw-r--r--Python/compile.c89
-rw-r--r--Python/intrinsics.c1
-rw-r--r--Python/symtable.c59
5 files changed, 286 insertions, 53 deletions
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 60b4626..cc7734e 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -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;
}
diff --git a/Python/ast.c b/Python/ast.c
index 71b09d8..1d1a48e 100644
--- a/Python/ast.c
+++ b/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;
diff --git a/Python/compile.c b/Python/compile.c
index feedd98..ec47af1 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2117,12 +2117,43 @@ wrap_in_stopiteration_handler(struct compiler *c)
}
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)
{
if (!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;
diff --git a/Python/intrinsics.c b/Python/intrinsics.c
index d314697..5b10c3c 100644
--- a/Python/intrinsics.c
+++ b/Python/intrinsics.c
@@ -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
diff --git a/Python/symtable.c b/Python/symtable.c
index eecd159..2ec21a2 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -2276,6 +2276,24 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
}
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)
{
if (++st->recursion_depth > st->recursion_limit) {
@@ -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);