Rollup merge of #65248 - estebank:mention-if-let, r=cramertj
Suggest `if let` on `let` refutable binding Fix #58385.
This commit is contained in:
commit
963e4bc756
14 changed files with 169 additions and 9 deletions
|
@ -62,12 +62,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
|||
fn visit_local(&mut self, loc: &'tcx hir::Local) {
|
||||
intravisit::walk_local(self, loc);
|
||||
|
||||
self.check_irrefutable(&loc.pat, match loc.source {
|
||||
hir::LocalSource::Normal => "local binding",
|
||||
hir::LocalSource::ForLoopDesugar => "`for` loop binding",
|
||||
hir::LocalSource::AsyncFn => "async fn binding",
|
||||
hir::LocalSource::AwaitDesugar => "`await` future binding",
|
||||
});
|
||||
let (msg, sp) = match loc.source {
|
||||
hir::LocalSource::Normal => ("local binding", Some(loc.span)),
|
||||
hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
|
||||
hir::LocalSource::AsyncFn => ("async fn binding", None),
|
||||
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
|
||||
};
|
||||
self.check_irrefutable(&loc.pat, msg, sp);
|
||||
|
||||
// Check legality of move bindings and `@` patterns.
|
||||
self.check_patterns(false, &loc.pat);
|
||||
|
@ -77,7 +78,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
|||
intravisit::walk_body(self, body);
|
||||
|
||||
for param in &body.params {
|
||||
self.check_irrefutable(¶m.pat, "function argument");
|
||||
self.check_irrefutable(¶m.pat, "function argument", None);
|
||||
self.check_patterns(false, ¶m.pat);
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +243,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
|
||||
fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str, sp: Option<Span>) {
|
||||
let module = self.tcx.hir().get_module_parent(pat.hir_id);
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
|
||||
let mut patcx = PatCtxt::new(self.tcx,
|
||||
|
@ -266,18 +267,35 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
|||
"refutable pattern in {}: {} not covered",
|
||||
origin, joined_patterns
|
||||
);
|
||||
match &pat.kind {
|
||||
let suggest_if_let = match &pat.kind {
|
||||
hir::PatKind::Path(hir::QPath::Resolved(None, path))
|
||||
if path.segments.len() == 1 && path.segments[0].args.is_none() =>
|
||||
{
|
||||
const_not_var(&mut err, cx.tcx, pat, path);
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
err.span_label(
|
||||
pat.span,
|
||||
pattern_not_covered_label(&witnesses, &joined_patterns),
|
||||
);
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
if let (Some(span), true) = (sp, suggest_if_let) {
|
||||
err.note("`let` bindings require an \"irrefutable pattern\", like a `struct` or \
|
||||
an `enum` with only one variant");
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"you might want to use `if let` to ignore the variant that isn't matched",
|
||||
format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
err.note("for more information, visit \
|
||||
https://doc.rust-lang.org/book/ch18-02-refutability.html");
|
||||
}
|
||||
|
||||
adt_defined_here(cx, &mut err, pattern_ty, &witnesses);
|
||||
|
|
|
@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1
|
|||
|
|
||||
LL | A = { let 0 = 0; 0 },
|
||||
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | A = { if let 0 = 0 { /* */ } 0 },
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1
|
|||
|
|
||||
LL | let x: [i32; { let 0 = 0; 0 }] = [];
|
||||
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | let x: [i32; { if let 0 = 0 { /* */ } 0 }] = [];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -3,24 +3,52 @@ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1
|
|||
|
|
||||
LL | const X: i32 = { let 0 = 0; 0 };
|
||||
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
|
||||
--> $DIR/const-match-check.rs:8:23
|
||||
|
|
||||
LL | static Y: i32 = { let 0 = 0; 0 };
|
||||
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
|
||||
--> $DIR/const-match-check.rs:13:26
|
||||
|
|
||||
LL | const X: i32 = { let 0 = 0; 0 };
|
||||
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
|
||||
--> $DIR/const-match-check.rs:19:26
|
||||
|
|
||||
LL | const X: i32 = { let 0 = 0; 0 };
|
||||
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@ LL | | }
|
|||
...
|
||||
LL | let Helper::U(u) = Helper::T(t, []);
|
||||
| ^^^^^^^^^^^^ pattern `T(_, _)` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Helper::U(u) = Helper::T(t, []) { /* */ }
|
||||
|
|
||||
|
||||
error[E0381]: use of possibly-uninitialized variable: `u`
|
||||
--> $DIR/empty-never-array.rs:12:5
|
||||
|
|
|
@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `None` not covered
|
|||
|
|
||||
LL | let Some(y) = x;
|
||||
| ^^^^^^^ pattern `None` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Some(y) = x { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
|
||||
--> $DIR/feature-gate-exhaustive-patterns.rs:7:9
|
||||
|
|
||||
LL | let Ok(_x) = foo();
|
||||
| ^^^^^^ pattern `Err(_)` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Ok(_x) = foo() { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0005`.
|
|
@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
|
|||
|
|
||||
LL | let Ok(_x) = foo();
|
||||
| ^^^^^^ pattern `Err(_)` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Ok(_x) = foo() { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -12,6 +12,13 @@ LL | | }
|
|||
...
|
||||
LL | let Thing::Foo(y) = Thing::Foo(1);
|
||||
| ^^^^^^^^^^^^^ patterns `Bar` and `Baz` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -41,6 +41,13 @@ LL | | }
|
|||
...
|
||||
LL | let E::A = e;
|
||||
| ^^^^ patterns `B` and `C` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let E::A = e { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
|
||||
--> $DIR/non-exhaustive-defined-here.rs:40:11
|
||||
|
@ -85,6 +92,13 @@ LL | | }
|
|||
...
|
||||
LL | let E::A = e;
|
||||
| ^^^^ patterns `&B` and `&C` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let E::A = e { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
|
||||
--> $DIR/non-exhaustive-defined-here.rs:48:11
|
||||
|
@ -129,6 +143,13 @@ LL | | }
|
|||
...
|
||||
LL | let E::A = e;
|
||||
| ^^^^ patterns `&&mut &B` and `&&mut &C` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let E::A = e { /* */ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `None` not covered
|
||||
--> $DIR/non-exhaustive-defined-here.rs:65:11
|
||||
|
@ -163,6 +184,13 @@ LL | | }
|
|||
...
|
||||
LL | let Opt::Some(ref _x) = e;
|
||||
| ^^^^^^^^^^^^^^^^^ pattern `None` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Opt::Some(ref _x) = e { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
|
|||
|
|
||||
LL | let Ok(x) = res;
|
||||
| ^^^^^ pattern `Err(_)` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Ok(x) = res { /* */ }
|
||||
|
|
||||
|
||||
error[E0381]: use of possibly-uninitialized variable: `x`
|
||||
--> $DIR/recursive-types-are-not-uninhabited.rs:8:5
|
||||
|
|
|
@ -9,6 +9,13 @@ error[E0005]: refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` an
|
|||
|
|
||||
LL | let (1, (Some(1), 2..=3)) = (1, (None, 2));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ patterns `(std::i32::MIN..=0i32, _)` and `(2i32..=std::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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ }
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -12,6 +12,13 @@ LL | | }
|
|||
...
|
||||
LL | let Foo::D(_y) = x;
|
||||
| ^^^^^^^^^^ pattern `A(_)` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Foo::D(_y) = x { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -51,6 +51,13 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
|
|||
|
|
||||
LL | let Ok(x) = x;
|
||||
| ^^^^^ pattern `Err(_)` 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
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Ok(x) = x { /* */ }
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue