diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/nan_comparison.py b/crates/ruff_linter/resources/test/fixtures/pylint/nan_comparison.py index e9ef56c1304f5..3481b37d6e1ac 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/nan_comparison.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/nan_comparison.py @@ -53,6 +53,18 @@ if x == builtins.float("nan"): pass +# /~https://github.com/astral-sh/ruff/issues/16374 +match number: + # Errors + case np.nan: ... + case math.nan: ... + + # No errors + case np.nan(): ... + case math.nan(): ... + case float('nan'): ... + case npy_nan: ... + # OK if math.isnan(x): pass diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 77863086d6989..7b4aaa0a7e88e 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1742,6 +1742,15 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pylint::rules::useless_exception_statement(checker, expr); } } + Stmt::Match(ast::StmtMatch { + subject: _, + cases, + range: _, + }) => { + if checker.enabled(Rule::NanComparison) { + pylint::rules::nan_comparison_match(checker, cases); + } + } _ => {} } } diff --git a/crates/ruff_linter/src/rules/pylint/rules/nan_comparison.rs b/crates/ruff_linter/src/rules/pylint/rules/nan_comparison.rs index 5eee0a1ee5222..aca8fe15fcfd9 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/nan_comparison.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/nan_comparison.rs @@ -48,7 +48,21 @@ impl Violation for NanComparison { /// PLW0177 pub(crate) fn nan_comparison(checker: &Checker, left: &Expr, comparators: &[Expr]) { - for expr in std::iter::once(left).chain(comparators) { + nan_comparison_impl(checker, std::iter::once(left).chain(comparators)); +} + +/// PLW0177 +pub(crate) fn nan_comparison_match(checker: &Checker, cases: &[ast::MatchCase]) { + nan_comparison_impl( + checker, + cases + .iter() + .filter_map(|case| case.pattern.as_match_value().map(|pattern| &*pattern.value)), + ); +} + +fn nan_comparison_impl<'a>(checker: &Checker, comparators: impl Iterator) { + for expr in comparators { if let Some(qualified_name) = checker.semantic().resolve_qualified_name(expr) { match qualified_name.segments() { ["numpy", "nan" | "NAN" | "NaN"] => { diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0177_nan_comparison.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0177_nan_comparison.py.snap index 3b87327d734f6..a9c4292f14771 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0177_nan_comparison.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0177_nan_comparison.py.snap @@ -1,6 +1,5 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs -snapshot_kind: text --- nan_comparison.py:11:9: PLW0177 Comparing against a NaN value; use `math.isnan` instead | @@ -89,3 +88,22 @@ nan_comparison.py:53:9: PLW0177 Comparing against a NaN value; use `math.isnan` | ^^^^^^^^^^^^^^^^^^^^^ PLW0177 54 | pass | + +nan_comparison.py:59:10: PLW0177 Comparing against a NaN value; use `np.isnan` instead + | +57 | match number: +58 | # Errors +59 | case np.nan: ... + | ^^^^^^ PLW0177 +60 | case math.nan: ... + | + +nan_comparison.py:60:10: PLW0177 Comparing against a NaN value; use `math.isnan` instead + | +58 | # Errors +59 | case np.nan: ... +60 | case math.nan: ... + | ^^^^^^^^ PLW0177 +61 | +62 | # No errors + |