@@ -62,12 +62,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
62
62
fn visit_local ( & mut self , loc : & ' tcx hir:: Local ) {
63
63
intravisit:: walk_local ( self , loc) ;
64
64
65
- self . check_irrefutable ( & loc. pat , match loc. source {
66
- hir:: LocalSource :: Normal => "local binding" ,
67
- hir:: LocalSource :: ForLoopDesugar => "`for` loop binding" ,
68
- hir:: LocalSource :: AsyncFn => "async fn binding" ,
69
- hir:: LocalSource :: AwaitDesugar => "`await` future binding" ,
70
- } ) ;
65
+ let ( msg, sp) = match loc. source {
66
+ hir:: LocalSource :: Normal => ( "local binding" , Some ( loc. span ) ) ,
67
+ hir:: LocalSource :: ForLoopDesugar => ( "`for` loop binding" , None ) ,
68
+ hir:: LocalSource :: AsyncFn => ( "async fn binding" , None ) ,
69
+ hir:: LocalSource :: AwaitDesugar => ( "`await` future binding" , None ) ,
70
+ } ;
71
+ self . check_irrefutable ( & loc. pat , msg, sp) ;
71
72
72
73
// Check legality of move bindings and `@` patterns.
73
74
self . check_patterns ( false , & loc. pat ) ;
@@ -77,7 +78,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
77
78
intravisit:: walk_body ( self , body) ;
78
79
79
80
for param in & body. params {
80
- self . check_irrefutable ( & param. pat , "function argument" ) ;
81
+ self . check_irrefutable ( & param. pat , "function argument" , None ) ;
81
82
self . check_patterns ( false , & param. pat ) ;
82
83
}
83
84
}
@@ -242,7 +243,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
242
243
} )
243
244
}
244
245
245
- fn check_irrefutable ( & self , pat : & ' tcx Pat , origin : & str ) {
246
+ fn check_irrefutable ( & self , pat : & ' tcx Pat , origin : & str , sp : Option < Span > ) {
246
247
let module = self . tcx . hir ( ) . get_module_parent ( pat. hir_id ) ;
247
248
MatchCheckCtxt :: create_and_enter ( self . tcx , self . param_env , module, |ref mut cx| {
248
249
let mut patcx = PatCtxt :: new ( self . tcx ,
@@ -266,18 +267,35 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
266
267
"refutable pattern in {}: {} not covered" ,
267
268
origin, joined_patterns
268
269
) ;
269
- match & pat. kind {
270
+ let suggest_if_let = match & pat. kind {
270
271
hir:: PatKind :: Path ( hir:: QPath :: Resolved ( None , path) )
271
272
if path. segments . len ( ) == 1 && path. segments [ 0 ] . args . is_none ( ) =>
272
273
{
273
274
const_not_var ( & mut err, cx. tcx , pat, path) ;
275
+ false
274
276
}
275
277
_ => {
276
278
err. span_label (
277
279
pat. span ,
278
280
pattern_not_covered_label ( & witnesses, & joined_patterns) ,
279
281
) ;
282
+ true
283
+ }
284
+ } ;
285
+
286
+ if let ( Some ( span) , true ) = ( sp, suggest_if_let) {
287
+ err. note ( "`let` bindings require an \" irrefutable pattern\" , like a `struct` or \
288
+ an `enum` with only one variant") ;
289
+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
290
+ err. span_suggestion (
291
+ span,
292
+ "you might want to use `if let` to ignore the variant that isn't matched" ,
293
+ format ! ( "if {} {{ /* */ }}" , & snippet[ ..snippet. len( ) - 1 ] ) ,
294
+ Applicability :: HasPlaceholders ,
295
+ ) ;
280
296
}
297
+ err. note ( "for more information, visit \
298
+ https://doc.rust-lang.org/book/ch18-02-refutability.html") ;
281
299
}
282
300
283
301
adt_defined_here ( cx, & mut err, pattern_ty, & witnesses) ;
0 commit comments