diff --git a/crates/ruff_python_parser/resources/inline/err/except_star_py310.py b/crates/ruff_python_parser/resources/inline/err/except_star_py310.py index 17c373fb9a..b681632543 100644 --- a/crates/ruff_python_parser/resources/inline/err/except_star_py310.py +++ b/crates/ruff_python_parser/resources/inline/err/except_star_py310.py @@ -1,3 +1,5 @@ # parse_options: {"target-version": "3.10"} try: ... except* ValueError: ... +except* KeyError: ... +except * Error: ... diff --git a/crates/ruff_python_parser/src/parser/statement.rs b/crates/ruff_python_parser/src/parser/statement.rs index 5f7f870a00..bfe4678acc 100644 --- a/crates/ruff_python_parser/src/parser/statement.rs +++ b/crates/ruff_python_parser/src/parser/statement.rs @@ -7,7 +7,7 @@ use ruff_python_ast::name::Name; use ruff_python_ast::{ self as ast, ExceptHandler, Expr, ExprContext, IpyEscapeKind, Operator, Stmt, WithItem, }; -use ruff_text_size::{Ranged, TextSize}; +use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::parser::expression::{ParsedExpr, EXPR_SET}; use crate::parser::progress::ParserProgress; @@ -1377,6 +1377,9 @@ impl<'src> Parser<'src> { let mut mixed_except_ranges = Vec::new(); let handlers = self.parse_clauses(Clause::Except, |p| { let (handler, kind) = p.parse_except_clause(); + if let ExceptClauseKind::Star(range) = kind { + p.add_unsupported_syntax_error(UnsupportedSyntaxErrorKind::ExceptStar, range); + } if is_star.is_none() { is_star = Some(kind.is_star()); } else if is_star != Some(kind.is_star()) { @@ -1466,11 +1469,8 @@ impl<'src> Parser<'src> { // # parse_options: {"target-version": "3.10"} // try: ... // except* ValueError: ... - - let range = self.node_range(try_start); - if is_star { - self.add_unsupported_syntax_error(UnsupportedSyntaxErrorKind::ExceptStar, range); - } + // except* KeyError: ... + // except * Error: ... ast::StmtTry { body: try_body, @@ -1478,7 +1478,7 @@ impl<'src> Parser<'src> { orelse, finalbody, is_star, - range, + range: self.node_range(try_start), } } @@ -1491,8 +1491,9 @@ impl<'src> Parser<'src> { let start = self.node_start(); self.bump(TokenKind::Except); + let star_token_range = self.current_token_range(); let block_kind = if self.eat(TokenKind::Star) { - ExceptClauseKind::Star + ExceptClauseKind::Star(star_token_range) } else { ExceptClauseKind::Normal }; @@ -3650,12 +3651,14 @@ enum ExceptClauseKind { /// A normal except clause e.g., `except Exception as e: ...`. Normal, /// An except clause with a star e.g., `except *: ...`. - Star, + /// + /// Contains the star's [`TextRange`] for error reporting. + Star(TextRange), } impl ExceptClauseKind { const fn is_star(self) -> bool { - matches!(self, ExceptClauseKind::Star) + matches!(self, ExceptClauseKind::Star(..)) } } diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@except_star_py310.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@except_star_py310.py.snap index a7c20d6e23..070d99e74d 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@except_star_py310.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@except_star_py310.py.snap @@ -7,11 +7,11 @@ input_file: crates/ruff_python_parser/resources/inline/err/except_star_py310.py ``` Module( ModModule { - range: 0..77, + range: 0..126, body: [ Try( StmtTry { - range: 44..76, + range: 44..125, body: [ Expr( StmtExpr { @@ -52,6 +52,60 @@ Module( ], }, ), + ExceptHandler( + ExceptHandlerExceptHandler { + range: 77..98, + type_: Some( + Name( + ExprName { + range: 85..93, + id: Name("KeyError"), + ctx: Load, + }, + ), + ), + name: None, + body: [ + Expr( + StmtExpr { + range: 95..98, + value: EllipsisLiteral( + ExprEllipsisLiteral { + range: 95..98, + }, + ), + }, + ), + ], + }, + ), + ExceptHandler( + ExceptHandlerExceptHandler { + range: 99..125, + type_: Some( + Name( + ExprName { + range: 115..120, + id: Name("Error"), + ctx: Load, + }, + ), + ), + name: None, + body: [ + Expr( + StmtExpr { + range: 122..125, + value: EllipsisLiteral( + ExprEllipsisLiteral { + range: 122..125, + }, + ), + }, + ), + ], + }, + ), ], orelse: [], finalbody: [], @@ -65,8 +119,27 @@ Module( ## Unsupported Syntax Errors | -1 | # parse_options: {"target-version": "3.10"} -2 | / try: ... -3 | | except* ValueError: ... - | |_______________________^ Syntax Error: Cannot use `except*` on Python 3.10 (syntax was added in Python 3.11) +1 | # parse_options: {"target-version": "3.10"} +2 | try: ... +3 | except* ValueError: ... + | ^ Syntax Error: Cannot use `except*` on Python 3.10 (syntax was added in Python 3.11) +4 | except* KeyError: ... +5 | except * Error: ... + | + + + | +2 | try: ... +3 | except* ValueError: ... +4 | except* KeyError: ... + | ^ Syntax Error: Cannot use `except*` on Python 3.10 (syntax was added in Python 3.11) +5 | except * Error: ... + | + + + | +3 | except* ValueError: ... +4 | except* KeyError: ... +5 | except * Error: ... + | ^ Syntax Error: Cannot use `except*` on Python 3.10 (syntax was added in Python 3.11) |