diff --git a/libcst/_nodes/statement.py b/libcst/_nodes/statement.py index cdc49edc..5546f143 100644 --- a/libcst/_nodes/statement.py +++ b/libcst/_nodes/statement.py @@ -3245,8 +3245,6 @@ class MatchMapping(MatchPattern): rpar: Sequence[RightParen] = () def _validate(self) -> None: - if isinstance(self.trailing_comma, Comma) and self.rest is not None: - raise CSTValidationError("Cannot have a trailing comma without **rest") super(MatchMapping, self)._validate() def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchMapping": diff --git a/libcst/_nodes/tests/test_match.py b/libcst/_nodes/tests/test_match.py index 2335b7c3..55533293 100644 --- a/libcst/_nodes/tests/test_match.py +++ b/libcst/_nodes/tests/test_match.py @@ -226,6 +226,22 @@ class MatchTest(CSTNodeTest): ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), + cst.MatchCase( # rest with trailing comma - valid syntax (issue #1436) + pattern=cst.MatchMapping( + [ + cst.MatchMappingElement( + key=cst.SimpleString('"a"'), + pattern=cst.MatchValue(cst.Integer("1")), + comma=cst.Comma( + whitespace_after=cst.SimpleWhitespace(" ") + ), + ), + ], + rest=cst.Name("keys"), + trailing_comma=cst.Comma(), + ), + body=cst.SimpleStatementSuite((cst.Pass(),)), + ), ], ), "code": ( @@ -234,6 +250,7 @@ class MatchTest(CSTNodeTest): + ' case {"a": None,"b": None}: pass\n' + ' case {"a": None,}: pass\n' + " case {**rest}: pass\n" + + ' case {"a": 1, **keys,}: pass\n' ), "parser": parser, }, diff --git a/native/libcst/tests/fixtures/malicious_match.py b/native/libcst/tests/fixtures/malicious_match.py index 54840022..8277ed88 100644 --- a/native/libcst/tests/fixtures/malicious_match.py +++ b/native/libcst/tests/fixtures/malicious_match.py @@ -39,4 +39,6 @@ case 1, 2: pass case ( Foo ( ) ) : pass case (lol) if ( True , ) :pass + case {"a": 1, **keys,} : pass + case {**rest,} : pass