diff --git a/Grammar/python.gram b/Grammar/python.gram index 9f470949146..4915cc43e84 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -646,7 +646,7 @@ invalid_arguments: RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "Generator expression must be parenthesized") } | a=args ',' args { _PyPegen_arguments_parsing_error(p, a) } invalid_kwarg: - | a=expression '=' { + | expression a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION( a, "expression cannot contain assignment, perhaps you meant \"==\"?") } invalid_named_expression: diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 1bdd3f2ce59..e752ab72ccf 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -252,7 +252,7 @@ class ExceptionTests(unittest.TestCase): check('from __future__ import doesnt_exist', 1, 1) check('from __future__ import braces', 1, 1) check('x=1\nfrom __future__ import division', 2, 1) - check('foo(1=2)', 1, 5) + check('foo(1=2)', 1, 6) check('def f():\n x, y: int', 2, 3) check('[*x for x in xs]', 1, 2) check('foo(x for x in range(10), 100)', 1, 5) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 91ca1db43a7..d8255607dcf 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -802,6 +802,13 @@ class SyntaxTestCase(unittest.TestCase): else: self.fail("compile() did not raise SyntaxError") + def test_expression_with_assignment(self): + self._check_error( + "print(end1 + end2 = ' ')", + 'expression cannot contain assignment, perhaps you meant "=="?', + offset=19 + ) + def test_curly_brace_after_primary_raises_immediately(self): self._check_error("f{", "invalid syntax", mode="single") diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-13-15-23-09.bpo-30858.-f9G4z.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-13-15-23-09.bpo-30858.-f9G4z.rst new file mode 100644 index 00000000000..f2d06c3009c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-12-13-15-23-09.bpo-30858.-f9G4z.rst @@ -0,0 +1,2 @@ +Improve error location in expressions that contain assignments. Patch by +Pablo Galindo and Lysandros Nikolaou. diff --git a/Parser/parser.c b/Parser/parser.c index b6c04953c89..2559969f86e 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -14562,12 +14562,12 @@ invalid_kwarg_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_kwarg[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression '='")); - Token * _literal; - expr_ty a; + Token * a; + expr_ty expression_var; if ( - (a = expression_rule(p)) // expression + (expression_var = expression_rule(p)) // expression && - (_literal = _PyPegen_expect_token(p, 22)) // token='=' + (a = _PyPegen_expect_token(p, 22)) // token='=' ) { D(fprintf(stderr, "%*c+ invalid_kwarg[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression '='"));