@@ -7,7 +7,8 @@ use super::{PatCtxt, PatternError};
7
7
use rustc_arena:: TypedArena ;
8
8
use rustc_ast:: Mutability ;
9
9
use rustc_errors:: {
10
- error_code, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
10
+ error_code, pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder ,
11
+ ErrorGuaranteed ,
11
12
} ;
12
13
use rustc_hir as hir;
13
14
use rustc_hir:: def:: * ;
@@ -20,7 +21,7 @@ use rustc_session::lint::builtin::{
20
21
} ;
21
22
use rustc_session:: Session ;
22
23
use rustc_span:: source_map:: Spanned ;
23
- use rustc_span:: { DesugaringKind , ExpnKind , MultiSpan , Span } ;
24
+ use rustc_span:: { BytePos , DesugaringKind , ExpnKind , MultiSpan , Span } ;
24
25
25
26
crate fn check_match ( tcx : TyCtxt < ' _ > , def_id : DefId ) {
26
27
let body_id = match def_id. as_local ( ) {
@@ -241,6 +242,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
241
242
}
242
243
243
244
let joined_patterns = joined_uncovered_patterns ( & cx, & witnesses) ;
245
+
246
+ let mut bindings = vec ! [ ] ;
247
+
244
248
let mut err = struct_span_err ! (
245
249
self . tcx. sess,
246
250
pat. span,
@@ -257,6 +261,16 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
257
261
false
258
262
}
259
263
_ => {
264
+ pat. walk ( & mut |pat : & hir:: Pat < ' _ > | {
265
+ match pat. kind {
266
+ hir:: PatKind :: Binding ( _, _, ident, _) => {
267
+ bindings. push ( ident) ;
268
+ }
269
+ _ => { }
270
+ }
271
+ true
272
+ } ) ;
273
+
260
274
err. span_label ( pat. span , pattern_not_covered_label ( & witnesses, & joined_patterns) ) ;
261
275
true
262
276
}
@@ -267,13 +281,71 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
267
281
"`let` bindings require an \" irrefutable pattern\" , like a `struct` or \
268
282
an `enum` with only one variant",
269
283
) ;
270
- if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
271
- err. span_suggestion (
272
- span,
273
- "you might want to use `if let` to ignore the variant that isn't matched" ,
274
- format ! ( "if {} {{ /* */ }}" , & snippet[ ..snippet. len( ) - 1 ] ) ,
284
+ if self . tcx . sess . source_map ( ) . span_to_snippet ( span) . is_ok ( ) {
285
+ let semi_span = span. shrink_to_hi ( ) . with_lo ( span. hi ( ) - BytePos ( 1 ) ) ;
286
+ let start_span = span. shrink_to_lo ( ) ;
287
+ let end_span = semi_span. shrink_to_lo ( ) ;
288
+ err. multipart_suggestion (
289
+ & format ! (
290
+ "you might want to use `if let` to ignore the variant{} that {} matched" ,
291
+ pluralize!( witnesses. len( ) ) ,
292
+ match witnesses. len( ) {
293
+ 1 => "isn't" ,
294
+ _ => "aren't" ,
295
+ } ,
296
+ ) ,
297
+ vec ! [
298
+ match & bindings[ ..] {
299
+ [ ] => ( start_span, "if " . to_string( ) ) ,
300
+ [ binding] => ( start_span, format!( "let {} = if " , binding) ) ,
301
+ bindings => (
302
+ start_span,
303
+ format!(
304
+ "let ({}) = if " ,
305
+ bindings
306
+ . iter( )
307
+ . map( |ident| ident. to_string( ) )
308
+ . collect:: <Vec <_>>( )
309
+ . join( ", " )
310
+ ) ,
311
+ ) ,
312
+ } ,
313
+ match & bindings[ ..] {
314
+ [ ] => ( semi_span, " { todo!() }" . to_string( ) ) ,
315
+ [ binding] => {
316
+ ( end_span, format!( " {{ {} }} else {{ todo!() }}" , binding) )
317
+ }
318
+ bindings => (
319
+ end_span,
320
+ format!(
321
+ " {{ ({}) }} else {{ todo!() }}" ,
322
+ bindings
323
+ . iter( )
324
+ . map( |ident| ident. to_string( ) )
325
+ . collect:: <Vec <_>>( )
326
+ . join( ", " )
327
+ ) ,
328
+ ) ,
329
+ } ,
330
+ ] ,
275
331
Applicability :: HasPlaceholders ,
276
332
) ;
333
+ if !bindings. is_empty ( ) && cx. tcx . sess . is_nightly_build ( ) {
334
+ err. span_suggestion_verbose (
335
+ semi_span. shrink_to_lo ( ) ,
336
+ & format ! (
337
+ "alternatively, on nightly, you might want to use \
338
+ `#![feature(let_else)]` to handle the variant{} that {} matched",
339
+ pluralize!( witnesses. len( ) ) ,
340
+ match witnesses. len( ) {
341
+ 1 => "isn't" ,
342
+ _ => "aren't" ,
343
+ } ,
344
+ ) ,
345
+ " else { todo!() }" . to_string ( ) ,
346
+ Applicability :: HasPlaceholders ,
347
+ ) ;
348
+ }
277
349
}
278
350
err. note (
279
351
"for more information, visit \
0 commit comments