diff --git a/crates/ruff/resources/test/fixtures/pyflakes/F821_9.py b/crates/ruff/resources/test/fixtures/pyflakes/F821_9.py index e7490cbb51..13f6386c5c 100644 --- a/crates/ruff/resources/test/fixtures/pyflakes/F821_9.py +++ b/crates/ruff/resources/test/fixtures/pyflakes/F821_9.py @@ -14,13 +14,26 @@ def f(): print(model) case Car(make, "Corolla"): print(make) + case Car(_, _): + print(make, model) + case _: + print("No match") def f(provided: int) -> int: match provided: case True: return captured # F821 + case [*_] as captured: + return captured case [captured, *_]: return captured case captured: return captured + + +match 1: + case 1: + x = 1 + +print(x) diff --git a/crates/ruff/resources/test/fixtures/pyflakes/F841_0.py b/crates/ruff/resources/test/fixtures/pyflakes/F841_0.py index 90c44f761c..ebcd25b8ad 100644 --- a/crates/ruff/resources/test/fixtures/pyflakes/F841_0.py +++ b/crates/ruff/resources/test/fixtures/pyflakes/F841_0.py @@ -119,5 +119,7 @@ def f(x: int): print("A") case [Bar.A, *_]: print("A") + case [*_] as y: + z = 1 case y: pass diff --git a/crates/ruff/src/ast/types.rs b/crates/ruff/src/ast/types.rs index d4904bce62..6a0811b438 100644 --- a/crates/ruff/src/ast/types.rs +++ b/crates/ruff/src/ast/types.rs @@ -78,6 +78,7 @@ pub enum ScopeKind<'a> { Generator, Module, Lambda(Lambda<'a>), + Case, } #[derive(Debug)] diff --git a/crates/ruff/src/checkers/ast.rs b/crates/ruff/src/checkers/ast.rs index 0ad020c53b..36f6597116 100644 --- a/crates/ruff/src/checkers/ast.rs +++ b/crates/ruff/src/checkers/ast.rs @@ -10,8 +10,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; use rustpython_common::cformat::{CFormatError, CFormatErrorType}; use rustpython_parser::ast::{ Arg, Arguments, Comprehension, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, - ExprKind, KeywordData, Located, Location, Operator, Pattern, PatternKind, Stmt, StmtKind, - Suite, + ExprKind, KeywordData, Located, Location, MatchCase, Operator, Pattern, PatternKind, Stmt, + StmtKind, Suite, }; use rustpython_parser::parser; use smallvec::smallvec; @@ -29,7 +29,7 @@ use crate::ast::types::{ RefEquality, Scope, ScopeKind, }; use crate::ast::typing::{match_annotated_subscript, Callable, SubscriptKind}; -use crate::ast::visitor::{walk_excepthandler, walk_pattern, Visitor}; +use crate::ast::visitor::{walk_excepthandler, walk_match_case, walk_pattern, Visitor}; use crate::ast::{branch_detection, cast, helpers, operations, typing, visitor}; use crate::docstrings::definition::{Definition, DefinitionKind, Docstring, Documentable}; use crate::registry::{Diagnostic, Rule}; @@ -3841,6 +3841,14 @@ where } } + fn visit_match_case(&mut self, match_case: &'b MatchCase) { + self.push_scope(Scope::new(ScopeKind::Case)); + walk_match_case(self, match_case); + self.deferred_assignments + .push((self.scope_stack.clone(), self.parents.clone())); + self.pop_scope(); + } + fn visit_pattern(&mut self, pattern: &'b Pattern) { if let PatternKind::MatchAs { name: Some(name), .. diff --git a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F821_F821_9.py.snap b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F821_F821_9.py.snap index e25170c57e..ae88f75066 100644 --- a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F821_F821_9.py.snap +++ b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F821_F821_9.py.snap @@ -2,14 +2,36 @@ source: crates/ruff/src/rules/pyflakes/mod.rs expression: diagnostics --- +- kind: + UndefinedName: + name: make + location: + row: 18 + column: 18 + end_location: + row: 18 + column: 22 + fix: ~ + parent: ~ +- kind: + UndefinedName: + name: model + location: + row: 18 + column: 24 + end_location: + row: 18 + column: 29 + fix: ~ + parent: ~ - kind: UndefinedName: name: captured location: - row: 22 + row: 26 column: 19 end_location: - row: 22 + row: 26 column: 27 fix: ~ parent: ~ diff --git a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F841_F841_0.py.snap b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F841_F841_0.py.snap index d178b025fa..173c7d27a4 100644 --- a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F841_F841_0.py.snap +++ b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F841_F841_0.py.snap @@ -194,6 +194,35 @@ expression: diagnostics column: 13 end_location: row: 122 + column: 22 + fix: ~ + parent: ~ +- kind: + UnusedVariable: + name: z + location: + row: 123 + column: 12 + end_location: + row: 123 + column: 13 + fix: + content: pass + location: + row: 123 + column: 12 + end_location: + row: 123 + column: 17 + parent: ~ +- kind: + UnusedVariable: + name: y + location: + row: 124 + column: 13 + end_location: + row: 124 column: 14 fix: ~ parent: ~ diff --git a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__f841_dummy_variable_rgx.snap b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__f841_dummy_variable_rgx.snap index 73e7beebd4..14f654228e 100644 --- a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__f841_dummy_variable_rgx.snap +++ b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__f841_dummy_variable_rgx.snap @@ -230,6 +230,17 @@ expression: diagnostics column: 13 end_location: row: 122 + column: 22 + fix: ~ + parent: ~ +- kind: + UnusedVariable: + name: y + location: + row: 124 + column: 13 + end_location: + row: 124 column: 14 fix: ~ parent: ~