@@ -146,10 +146,9 @@ fn emit_manual_let_else(
146146 "this could be rewritten as `let...else`" ,
147147 |diag| {
148148 // This is far from perfect, for example there needs to be:
149- // * mut additions for the bindings
150- // * renamings of the bindings for `PatKind::Or`
149+ // * tracking for multi-binding cases: let (foo, bar) = if let (Some(foo), Ok(bar)) = ...
150+ // * renamings of the bindings for many `PatKind`s like structs, slices, etc.
151151 // * unused binding collision detection with existing ones
152- // * putting patterns with at the top level | inside ()
153152 // for this to be machine applicable.
154153 let mut app = Applicability :: HasPlaceholders ;
155154 let ( sn_expr, _) = snippet_with_context ( cx, expr. span , span. ctxt ( ) , "" , & mut app) ;
@@ -160,28 +159,62 @@ fn emit_manual_let_else(
160159 } else {
161160 format ! ( "{{ {sn_else} }}" )
162161 } ;
163- let sn_bl = match pat. kind {
164- PatKind :: Or ( ..) => {
165- let ( sn_pat, _) = snippet_with_context ( cx, pat. span , span. ctxt ( ) , "" , & mut app) ;
166- format ! ( "({sn_pat})" )
167- } ,
168- // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
169- PatKind :: TupleStruct ( ref w, args, ..) if args. len ( ) == 1 => {
170- let sn_wrapper = cx. sess ( ) . source_map ( ) . span_to_snippet ( w. span ( ) ) . unwrap_or_default ( ) ;
171- let ( sn_inner, _) = snippet_with_context ( cx, local. span , span. ctxt ( ) , "" , & mut app) ;
172- format ! ( "{sn_wrapper}({sn_inner})" )
173- } ,
174- _ => {
175- let ( sn_pat, _) = snippet_with_context ( cx, pat. span , span. ctxt ( ) , "" , & mut app) ;
176- sn_pat. into_owned ( )
177- } ,
178- } ;
162+ let sn_bl = replace_in_pattern ( cx, span, local, pat, & mut app) ;
179163 let sugg = format ! ( "let {sn_bl} = {sn_expr} else {else_bl};" ) ;
180164 diag. span_suggestion ( span, "consider writing" , sugg, app) ;
181165 } ,
182166 ) ;
183167}
184168
169+ // replaces the locals in the pattern
170+ fn replace_in_pattern (
171+ cx : & LateContext < ' _ > ,
172+ span : Span ,
173+ local : & Pat < ' _ > ,
174+ pat : & Pat < ' _ > ,
175+ app : & mut Applicability ,
176+ ) -> String {
177+ let mut bindings_count = 0 ;
178+ pat. each_binding_or_first ( & mut |_, _, _, _| bindings_count += 1 ) ;
179+ // If the pattern creates multiple bindings, exit early,
180+ // as otherwise we might paste the pattern to the positions of multiple bindings.
181+ if bindings_count > 1 {
182+ let ( sn_pat, _) = snippet_with_context ( cx, pat. span , span. ctxt ( ) , "" , app) ;
183+ return sn_pat. into_owned ( ) ;
184+ }
185+
186+ match pat. kind {
187+ PatKind :: Binding ( ..) => {
188+ let ( sn_bdg, _) = snippet_with_context ( cx, local. span , span. ctxt ( ) , "" , app) ;
189+ return sn_bdg. to_string ( ) ;
190+ } ,
191+ PatKind :: Or ( pats) => {
192+ let patterns = pats
193+ . iter ( )
194+ . map ( |pat| replace_in_pattern ( cx, span, local, pat, app) )
195+ . collect :: < Vec < _ > > ( ) ;
196+ let or_pat = patterns. join ( " | " ) ;
197+ return format ! ( "({or_pat})" ) ;
198+ } ,
199+ // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
200+ PatKind :: TupleStruct ( ref w, args, dot_dot_pos) => {
201+ let mut args = args
202+ . iter ( )
203+ . map ( |pat| replace_in_pattern ( cx, span, local, pat, app) )
204+ . collect :: < Vec < _ > > ( ) ;
205+ if let Some ( pos) = dot_dot_pos. as_opt_usize ( ) {
206+ args. insert ( pos, ".." . to_owned ( ) ) ;
207+ }
208+ let args = args. join ( ", " ) ;
209+ let sn_wrapper = cx. sess ( ) . source_map ( ) . span_to_snippet ( w. span ( ) ) . unwrap_or_default ( ) ;
210+ return format ! ( "{sn_wrapper}({args})" ) ;
211+ } ,
212+ _ => { } ,
213+ }
214+ let ( sn_pat, _) = snippet_with_context ( cx, pat. span , span. ctxt ( ) , "" , app) ;
215+ sn_pat. into_owned ( )
216+ }
217+
185218/// Check whether an expression is divergent. May give false negatives.
186219fn expr_diverges ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
187220 struct V < ' cx , ' tcx > {
0 commit comments