Skip to content

suggestion for attempted integer identifier in patterns #106591

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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!() };
| ++++++++++++++++
Comment on lines +19 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this with fresh eyes, shouldn't we be suggesting if let here? 🤔

Copy link
Contributor Author

@Ezrashaw Ezrashaw Jan 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't touched the if let and else suggestion code, so I haven't really looked at this but: My understanding is that this situation is a bit like an alternative if let. You can bind the value, and if it doesn't match, the else branch is called (which must diverge).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not asking you to fix it now necessarily, just leaving a paper trail of my thinking so we don't forget to fix it in the future :)


error: aborting due to 2 previous errors

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