[syntax-errors] Starred expressions in return, yield, and for (#17134)

Summary
--

Fixes https://github.com/astral-sh/ruff/issues/16520 by flagging single,
starred expressions in `return`, `yield`, and
`for` statements.

I thought `yield from` would also be included here, but that error is
emitted by
the CPython parser:

```pycon
>>> ast.parse("def f(): yield from *x")
Traceback (most recent call last):
  File "<python-input-214>", line 1, in <module>
    ast.parse("def f(): yield from *x")
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/ast.py", line 54, in parse
    return compile(source, filename, mode, flags,
                   _feature_version=feature_version, optimize=optimize)
  File "<unknown>", line 1
    def f(): yield from *x
                        ^
SyntaxError: invalid syntax
```

And we also already catch it in our parser.

Test Plan
--

New inline tests and updates to existing tests.
This commit is contained in:
Brent Westbrook 2025-04-02 08:38:25 -04:00 committed by GitHub
parent 2ae39edccf
commit d45593288f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 679 additions and 435 deletions

View file

@ -89,12 +89,42 @@ impl SemanticSyntaxChecker {
);
}
}
Stmt::Return(ast::StmtReturn {
value: Some(value), ..
}) => {
// test_err single_star_return
// def f(): return *x
Self::invalid_star_expression(value, ctx);
}
Stmt::For(ast::StmtFor { target, iter, .. }) => {
// test_err single_star_for
// for _ in *x: ...
// for *x in xs: ...
Self::invalid_star_expression(target, ctx);
Self::invalid_star_expression(iter, ctx);
}
_ => {}
}
Self::debug_shadowing(stmt, ctx);
}
/// Emit a [`SemanticSyntaxErrorKind::InvalidStarExpression`] if `expr` is starred.
fn invalid_star_expression<Ctx: SemanticSyntaxContext>(expr: &Expr, ctx: &Ctx) {
// test_ok single_star_in_tuple
// def f(): yield (*x,)
// def f(): return (*x,)
// for _ in (*x,): ...
// for (*x,) in xs: ...
if expr.is_starred_expr() {
Self::add_error(
ctx,
SemanticSyntaxErrorKind::InvalidStarExpression,
expr.range(),
);
}
}
/// Check for [`SemanticSyntaxErrorKind::WriteToDebug`] in `stmt`.
fn debug_shadowing<Ctx: SemanticSyntaxContext>(stmt: &ast::Stmt, ctx: &Ctx) {
match stmt {
@ -368,6 +398,13 @@ impl SemanticSyntaxChecker {
};
}
}
Expr::Yield(ast::ExprYield {
value: Some(value), ..
}) => {
// test_err single_star_yield
// def f(): yield *x
Self::invalid_star_expression(value, ctx);
}
_ => {}
}
}
@ -462,6 +499,9 @@ impl Display for SemanticSyntaxError {
write!(f, "cannot delete `__debug__` on Python {python_version} (syntax was removed in 3.9)")
}
},
SemanticSyntaxErrorKind::InvalidStarExpression => {
f.write_str("can't use starred expression here")
}
}
}
}
@ -575,6 +615,19 @@ pub enum SemanticSyntaxErrorKind {
///
/// [BPO 45000]: https://github.com/python/cpython/issues/89163
WriteToDebug(WriteToDebugKind),
/// Represents the use of a starred expression in an invalid location, such as a `return` or
/// `yield` statement.
///
/// ## Examples
///
/// ```python
/// def f(): return *x
/// def f(): yield *x
/// for _ in *x: ...
/// for *x in xs: ...
/// ```
InvalidStarExpression,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]