Skip to content

Commit 2eb87ca

Browse files
authored
Merge pull request RustPython#4367 from andersk/star-order
Prohibit starred arguments after double-starred arguments
2 parents 27d315c + 52ce437 commit 2eb87ca

File tree

3 files changed

+17
-3
lines changed

3 files changed

+17
-3
lines changed

Lib/test/test_syntax.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,8 +1453,6 @@ def test_kwargs_last2(self):
14531453
"positional argument follows "
14541454
"keyword argument unpacking")
14551455

1456-
# TODO: RUSTPYTHON
1457-
@unittest.expectedFailure
14581456
def test_kwargs_last3(self):
14591457
self._check_error("int(**{'base': 10}, *['2'])",
14601458
"iterable argument unpacking follows "

compiler/parser/src/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub enum LexicalErrorType {
2222
TabsAfterSpaces,
2323
DefaultArgumentError,
2424
PositionalArgumentError,
25+
UnpackedArgumentError,
2526
DuplicateKeywordArgumentError,
2627
UnrecognizedToken { tok: char },
2728
FStringError(FStringErrorType),
@@ -55,6 +56,12 @@ impl fmt::Display for LexicalErrorType {
5556
LexicalErrorType::PositionalArgumentError => {
5657
write!(f, "positional argument follows keyword argument")
5758
}
59+
LexicalErrorType::UnpackedArgumentError => {
60+
write!(
61+
f,
62+
"iterable argument unpacking follows keyword argument unpacking"
63+
)
64+
}
5865
LexicalErrorType::UnrecognizedToken { tok } => {
5966
write!(f, "Got unexpected token {tok}")
6067
}

compiler/parser/src/function.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, Lexi
5555

5656
let mut keyword_names =
5757
FxHashSet::with_capacity_and_hasher(func_args.len(), Default::default());
58+
let mut double_starred = false;
5859
for (name, value) in func_args {
5960
match name {
6061
Some((start, end, name)) => {
@@ -67,6 +68,8 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, Lexi
6768
}
6869

6970
keyword_names.insert(keyword_name.clone());
71+
} else {
72+
double_starred = true;
7073
}
7174

7275
keywords.push(ast::Keyword::new(
@@ -76,12 +79,18 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, Lexi
7679
));
7780
}
7881
None => {
79-
// Allow starred args after keyword arguments.
82+
// Allow starred arguments after keyword arguments but
83+
// not after double-starred arguments.
8084
if !keywords.is_empty() && !is_starred(&value) {
8185
return Err(LexicalError {
8286
error: LexicalErrorType::PositionalArgumentError,
8387
location: value.location,
8488
});
89+
} else if double_starred {
90+
return Err(LexicalError {
91+
error: LexicalErrorType::UnpackedArgumentError,
92+
location: value.location,
93+
});
8594
}
8695

8796
args.push(value);

0 commit comments

Comments
 (0)