Skip to content

gh-146495: Improve SyntaxError message for && and || operators#150906

Open
Aniketsy wants to merge 12 commits into
python:mainfrom
Aniketsy:fix-146495
Open

gh-146495: Improve SyntaxError message for && and || operators#150906
Aniketsy wants to merge 12 commits into
python:mainfrom
Aniketsy:fix-146495

Conversation

@Aniketsy

@Aniketsy Aniketsy commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

fixes #146495

@Aniketsy I would prefer that a parser expert takes care of that. This is likely a non-trivial change so to make it easier to review, it would be better if a core dev or someone familiar with the parser takes care of this.

As there was not any pr for this for long time, so i thought to give a try for this as @skirpichev have shared the patch towards fix. Hoping it does not create much pain to review for members. Thank you !

Comment thread Parser/pegen_errors.c Fixed
Comment thread Parser/pegen_errors.c Fixed

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea! Before it was:

Image

Comment thread Lib/test/test_syntax.py Outdated

@pablogsal pablogsal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @Aniketsy! Unfortunately this is not the correct approach for such an error message. See my comment below

Comment thread Parser/pegen_errors.c Outdated
@bedevere-app

bedevere-app Bot commented Jun 4, 2026

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@skirpichev skirpichev self-requested a review June 5, 2026 04:14

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. 👍

As I proposed in #151129 (comment), we can also add suggestions for <> ("not equal" in Pascal and Python 2), "=<", "=>" and "=!" (typo in "<=", ">=" and "!="), "===" ("is" in JavaScript and PHP).

@Aniketsy

Copy link
Copy Markdown
Contributor Author

LGTM. 👍

Thanks!

As I proposed in #151129 (comment), we can also add suggestions for <> ("not equal" in Pascal and Python 2), "=<", "=>" and "=!" (typo in "<=", ">=" and "!="), "===" ("is" in JavaScript and PHP).

I'd be happy to create a follow up PR or should i open issue and then link pr for this

@skirpichev

Copy link
Copy Markdown
Member

"===" ("is" in JavaScript and PHP).

And Mathematica.

I'd be happy to create a follow up PR or should i open issue and then link pr for this

Yes, please open a separate issue.

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Comment thread Misc/NEWS.d/next/Core_and_Builtins/2026-06-04-15-02-35.gh-issue-146495.wWRRvx.rst Outdated
…e-146495.wWRRvx.rst

Co-authored-by: sobolevn <mail@sobolevn.me>
@serhiy-storchaka

Copy link
Copy Markdown
Member

I'd be happy to create a follow up PR or should i open issue and then link pr for this

Up to you. You can also include them in this PR.

Comment thread Grammar/python.gram Outdated
skirpichev
skirpichev previously approved these changes Jun 12, 2026
Comment thread Lib/test/test_syntax.py Outdated
Comment thread Lib/test/test_syntax.py Outdated
Aniketsy and others added 2 commits June 12, 2026 09:01
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
@skirpichev skirpichev dismissed their stale review June 14, 2026 02:17

Second look.

@skirpichev

Copy link
Copy Markdown
Member

Sorry, this doesn't look acceptable for me:

>>> 1 & & 2
  File "<python-input-1>", line 1
    1 & & 2
      ^^^
SyntaxError: invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?

I think you should raise a different exception message only for cases, when '&&' or '||' could be interpreted as distinct tokens.

@Aniketsy

Copy link
Copy Markdown
Contributor Author

Sorry, this doesn't look acceptable for me:

>>> 1 & & 2
  File "<python-input-1>", line 1
    1 & & 2
      ^^^
SyntaxError: invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?

I think you should raise a different exception message only for cases, when '&&' or '||' could be interpreted as distinct tokens.

should we fall back to generic error message if we have gap between them ?

@skirpichev

Copy link
Copy Markdown
Member

should we fall back to generic error message if we have gap between them ?

Yes, I think so.

@serhiy-storchaka, @sobolevn ?

@Aniketsy

Copy link
Copy Markdown
Contributor Author

with this patch

aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ git diff Grammar/python.gram
diff --git a/Grammar/python.gram b/Grammar/python.gram
index c45e2f3a28..823af82397 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -1642,7 +1642,19 @@ invalid_type_params:
             "Type parameter list cannot be empty")}

 invalid_bitwise_and:
