Skip to content

Commit 1babece

Browse files
committed
suggest fix for attempted integer identifier in patterns
1 parent 61a415b commit 1babece

File tree

8 files changed

+99
-4
lines changed

8 files changed

+99
-4
lines changed

compiler/rustc_error_messages/locales/en-US/mir_build.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,5 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
364364
[one] variant that isn't
365365
*[other] variants that aren't
366366
} matched
367+
368+
mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits

compiler/rustc_mir_build/src/errors.rs

+15
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
770770
#[subdiagnostic]
771771
pub let_suggestion: Option<SuggestLet>,
772772
#[subdiagnostic]
773+
pub misc_suggestion: Option<MiscPatternSuggestion>,
774+
#[subdiagnostic]
773775
pub res_defined_here: Option<ResDefinedHere>,
774776
}
775777

@@ -848,3 +850,16 @@ pub enum SuggestLet {
848850
count: usize,
849851
},
850852
}
853+
854+
#[derive(Subdiagnostic)]
855+
pub enum MiscPatternSuggestion {
856+
#[suggestion(
857+
mir_build_suggest_attempted_int_lit,
858+
code = "_",
859+
applicability = "maybe-incorrect"
860+
)]
861+
AttemptedIntegerLiteral {
862+
#[primary_span]
863+
start_span: Span,
864+
},
865+
}

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

+16-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use super::{PatCtxt, PatternError};
66

77
use crate::errors::*;
88

9+
use hir::{ExprKind, PatKind};
910
use rustc_arena::TypedArena;
10-
use rustc_ast::Mutability;
11+
use rustc_ast::{LitKind, Mutability};
1112
use rustc_errors::{
1213
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
1314
};
@@ -389,7 +390,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
389390
return;
390391
}
391392

392-
let (inform, interpreted_as_const, res_defined_here,let_suggestion) =
393+
let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) =
393394
if let hir::PatKind::Path(hir::QPath::Resolved(
394395
None,
395396
hir::Path {
@@ -413,6 +414,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
413414
}
414415
},
415416
None,
417+
None,
416418
)
417419
} else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
418420
let mut bindings = vec![];
@@ -426,10 +428,19 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
426428
let end_span = semi_span.shrink_to_lo();
427429
let count = witnesses.len();
428430

431+
// If the pattern to match is an integer literal:
432+
let int_suggestion = if
433+
let PatKind::Lit(expr) = &pat.kind
434+
&& bindings.is_empty()
435+
&& let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind {
436+
// Then give a suggestion, the user might've meant to create a binding instead.
437+
Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() })
438+
} else { None };
439+
429440
let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
430-
(sp.map(|_|Inform), None, None, Some(let_suggestion))
441+
(sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion)
431442
} else{
432-
(sp.map(|_|Inform), None, None, None)
443+
(sp.map(|_|Inform), None, None, None, None)
433444
};
434445

435446
let adt_defined_here = try {
@@ -453,6 +464,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
453464
_p: (),
454465
pattern_ty,
455466
let_suggestion,
467+
misc_suggestion,
456468
res_defined_here,
457469
adt_defined_here,
458470
});

tests/ui/consts/const-match-check.eval1.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
1111
|
1212
LL | A = { if let 0 = 0 { todo!() } 0 },
1313
| ++ ~~~~~~~~~~~
14+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
15+
|
16+
LL | A = { let _0 = 0; 0 },
17+
| +
1418

1519
error: aborting due to previous error
1620

tests/ui/consts/const-match-check.eval2.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
1111
|
1212
LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
1313
| ++ ~~~~~~~~~~~
14+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
15+
|
16+
LL | let x: [i32; { let _0 = 0; 0 }] = [];
17+
| +
1418

1519
error: aborting due to previous error
1620

tests/ui/consts/const-match-check.matchck.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
1111
|
1212
LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
1313
| ++ ~~~~~~~~~~~
14+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
15+
|
16+
LL | const X: i32 = { let _0 = 0; 0 };
17+
| +
1418

1519
error[E0005]: refutable pattern in local binding
1620
--> $DIR/const-match-check.rs:8:23
@@ -25,6 +29,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
2529
|
2630
LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
2731
| ++ ~~~~~~~~~~~
32+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
33+
|
34+
LL | static Y: i32 = { let _0 = 0; 0 };
35+
| +
2836

2937
error[E0005]: refutable pattern in local binding
3038
--> $DIR/const-match-check.rs:13:26
@@ -39,6 +47,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
3947
|
4048
LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
4149
| ++ ~~~~~~~~~~~
50+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
51+
|
52+
LL | const X: i32 = { let _0 = 0; 0 };
53+
| +
4254

4355
error[E0005]: refutable pattern in local binding
4456
--> $DIR/const-match-check.rs:19:26
@@ -53,6 +65,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
5365
|
5466
LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
5567
| ++ ~~~~~~~~~~~
68+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
69+
|
70+
LL | const X: i32 = { let _0 = 0; 0 };
71+
| +
5672

5773
error: aborting due to 4 previous errors
5874

tests/ui/pattern/issue-106552.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let 5 = 6;
3+
//~^ error refutable pattern in local binding [E0005]
4+
5+
let x @ 5 = 6;
6+
//~^ error refutable pattern in local binding [E0005]
7+
}

tests/ui/pattern/issue-106552.stderr

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0005]: refutable pattern in local binding
2+
--> $DIR/issue-106552.rs:2:9
3+
|
4+
LL | let 5 = 6;
5+
| ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
6+
|
7+
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
8+
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
9+
= note: the matched value is of type `i32`
10+
help: you might want to use `if let` to ignore the variants that aren't matched
11+
|
12+
LL | if let 5 = 6 { todo!() }
13+
| ++ ~~~~~~~~~~~
14+
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
15+
|
16+
LL | let _5 = 6;
17+
| +
18+
19+
error[E0005]: refutable pattern in local binding
20+
--> $DIR/issue-106552.rs:5:9
21+
|
22+
LL | let x @ 5 = 6;
23+
| ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
24+
|
25+
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
26+
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
27+
= note: the matched value is of type `i32`
28+
help: you might want to use `let else` to handle the variants that aren't matched
29+
|
30+
LL | let x @ 5 = 6 else { todo!() };
31+
| ++++++++++++++++
32+
33+
error: aborting due to 2 previous errors
34+
35+
For more information about this error, try `rustc --explain E0005`.

0 commit comments

Comments
 (0)