Skip to content

Commit

Permalink
Rollup merge of #106591 - Ezrashaw:attempted-integer-identifer, r=Est…
Browse files Browse the repository at this point in the history
…ebank

suggestion for attempted integer identifier in patterns

Fixes #106552

Implemented a suggestion on `E0005` that occurs when no bindings are present and the pattern is a literal integer.
  • Loading branch information
matthiaskrgr authored Jan 17, 2023
2 parents 4781233 + 1babece commit f740442
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 4 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/mir_build.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,5 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
[one] variant that isn't
*[other] variants that aren't
} matched
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
15 changes: 15 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
#[subdiagnostic]
pub let_suggestion: Option<SuggestLet>,
#[subdiagnostic]
pub misc_suggestion: Option<MiscPatternSuggestion>,
#[subdiagnostic]
pub res_defined_here: Option<ResDefinedHere>,
}

Expand Down Expand Up @@ -848,3 +850,16 @@ pub enum SuggestLet {
count: usize,
},
}

#[derive(Subdiagnostic)]
pub enum MiscPatternSuggestion {
#[suggestion(
mir_build_suggest_attempted_int_lit,
code = "_",
applicability = "maybe-incorrect"
)]
AttemptedIntegerLiteral {
#[primary_span]
start_span: Span,
},
}
20 changes: 16 additions & 4 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use super::{PatCtxt, PatternError};

use crate::errors::*;

use hir::{ExprKind, PatKind};
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_ast::{LitKind, Mutability};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
Expand Down Expand Up @@ -389,7 +390,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
return;
}

let (inform, interpreted_as_const, res_defined_here,let_suggestion) =
let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) =
if let hir::PatKind::Path(hir::QPath::Resolved(
None,
hir::Path {
Expand All @@ -413,6 +414,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
}
},
None,
None,
)
} else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
let mut bindings = vec![];
Expand All @@ -426,10 +428,19 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let end_span = semi_span.shrink_to_lo();
let count = witnesses.len();

// If the pattern to match is an integer literal:
let int_suggestion = if
let PatKind::Lit(expr) = &pat.kind
&& bindings.is_empty()
&& let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind {
// Then give a suggestion, the user might've meant to create a binding instead.
Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() })
} else { None };

let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
(sp.map(|_|Inform), None, None, Some(let_suggestion))
(sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion)
} else{
(sp.map(|_|Inform), None, None, None)
(sp.map(|_|Inform), None, None, None, None)
};

let adt_defined_here = try {
Expand All @@ -453,6 +464,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
_p: (),
pattern_ty,
let_suggestion,
misc_suggestion,
res_defined_here,
adt_defined_here,
});
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/consts/const-match-check.eval1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
|
LL | A = { if let 0 = 0 { todo!() } 0 },
| ++ ~~~~~~~~~~~
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
|
LL | A = { let _0 = 0; 0 },
| +

error: aborting due to previous error

Expand Down
4 changes: 4 additions & 0 deletions tests/ui/consts/const-match-check.eval2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
|
LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
| ++ ~~~~~~~~~~~
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
|
LL | let x: [i32; { let _0 = 0; 0 }] = [];
| +

error: aborting due to previous error

Expand Down
16 changes: 16 additions & 0 deletions tests/ui/consts/const-match-check.matchck.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
|
LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
| ++ ~~~~~~~~~~~
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
|
LL | const X: i32 = { let _0 = 0; 0 };
| +

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

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

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

error: aborting due to 4 previous errors

Expand Down
7 changes: 7 additions & 0 deletions tests/ui/pattern/issue-106552.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() {
let 5 = 6;
//~^ error refutable pattern in local binding [E0005]

let x @ 5 = 6;
//~^ error refutable pattern in local binding [E0005]
}
35 changes: 35 additions & 0 deletions tests/ui/pattern/issue-106552.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error[E0005]: refutable pattern in local binding
--> $DIR/issue-106552.rs:2:9
|
LL | let 5 = 6;
| ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
help: you might want to use `if let` to ignore the variants that aren't matched
|
LL | if let 5 = 6 { todo!() }
| ++ ~~~~~~~~~~~
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
|
LL | let _5 = 6;
| +

error[E0005]: refutable pattern in local binding
--> $DIR/issue-106552.rs:5:9
|
LL | let x @ 5 = 6;
| ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
help: you might want to use `let else` to handle the variants that aren't matched
|
LL | let x @ 5 = 6 else { todo!() };
| ++++++++++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0005`.

0 comments on commit f740442

Please sign in to comment.