From 4201eb3e728ee7958a6553ca2f92dcf825d98e37 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Jul 2026 13:51:42 -0500 Subject: [PATCH 1/2] Test more indentation cases --- .../invalid/statements/if_extra_indent.py | 42 ++ ...syntax@statements__if_extra_indent.py.snap | 574 +++++++++++++++++- 2 files changed, 609 insertions(+), 7 deletions(-) diff --git a/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py b/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py index 647626cb5d359..55cc8886e569e 100644 --- a/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py +++ b/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py @@ -6,3 +6,45 @@ pass a = 10 + +# Multiple nested unexpected indents. +if True: + before_nested + first_nested + second_nested + after_nested + +outside_nested + +# A valid compound statement inside recovered indentation. +if True: + before_compound + if condition: + nested_compound + recovered_compound + after_compound + +outside_compound + +# Multiple independent unexpected-indent regions in the same body. +if True: + before_regions + first_region + middle_region + second_region + after_region + +outside_regions + +# An independent syntax error inside recovered indentation stays visible. +if True: + before_error + broken(,) + after_error + +outside_error + +# Outstanding unexpected indents are flushed at EOF. +if True: + before_eof + final_eof diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap index 6a36fcb277c90..800e52f16b2f1 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap @@ -8,7 +8,7 @@ input_file: crates/ruff_python_parser/resources/invalid/statements/if_extra_inde Module( ModModule { node_index: NodeIndex(None), - range: 0..153, + range: 0..939, body: [ If( StmtIf { @@ -92,6 +92,423 @@ Module( ), }, ), + If( + StmtIf { + node_index: NodeIndex(None), + range: 192..265, + test: BooleanLiteral( + ExprBooleanLiteral { + node_index: NodeIndex(None), + range: 195..199, + value: true, + }, + ), + body: [ + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 205..218, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 205..218, + id: Name("before_nested"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 227..239, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 227..239, + id: Name("first_nested"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 252..265, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 252..265, + id: Name("second_nested"), + ctx: Load, + }, + ), + }, + ), + ], + elif_else_clauses: [], + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 270..282, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 270..282, + id: Name("after_nested"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 284..298, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 284..298, + id: Name("outside_nested"), + ctx: Load, + }, + ), + }, + ), + If( + StmtIf { + node_index: NodeIndex(None), + range: 359..464, + test: BooleanLiteral( + ExprBooleanLiteral { + node_index: NodeIndex(None), + range: 362..366, + value: true, + }, + ), + body: [ + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 372..387, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 372..387, + id: Name("before_compound"), + ctx: Load, + }, + ), + }, + ), + If( + StmtIf { + node_index: NodeIndex(None), + range: 396..437, + test: Name( + ExprName { + node_index: NodeIndex(None), + range: 399..408, + id: Name("condition"), + ctx: Load, + }, + ), + body: [ + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 422..437, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 422..437, + id: Name("nested_compound"), + ctx: Load, + }, + ), + }, + ), + ], + elif_else_clauses: [], + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 446..464, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 446..464, + id: Name("recovered_compound"), + ctx: Load, + }, + ), + }, + ), + ], + elif_else_clauses: [], + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 469..483, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 469..483, + id: Name("after_compound"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 485..501, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 485..501, + id: Name("outside_compound"), + ctx: Load, + }, + ), + }, + ), + If( + StmtIf { + node_index: NodeIndex(None), + range: 570..618, + test: BooleanLiteral( + ExprBooleanLiteral { + node_index: NodeIndex(None), + range: 573..577, + value: true, + }, + ), + body: [ + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 583..597, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 583..597, + id: Name("before_regions"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 606..618, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 606..618, + id: Name("first_region"), + ctx: Load, + }, + ), + }, + ), + ], + elif_else_clauses: [], + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 623..636, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 623..636, + id: Name("middle_region"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 645..658, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 645..658, + id: Name("second_region"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 663..675, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 663..675, + id: Name("after_region"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 677..692, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 677..692, + id: Name("outside_regions"), + ctx: Load, + }, + ), + }, + ), + If( + StmtIf { + node_index: NodeIndex(None), + range: 768..811, + test: BooleanLiteral( + ExprBooleanLiteral { + node_index: NodeIndex(None), + range: 771..775, + value: true, + }, + ), + body: [ + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 781..793, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 781..793, + id: Name("before_error"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 802..811, + value: Call( + ExprCall { + node_index: NodeIndex(None), + range: 802..811, + func: Name( + ExprName { + node_index: NodeIndex(None), + range: 802..808, + id: Name("broken"), + ctx: Load, + }, + ), + arguments: Arguments { + range: 808..811, + node_index: NodeIndex(None), + args: [], + keywords: [], + }, + }, + ), + }, + ), + ], + elif_else_clauses: [], + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 816..827, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 816..827, + id: Name("after_error"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 829..842, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 829..842, + id: Name("outside_error"), + ctx: Load, + }, + ), + }, + ), + If( + StmtIf { + node_index: NodeIndex(None), + range: 897..938, + test: BooleanLiteral( + ExprBooleanLiteral { + node_index: NodeIndex(None), + range: 900..904, + value: true, + }, + ), + body: [ + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 910..920, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 910..920, + id: Name("before_eof"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 929..938, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 929..938, + id: Name("final_eof"), + ctx: Load, + }, + ), + }, + ), + ], + elif_else_clauses: [], + }, + ), ], }, ) @@ -108,9 +525,152 @@ Module( | - | -6 | pass -7 | - | ^ Syntax Error: Expected a statement -8 | a = 10 - | + | + 6 | pass + 7 | + | ^ Syntax Error: Expected a statement + 8 | a = 10 + 9 | +10 | # Multiple nested unexpected indents. + | + + + | +11 | if True: +12 | before_nested +13 | first_nested + | ^^^^^^^^ Syntax Error: Unexpected indentation +14 | second_nested +15 | after_nested + | + + + | +12 | before_nested +13 | first_nested +14 | second_nested + | ^^^^^^^^^^^^ Syntax Error: Unexpected indentation +15 | after_nested + | + + + | +13 | first_nested +14 | second_nested +15 | after_nested + | ^ Syntax Error: Expected a statement +16 | +17 | outside_nested + | + + + | +15 | after_nested +16 | + | ^ Syntax Error: Expected a statement +17 | outside_nested +18 | +19 | # A valid compound statement inside recovered indentation. + | + + + | +20 | if True: +21 | before_compound +22 | if condition: + | ^^^^^^^^ Syntax Error: Unexpected indentation +23 | nested_compound +24 | recovered_compound + | + + + | +25 | after_compound +26 | + | ^ Syntax Error: Expected a statement +27 | outside_compound +28 | +29 | # Multiple independent unexpected-indent regions in the same body. + | + + + | +30 | if True: +31 | before_regions +32 | first_region + | ^^^^^^^^ Syntax Error: Unexpected indentation +33 | middle_region +34 | second_region + | + + + | +32 | first_region +33 | middle_region +34 | second_region + | ^^^^^^^^ Syntax Error: Unexpected indentation +35 | after_region + | + + + | +33 | middle_region +34 | second_region +35 | after_region + | ^ Syntax Error: Expected a statement +36 | +37 | outside_regions + | + + + | +35 | after_region +36 | + | ^ Syntax Error: Expected a statement +37 | outside_regions +38 | +39 | # An independent syntax error inside recovered indentation stays visible. + | + + + | +40 | if True: +41 | before_error +42 | broken(,) + | ^^^^^^^^ Syntax Error: Unexpected indentation +43 | after_error + | + + + | +40 | if True: +41 | before_error +42 | broken(,) + | ^ Syntax Error: Expected an expression or a ')' +43 | after_error + | + + + | +43 | after_error +44 | + | ^ Syntax Error: Expected a statement +45 | outside_error +46 | +47 | # Outstanding unexpected indents are flushed at EOF. + | + + + | +48 | if True: +49 | before_eof +50 | final_eof + | ^^^^^^^^ Syntax Error: Unexpected indentation + | + + + | +49 | before_eof +50 | final_eof + | ^ Syntax Error: Expected a statement + | From 94d5ee4e9c4bb3b07c2de14b695dabffd6150327 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Jul 2026 12:49:05 -0500 Subject: [PATCH 2/2] Reduce syntax error noise by swallowing dedents like indents --- ...ules__pycodestyle__tests__E111_E11.py.snap | 11 - ...ules__pycodestyle__tests__E112_E11.py.snap | 11 - ...ules__pycodestyle__tests__E113_E11.py.snap | 11 - ...ules__pycodestyle__tests__E114_E11.py.snap | 11 - ...ules__pycodestyle__tests__E115_E11.py.snap | 11 - ...ules__pycodestyle__tests__E116_E11.py.snap | 11 - ...ules__pycodestyle__tests__E117_E11.py.snap | 11 - ...ules__pycodestyle__tests__W191_W19.py.snap | 10 - .../invalid/statements/if_extra_indent.py | 2 +- crates/ruff_python_parser/src/parser/mod.rs | 16 +- ...ash_continuation_indentation_error.py.snap | 7 - ...lid_syntax@if_stmt_misspelled_elif.py.snap | 9 +- ...x@re_lexing__fstring_format_spec_1.py.snap | 9 - ...ents__if_extra_closing_parentheses.py.snap | 7 - ...syntax@statements__if_extra_indent.py.snap | 371 +++++++----------- ...alid_syntax@try_stmt_invalid_order.py.snap | 7 - ..._syntax@try_stmt_misspelled_except.py.snap | 20 +- .../mdtest/generics/pep695/paramspec.md | 1 - .../resources/mdtest/invalid_syntax.md | 2 - 19 files changed, 165 insertions(+), 373 deletions(-) diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E111_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E111_E11.py.snap index 45ab478836692..23a8aedbd77b0 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E111_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E111_E11.py.snap @@ -45,17 +45,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - invalid-syntax: Expected an indented block after `if` statement --> E11.py:45:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E112_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E112_E11.py.snap index b2544e4212f41..791dea7b0f1c5 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E112_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E112_E11.py.snap @@ -34,17 +34,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - E112 Expected an indented block --> E11.py:45:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E113_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E113_E11.py.snap index 4fdbcf5e3cc59..268421098144b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E113_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E113_E11.py.snap @@ -34,17 +34,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - invalid-syntax: Expected an indented block after `if` statement --> E11.py:45:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E114_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E114_E11.py.snap index 06eb01f6827eb..5829e15a107d6 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E114_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E114_E11.py.snap @@ -23,17 +23,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - E114 Indentation is not a multiple of 4 (comment) --> E11.py:15:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E115_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E115_E11.py.snap index b4655dd131ce5..223bfca4b0b34 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E115_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E115_E11.py.snap @@ -23,17 +23,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - E115 Expected an indented block (comment) --> E11.py:30:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E116_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E116_E11.py.snap index f70307eaa6b4a..33ae7f29b729f 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E116_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E116_E11.py.snap @@ -23,17 +23,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - E116 Unexpected indentation (comment) --> E11.py:15:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E117_E11.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E117_E11.py.snap index 10f126e602ec5..aa9f69284068a 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E117_E11.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E117_E11.py.snap @@ -34,17 +34,6 @@ invalid-syntax: Unexpected indentation 14 | mimetype = 'application/x-directory' | -invalid-syntax: Expected a statement - --> E11.py:14:1 - | -12 | print() -13 | #: E114 E116 -14 | mimetype = 'application/x-directory' - | ^ -15 | # 'httpd/unix-directory' -16 | create_date = False - | - E117 Over-indented --> E11.py:39:1 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W191_W19.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W191_W19.py.snap index 8d88eef99b46c..1dd6489e64ca6 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W191_W19.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W191_W19.py.snap @@ -17,16 +17,6 @@ invalid-syntax: Unexpected indentation 2 | multiline string with tab in it''' | -invalid-syntax: Expected a statement - --> W19.py:5:1 - | -4 | #: W191 -5 | if False: - | ^ -6 | print # indented with 1 tab -7 | #: - | - W191 Indentation contains tabs --> W19.py:6:1 | diff --git a/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py b/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py index 55cc8886e569e..2ab639c6cb11b 100644 --- a/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py +++ b/crates/ruff_python_parser/resources/invalid/statements/if_extra_indent.py @@ -1,4 +1,4 @@ -# Improving the recovery would require changing the lexer to emit an extra dedent token after `a + b`. +# On invalid indentation, recover as if the indentation wasn't there if True: pass a + b diff --git a/crates/ruff_python_parser/src/parser/mod.rs b/crates/ruff_python_parser/src/parser/mod.rs index e3e9af569f1c6..6719c0ab86fcf 100644 --- a/crates/ruff_python_parser/src/parser/mod.rs +++ b/crates/ruff_python_parser/src/parser/mod.rs @@ -736,6 +736,7 @@ impl<'src> Parser<'src> { mut parse_element: impl FnMut(&mut Parser<'src>), ) { let mut progress = ParserProgress::default(); + let mut unexpected_indents = 0; let saved_context = self.recovery_context; self.recovery_context = self @@ -745,7 +746,12 @@ impl<'src> Parser<'src> { loop { progress.assert_progressing(self); - if recovery_context_kind.is_list_element(self) { + if 0 < unexpected_indents && self.at(TokenKind::Dedent) { + // Ignore this `Dedent` like we ignored the `Indent`, avoiding extra errors from + // being imbalanced + unexpected_indents -= 1; + self.bump(TokenKind::Dedent); + } else if recovery_context_kind.is_list_element(self) { parse_element(self); } else if recovery_context_kind.is_regular_list_terminator(self) { break; @@ -763,6 +769,14 @@ impl<'src> Parser<'src> { self.current_token_range(), ); + if matches!( + recovery_context_kind, + RecoveryContextKind::ModuleStatements | RecoveryContextKind::BlockStatements + ) && self.at(TokenKind::Indent) + { + // For this invalid `Indent`, ensure the matching `Dedent` gets consumed as well + unexpected_indents += 1; + } self.bump_any(); } } diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@backslash_continuation_indentation_error.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@backslash_continuation_indentation_error.py.snap index cb857a67d4102..c8a556e09bee4 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@backslash_continuation_indentation_error.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@backslash_continuation_indentation_error.py.snap @@ -69,10 +69,3 @@ Module( 4 | | 2 | |____^ Syntax Error: Unexpected indentation | - - - | -3 | \ -4 | 2 - | ^ Syntax Error: Expected a statement - | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@if_stmt_misspelled_elif.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@if_stmt_misspelled_elif.py.snap index e932a526c41fd..4a0f4d0afaefd 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@if_stmt_misspelled_elif.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@if_stmt_misspelled_elif.py.snap @@ -98,8 +98,8 @@ Module( | 3 | elf: 4 | pass - | ^ Syntax Error: Expected a statement 5 | else: + | ^^^^ Syntax Error: Expected a statement 6 | pass | @@ -128,10 +128,3 @@ Module( 6 | pass | ^^^^ Syntax Error: Unexpected indentation | - - - | -5 | else: -6 | pass - | ^ Syntax Error: Expected a statement - | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@re_lexing__fstring_format_spec_1.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@re_lexing__fstring_format_spec_1.py.snap index d836318aea793..f0d3b3104c632 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@re_lexing__fstring_format_spec_1.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@re_lexing__fstring_format_spec_1.py.snap @@ -480,15 +480,6 @@ Module( | - | - 9 | 'format spec'} -10 | - | ^ Syntax Error: Expected a statement -11 | f'middle {'string':\\\ -12 | 'format spec'} - | - - | 11 | f'middle {'string':\\\ 12 | 'format spec'} diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_closing_parentheses.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_closing_parentheses.py.snap index 780f943a967b2..126138f28ade2 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_closing_parentheses.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_closing_parentheses.py.snap @@ -75,10 +75,3 @@ Module( 3 | pass | ^^^^ Syntax Error: Unexpected indentation | - - - | -2 | if True)): -3 | pass - | ^ Syntax Error: Expected a statement - | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap index 800e52f16b2f1..e3796a8d1f3e1 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__if_extra_indent.py.snap @@ -8,16 +8,16 @@ input_file: crates/ruff_python_parser/resources/invalid/statements/if_extra_inde Module( ModModule { node_index: NodeIndex(None), - range: 0..939, + range: 0..905, body: [ If( StmtIf { node_index: NodeIndex(None), - range: 103..134, + range: 69..110, test: BooleanLiteral( ExprBooleanLiteral { node_index: NodeIndex(None), - range: 106..110, + range: 72..76, value: true, }, ), @@ -25,21 +25,21 @@ Module( Pass( StmtPass { node_index: NodeIndex(None), - range: 116..120, + range: 82..86, }, ), Expr( StmtExpr { node_index: NodeIndex(None), - range: 129..134, + range: 95..100, value: BinOp( ExprBinOp { node_index: NodeIndex(None), - range: 129..134, + range: 95..100, left: Name( ExprName { node_index: NodeIndex(None), - range: 129..130, + range: 95..96, id: Name("a"), ctx: Load, }, @@ -48,7 +48,7 @@ Module( right: Name( ExprName { node_index: NodeIndex(None), - range: 133..134, + range: 99..100, id: Name("b"), ctx: Load, }, @@ -57,25 +57,25 @@ Module( ), }, ), + Pass( + StmtPass { + node_index: NodeIndex(None), + range: 106..110, + }, + ), ], elif_else_clauses: [], }, ), - Pass( - StmtPass { - node_index: NodeIndex(None), - range: 140..144, - }, - ), Assign( StmtAssign { node_index: NodeIndex(None), - range: 146..152, + range: 112..118, targets: [ Name( ExprName { node_index: NodeIndex(None), - range: 146..147, + range: 112..113, id: Name("a"), ctx: Store, }, @@ -84,7 +84,7 @@ Module( value: NumberLiteral( ExprNumberLiteral { node_index: NodeIndex(None), - range: 150..152, + range: 116..118, value: Int( 10, ), @@ -95,11 +95,11 @@ Module( If( StmtIf { node_index: NodeIndex(None), - range: 192..265, + range: 158..248, test: BooleanLiteral( ExprBooleanLiteral { node_index: NodeIndex(None), - range: 195..199, + range: 161..165, value: true, }, ), @@ -107,11 +107,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 205..218, + range: 171..184, value: Name( ExprName { node_index: NodeIndex(None), - range: 205..218, + range: 171..184, id: Name("before_nested"), ctx: Load, }, @@ -121,11 +121,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 227..239, + range: 193..205, value: Name( ExprName { node_index: NodeIndex(None), - range: 227..239, + range: 193..205, id: Name("first_nested"), ctx: Load, }, @@ -135,17 +135,31 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 252..265, + range: 218..231, value: Name( ExprName { node_index: NodeIndex(None), - range: 252..265, + range: 218..231, id: Name("second_nested"), ctx: Load, }, ), }, ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 236..248, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 236..248, + id: Name("after_nested"), + ctx: Load, + }, + ), + }, + ), ], elif_else_clauses: [], }, @@ -153,25 +167,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 270..282, - value: Name( - ExprName { - node_index: NodeIndex(None), - range: 270..282, - id: Name("after_nested"), - ctx: Load, - }, - ), - }, - ), - Expr( - StmtExpr { - node_index: NodeIndex(None), - range: 284..298, + range: 250..264, value: Name( ExprName { node_index: NodeIndex(None), - range: 284..298, + range: 250..264, id: Name("outside_nested"), ctx: Load, }, @@ -181,11 +181,11 @@ Module( If( StmtIf { node_index: NodeIndex(None), - range: 359..464, + range: 325..449, test: BooleanLiteral( ExprBooleanLiteral { node_index: NodeIndex(None), - range: 362..366, + range: 328..332, value: true, }, ), @@ -193,11 +193,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 372..387, + range: 338..353, value: Name( ExprName { node_index: NodeIndex(None), - range: 372..387, + range: 338..353, id: Name("before_compound"), ctx: Load, }, @@ -207,11 +207,11 @@ Module( If( StmtIf { node_index: NodeIndex(None), - range: 396..437, + range: 362..403, test: Name( ExprName { node_index: NodeIndex(None), - range: 399..408, + range: 365..374, id: Name("condition"), ctx: Load, }, @@ -220,11 +220,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 422..437, + range: 388..403, value: Name( ExprName { node_index: NodeIndex(None), - range: 422..437, + range: 388..403, id: Name("nested_compound"), ctx: Load, }, @@ -238,17 +238,31 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 446..464, + range: 412..430, value: Name( ExprName { node_index: NodeIndex(None), - range: 446..464, + range: 412..430, id: Name("recovered_compound"), ctx: Load, }, ), }, ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 435..449, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 435..449, + id: Name("after_compound"), + ctx: Load, + }, + ), + }, + ), ], elif_else_clauses: [], }, @@ -256,25 +270,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 469..483, - value: Name( - ExprName { - node_index: NodeIndex(None), - range: 469..483, - id: Name("after_compound"), - ctx: Load, - }, - ), - }, - ), - Expr( - StmtExpr { - node_index: NodeIndex(None), - range: 485..501, + range: 451..467, value: Name( ExprName { node_index: NodeIndex(None), - range: 485..501, + range: 451..467, id: Name("outside_compound"), ctx: Load, }, @@ -284,11 +284,11 @@ Module( If( StmtIf { node_index: NodeIndex(None), - range: 570..618, + range: 536..641, test: BooleanLiteral( ExprBooleanLiteral { node_index: NodeIndex(None), - range: 573..577, + range: 539..543, value: true, }, ), @@ -296,11 +296,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 583..597, + range: 549..563, value: Name( ExprName { node_index: NodeIndex(None), - range: 583..597, + range: 549..563, id: Name("before_regions"), ctx: Load, }, @@ -310,17 +310,59 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 606..618, + range: 572..584, value: Name( ExprName { node_index: NodeIndex(None), - range: 606..618, + range: 572..584, id: Name("first_region"), ctx: Load, }, ), }, ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 589..602, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 589..602, + id: Name("middle_region"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 611..624, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 611..624, + id: Name("second_region"), + ctx: Load, + }, + ), + }, + ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 629..641, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 629..641, + id: Name("after_region"), + ctx: Load, + }, + ), + }, + ), ], elif_else_clauses: [], }, @@ -328,53 +370,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 623..636, + range: 643..658, value: Name( ExprName { node_index: NodeIndex(None), - range: 623..636, - id: Name("middle_region"), - ctx: Load, - }, - ), - }, - ), - Expr( - StmtExpr { - node_index: NodeIndex(None), - range: 645..658, - value: Name( - ExprName { - node_index: NodeIndex(None), - range: 645..658, - id: Name("second_region"), - ctx: Load, - }, - ), - }, - ), - Expr( - StmtExpr { - node_index: NodeIndex(None), - range: 663..675, - value: Name( - ExprName { - node_index: NodeIndex(None), - range: 663..675, - id: Name("after_region"), - ctx: Load, - }, - ), - }, - ), - Expr( - StmtExpr { - node_index: NodeIndex(None), - range: 677..692, - value: Name( - ExprName { - node_index: NodeIndex(None), - range: 677..692, + range: 643..658, id: Name("outside_regions"), ctx: Load, }, @@ -384,11 +384,11 @@ Module( If( StmtIf { node_index: NodeIndex(None), - range: 768..811, + range: 734..793, test: BooleanLiteral( ExprBooleanLiteral { node_index: NodeIndex(None), - range: 771..775, + range: 737..741, value: true, }, ), @@ -396,11 +396,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 781..793, + range: 747..759, value: Name( ExprName { node_index: NodeIndex(None), - range: 781..793, + range: 747..759, id: Name("before_error"), ctx: Load, }, @@ -410,21 +410,21 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 802..811, + range: 768..777, value: Call( ExprCall { node_index: NodeIndex(None), - range: 802..811, + range: 768..777, func: Name( ExprName { node_index: NodeIndex(None), - range: 802..808, + range: 768..774, id: Name("broken"), ctx: Load, }, ), arguments: Arguments { - range: 808..811, + range: 774..777, node_index: NodeIndex(None), args: [], keywords: [], @@ -433,6 +433,20 @@ Module( ), }, ), + Expr( + StmtExpr { + node_index: NodeIndex(None), + range: 782..793, + value: Name( + ExprName { + node_index: NodeIndex(None), + range: 782..793, + id: Name("after_error"), + ctx: Load, + }, + ), + }, + ), ], elif_else_clauses: [], }, @@ -440,25 +454,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 816..827, + range: 795..808, value: Name( ExprName { node_index: NodeIndex(None), - range: 816..827, - id: Name("after_error"), - ctx: Load, - }, - ), - }, - ), - Expr( - StmtExpr { - node_index: NodeIndex(None), - range: 829..842, - value: Name( - ExprName { - node_index: NodeIndex(None), - range: 829..842, + range: 795..808, id: Name("outside_error"), ctx: Load, }, @@ -468,11 +468,11 @@ Module( If( StmtIf { node_index: NodeIndex(None), - range: 897..938, + range: 863..904, test: BooleanLiteral( ExprBooleanLiteral { node_index: NodeIndex(None), - range: 900..904, + range: 866..870, value: true, }, ), @@ -480,11 +480,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 910..920, + range: 876..886, value: Name( ExprName { node_index: NodeIndex(None), - range: 910..920, + range: 876..886, id: Name("before_eof"), ctx: Load, }, @@ -494,11 +494,11 @@ Module( Expr( StmtExpr { node_index: NodeIndex(None), - range: 929..938, + range: 895..904, value: Name( ExprName { node_index: NodeIndex(None), - range: 929..938, + range: 895..904, id: Name("final_eof"), ctx: Load, }, @@ -525,16 +525,6 @@ Module( | - | - 6 | pass - 7 | - | ^ Syntax Error: Expected a statement - 8 | a = 10 - 9 | -10 | # Multiple nested unexpected indents. - | - - | 11 | if True: 12 | before_nested @@ -554,26 +544,6 @@ Module( | - | -13 | first_nested -14 | second_nested -15 | after_nested - | ^ Syntax Error: Expected a statement -16 | -17 | outside_nested - | - - - | -15 | after_nested -16 | - | ^ Syntax Error: Expected a statement -17 | outside_nested -18 | -19 | # A valid compound statement inside recovered indentation. - | - - | 20 | if True: 21 | before_compound @@ -584,16 +554,6 @@ Module( | - | -25 | after_compound -26 | - | ^ Syntax Error: Expected a statement -27 | outside_compound -28 | -29 | # Multiple independent unexpected-indent regions in the same body. - | - - | 30 | if True: 31 | before_regions @@ -613,26 +573,6 @@ Module( | - | -33 | middle_region -34 | second_region -35 | after_region - | ^ Syntax Error: Expected a statement -36 | -37 | outside_regions - | - - - | -35 | after_region -36 | - | ^ Syntax Error: Expected a statement -37 | outside_regions -38 | -39 | # An independent syntax error inside recovered indentation stays visible. - | - - | 40 | if True: 41 | before_error @@ -651,26 +591,9 @@ Module( | - | -43 | after_error -44 | - | ^ Syntax Error: Expected a statement -45 | outside_error -46 | -47 | # Outstanding unexpected indents are flushed at EOF. - | - - | 48 | if True: 49 | before_eof 50 | final_eof | ^^^^^^^^ Syntax Error: Unexpected indentation | - - - | -49 | before_eof -50 | final_eof - | ^ Syntax Error: Expected a statement - | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_invalid_order.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_invalid_order.py.snap index 0bcf4355aa95e..9f55c082517cb 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_invalid_order.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_invalid_order.py.snap @@ -80,10 +80,3 @@ Module( 6 | pass | ^^^^ Syntax Error: Unexpected indentation | - - - | -5 | else: -6 | pass - | ^ Syntax Error: Expected a statement - | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_misspelled_except.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_misspelled_except.py.snap index 1803efb100daa..e65db427d0db0 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_misspelled_except.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@try_stmt_misspelled_except.py.snap @@ -219,8 +219,8 @@ Module( | 3 | exept: # spellchecker:disable-line 4 | pass - | ^ Syntax Error: Expected a statement 5 | finally: + | ^^^^^^^ Syntax Error: Expected a statement 6 | pass 7 | a = 1 | @@ -257,16 +257,6 @@ Module( | - | -5 | finally: -6 | pass - | ^ Syntax Error: Expected a statement -7 | a = 1 -8 | try: -9 | pass - | - - | 10 | except: 11 | pass @@ -284,11 +274,3 @@ Module( | ^^^^ Syntax Error: Unexpected indentation 14 | b = 1 | - - - | -12 | exept: # spellchecker:disable-line -13 | pass - | ^ Syntax Error: Expected a statement -14 | b = 1 - | diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md index 5d0dae7b3d964..c714ce6181dbc 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md @@ -32,7 +32,6 @@ position. The parser could do a better job in recovering from these errors. # error: [invalid-syntax] # error: [invalid-syntax] def foo[**P: int]() -> None: - # error: [invalid-syntax] # error: [invalid-syntax] pass ``` diff --git a/crates/ty_python_semantic/resources/mdtest/invalid_syntax.md b/crates/ty_python_semantic/resources/mdtest/invalid_syntax.md index 53acc4fbe3252..7a88c70b62402 100644 --- a/crates/ty_python_semantic/resources/mdtest/invalid_syntax.md +++ b/crates/ty_python_semantic/resources/mdtest/invalid_syntax.md @@ -40,7 +40,6 @@ type pass = 1 # error: [invalid-syntax] # error: [invalid-syntax] def True(for): - # error: [invalid-syntax] # error: [invalid-syntax] pass ``` @@ -76,7 +75,6 @@ match while: # error: [invalid-syntax] # error: [unresolved-reference] "Name `case` used when not defined" case in: - # error: [invalid-syntax] # error: [invalid-syntax] pass ```