[syntax-errors] Parenthesized keyword argument names after Python 3.8 (#16482)

Summary
--

Unlike the other syntax errors detected so far, parenthesized keyword
arguments are only allowed *before* 3.8. It sounds like they were only
accidentally allowed before that [^1].

As an aside, you get a pretty confusing error from Python for this, so
it's nice that we can catch it:

```pycon
>>> def f(**kwargs): ...
... f((a)=1)
...
  File "<python-input-0>", line 2
    f((a)=1)
       ^^^
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
>>>
```
Test Plan
--
Inline tests.

[^1]: https://github.com/python/cpython/issues/78822
This commit is contained in:
Brent Westbrook 2025-03-06 12:18:13 -05:00 committed by GitHub
parent 6c14225c66
commit b3c884f4f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 319 additions and 22 deletions

View file

@ -702,9 +702,31 @@ impl<'src> Parser<'src> {
}
}
let arg_range = parser.node_range(start);
if parser.eat(TokenKind::Equal) {
seen_keyword_argument = true;
let arg = if let Expr::Name(ident_expr) = parsed_expr.expr {
let arg = if let ParsedExpr {
expr: Expr::Name(ident_expr),
is_parenthesized,
} = parsed_expr
{
// test_ok parenthesized_kwarg_py37
// # parse_options: {"target-version": "3.7"}
// f((a)=1)
// test_err parenthesized_kwarg_py38
// # parse_options: {"target-version": "3.8"}
// f((a)=1)
// f((a) = 1)
// f( ( a ) = 1)
if is_parenthesized {
parser.add_unsupported_syntax_error(
UnsupportedSyntaxErrorKind::ParenthesizedKeywordArgumentName,
arg_range,
);
}
ast::Identifier {
id: ident_expr.id,
range: ident_expr.range,

View file

@ -441,7 +441,7 @@ impl<'src> Parser<'src> {
/// Add an [`UnsupportedSyntaxError`] with the given [`UnsupportedSyntaxErrorKind`] and
/// [`TextRange`] if its minimum version is less than [`Parser::target_version`].
fn add_unsupported_syntax_error(&mut self, kind: UnsupportedSyntaxErrorKind, range: TextRange) {
if self.options.target_version < kind.minimum_version() {
if kind.is_unsupported(self.options.target_version) {
self.unsupported_syntax_errors.push(UnsupportedSyntaxError {
kind,
range,

View file

@ -424,7 +424,7 @@ impl<'src> Parser<'src> {
/// are only allowed in Python 3.8 and later: <https://github.com/python/cpython/issues/76298>.
pub(crate) fn check_tuple_unpacking(&mut self, expr: &Expr, kind: StarTupleKind) {
let kind = UnsupportedSyntaxErrorKind::StarTuple(kind);
if self.options.target_version >= kind.minimum_version() {
if kind.is_supported(self.options.target_version) {
return;
}