@@ -62,12 +62,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
6262 fn visit_local ( & mut self , loc : & ' tcx hir:: Local ) {
6363 intravisit:: walk_local ( self , loc) ;
6464
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) ;
7172
7273 // Check legality of move bindings and `@` patterns.
7374 self . check_patterns ( false , & loc. pat ) ;
@@ -77,7 +78,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
7778 intravisit:: walk_body ( self , body) ;
7879
7980 for param in & body. params {
80- self . check_irrefutable ( & param. pat , "function argument" ) ;
81+ self . check_irrefutable ( & param. pat , "function argument" , None ) ;
8182 self . check_patterns ( false , & param. pat ) ;
8283 }
8384 }
@@ -242,7 +243,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
242243 } )
243244 }
244245
245- fn check_irrefutable ( & self , pat : & ' tcx Pat , origin : & str ) {
246+ fn check_irrefutable ( & self , pat : & ' tcx Pat , origin : & str , sp : Option < Span > ) {
246247 let module = self . tcx . hir ( ) . get_module_parent ( pat. hir_id ) ;
247248 MatchCheckCtxt :: create_and_enter ( self . tcx , self . param_env , module, |ref mut cx| {
248249 let mut patcx = PatCtxt :: new ( self . tcx ,
@@ -266,18 +267,35 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
266267 "refutable pattern in {}: {} not covered" ,
267268 origin, joined_patterns
268269 ) ;
269- match & pat. kind {
270+ let suggest_if_let = match & pat. kind {
270271 hir:: PatKind :: Path ( hir:: QPath :: Resolved ( None , path) )
271272 if path. segments . len ( ) == 1 && path. segments [ 0 ] . args . is_none ( ) =>
272273 {
273274 const_not_var ( & mut err, cx. tcx , pat, path) ;
275+ false
274276 }
275277 _ => {
276278 err. span_label (
277279 pat. span ,
278280 pattern_not_covered_label ( & witnesses, & joined_patterns) ,
279281 ) ;
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+ ) ;
280296 }
297+ err. note ( "for more information, visit \
298+ https://doc.rust-lang.org/book/ch18-02-refutability.html") ;
281299 }
282300
283301 adt_defined_here ( cx, & mut err, pattern_ty, & witnesses) ;
0 commit comments