1
Fork 0

Suggest if let on let refutable binding

This commit is contained in:
Esteban Küber 2019-10-09 12:25:48 -07:00
parent ec557aa818
commit 4bb1592402
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) { fn visit_local(&mut self, loc: &'tcx hir::Local) {
intravisit::walk_local(self, loc); intravisit::walk_local(self, loc);
self.check_irrefutable(&loc.pat, match loc.source { let (msg, sp) = match loc.source {
hir::LocalSource::Normal => "local binding", hir::LocalSource::Normal => ("local binding", Some(loc.span)),
hir::LocalSource::ForLoopDesugar => "`for` loop binding", hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
hir::LocalSource::AsyncFn => "async fn binding", hir::LocalSource::AsyncFn => ("async fn binding", None),
hir::LocalSource::AwaitDesugar => "`await` future binding", hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
}); };
self.check_irrefutable(&loc.pat, msg, sp);
// Check legality of move bindings and `@` patterns. // Check legality of move bindings and `@` patterns.
self.check_patterns(false, &loc.pat); self.check_patterns(false, &loc.pat);
@ -77,7 +78,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
intravisit::walk_body(self, body); intravisit::walk_body(self, body);
for param in &body.params { 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); 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); let module = self.tcx.hir().get_module_parent(pat.hir_id);
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
let mut patcx = PatCtxt::new(self.tcx, let mut patcx = PatCtxt::new(self.tcx,
@ -266,18 +267,35 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
"refutable pattern in {}: {} not covered", "refutable pattern in {}: {} not covered",
origin, joined_patterns origin, joined_patterns
); );
match &pat.kind { let suggest_if_let = match &pat.kind {
hir::PatKind::Path(hir::QPath::Resolved(None, path)) hir::PatKind::Path(hir::QPath::Resolved(None, path))
if path.segments.len() == 1 && path.segments[0].args.is_none() => if path.segments.len() == 1 && path.segments[0].args.is_none() =>
{ {
const_not_var(&mut err, cx.tcx, pat, path); const_not_var(&mut err, cx.tcx, pat, path);
false
} }
_ => { _ => {
err.span_label( err.span_label(
pat.span, pat.span,
pattern_not_covered_label(&witnesses, &joined_patterns), 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); 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 }, LL | A = { let 0 = 0; 0 },
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered | ^ 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 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 }] = []; LL | let x: [i32; { let 0 = 0; 0 }] = [];
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered | ^ 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 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 }; LL | const X: i32 = { let 0 = 0; 0 };
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered | ^ 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 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 --> $DIR/const-match-check.rs:8:23
| |
LL | static Y: i32 = { let 0 = 0; 0 }; LL | static Y: i32 = { let 0 = 0; 0 };
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered | ^ 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 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 --> $DIR/const-match-check.rs:13:26
| |
LL | const X: i32 = { let 0 = 0; 0 }; LL | const X: i32 = { let 0 = 0; 0 };
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered | ^ 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 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 --> $DIR/const-match-check.rs:19:26
| |
LL | const X: i32 = { let 0 = 0; 0 }; LL | const X: i32 = { let 0 = 0; 0 };
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered | ^ 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 error: aborting due to 4 previous errors

View file

@ -11,6 +11,13 @@ LL | | }
... ...
LL | let Helper::U(u) = Helper::T(t, []); LL | let Helper::U(u) = Helper::T(t, []);
| ^^^^^^^^^^^^ pattern `T(_, _)` not covered | ^^^^^^^^^^^^ 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` error[E0381]: use of possibly-uninitialized variable: `u`
--> $DIR/empty-never-array.rs:12:5 --> $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; LL | let Some(y) = x;
| ^^^^^^^ pattern `None` not covered | ^^^^^^^ 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 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(); LL | let Ok(_x) = foo();
| ^^^^^^ pattern `Err(_)` not covered | ^^^^^^ 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 error: aborting due to previous error

View file

@ -12,6 +12,13 @@ LL | | }
... ...
LL | let Thing::Foo(y) = Thing::Foo(1); LL | let Thing::Foo(y) = Thing::Foo(1);
| ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered | ^^^^^^^^^^^^^ 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 error: aborting due to previous error

View file

@ -41,6 +41,13 @@ LL | | }
... ...
LL | let E::A = e; LL | let E::A = e;
| ^^^^ patterns `B` and `C` not covered | ^^^^ 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 error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
--> $DIR/non-exhaustive-defined-here.rs:40:11 --> $DIR/non-exhaustive-defined-here.rs:40:11
@ -85,6 +92,13 @@ LL | | }
... ...
LL | let E::A = e; LL | let E::A = e;
| ^^^^ patterns `&B` and `&C` not covered | ^^^^ 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 error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
--> $DIR/non-exhaustive-defined-here.rs:48:11 --> $DIR/non-exhaustive-defined-here.rs:48:11
@ -129,6 +143,13 @@ LL | | }
... ...
LL | let E::A = e; LL | let E::A = e;
| ^^^^ patterns `&&mut &B` and `&&mut &C` not covered | ^^^^ 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 error[E0004]: non-exhaustive patterns: `None` not covered
--> $DIR/non-exhaustive-defined-here.rs:65:11 --> $DIR/non-exhaustive-defined-here.rs:65:11
@ -163,6 +184,13 @@ LL | | }
... ...
LL | let Opt::Some(ref _x) = e; LL | let Opt::Some(ref _x) = e;
| ^^^^^^^^^^^^^^^^^ pattern `None` not covered | ^^^^^^^^^^^^^^^^^ 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 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; LL | let Ok(x) = res;
| ^^^^^ pattern `Err(_)` not covered | ^^^^^ 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` error[E0381]: use of possibly-uninitialized variable: `x`
--> $DIR/recursive-types-are-not-uninhabited.rs:8:5 --> $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)); LL | let (1, (Some(1), 2..=3)) = (1, (None, 2));
| ^^^^^^^^^^^^^^^^^^^^^ patterns `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered | ^^^^^^^^^^^^^^^^^^^^^ 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 error: aborting due to 2 previous errors

View file

@ -12,6 +12,13 @@ LL | | }
... ...
LL | let Foo::D(_y) = x; LL | let Foo::D(_y) = x;
| ^^^^^^^^^^ pattern `A(_)` not covered | ^^^^^^^^^^ 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 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; LL | let Ok(x) = x;
| ^^^^^ pattern `Err(_)` not covered | ^^^^^ 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 error: aborting due to 7 previous errors