Skip to content

Commit 61599a4

Browse files
bpo-24612: Improve syntax error for 'not' after an operator (GH-28170)
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
1 parent 771902c commit 61599a4

File tree

4 files changed

+1022
-594
lines changed

4 files changed

+1022
-594
lines changed

Grammar/python.gram

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ bitwise_and[expr_ty]:
778778
shift_expr[expr_ty]:
779779
| a=shift_expr '<<' b=sum { _PyAST_BinOp(a, LShift, b, EXTRA) }
780780
| a=shift_expr '>>' b=sum { _PyAST_BinOp(a, RShift, b, EXTRA) }
781+
| invalid_arithmetic
781782
| sum
782783

783784
# Arithmetic operators
@@ -794,6 +795,7 @@ term[expr_ty]:
794795
| a=term '//' b=factor { _PyAST_BinOp(a, FloorDiv, b, EXTRA) }
795796
| a=term '%' b=factor { _PyAST_BinOp(a, Mod, b, EXTRA) }
796797
| a=term '@' b=factor { CHECK_VERSION(expr_ty, 5, "The '@' operator is", _PyAST_BinOp(a, MatMult, b, EXTRA)) }
798+
| invalid_factor
797799
| factor
798800

799801
factor[expr_ty] (memo):
@@ -1415,3 +1417,8 @@ invalid_replacement_field:
14151417
invalid_conversion_character:
14161418
| '!' &(':' | '}') { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: missing conversion character") }
14171419
| '!' !NAME { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: invalid conversion character") }
1420+
1421+
invalid_arithmetic:
1422+
| sum ('+'|'-'|'*'|'/'|'%'|'//'|'@') a='not' b=inversion { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "'not' after an operator must be parenthesized") }
1423+
invalid_factor:
1424+
| ('+' | '-' | '~') a='not' b=factor { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "'not' after an operator must be parenthesized") }

Lib/test/test_syntax.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,49 @@
17121712
Traceback (most recent call last):
17131713
SyntaxError: only single target (not list) can be annotated
17141714
1715+
# 'not' after operators:
1716+
1717+
>>> 3 + not 3
1718+
Traceback (most recent call last):
1719+
SyntaxError: 'not' after an operator must be parenthesized
1720+
1721+
>>> 3 * not 3
1722+
Traceback (most recent call last):
1723+
SyntaxError: 'not' after an operator must be parenthesized
1724+
1725+
>>> + not 3
1726+
Traceback (most recent call last):
1727+
SyntaxError: 'not' after an operator must be parenthesized
1728+
1729+
>>> - not 3
1730+
Traceback (most recent call last):
1731+
SyntaxError: 'not' after an operator must be parenthesized
1732+
1733+
>>> ~ not 3
1734+
Traceback (most recent call last):
1735+
SyntaxError: 'not' after an operator must be parenthesized
1736+
1737+
>>> 3 + - not 3
1738+
Traceback (most recent call last):
1739+
SyntaxError: 'not' after an operator must be parenthesized
1740+
1741+
>>> 3 + not -1
1742+
Traceback (most recent call last):
1743+
SyntaxError: 'not' after an operator must be parenthesized
1744+
1745+
# Check that we don't introduce misleading errors
1746+
>>> not 1 */ 2
1747+
Traceback (most recent call last):
1748+
SyntaxError: invalid syntax
1749+
1750+
>>> not 1 +
1751+
Traceback (most recent call last):
1752+
SyntaxError: invalid syntax
1753+
1754+
>>> not + 1 +
1755+
Traceback (most recent call last):
1756+
SyntaxError: invalid syntax
1757+
17151758
Corner-cases that used to fail to raise the correct error:
17161759
17171760
>>> def f(*, x=lambda __debug__:0): pass
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve the :exc:`SyntaxError` that happens when 'not' appears after an
2+
operator. Patch by Pablo Galindo

0 commit comments

Comments
 (0)