Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
(*x or y for x in z); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
f(*x if c else y for x in z); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
(*x < y for x in z); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# parse_options: {"target-version": "3.15"}
[*x if x else y]
{**x if x else y}
[x if x else *y]
{x if x else **y}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
(*x if c else y for x in z); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# parse_options: {"target-version": "3.15"}
[**x for x in xs]
(**x for x in xs)
f(**x for x in xs)
{*x: y for x in xs}
{**x: y for x in xs}
{x: *y for x in xs}
{x: **y for x in xs}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
(*lambda: x for x in z); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# parse_options: {"target-version": "3.15"}
[**]
(**)
[**, x]
[** for x in z]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
(*(*x if c else y for x in xs) if d else z for z in zs); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# parse_options: {"target-version": "3.15"}
[**(x if x else *y) for x in z]
(**(x if x else **y) for x in z)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.15"}
(*(*x or y for x in z) for z in zs); a =
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# parse_options: {"target-version": "3.15"}
[**match]
[**case]
[**type]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# parse_options: {"target-version": "3.15"}
{**x if c else y for x in xs}
{**x or y for x in xs}
{**x < y for x in xs}
{**lambda: x for x in xs}
(*x if c else y for x in xs)
(*x or y for x in xs)
(*x < y for x in xs)
(*lambda: x for x in xs)
f(*x if c else y for x in xs)
f(*x if c else y)
(*(*x or y for x in z) for z in zs)
async def unpack(xs):
return {**x if c else y async for x in xs}
async def iterate(xs):
return (*x if c else y async for x in xs)
55 changes: 55 additions & 0 deletions crates/ruff_python_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ pub enum ParseErrorType {
InvalidYieldExpressionUsage,
/// An invalid usage of a starred expression was found.
InvalidStarredExpressionUsage,
/// An unpacked conditional expression is missing parentheses.
InvalidConditionalUnpacking { double_starred: bool },
/// Only the else branch of a conditional expression is unpacked.
InvalidConditionalBranchUnpacking { double_starred: bool },
/// Dictionary unpacking is used in a list or generator comprehension.
InvalidComprehensionDictUnpacking { generator: bool },
/// An unpacked expression is used as a dictionary key.
InvalidDictKeyUnpacking { double_starred: bool },
/// An unpacked expression is used as a dictionary value.
InvalidDictValueUnpacking { double_starred: bool },
/// Dictionary unpacking is used outside a dictionary or call argument.
InvalidDictUnpacking,
/// A star pattern was found outside a sequence pattern.
InvalidStarPatternUsage,
/// An underscore was used as a binding target in a match pattern.
Expand Down Expand Up @@ -538,6 +550,49 @@ impl std::fmt::Display for ParseErrorType {
ParseErrorType::InvalidLambdaExpressionUsage => {
f.write_str("lambda expression cannot be used here")
}
ParseErrorType::InvalidConditionalUnpacking { double_starred } => {
let kind = if *double_starred {
"double starred"
} else {
"starred"
};
write!(
f,
"invalid {kind} expression. Did you forget to wrap the conditional expression in parentheses?"
)
}
ParseErrorType::InvalidConditionalBranchUnpacking { double_starred } => {
if *double_starred {
f.write_str(
"cannot use dict unpacking on only part of a conditional expression",
)
} else {
f.write_str("cannot unpack only part of a conditional expression")
}
}
ParseErrorType::InvalidComprehensionDictUnpacking { generator } => {
let kind = if *generator {
"generator expression"
} else {
"list comprehension"
};
write!(f, "cannot use dict unpacking in {kind}")
}
ParseErrorType::InvalidDictKeyUnpacking { double_starred }
| ParseErrorType::InvalidDictValueUnpacking { double_starred } => {
let kind = if *double_starred {
"dict unpacking"
} else {
"a starred expression"
};
let position = if matches!(self, ParseErrorType::InvalidDictKeyUnpacking { .. }) {
"key"
} else {
"value"
};
write!(f, "cannot use {kind} in a dictionary {position}")
}
ParseErrorType::InvalidDictUnpacking => f.write_str("cannot use dict unpacking here"),
ParseErrorType::InvalidStarredExpressionUsage => f.write_str("invalid syntax"),
ParseErrorType::PositionalAfterKeywordArgument => {
f.write_str("positional argument follows keyword argument")
Expand Down
Loading