@@ -39,6 +39,13 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu
3939 struct_span_err ! ( sess, sp, E0004 , "{}" , & error_message)
4040}
4141
42+ #[ derive( PartialEq ) ]
43+ enum RefutableFlag {
44+ Irrefutable ,
45+ Refutable ,
46+ }
47+ use RefutableFlag :: * ;
48+
4249struct MatchVisitor < ' a , ' p , ' tcx > {
4350 tcx : TyCtxt < ' tcx > ,
4451 typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
@@ -73,13 +80,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
7380 hir:: LocalSource :: AssignDesugar ( _) => ( "destructuring assignment binding" , None ) ,
7481 } ;
7582 self . check_irrefutable ( & loc. pat , msg, sp) ;
76- self . check_patterns ( & loc. pat ) ;
83+ self . check_patterns ( & loc. pat , Irrefutable ) ;
7784 }
7885
7986 fn visit_param ( & mut self , param : & ' tcx hir:: Param < ' tcx > ) {
8087 intravisit:: walk_param ( self , param) ;
8188 self . check_irrefutable ( & param. pat , "function argument" , None ) ;
82- self . check_patterns ( & param. pat ) ;
89+ self . check_patterns ( & param. pat , Irrefutable ) ;
8390 }
8491}
8592
@@ -113,9 +120,9 @@ impl PatCtxt<'_, '_> {
113120}
114121
115122impl < ' p , ' tcx > MatchVisitor < ' _ , ' p , ' tcx > {
116- fn check_patterns ( & self , pat : & Pat < ' _ > ) {
123+ fn check_patterns ( & self , pat : & Pat < ' _ > , rf : RefutableFlag ) {
117124 pat. walk_always ( |pat| check_borrow_conflicts_in_at_patterns ( self , pat) ) ;
118- check_for_bindings_named_same_as_variants ( self , pat) ;
125+ check_for_bindings_named_same_as_variants ( self , pat, rf ) ;
119126 }
120127
121128 fn lower_pattern (
@@ -145,7 +152,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
145152 }
146153
147154 fn check_let ( & mut self , pat : & ' tcx hir:: Pat < ' tcx > , expr : & hir:: Expr < ' _ > , span : Span ) {
148- self . check_patterns ( pat) ;
155+ self . check_patterns ( pat, Refutable ) ;
149156 let mut cx = self . new_cx ( expr. hir_id ) ;
150157 let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) ;
151158 check_let_reachability ( & mut cx, pat. hir_id , tpat, span) ;
@@ -161,9 +168,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
161168
162169 for arm in arms {
163170 // Check the arm for some things unrelated to exhaustiveness.
164- self . check_patterns ( & arm. pat ) ;
171+ self . check_patterns ( & arm. pat , Refutable ) ;
165172 if let Some ( hir:: Guard :: IfLet ( ref pat, _) ) = arm. guard {
166- self . check_patterns ( pat) ;
173+ self . check_patterns ( pat, Refutable ) ;
167174 let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) ;
168175 check_let_reachability ( & mut cx, pat. hir_id , tpat, tpat. span ( ) ) ;
169176 }
@@ -297,7 +304,11 @@ fn const_not_var(
297304 }
298305}
299306
300- fn check_for_bindings_named_same_as_variants ( cx : & MatchVisitor < ' _ , ' _ , ' _ > , pat : & Pat < ' _ > ) {
307+ fn check_for_bindings_named_same_as_variants (
308+ cx : & MatchVisitor < ' _ , ' _ , ' _ > ,
309+ pat : & Pat < ' _ > ,
310+ rf : RefutableFlag ,
311+ ) {
301312 pat. walk_always ( |p| {
302313 if let hir:: PatKind :: Binding ( _, _, ident, None ) = p. kind {
303314 if let Some ( ty:: BindByValue ( hir:: Mutability :: Not ) ) =
@@ -310,25 +321,31 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_, '_>, pat:
310321 variant. ident == ident && variant. ctor_kind == CtorKind :: Const
311322 } )
312323 {
324+ let variant_count = edef. variants . len ( ) ;
313325 cx. tcx . struct_span_lint_hir (
314326 BINDINGS_WITH_VARIANT_NAME ,
315327 p. hir_id ,
316328 p. span ,
317329 |lint| {
318330 let ty_path = cx. tcx . def_path_str ( edef. did ) ;
319- lint. build ( & format ! (
331+ let mut err = lint. build ( & format ! (
320332 "pattern binding `{}` is named the same as one \
321- of the variants of the type `{}`",
333+ of the variants of the type `{}`",
322334 ident, ty_path
323- ) )
324- . code ( error_code ! ( E0170 ) )
325- . span_suggestion (
326- p. span ,
327- "to match on the variant, qualify the path" ,
328- format ! ( "{}::{}" , ty_path, ident) ,
329- Applicability :: MachineApplicable ,
330- )
331- . emit ( ) ;
335+ ) ) ;
336+ err. code ( error_code ! ( E0170 ) ) ;
337+ // If this is an irrefutable pattern, and there's > 1 variant,
338+ // then we can't actually match on this. Applying the below
339+ // suggestion would produce code that breaks on `check_irrefutable`.
340+ if rf == Refutable || variant_count == 1 {
341+ err. span_suggestion (
342+ p. span ,
343+ "to match on the variant, qualify the path" ,
344+ format ! ( "{}::{}" , ty_path, ident) ,
345+ Applicability :: MachineApplicable ,
346+ ) ;
347+ }
348+ err. emit ( ) ;
332349 } ,
333350 )
334351 }
0 commit comments