Skip to content

Commit b8b3eb9

Browse files
authored
Merge pull request #1229 from Manishearth/loops
Fix #1188
2 parents 766217f + c8986b4 commit b8b3eb9

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

clippy_lints/src/loops.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use std::collections::HashMap;
1414
use syntax::ast;
1515
use utils::sugg;
1616

17-
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro,
18-
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher,
19-
walk_ptrs_ty};
17+
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg,
18+
in_external_macro, is_refutable, span_help_and_lint, is_integer_literal,
19+
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty};
2020
use utils::paths;
2121

2222
/// **What it does:** Checks for looping over the range of `0..len` of some
@@ -354,6 +354,7 @@ impl LateLintPass for Pass {
354354
if method_name.node.as_str() == "next" &&
355355
match_trait_method(cx, match_expr, &paths::ITERATOR) &&
356356
lhs_constructor.name.as_str() == "Some" &&
357+
!is_refutable(cx, &pat_args[0]) &&
357358
!is_iterator_used_after_while_let(cx, iter_expr) {
358359
let iterator = snippet(cx, method_args[0].span, "_");
359360
let loop_var = snippet(cx, pat_args[0].span, "_");

clippy_lints/src/utils/mod.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,43 @@ pub fn type_is_unsafe_function(ty: ty::Ty) -> bool {
721721
}
722722
}
723723

724-
pub fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, env: NodeId) -> bool {
724+
pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, env: NodeId) -> bool {
725725
let env = ty::ParameterEnvironment::for_item(cx.tcx, env);
726726
!ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, DUMMY_SP)
727727
}
728+
729+
/// Return whether a pattern is refutable.
730+
pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
731+
fn is_enum_variant(cx: &LateContext, did: NodeId) -> bool {
732+
matches!(cx.tcx.def_map.borrow().get(&did).map(|d| d.full_def()), Some(def::Def::Variant(..)))
733+
}
734+
735+
fn are_refutable<'a, I: Iterator<Item=&'a Pat>>(cx: &LateContext, mut i: I) -> bool {
736+
i.any(|pat| is_refutable(cx, pat))
737+
}
738+
739+
match pat.node {
740+
PatKind::Binding(..) | PatKind::Wild => false,
741+
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
742+
PatKind::Lit(..) | PatKind::Range(..) => true,
743+
PatKind::Path(..) => is_enum_variant(cx, pat.id),
744+
PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
745+
PatKind::Struct(_, ref fields, _) => {
746+
if is_enum_variant(cx, pat.id) {
747+
true
748+
} else {
749+
are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
750+
}
751+
}
752+
PatKind::TupleStruct(_, ref pats, _) => {
753+
if is_enum_variant(cx, pat.id) {
754+
true
755+
} else {
756+
are_refutable(cx, pats.iter().map(|pat| &**pat))
757+
}
758+
}
759+
PatKind::Vec(ref head, ref middle, ref tail) => {
760+
are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
761+
}
762+
}
763+
}

tests/compile-fail/while_loop.rs

+28
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,31 @@ fn issue1017() {
165165
}
166166
}
167167
}
168+
169+
// Issue #1188
170+
fn refutable() {
171+
let a = [42, 1337];
172+
let mut b = a.iter();
173+
174+
// consume all the 42s
175+
while let Some(&42) = b.next() {
176+
}
177+
178+
let a = [(1, 2, 3)];
179+
let mut b = a.iter();
180+
181+
while let Some(&(1, 2, 3)) = b.next() {
182+
}
183+
184+
let a = [Some(42)];
185+
let mut b = a.iter();
186+
187+
while let Some(&None) = b.next() {
188+
}
189+
190+
/* This gives “refutable pattern in `for` loop binding: `&_` not covered”
191+
for &42 in b {}
192+
for &(1, 2, 3) in b {}
193+
for &Option::None in b.next() {}
194+
// */
195+
}

0 commit comments

Comments
 (0)