Skip to content

Commit 445c7fd

Browse files
committed
bpo-40334: Correctly identify invalid target in assignment errors
1 parent 4b972fa commit 445c7fd

File tree

6 files changed

+77
-15
lines changed

6 files changed

+77
-15
lines changed

Grammar/python.gram

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,10 @@ invalid_assignment:
641641
| a=expression ':' expression ['=' annotated_rhs] {
642642
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "illegal target for annotation") }
643643
| a=expression ('=' | augassign) (yield_expr | star_expressions) {
644-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot assign to %s", _PyPegen_get_expr_name(a)) }
644+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
645+
_PyPegen_get_invalid_target(a),
646+
"cannot assign to %s", _PyPegen_get_expr_name(_PyPegen_get_invalid_target(a))
647+
)}
645648
invalid_block:
646649
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
647650
invalid_comprehension:

Lib/test/test_foo.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import unittest
2+
import zoneinfo
3+
import tracemalloc
4+
5+
class Test(unittest.TestCase):
6+
def test_foo(self):
7+
# snapshot1 = tracemalloc.take_snapshot()
8+
zoneinfo.ZoneInfo.no_cache("America/Los_Angeles")
9+
# snapshot2 = tracemalloc.take_snapshot()
10+
# top_stats = snapshot2.compare_to(snapshot1, 'lineno')
11+
12+
# print("[ Top 10 differences ]")
13+
# for stat in top_stats[:10]:
14+
# print(stat)
15+
16+

Lib/test/test_syntax.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,30 +100,29 @@
100100
This test just checks a couple of cases rather than enumerating all of
101101
them.
102102
103-
# All of the following also produce different error messages with pegen
104-
# >>> (a, "b", c) = (1, 2, 3)
105-
# Traceback (most recent call last):
106-
# SyntaxError: cannot assign to literal
103+
>>> (a, "b", c) = (1, 2, 3)
104+
Traceback (most recent call last):
105+
SyntaxError: cannot assign to literal
107106
108-
# >>> (a, True, c) = (1, 2, 3)
109-
# Traceback (most recent call last):
110-
# SyntaxError: cannot assign to True
107+
>>> (a, True, c) = (1, 2, 3)
108+
Traceback (most recent call last):
109+
SyntaxError: cannot assign to True
111110
112111
>>> (a, __debug__, c) = (1, 2, 3)
113112
Traceback (most recent call last):
114113
SyntaxError: cannot assign to __debug__
115114
116-
# >>> (a, *True, c) = (1, 2, 3)
117-
# Traceback (most recent call last):
118-
# SyntaxError: cannot assign to True
115+
>>> (a, *True, c) = (1, 2, 3)
116+
Traceback (most recent call last):
117+
SyntaxError: cannot assign to True
119118
120119
>>> (a, *__debug__, c) = (1, 2, 3)
121120
Traceback (most recent call last):
122121
SyntaxError: cannot assign to __debug__
123122
124-
# >>> [a, b, c + 1] = [1, 2, 3]
125-
# Traceback (most recent call last):
126-
# SyntaxError: cannot assign to operator
123+
>>> [a, b, c + 1] = [1, 2, 3]
124+
Traceback (most recent call last):
125+
SyntaxError: cannot assign to operator
127126
128127
>>> a if 1 else b = 1
129128
Traceback (most recent call last):

Parser/pegen/parse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10853,7 +10853,7 @@ invalid_assignment_rule(Parser *p)
1085310853
(_tmp_129_var = _tmp_129_rule(p)) // yield_expr | star_expressions
1085410854
)
1085510855
{
10856-
_res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot assign to %s" , _PyPegen_get_expr_name ( a ) );
10856+
_res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( _PyPegen_get_invalid_target ( a ) , "cannot assign to %s" , _PyPegen_get_expr_name ( _PyPegen_get_invalid_target ( a ) ) );
1085710857
if (_res == NULL && PyErr_Occurred()) {
1085810858
p->error_indicator = 1;
1085910859
return NULL;

Parser/pegen/pegen.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,3 +2054,42 @@ _PyPegen_make_module(Parser *p, asdl_seq *a) {
20542054
}
20552055
return Module(a, type_ignores, p->arena);
20562056
}
2057+
2058+
// Error reporting helpers
2059+
2060+
expr_ty
2061+
_PyPegen_get_invalid_target(expr_ty e)
2062+
{
2063+
if (e == NULL) {
2064+
return NULL;
2065+
}
2066+
switch (e->kind) {
2067+
case List_kind: {
2068+
Py_ssize_t len = asdl_seq_LEN(e->v.List.elts);
2069+
for (Py_ssize_t i = 0; i < len; i++) {
2070+
expr_ty other = asdl_seq_GET(e->v.List.elts, i);
2071+
if (_PyPegen_get_invalid_target(other)) {
2072+
return other;
2073+
}
2074+
}
2075+
return NULL;
2076+
}
2077+
case Tuple_kind: {
2078+
Py_ssize_t len = asdl_seq_LEN(e->v.Tuple.elts);
2079+
for (Py_ssize_t i = 0; i < len; i++) {
2080+
expr_ty other = asdl_seq_GET(e->v.Tuple.elts, i);
2081+
expr_ty child = _PyPegen_get_invalid_target(other);
2082+
if (child != NULL) {
2083+
return child;
2084+
}
2085+
}
2086+
return NULL;
2087+
}
2088+
case Starred_kind:
2089+
return _PyPegen_get_invalid_target(e->v.Starred.value);
2090+
case Name_kind:
2091+
return NULL;
2092+
default:
2093+
return e;
2094+
}
2095+
}

Parser/pegen/pegen.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ void *_PyPegen_arguments_parsing_error(Parser *, expr_ty);
260260
int _PyPegen_check_barry_as_flufl(Parser *);
261261
mod_ty _PyPegen_make_module(Parser *, asdl_seq *);
262262

263+
// Error reporting helpers
264+
265+
expr_ty _PyPegen_get_invalid_target(expr_ty e);
266+
267+
263268
void *_PyPegen_parse(Parser *);
264269

265270
#endif

0 commit comments

Comments
 (0)