From e27ec429a1de51ecf619bf0c6edfcb73d4b1f506 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 3 Oct 2023 22:10:20 -0700 Subject: [PATCH] Fix SIM110 with a yield in the condition And allow "await" in the loop iterable. Fixes #7800 --- .../test/fixtures/flake8_simplify/SIM110.py | 21 ++++++++++++ .../rules/reimplemented_builtin.rs | 11 ++++--- ...ke8_simplify__tests__SIM110_SIM110.py.snap | 33 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM110.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM110.py index cc2527e0922f8..2ac86dca61b10 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM110.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM110.py @@ -185,3 +185,24 @@ async def f(): if check(x): return True return False + +async def f(): + # SIM110 + for x in await iterable: + if check(x): + return True + return False + +def f(): + # OK (can't turn this into any() because the yield would end up inside a genexp) + for x in iterable: + if (yield check(x)): + return True + return False + +def f(): + # OK (same) + for x in iterable: + if (yield from check(x)): + return True + return False diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/reimplemented_builtin.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/reimplemented_builtin.rs index cd1bc13905ba5..31f900250a0ef 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/reimplemented_builtin.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/reimplemented_builtin.rs @@ -80,8 +80,9 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) { return; }; - // Check if any of the expressions contain an `await` expression. - if contains_await(loop_.target) || contains_await(loop_.iter) || contains_await(loop_.test) { + // Check if any of the expressions contain an `await`, `yield`, or `yield from` expression. + // If so, turning the code into an any() or all() call would produce a SyntaxError. + if contains_yield_like(loop_.target) || contains_yield_like(loop_.test) { return; } @@ -413,7 +414,9 @@ fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Gen generator.stmt(&node3.into()) } -/// Return `true` if the [`Expr`] contains an `await` expression. -fn contains_await(expr: &Expr) -> bool { +/// Return `true` if the [`Expr`] contains an `await`, `yield`, or `yield from` expression. +fn contains_yield_like(expr: &Expr) -> bool { any_over_expr(expr, &Expr::is_await_expr) + || any_over_expr(expr, &Expr::is_yield_expr) + || any_over_expr(expr, &Expr::is_yield_from_expr) } diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM110_SIM110.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM110_SIM110.py.snap index 1473e4bfdaab3..6ddf17ea9046f 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM110_SIM110.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM110_SIM110.py.snap @@ -304,6 +304,8 @@ SIM110.py:184:5: SIM110 [*] Use `return any(check(x) for x in iterable)` instead 186 | | return True 187 | | return False | |________________^ SIM110 +188 | +189 | async def f(): | = help: Replace with `return any(check(x) for x in iterable)` @@ -316,5 +318,36 @@ SIM110.py:184:5: SIM110 [*] Use `return any(check(x) for x in iterable)` instead 186 |- return True 187 |- return False 184 |+ return any(check(x) for x in iterable) +188 185 | +189 186 | async def f(): +190 187 | # SIM110 + +SIM110.py:191:5: SIM110 [*] Use `return any(check(x) for x in await iterable)` instead of `for` loop + | +189 | async def f(): +190 | # SIM110 +191 | for x in await iterable: + | _____^ +192 | | if check(x): +193 | | return True +194 | | return False + | |________________^ SIM110 +195 | +196 | def f(): + | + = help: Replace with `return any(check(x) for x in await iterable)` + +ℹ Suggested fix +188 188 | +189 189 | async def f(): +190 190 | # SIM110 +191 |- for x in await iterable: +192 |- if check(x): +193 |- return True +194 |- return False + 191 |+ return any(check(x) for x in await iterable) +195 192 | +196 193 | def f(): +197 194 | # OK (can't turn this into any() because the yield would end up inside a genexp)