]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-123562: Improve `SyntaxError` message for `case ... as a.b` (#123563)
authorsobolevn <mail@sobolevn.me>
Mon, 2 Sep 2024 11:11:44 +0000 (14:11 +0300)
committerGitHub <noreply@github.com>
Mon, 2 Sep 2024 11:11:44 +0000 (13:11 +0200)
Grammar/python.gram
Lib/test/test_patma.py
Lib/test/test_syntax.py
Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst [new file with mode: 0644]
Parser/parser.c

index 431bb90830a02a5eff5fe45c2f1930e4b10bb1a1..e9a8c69c4fa27c005a893785ea7f9906e41fba96 100644 (file)
@@ -1375,7 +1375,9 @@ invalid_case_block:
         RAISE_INDENTATION_ERROR("expected an indented block after 'case' statement on line %d", a->lineno) }
 invalid_as_pattern:
     | or_pattern 'as' a="_" { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use '_' as a target") }
-    | or_pattern 'as' !NAME a=expression { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "invalid pattern target") }
+    | or_pattern 'as' a=expression {
+        RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
+            a, "cannot use %s as pattern target", _PyPegen_get_expr_name(a)) }
 invalid_class_pattern:
     | name_or_attr '(' a=invalid_class_argument_pattern  { RAISE_SYNTAX_ERROR_KNOWN_RANGE(
         PyPegen_first_item(a, pattern_ty),
index 8325b83a5932b91e5f6f66f879de3bbc59426ffe..dae6d898964cffc6d4aa97fd28c6be59f890ef3d 100644 (file)
@@ -3015,6 +3015,13 @@ class TestSyntaxErrors(unittest.TestCase):
                 pass
         """)
 
+    def test_multiple_assignments_to_name_in_pattern_6(self):
+        self.assert_syntax_error("""
+        match ...:
+            case a as a + 1:  # NAME and expression with no ()
+                pass
+        """)
+
     def test_multiple_starred_names_in_sequence_pattern_0(self):
         self.assert_syntax_error("""
         match ...:
index 406ea2118f26100d1b88de35a81d7532765d62bb..132e2b839627bc68fa45382d18fda941f930361f 100644 (file)
@@ -1932,7 +1932,31 @@ Corner-cases that used to crash:
     ...   case 42 as 1+2+4:
     ...     ...
     Traceback (most recent call last):
-    SyntaxError: invalid pattern target
+    SyntaxError: cannot use expression as pattern target
+
+    >>> match ...:
+    ...   case 42 as a.b:
+    ...     ...
+    Traceback (most recent call last):
+    SyntaxError: cannot use attribute as pattern target
+
+    >>> match ...:
+    ...   case 42 as (a, b):
+    ...     ...
+    Traceback (most recent call last):
+    SyntaxError: cannot use tuple as pattern target
+
+    >>> match ...:
+    ...   case 42 as (a + 1):
+    ...     ...
+    Traceback (most recent call last):
+    SyntaxError: cannot use expression as pattern target
+
+    >>> match ...:
+    ...   case (32 as x) | (42 as a()):
+    ...     ...
+    Traceback (most recent call last):
+    SyntaxError: cannot use function call as pattern target
 
     >>> match ...:
     ...   case Foo(z=1, y=2, x):
@@ -2817,6 +2841,22 @@ while 1:
             end_offset=22 + len("obj.attr"),
         )
 
+    def test_match_stmt_invalid_as_expr(self):
+        self._check_error(
+            textwrap.dedent(
+                """
+                match 1:
+                    case x as obj.attr:
+                        ...
+                """
+            ),
+            errtext="cannot use attribute as pattern target",
+            lineno=3,
+            end_lineno=3,
+            offset=15,
+            end_offset=15 + len("obj.attr"),
+        )
+
 
 def load_tests(loader, tests, pattern):
     tests.addTest(doctest.DocTestSuite())
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst
new file mode 100644 (file)
index 0000000..10ef82c
--- /dev/null
@@ -0,0 +1,2 @@
+Improve :exc:`SyntaxError` message for using ``case ... as ...`` with not a
+name.
index 3c403958e65a57cb2096e5d4e003659c2f5f4247..e5567d0f63f03b2fa1fea8e66f56da536333f2e1 100644 (file)
@@ -24005,7 +24005,7 @@ invalid_case_block_rule(Parser *p)
     return _res;
 }
 
-// invalid_as_pattern: or_pattern 'as' "_" | or_pattern 'as' !NAME expression
+// invalid_as_pattern: or_pattern 'as' "_" | or_pattern 'as' expression
 static void *
 invalid_as_pattern_rule(Parser *p)
 {
@@ -24048,12 +24048,12 @@ invalid_as_pattern_rule(Parser *p)
         D(fprintf(stderr, "%*c%s invalid_as_pattern[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "or_pattern 'as' \"_\""));
     }
-    { // or_pattern 'as' !NAME expression
+    { // or_pattern 'as' expression
         if (p->error_indicator) {
             p->level--;
             return NULL;
         }
-        D(fprintf(stderr, "%*c> invalid_as_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' !NAME expression"));
+        D(fprintf(stderr, "%*c> invalid_as_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' expression"));
         Token * _keyword;
         expr_ty a;
         pattern_ty or_pattern_var;
@@ -24062,13 +24062,11 @@ invalid_as_pattern_rule(Parser *p)
             &&
             (_keyword = _PyPegen_expect_token(p, 666))  // token='as'
             &&
-            _PyPegen_lookahead_with_name(0, _PyPegen_name_token, p)
-            &&
             (a = expression_rule(p))  // expression
         )
         {
-            D(fprintf(stderr, "%*c+ invalid_as_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' !NAME expression"));
-            _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "invalid pattern target" );
+            D(fprintf(stderr, "%*c+ invalid_as_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' expression"));
+            _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use %s as pattern target" , _PyPegen_get_expr_name ( a ) );
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
                 p->level--;
@@ -24078,7 +24076,7 @@ invalid_as_pattern_rule(Parser *p)
         }
         p->mark = _mark;
         D(fprintf(stderr, "%*c%s invalid_as_pattern[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "or_pattern 'as' !NAME expression"));
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "or_pattern 'as' expression"));
     }
     _res = NULL;
   done: