Skip to content

Commit b890639

Browse files
committed
Use an enum
1 parent 3da2dbb commit b890639

File tree

2 files changed

+44
-35
lines changed

2 files changed

+44
-35
lines changed

crates/ruff_linter/src/rules/refurb/rules/reimplemented_starmap.rs

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pub(crate) fn reimplemented_starmap(checker: &mut Checker, target: &StarmapCandi
8282
// ```
8383
//
8484
// `x, y, z, ...` are what we call `elts` for short.
85-
let Some((elts, iter)) = match_comprehension(comprehension) else {
85+
let Some(value) = match_comprehension_target(comprehension) else {
8686
return;
8787
};
8888

@@ -99,27 +99,30 @@ pub(crate) fn reimplemented_starmap(checker: &mut Checker, target: &StarmapCandi
9999
return;
100100
};
101101

102-
// Here we want to check that `args` and `elts` are the same (same length, same elements,
103-
// same order).
104-
if elts.len() != args.len() {
105-
return;
106-
}
102+
match value {
103+
// Ex) `f(*x) for x in iter`
104+
ComprehensionTarget::Name(name) => {
105+
let [arg] = args else {
106+
return;
107+
};
107108

108-
// If there is only one element (and, thus, one argument), we can still do our fix if the
109-
// argument is just the element starred; otherwise, bail.
110-
if elts.len() == 1 {
111-
if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = args.first().unwrap() {
112-
if ComparableExpr::from(value.as_ref()) != ComparableExpr::from(elts.first().unwrap()) {
109+
let Expr::Starred(ast::ExprStarred { value, .. }) = arg else {
110+
return;
111+
};
112+
113+
if ComparableExpr::from(value.as_ref()) != ComparableExpr::from(name) {
114+
return;
115+
}
116+
}
117+
// Ex) `f(x, y, z) for x, y, z in iter`
118+
ComprehensionTarget::Tuple(tuple) => {
119+
if tuple.elts.len() != args.len()
120+
|| !std::iter::zip(&tuple.elts, args)
121+
.all(|(x, y)| ComparableExpr::from(x) == ComparableExpr::from(y))
122+
{
113123
return;
114124
}
115-
} else {
116-
return;
117125
}
118-
// Otherwise, check that all elements are the same as the arguments.
119-
} else if !std::iter::zip(elts, args)
120-
.all(|(x, y)| ComparableExpr::from(x) == ComparableExpr::from(y))
121-
{
122-
return;
123126
}
124127

125128
let mut diagnostic = Diagnostic::new(ReimplementedStarmap, target.range());
@@ -141,7 +144,7 @@ pub(crate) fn reimplemented_starmap(checker: &mut Checker, target: &StarmapCandi
141144
// - For list and set comprehensions, we'd want to wrap it with `list` and `set`
142145
// correspondingly.
143146
let main_edit = Edit::range_replacement(
144-
target.try_make_suggestion(starmap_name, iter, func, checker)?,
147+
target.try_make_suggestion(starmap_name, &comprehension.iter, func, checker)?,
145148
target.range(),
146149
);
147150
Ok(Fix::suggested_edits(import_edit, [main_edit]))
@@ -266,7 +269,7 @@ fn try_construct_call(
266269
// We can only do our fix if `builtin` identifier is still bound to
267270
// the built-in type.
268271
if !checker.semantic().is_builtin(builtin) {
269-
bail!(format!("Can't use built-in `{builtin}` constructor"))
272+
bail!("Can't use built-in `{builtin}` constructor")
270273
}
271274

272275
// In general, we replace:
@@ -320,20 +323,22 @@ fn wrap_with_call_to(call: ast::ExprCall, func_name: &str) -> ast::ExprCall {
320323
}
321324
}
322325

323-
/// Match that the given comprehension is `(x, y, z, ...) in iter`.
324-
fn match_comprehension(comprehension: &ast::Comprehension) -> Option<(&[Expr], &Expr)> {
326+
#[derive(Debug)]
327+
enum ComprehensionTarget<'a> {
328+
/// E.g., `(x, y, z, ...)` in `(x, y, z, ...) in iter`.
329+
Tuple(&'a ast::ExprTuple),
330+
/// E.g., `x` in `x in iter`.
331+
Name(&'a ast::ExprName),
332+
}
333+
334+
/// Extract the target from the comprehension (e.g., `(x, y, z)` in `(x, y, z, ...) in iter`).
335+
fn match_comprehension_target(comprehension: &ast::Comprehension) -> Option<ComprehensionTarget> {
325336
if comprehension.is_async || !comprehension.ifs.is_empty() {
326337
return None;
327338
}
328-
329339
match &comprehension.target {
330-
// Get the elements of the tuple.
331-
ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => Some((elts, &comprehension.iter)),
332-
// If there is only one element, it might still be starred later on.
333-
ast::Expr::Name(_) => {
334-
let elt = std::slice::from_ref(&comprehension.target);
335-
Some((elt, &comprehension.iter))
336-
}
340+
Expr::Tuple(tuple) => Some(ComprehensionTarget::Tuple(tuple)),
341+
Expr::Name(name) => Some(ComprehensionTarget::Name(name)),
337342
_ => None,
338343
}
339344
}

crates/ruff_python_ast/src/comparable.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -927,11 +927,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
927927
}) => Self::Starred(ExprStarred {
928928
value: value.into(),
929929
}),
930-
ast::Expr::Name(ast::ExprName {
931-
id,
932-
ctx: _,
933-
range: _,
934-
}) => Self::Name(ExprName { id: id.as_str() }),
930+
ast::Expr::Name(name) => name.into(),
935931
ast::Expr::List(ast::ExprList {
936932
elts,
937933
ctx: _,
@@ -968,6 +964,14 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
968964
}
969965
}
970966

967+
impl<'a> From<&'a ast::ExprName> for ComparableExpr<'a> {
968+
fn from(expr: &'a ast::ExprName) -> Self {
969+
Self::Name(ExprName {
970+
id: expr.id.as_str(),
971+
})
972+
}
973+
}
974+
971975
#[derive(Debug, PartialEq, Eq, Hash)]
972976
pub struct StmtFunctionDef<'a> {
973977
is_async: bool,

0 commit comments

Comments
 (0)