https://github.com/python/cpython/commit/a85830c7f8456c047b02d4f3549113542cc01b72
commit: a85830c7f8456c047b02d4f3549113542cc01b72
branch: main
author: Petr Viktorin <[email protected]>
committer: encukou <[email protected]>
date: 2026-07-28T09:19:46+02:00
summary:

gh-154775: Don't accept duplicate plus sign when matching complex number 
(GH-154776)


Co-authored-by: Bartosz SÅ‚awecki <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-07-27-16-29-10.gh-issue-154775._ISRIk.rst
M Grammar/python.gram
M Lib/test/test_patma.py
M Parser/parser.c

diff --git a/Grammar/python.gram b/Grammar/python.gram
index ac1b4a64f38c75a..2713ba9466a0b1d 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -568,7 +568,6 @@ real_number[expr_ty]:
 
 imaginary_number[expr_ty]:
     | imag=NUMBER { _PyPegen_ensure_imaginary(p, imag) }
-    | '+' imag=NUMBER { _PyPegen_ensure_imaginary(p, imag) }
 
 capture_pattern[pattern_ty]:
     | target=pattern_capture_target { _PyAST_MatchAs(NULL, target->v.Name.id, 
EXTRA) }
diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py
index e3aaea84ea7ce84..0825d9d980c5e7f 100644
--- a/Lib/test/test_patma.py
+++ b/Lib/test/test_patma.py
@@ -2835,14 +2835,6 @@ def test_patma_264(self):
         self.assertEqual(y, 0)
 
     def test_patma_265(self):
-        x = 0.25 - 1.75j
-        match x:
-            case 0.25 - +1.75j:
-                y = 0
-        self.assertEqual(x, 0.25 - 1.75j)
-        self.assertEqual(y, 0)
-
-    def test_patma_266(self):
         x = 0
         match x:
             case +1e1000:
@@ -3329,6 +3321,34 @@ def test_mapping_pattern_duplicate_key_edge_case3(self):
                 pass
         """)
 
+    def test_duplicate_sign_in_complex_1(self):
+        self.assert_syntax_error("""
+        match ...:
+            case 0 ++ 0j:
+                pass
+        """)
+
+    def test_duplicate_sign_in_complex_2(self):
+        self.assert_syntax_error("""
+        match ...:
+            case 0 -+ 0j:
+                pass
+        """)
+
+    def test_duplicate_sign_in_complex_3(self):
+        self.assert_syntax_error("""
+        match ...:
+            case 0 +- 0j:
+                pass
+        """)
+
+    def test_duplicate_sign_in_complex_4(self):
+        self.assert_syntax_error("""
+        match ...:
+            case 0 -- 0j:
+                pass
+        """)
+
 class TestTypeErrors(unittest.TestCase):
 
     def test_accepts_positional_subpatterns_0(self):
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-27-16-29-10.gh-issue-154775._ISRIk.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-27-16-29-10.gh-issue-154775._ISRIk.rst
new file mode 100644
index 000000000000000..b0035c7e1bc0640
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-27-16-29-10.gh-issue-154775._ISRIk.rst
@@ -0,0 +1,2 @@
+When matching a complex literal in :keyword:`case` statements, an extraneous
+``+`` sign (for example, ``1++1j`` or ``1-+1j``) is no longer allowed.
diff --git a/Parser/parser.c b/Parser/parser.c
index 4f4fd3ed46d1f02..800db5b490fea98 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -9355,7 +9355,7 @@ real_number_rule(Parser *p)
     return _res;
 }
 
-// imaginary_number: NUMBER | '+' NUMBER
+// imaginary_number: NUMBER
 static expr_ty
 imaginary_number_rule(Parser *p)
 {
@@ -9392,33 +9392,6 @@ imaginary_number_rule(Parser *p)
         D(fprintf(stderr, "%*c%s imaginary_number[%d-%d]: %s failed!\n", 
p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, 
"NUMBER"));
     }
-    { // '+' NUMBER
-        if (p->error_indicator) {
-            p->level--;
-            return NULL;
-        }
-        D(fprintf(stderr, "%*c> imaginary_number[%d-%d]: %s\n", p->level, ' ', 
_mark, p->mark, "'+' NUMBER"));
-        Token * _literal;
-        expr_ty imag;
-        if (
-            (_literal = _PyPegen_expect_token(p, 14))  // token='+'
-            &&
-            (imag = _PyPegen_number_token(p))  // NUMBER
-        )
-        {
-            D(fprintf(stderr, "%*c+ imaginary_number[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "'+' NUMBER"));
-            _res = _PyPegen_ensure_imaginary ( p , imag );
-            if ((_res == NULL || p->error_indicator) && PyErr_Occurred()) {
-                p->error_indicator = 1;
-                p->level--;
-                return NULL;
-            }
-            goto done;
-        }
-        p->mark = _mark;
-        D(fprintf(stderr, "%*c%s imaginary_number[%d-%d]: %s failed!\n", 
p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+' 
NUMBER"));
-    }
     _res = NULL;
   done:
     p->level--;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to