Rollup merge of #65248 - estebank:mention-if-let, r=cramertj

Suggest `if let` on `let` refutable binding

Fix #58385.
This commit is contained in:
Mazdak Farrokhzad 2019-10-13 13:34:32 +02:00 committed by GitHub
commit 963e4bc756
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 169 additions and 9 deletions

View file

@ -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(&param.pat, "function argument");
self.check_irrefutable(&param.pat, "function argument", None);
self.check_patterns(false, &param.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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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`.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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