@@ -39,6 +39,13 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu
39
39
struct_span_err ! ( sess, sp, E0004 , "{}" , & error_message)
40
40
}
41
41
42
+ #[ derive( PartialEq ) ]
43
+ enum RefutableFlag {
44
+ Irrefutable ,
45
+ Refutable ,
46
+ }
47
+ use RefutableFlag :: * ;
48
+
42
49
struct MatchVisitor < ' a , ' p , ' tcx > {
43
50
tcx : TyCtxt < ' tcx > ,
44
51
typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
@@ -73,13 +80,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
73
80
hir:: LocalSource :: AssignDesugar ( _) => ( "destructuring assignment binding" , None ) ,
74
81
} ;
75
82
self . check_irrefutable ( & loc. pat , msg, sp) ;
76
- self . check_patterns ( & loc. pat ) ;
83
+ self . check_patterns ( & loc. pat , Irrefutable ) ;
77
84
}
78
85
79
86
fn visit_param ( & mut self , param : & ' tcx hir:: Param < ' tcx > ) {
80
87
intravisit:: walk_param ( self , param) ;
81
88
self . check_irrefutable ( & param. pat , "function argument" , None ) ;
82
- self . check_patterns ( & param. pat ) ;
89
+ self . check_patterns ( & param. pat , Irrefutable ) ;
83
90
}
84
91
}
85
92
@@ -113,9 +120,9 @@ impl PatCtxt<'_, '_> {
113
120
}
114
121
115
122
impl < ' p , ' tcx > MatchVisitor < ' _ , ' p , ' tcx > {
116
- fn check_patterns ( & self , pat : & Pat < ' _ > ) {
123
+ fn check_patterns ( & self , pat : & Pat < ' _ > , rf : RefutableFlag ) {
117
124
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 ) ;
119
126
}
120
127
121
128
fn lower_pattern (
@@ -145,7 +152,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
145
152
}
146
153
147
154
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 ) ;
149
156
let mut cx = self . new_cx ( expr. hir_id ) ;
150
157
let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) ;
151
158
check_let_reachability ( & mut cx, pat. hir_id , tpat, span) ;
@@ -161,9 +168,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
161
168
162
169
for arm in arms {
163
170
// Check the arm for some things unrelated to exhaustiveness.
164
- self . check_patterns ( & arm. pat ) ;
171
+ self . check_patterns ( & arm. pat , Refutable ) ;
165
172
if let Some ( hir:: Guard :: IfLet ( ref pat, _) ) = arm. guard {
166
- self . check_patterns ( pat) ;
173
+ self . check_patterns ( pat, Refutable ) ;
167
174
let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) ;
168
175
check_let_reachability ( & mut cx, pat. hir_id , tpat, tpat. span ( ) ) ;
169
176
}
@@ -297,7 +304,11 @@ fn const_not_var(
297
304
}
298
305
}
299
306
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
+ ) {
301
312
pat. walk_always ( |p| {
302
313
if let hir:: PatKind :: Binding ( _, _, ident, None ) = p. kind {
303
314
if let Some ( ty:: BindByValue ( hir:: Mutability :: Not ) ) =
@@ -310,25 +321,31 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_, '_>, pat:
310
321
variant. ident == ident && variant. ctor_kind == CtorKind :: Const
311
322
} )
312
323
{
324
+ let variant_count = edef. variants . len ( ) ;
313
325
cx. tcx . struct_span_lint_hir (
314
326
BINDINGS_WITH_VARIANT_NAME ,
315
327
p. hir_id ,
316
328
p. span ,
317
329
|lint| {
318
330
let ty_path = cx. tcx . def_path_str ( edef. did ) ;
319
- lint. build ( & format ! (
331
+ let mut err = lint. build ( & format ! (
320
332
"pattern binding `{}` is named the same as one \
321
- of the variants of the type `{}`",
333
+ of the variants of the type `{}`",
322
334
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 ( ) ;
332
349
} ,
333
350
)
334
351
}
0 commit comments