From d4fee7dad053478d30d5ea04f2b6edbcc46639b6 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 29 Mar 2024 20:55:53 -0400 Subject: [PATCH] Make unnecessary-lambda an unsafe fix always --- .../rules/pylint/rules/unnecessary_lambda.rs | 24 +++++++++++-------- ..._tests__PLW0108_unnecessary_lambda.py.snap | 14 +++++------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_lambda.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_lambda.rs index 3900031ac03cd2..7fc68782dc5151 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_lambda.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_lambda.rs @@ -1,6 +1,5 @@ use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::helpers::contains_effect; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{self as ast, visitor, Expr, ExprLambda, Parameter, ParameterWithDefault}; use ruff_text_size::Ranged; @@ -27,15 +26,24 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Fix safety -/// This rule's fix is marked as unsafe in cases in which the lambda body itself -/// contains an effect. +/// This rule's fix is marked as unsafe for two primary reasons. +/// +/// First, the lambda body itself could contain an effect. /// /// For example, replacing `lambda x, y: (func()(x, y))` with `func()` would /// lead to a change in behavior, as `func()` would be evaluated eagerly when /// defining the lambda, rather than when the lambda is called. /// -/// When the lambda body contains no visible effects, the fix is considered -/// safe. +/// However, even when the lambda body itself is pure, the lambda may +/// change the argument names, which can lead to a change in behavior when +/// callers pass arguments by name. +/// +/// For example, replacing `foo = lambda x, y: func(x, y)` with `foo = func`, +/// where `func` is defined as `def func(a, b): return a + b`, would be a +/// breaking change for callers that execute the lambda by passing arguments by +/// name, as in: `foo(x=1, y=2)`. Since `func` does not define the arguments +/// `x` and `y`, unlike the lambda, the call would raise a `TypeError`. +/// #[violation] pub struct UnnecessaryLambda; @@ -206,11 +214,7 @@ pub(crate) fn unnecessary_lambda(checker: &mut Checker, lambda: &ExprLambda) { checker.locator().slice(func.as_ref()).to_string(), lambda.range(), ), - if contains_effect(func.as_ref(), |id| checker.semantic().is_builtin(id)) { - Applicability::Unsafe - } else { - Applicability::Safe - }, + Applicability::Unsafe, )); checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0108_unnecessary_lambda.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0108_unnecessary_lambda.py.snap index 5247ac88bd92cf..74af7a647f7b6b 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0108_unnecessary_lambda.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0108_unnecessary_lambda.py.snap @@ -9,7 +9,7 @@ unnecessary_lambda.py:1:5: PLW0108 [*] Lambda may be unnecessary; consider inlin | = help: Inline function call -ℹ Safe fix +ℹ Unsafe fix 1 |-_ = lambda: print() # [unnecessary-lambda] 1 |+_ = print # [unnecessary-lambda] 2 2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda] @@ -26,7 +26,7 @@ unnecessary_lambda.py:2:5: PLW0108 [*] Lambda may be unnecessary; consider inlin | = help: Inline function call -ℹ Safe fix +ℹ Unsafe fix 1 1 | _ = lambda: print() # [unnecessary-lambda] 2 |-_ = lambda x, y: min(x, y) # [unnecessary-lambda] 2 |+_ = min # [unnecessary-lambda] @@ -45,7 +45,7 @@ unnecessary_lambda.py:4:5: PLW0108 [*] Lambda may be unnecessary; consider inlin | = help: Inline function call -ℹ Safe fix +ℹ Unsafe fix 1 1 | _ = lambda: print() # [unnecessary-lambda] 2 2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda] 3 3 | @@ -65,7 +65,7 @@ unnecessary_lambda.py:5:5: PLW0108 [*] Lambda may be unnecessary; consider inlin | = help: Inline function call -ℹ Safe fix +ℹ Unsafe fix 2 2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda] 3 3 | 4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda] @@ -85,7 +85,7 @@ unnecessary_lambda.py:6:5: PLW0108 [*] Lambda may be unnecessary; consider inlin | = help: Inline function call -ℹ Safe fix +ℹ Unsafe fix 3 3 | 4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda] 5 5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda] @@ -106,7 +106,7 @@ unnecessary_lambda.py:7:5: PLW0108 [*] Lambda may be unnecessary; consider inlin | = help: Inline function call -ℹ Safe fix +ℹ Unsafe fix 4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda] 5 5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda] 6 6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda] @@ -155,5 +155,3 @@ unnecessary_lambda.py:10:5: PLW0108 [*] Lambda may be unnecessary; consider inli 11 11 | 12 12 | # default value in lambda parameters 13 13 | _ = lambda x=42: print(x) - -