-    | a=bitwise_and b='&' c='&' { RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?") }
+    | a=bitwise_and b='&' c='&' {
+        (b->end_lineno == c->lineno)
+        ? ((b->end_col_offset == c->col_offset)
+            ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?")
+            : NULL)
+        : NULL
+    }

 invalid_bitwise_or:
-    | a=bitwise_or b='|' c='|' { RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax.  Maybe you meant 'or' or '|' instead of '||'?") }
+    | a=bitwise_or b='|' c='|' {
+        (b->end_lineno == c->lineno)
+        ? ((b->end_col_offset == c->col_offset)
+            ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax.  Maybe you meant 'or' or '|' instead of '||'?")
+            : NULL)
+        : NULL
+    }

output :

aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "1 && 2"
  File "<string>", line 1
    1 && 2
      ^^
SyntaxError: invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?
aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "1 & & 2"
  File "<string>", line 1
    1 & & 2
        ^
SyntaxError: invalid syntax
aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "1 || 2"
  File "<string>", line 1
    1 || 2
      ^^
SyntaxError: invalid syntax.  Maybe you meant 'or' or '|' instead of '||'?
aniket@DESKTOP-074O80J:/mnt/d/cpython/cpython$ ./python.exe -c "1 | | 2"
  File "<string>", line 1
    1 | | 2
        ^
SyntaxError: invalid syntax

previously i tried something like this but it was throwing warning during compiling

invalid_bitwise_and:
   | a=bitwise_and b='&' c='&' {
        (b->end_lineno == c->lineno && b->end_col_offset == c->col_offset)
        ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?")
        : NULL
    }

these were the warning :--

lude    -DPy_BUILD_CORE -o Parser/parser.o Parser/parser.c
Parser/parser.c: In function ‘invalid_bitwise_and_rule’:
Parser/parser.c:28511:77: warning: comparison between pointer and integer
28511 |             _res = ( b -> end_lineno == c -> lineno & & b -> end_col_offset == c -> col_offset ) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE ( b , c , "invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?" ) : NULL;
      |                                                                             ^~
Parser/parser.c:28511:38: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
28511 |             _res = ( b -> end_lineno == c -> lineno & & b -> end_col_offset == c -> col_offset ) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE ( b , c , "invalid syntax.  Maybe you meant 'and' or '&' instead of '&&'?" ) : NULL;
      |                      ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
Parser/parser.c: In function ‘invalid_bitwise_or_rule’:
Parser/parser.c:28560:77: warning: comparison between pointer and integer
28560 |             _res = ( b -> end_lineno == c -> lineno & & b -> end_col_offset == c -> col_offset ) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE ( b , c , "invalid syntax.  Maybe you meant 'or' or '|' instead of '||'?" ) : NULL;
      |                                                                             ^~
Parser/parser.c:28560:38: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
28560 |             _res = ( b -> end_lineno == c -> lineno & & b -> end_col_offset == c -> col_offset ) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE ( b , c , "invalid syntax.  Maybe you meant 'or' or '|' instead of '||'?" ) : NULL;
      |                      ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~

@skirpichev

Copy link
Copy Markdown
Member

with this patch

Yes, like that. Though, I think it could be factored to a helper function.

these were the warning

You should take into account operator precedence rules in C.

@serhiy-storchaka

Copy link
Copy Markdown
Member

The code was correct, but errorprone, thus the compiler warning. Simply add parentheses: ((b->end_lineno == c->lineno) && (b->end_col_offset == c->col_offset)).

@serhiy-storchaka

Copy link
Copy Markdown
Member

Hmm, it seems there is a bug in the python.gram parser or the Parser/parser.c generator which parses && in C code as two tokens & and & and then inserts a space between them.

@serhiy-storchaka

Copy link
Copy Markdown
Member

Anyway, if you add a helper that tests this condition in Parser/pegen.h, you can simply use it in python.gram.

@sobolevn

Copy link
Copy Markdown
Member

In my opinion && and & & are both incorrect, the error message is good enough.

@Aniketsy

Copy link
Copy Markdown
Contributor Author

In my opinion && and & & are both incorrect, the error message is good enough.

+1 make sense

Hmm, it seems there is a bug in the python.gram parser or the Parser/parser.c generator which parses && in C code as two tokens & and & and then inserts a space between them.

should we take care of this in follow up

@Aniketsy

Copy link
Copy Markdown
Contributor Author

Also please let me know your thoughts on this as well #151375

@skirpichev

Copy link
Copy Markdown
Member

In my opinion && and & & are both incorrect, the error message is good enough.

I typed '& &', not '&&'. And maybe actually meant something like '& 7' (a typo).

@skirpichev skirpichev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests with space between operators, e.g. a & & b.

Comment thread Lib/test/test_syntax.py Outdated
Comment thread Lib/test/test_syntax.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually a regexp. So escape ? (in other test too).

Comment thread Lib/test/test_syntax.py
Comment thread Lib/test/test_syntax.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider specialized syntax error for && and ||

6 participants