-
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] Parenthesized context managers before Python 3.9 #16523
base: main
Are you sure you want to change the base?
Changes from 3 commits
1d2c4fa
359686d
557142b
73f1047
f524953
256279b
4d74013
ba288ba
20c8b0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# parse_options: {"target-version": "3.8"} | ||
with (foo as x, bar as y): ... |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# parse_options: {"target-version": "3.9"} | ||
with (foo as x, bar as y): ... |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2062,6 +2062,7 @@ impl<'src> Parser<'src> { | |
// We'll start with the assumption that the with items are parenthesized. | ||
let mut with_item_kind = WithItemKind::Parenthesized; | ||
|
||
let open_paren_range = self.current_token_range(); | ||
self.bump(TokenKind::Lpar); | ||
|
||
let mut parsed_with_items = vec![]; | ||
|
@@ -2103,6 +2104,17 @@ impl<'src> Parser<'src> { | |
}; | ||
self.add_error(error, &parsed_with_item.item.context_expr); | ||
} | ||
// test_ok parenthesized_context_manager_py39 | ||
// # parse_options: {"target-version": "3.9"} | ||
// with (foo as x, bar as y): ... | ||
|
||
// test_err parenthesized_context_manager_py38 | ||
// # parse_options: {"target-version": "3.8"} | ||
// with (foo as x, bar as y): ... | ||
self.add_unsupported_syntax_error( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we also need to emit the same diagnostic on line 2144, e.g. for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, that syntax is actually okay. I think As far as I can tell, the problem with parentheses is specific to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python 3.7.9 (default, Aug 23 2020, 00:57:53)
[Clang 10.0.1 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> ast.parse("with (foo, bar): ...")
<_ast.Module object at 0x70849fd20c10>
>>> ast.dump(_)
"Module(body=[With(items=[withitem(context_expr=Tuple(elts=[Name(id='foo', ctx=Load()), Name(id='bar', ctx=Load())], ctx=Load()), optional_vars=None)], body=[Expr(value=Ellipsis())])])" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we move this check down below where we're sure that the parenthesis belongs to the with items and not the expression? i.e., on line 2162 if with_item_kind.is_parenthesized() { There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or, in if self.at(TokenKind::Lpar) {
let lpar_range = self.current_token_range();
if let Some(items) = self.try_parse_parenthesized_with_items() {
// check target version and raise error
self.expect(TokenKind::Rpar);
items
} else { There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh nice, I moved it to |
||
UnsupportedSyntaxErrorKind::ParenthesizedContextManager, | ||
open_paren_range, | ||
); | ||
} else if self.at(TokenKind::Rpar) | ||
// test_err with_items_parenthesized_missing_colon | ||
// # `)` followed by a newline | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
--- | ||
source: crates/ruff_python_parser/tests/fixtures.rs | ||
input_file: crates/ruff_python_parser/resources/inline/err/parenthesized_context_manager_py38.py | ||
--- | ||
## AST | ||
|
||
``` | ||
Module( | ||
ModModule { | ||
range: 0..74, | ||
body: [ | ||
With( | ||
StmtWith { | ||
range: 43..73, | ||
is_async: false, | ||
items: [ | ||
WithItem { | ||
range: 49..57, | ||
context_expr: Name( | ||
ExprName { | ||
range: 49..52, | ||
id: Name("foo"), | ||
ctx: Load, | ||
}, | ||
), | ||
optional_vars: Some( | ||
Name( | ||
ExprName { | ||
range: 56..57, | ||
id: Name("x"), | ||
ctx: Store, | ||
}, | ||
), | ||
), | ||
}, | ||
WithItem { | ||
range: 59..67, | ||
context_expr: Name( | ||
ExprName { | ||
range: 59..62, | ||
id: Name("bar"), | ||
ctx: Load, | ||
}, | ||
), | ||
optional_vars: Some( | ||
Name( | ||
ExprName { | ||
range: 66..67, | ||
id: Name("y"), | ||
ctx: Store, | ||
}, | ||
), | ||
), | ||
}, | ||
], | ||
body: [ | ||
Expr( | ||
StmtExpr { | ||
range: 70..73, | ||
value: EllipsisLiteral( | ||
ExprEllipsisLiteral { | ||
range: 70..73, | ||
}, | ||
), | ||
}, | ||
), | ||
], | ||
}, | ||
), | ||
], | ||
}, | ||
) | ||
``` | ||
## Unsupported Syntax Errors | ||
|
||
| | ||
1 | # parse_options: {"target-version": "3.8"} | ||
2 | with (foo as x, bar as y): ... | ||
| ^ Syntax Error: Cannot use parentheses within a `with` statement on Python 3.8 (syntax was added in Python 3.9) | ||
| |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
--- | ||
source: crates/ruff_python_parser/tests/fixtures.rs | ||
input_file: crates/ruff_python_parser/resources/inline/ok/parenthesized_context_manager_py39.py | ||
--- | ||
## AST | ||
|
||
``` | ||
Module( | ||
ModModule { | ||
range: 0..74, | ||
body: [ | ||
With( | ||
StmtWith { | ||
range: 43..73, | ||
is_async: false, | ||
items: [ | ||
WithItem { | ||
range: 49..57, | ||
context_expr: Name( | ||
ExprName { | ||
range: 49..52, | ||
id: Name("foo"), | ||
ctx: Load, | ||
}, | ||
), | ||
optional_vars: Some( | ||
Name( | ||
ExprName { | ||
range: 56..57, | ||
id: Name("x"), | ||
ctx: Store, | ||
}, | ||
), | ||
), | ||
}, | ||
WithItem { | ||
range: 59..67, | ||
context_expr: Name( | ||
ExprName { | ||
range: 59..62, | ||
id: Name("bar"), | ||
ctx: Load, | ||
}, | ||
), | ||
optional_vars: Some( | ||
Name( | ||
ExprName { | ||
range: 66..67, | ||
id: Name("y"), | ||
ctx: Store, | ||
}, | ||
), | ||
), | ||
}, | ||
], | ||
body: [ | ||
Expr( | ||
StmtExpr { | ||
range: 70..73, | ||
value: EllipsisLiteral( | ||
ExprEllipsisLiteral { | ||
range: 70..73, | ||
}, | ||
), | ||
}, | ||
), | ||
], | ||
}, | ||
), | ||
], | ||
}, | ||
) | ||
``` |
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 would be nice to add documentation, similar to what you did for other variants.