Skip to content

Commit fbc67b5

Browse files
authored
Rollup merge of #89314 - notriddle:notriddle/lint-fix-enum-variant-match, r=davidtwco
fix(lint): don't suggest refutable patterns to "fix" irrefutable bind In function arguments and let bindings, do not suggest changing `C` to `Foo::C` unless `C` is the only variant of `Foo`, because it won't work. The general warning is still kept, because code like this is confusing. Fixes #88730 p.s. `src/test/ui/lint/lint-uppercase-variables.rs` already tests the one-variant case.
2 parents fccfc98 + 6e973f0 commit fbc67b5

File tree

3 files changed

+73
-19
lines changed

3 files changed

+73
-19
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+36-19
Original file line numberDiff line numberDiff line change
@@ -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+
4249
struct 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

115122
impl<'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
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![allow(unused, nonstandard_style)]
2+
#![deny(bindings_with_variant_name)]
3+
4+
// If an enum has two different variants,
5+
// then it cannot be matched upon in a function argument.
6+
// It still gets a warning, but no suggestions.
7+
enum Foo {
8+
C,
9+
D,
10+
}
11+
12+
fn foo(C: Foo) {} //~ERROR
13+
14+
fn main() {
15+
let C = Foo::D; //~ERROR
16+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo`
2+
--> $DIR/issue-88730.rs:12:8
3+
|
4+
LL | fn foo(C: Foo) {}
5+
| ^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/issue-88730.rs:2:9
9+
|
10+
LL | #![deny(bindings_with_variant_name)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo`
14+
--> $DIR/issue-88730.rs:15:9
15+
|
16+
LL | let C = Foo::D;
17+
| ^
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0170`.

0 commit comments

Comments
 (0)