@@ -146,10 +146,9 @@ fn emit_manual_let_else(
146
146
"this could be rewritten as `let...else`" ,
147
147
|diag| {
148
148
// 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.
151
151
// * unused binding collision detection with existing ones
152
- // * putting patterns with at the top level | inside ()
153
152
// for this to be machine applicable.
154
153
let mut app = Applicability :: HasPlaceholders ;
155
154
let ( sn_expr, _) = snippet_with_context ( cx, expr. span , span. ctxt ( ) , "" , & mut app) ;
@@ -160,28 +159,62 @@ fn emit_manual_let_else(
160
159
} else {
161
160
format ! ( "{{ {sn_else} }}" )
162
161
} ;
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) ;
179
163
let sugg = format ! ( "let {sn_bl} = {sn_expr} else {else_bl};" ) ;
180
164
diag. span_suggestion ( span, "consider writing" , sugg, app) ;
181
165
} ,
182
166
) ;
183
167
}
184
168
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
+
185
218
/// Check whether an expression is divergent. May give false negatives.
186
219
fn expr_diverges ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
187
220
struct V < ' cx , ' tcx > {
0 commit comments