summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2024-06-17 15:01:49 (GMT)
committerGitHub <noreply@github.com>2024-06-17 15:01:49 (GMT)
commit7c47f93dff878bdc43f5162dd878cbb375711570 (patch)
tree7b02b412d2bc0f718d9df2912fa0b6cd66205de1 /Python
parent03b89e3a3d155a06827f58d51238a731d8800cc9 (diff)
downloadcpython-7c47f93dff878bdc43f5162dd878cbb375711570.zip
cpython-7c47f93dff878bdc43f5162dd878cbb375711570.tar.gz
cpython-7c47f93dff878bdc43f5162dd878cbb375711570.tar.bz2
[3.13] gh-119933: Improve ``SyntaxError`` message for invalid type parameters expressions (GH-119976) (#120641)
(cherry picked from commit 4bf17c381fb7b465f0f26aecb94a6c54cf9be2d3) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Diffstat (limited to 'Python')
-rw-r--r--Python/symtable.c80
1 files changed, 54 insertions, 26 deletions
diff --git a/Python/symtable.c b/Python/symtable.c
index 35c1e4a..65dcf67 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -58,13 +58,13 @@
#define ANNOTATION_NOT_ALLOWED \
"%s cannot be used within an annotation"
-#define TYPEVAR_BOUND_NOT_ALLOWED \
-"%s cannot be used within a TypeVar bound"
+#define EXPR_NOT_ALLOWED_IN_TYPE_VARIABLE \
+"%s cannot be used within %s"
-#define TYPEALIAS_NOT_ALLOWED \
+#define EXPR_NOT_ALLOWED_IN_TYPE_ALIAS \
"%s cannot be used within a type alias"
-#define TYPEPARAM_NOT_ALLOWED \
+#define EXPR_NOT_ALLOWED_IN_TYPE_PARAMETERS \
"%s cannot be used within the definition of a generic"
#define DUPLICATE_TYPE_PARAM \
@@ -106,6 +106,8 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
ste->ste_mangled_names = NULL;
ste->ste_type = block;
+ ste->ste_scope_info = NULL;
+
ste->ste_nested = 0;
ste->ste_free = 0;
ste->ste_varargs = 0;
@@ -265,9 +267,9 @@ static void _dump_symtable(PySTEntryObject* ste, PyObject* prefix)
case ClassBlock: blocktype = "ClassBlock"; break;
case ModuleBlock: blocktype = "ModuleBlock"; break;
case AnnotationBlock: blocktype = "AnnotationBlock"; break;
- case TypeVarBoundBlock: blocktype = "TypeVarBoundBlock"; break;
+ case TypeVariableBlock: blocktype = "TypeVariableBlock"; break;
case TypeAliasBlock: blocktype = "TypeAliasBlock"; break;
- case TypeParamBlock: blocktype = "TypeParamBlock"; break;
+ case TypeParametersBlock: blocktype = "TypeParametersBlock"; break;
}
const char *comptype = "";
switch (ste->ste_comprehension) {
@@ -525,9 +527,9 @@ int
_PyST_IsFunctionLike(PySTEntryObject *ste)
{
return ste->ste_type == FunctionBlock
- || ste->ste_type == TypeVarBoundBlock
+ || ste->ste_type == TypeVariableBlock
|| ste->ste_type == TypeAliasBlock
- || ste->ste_type == TypeParamBlock;
+ || ste->ste_type == TypeParametersBlock;
}
static int
@@ -1494,7 +1496,7 @@ symtable_enter_type_param_block(struct symtable *st, identifier name,
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,
+ if(!symtable_enter_block(st, name, TypeParametersBlock, ast, lineno,
col_offset, end_lineno, end_col_offset)) {
return 0;
}
@@ -2069,20 +2071,20 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)
}
/* Disallow usage in ClassBlock and type scopes */
if (ste->ste_type == ClassBlock ||
- ste->ste_type == TypeParamBlock ||
+ ste->ste_type == TypeParametersBlock ||
ste->ste_type == TypeAliasBlock ||
- ste->ste_type == TypeVarBoundBlock) {
+ ste->ste_type == TypeVariableBlock) {
switch (ste->ste_type) {
case ClassBlock:
PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_CLASS);
break;
- case TypeParamBlock:
+ case TypeParametersBlock:
PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEPARAM);
break;
case TypeAliasBlock:
PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEALIAS);
break;
- case TypeVarBoundBlock:
+ case TypeVariableBlock:
PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEVAR_BOUND);
break;
default:
@@ -2288,19 +2290,27 @@ 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)
+symtable_visit_type_param_bound_or_default(
+ struct symtable *st, expr_ty e, identifier name,
+ void *key, const char *ste_scope_info)
{
if (e) {
int is_in_class = st->st_cur->ste_can_see_class_scope;
- if (!symtable_enter_block(st, name, TypeVarBoundBlock, key, LOCATION(e)))
+ if (!symtable_enter_block(st, name, TypeVariableBlock, 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);
}
+
+ assert(ste_scope_info != NULL);
+ st->st_cur->ste_scope_info = ste_scope_info;
VISIT(st, expr, e);
- if (!symtable_exit_block(st))
+
+ if (!symtable_exit_block(st)) {
return 0;
+ }
}
return 1;
}
@@ -2318,6 +2328,12 @@ symtable_visit_type_param(struct symtable *st, type_param_ty tp)
if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
VISIT_QUIT(st, 0);
+ const char *ste_scope_info = NULL;
+ const expr_ty bound = tp->v.TypeVar.bound;
+ if (bound != NULL) {
+ ste_scope_info = bound->kind == Tuple_kind ? "a TypeVar constraint" : "a TypeVar bound";
+ }
+
// 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
@@ -2325,11 +2341,12 @@ symtable_visit_type_param(struct symtable *st, type_param_ty tp)
// 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)) {
+ (void *)tp, ste_scope_info)) {
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))) {
+ (void *)((uintptr_t)tp + 1), "a TypeVar default")) {
VISIT_QUIT(st, 0);
}
break;
@@ -2337,8 +2354,9 @@ symtable_visit_type_param(struct symtable *st, type_param_ty 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)) {
+ (void *)tp, "a TypeVarTuple default")) {
VISIT_QUIT(st, 0);
}
break;
@@ -2346,8 +2364,9 @@ symtable_visit_type_param(struct symtable *st, type_param_ty 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)) {
+ (void *)tp, "a ParamSpec default")) {
VISIT_QUIT(st, 0);
}
break;
@@ -2729,12 +2748,21 @@ symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_t
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 if (type == TypeVariableBlock) {
+ const char *info = st->st_cur->ste_scope_info;
+ assert(info != NULL); // e.g., info == "a ParamSpec default"
+ PyErr_Format(PyExc_SyntaxError, EXPR_NOT_ALLOWED_IN_TYPE_VARIABLE, name, info);
+ }
+ else if (type == TypeAliasBlock) {
+ // for now, we do not have any extra information
+ assert(st->st_cur->ste_scope_info == NULL);
+ PyErr_Format(PyExc_SyntaxError, EXPR_NOT_ALLOWED_IN_TYPE_ALIAS, name);
+ }
+ else if (type == TypeParametersBlock) {
+ // for now, we do not have any extra information
+ assert(st->st_cur->ste_scope_info == NULL);
+ PyErr_Format(PyExc_SyntaxError, EXPR_NOT_ALLOWED_IN_TYPE_PARAMETERS, name);
+ }
else
return 1;