@@ -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}
0 commit comments