-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[syntax-errors] Tuple unpacking in return
and yield
before Python 3.8
#16485
Conversation
Summary -- Checks for tuple unpacking in `return` and `yield` statements before Python 3.8, as described [here]. I split the `ErrorKind` into two variants for the sake of more precise error messages. I thought that was nicer than having a single `StarTuple` variant containing another enum with two options. Test Plan -- Inline tests. [here]: python/cpython#76298
052265d
to
914d0a6
Compare
|
"iterable unpacking in return statements" | ||
} | ||
UnsupportedSyntaxErrorKind::StarTuple(StarTupleKind::Yield) => { | ||
"iterable unpacking in yield statements" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python also knows yield expressions. Is this something we have to distinguish / consider in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to test this out. The CPython PR said statements, but maybe I took it too literally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this also applies to expressions:
Python 3.7:
>>> def i(): yield 1, (yield 2, *rest), 3
File "<stdin>", line 1
def i(): yield 1, (yield 2, *rest), 3
^
SyntaxError: invalid syntax
if let Expr::Yield(ast::ExprYield { | ||
value: Some(expr), .. | ||
}) = &parsed_expr.expr | ||
{ | ||
self.check_tuple_unpacking(expr, StarTupleKind::Yield); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this also handle nested yield expressions a = yield x
Could this code be moved into parse_yield_expression
?
) | ||
let parsed_expr = self.parse_expression_list(ExpressionContext::starred_bitwise_or()); | ||
|
||
// test_ok iter_unpack_return_py37 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add test cases using single unpack element like return *rest
or yield *rest
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about yield 1, (*rest)
, yield 1, (yield 2, *rest), 3
(yield can be used as an expression)? I'm just throwing out random examples :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for these! The single cases are actually still invalid on my system Python (3.13):
>>> def foo(): return *rest
File "<python-input-0>", line 1
def foo(): return *rest
^^^^^
SyntaxError: can't use starred expression here
>>> def foo(): yield *rest
File "<python-input-1>", line 1
def foo(): yield *rest
^^^^^
SyntaxError: can't use starred expression here
But these aren't flagged as ParseError
s by ruff.
The second case is very interesting. It's actually accepted on both 3.7 and 3.8, but not on my 3.13 system Python (SyntaxError: cannot use starred expression here
). That might be another change not currently tracked in #6591.
I added your third case as an example of a yield expression and moved the check into parse_yield_expression
as @MichaReiser suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But these aren't flagged as
ParseError
s by ruff.
That's because the grammar says it's allowed.
return_stmt:
| 'return' [star_expressions]
star_expressions:
| star_expression (',' star_expression )+ [',']
| star_expression ','
| star_expression
star_expression:
| '*' bitwise_or
| expression
I think it's caught by the CPython compiler and not the parser. You can see that python -m ast test.py
wouldn't raise a syntax error here.
$ python -m ast _.py
Module(
body=[
FunctionDef(
name='foo',
args=arguments(
posonlyargs=[],
args=[
arg(arg='args')],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Return(
value=Starred(
value=Name(id='args', ctx=Load()),
ctx=Load()))],
decorator_list=[],
type_params=[])],
type_ignores=[])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, missed the issue #16520
I added more test cases (thanks for the suggestions!). Two of them became TODOs because I think they aren't exactly related to this PR:
I also checked on Finally, I changed the message for the |
Yes, that seems correct. Can you create an issue for it? |
Summary
Checks for tuple unpacking in
return
andyield
statements before Python 3.8, as described here.Test Plan
Inline tests.