Skip to content

Commit b587871

Browse files
committedNov 15, 2023
Simplify get_enclosing_loop_or_multi_call_closure
1 parent 0c42e45 commit b587871

File tree

5 files changed

+42
-78
lines changed

5 files changed

+42
-78
lines changed
 

‎clippy_utils/src/lib.rs

+6-43
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,7 @@ use visitors::Visitable;
113113

114114
use crate::consts::{constant, mir_to_const, Constant};
115115
use crate::higher::Range;
116-
use crate::ty::{
117-
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
118-
ty_is_fn_once_param,
119-
};
116+
use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
120117
use crate::visitors::for_each_expr;
121118

122119
use rustc_middle::hir::nested_filter;
@@ -1345,46 +1342,12 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
13451342
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
13461343
match node {
13471344
Node::Expr(e) => match e.kind {
1348-
ExprKind::Closure { .. } => {
1345+
ExprKind::Closure { .. }
13491346
if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
1350-
&& subs.as_closure().kind() == ClosureKind::FnOnce
1351-
{
1352-
continue;
1353-
}
1354-
let is_once = walk_to_expr_usage(cx, e, |node, id| {
1355-
let Node::Expr(e) = node else {
1356-
return None;
1357-
};
1358-
match e.kind {
1359-
ExprKind::Call(f, _) if f.hir_id == id => Some(()),
1360-
ExprKind::Call(f, args) => {
1361-
let i = args.iter().position(|arg| arg.hir_id == id)?;
1362-
let sig = expr_sig(cx, f)?;
1363-
let predicates = sig
1364-
.predicates_id()
1365-
.map_or(cx.param_env, |id| cx.tcx.param_env(id))
1366-
.caller_bounds();
1367-
sig.input(i).and_then(|ty| {
1368-
ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
1369-
})
1370-
},
1371-
ExprKind::MethodCall(_, receiver, args, _) => {
1372-
let i = std::iter::once(receiver)
1373-
.chain(args.iter())
1374-
.position(|arg| arg.hir_id == id)?;
1375-
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
1376-
let ty = cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i];
1377-
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
1378-
},
1379-
_ => None,
1380-
}
1381-
})
1382-
.is_some();
1383-
if !is_once {
1384-
return Some(e);
1385-
}
1386-
},
1387-
ExprKind::Loop(..) => return Some(e),
1347+
&& subs.as_closure().kind() == ClosureKind::FnOnce => {},
1348+
1349+
// Note: A closure's kind is determined by how it's used, not it's captures.
1350+
ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
13881351
_ => (),
13891352
},
13901353
Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),

‎clippy_utils/src/ty.rs

-29
Original file line numberDiff line numberDiff line change
@@ -972,35 +972,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
972972
}
973973
}
974974

975-
/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
976-
pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [ty::Clause<'_>]) -> bool {
977-
let ty::Param(ty) = *ty.kind() else {
978-
return false;
979-
};
980-
let lang = tcx.lang_items();
981-
let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id)) = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
982-
else {
983-
return false;
984-
};
985-
predicates
986-
.iter()
987-
.try_fold(false, |found, p| {
988-
if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
989-
&& let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
990-
&& ty.index == self_ty.index
991-
{
992-
// This should use `super_traits_of`, but that's a private function.
993-
if p.trait_ref.def_id == fn_once_id {
994-
return Some(true);
995-
} else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
996-
return None;
997-
}
998-
}
999-
Some(found)
1000-
})
1001-
.unwrap_or(false)
1002-
}
1003-
1004975
/// Comes up with an "at least" guesstimate for the type's size, not taking into
1005976
/// account the layout of type parameters.
1006977
pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {

‎tests/ui/while_let_on_iterator.fixed

+14-2
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ fn issue_8113() {
406406
fn fn_once_closure() {
407407
let mut it = 0..10;
408408
(|| {
409-
for x in it {
409+
for x in it.by_ref() {
410410
if x % 2 == 0 {
411411
break;
412412
}
@@ -441,7 +441,19 @@ fn fn_once_closure() {
441441
break;
442442
}
443443
}
444-
})
444+
});
445+
446+
trait MySpecialFnMut: FnOnce() {}
447+
impl<T: FnOnce()> MySpecialFnMut for T {}
448+
fn f4(_: impl MySpecialFnMut) {}
449+
let mut it = 0..10;
450+
f4(|| {
451+
for x in it {
452+
if x % 2 == 0 {
453+
break;
454+
}
455+
}
456+
});
445457
}
446458

447459
fn main() {

‎tests/ui/while_let_on_iterator.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,19 @@ fn fn_once_closure() {
441441
break;
442442
}
443443
}
444-
})
444+
});
445+
446+
trait MySpecialFnMut: FnOnce() {}
447+
impl<T: FnOnce()> MySpecialFnMut for T {}
448+
fn f4(_: impl MySpecialFnMut) {}
449+
let mut it = 0..10;
450+
f4(|| {
451+
while let Some(x) = it.next() {
452+
if x % 2 == 0 {
453+
break;
454+
}
455+
}
456+
});
445457
}
446458

447459
fn main() {

‎tests/ui/while_let_on_iterator.stderr

+9-3
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ error: this loop could be written as a `for` loop
131131
--> $DIR/while_let_on_iterator.rs:409:9
132132
|
133133
LL | while let Some(x) = it.next() {
134-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
134+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
135135

136136
error: this loop could be written as a `for` loop
137137
--> $DIR/while_let_on_iterator.rs:419:9
@@ -152,10 +152,16 @@ LL | while let Some(x) = it.next() {
152152
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
153153

154154
error: this loop could be written as a `for` loop
155-
--> $DIR/while_let_on_iterator.rs:449:5
155+
--> $DIR/while_let_on_iterator.rs:451:9
156+
|
157+
LL | while let Some(x) = it.next() {
158+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
159+
160+
error: this loop could be written as a `for` loop
161+
--> $DIR/while_let_on_iterator.rs:461:5
156162
|
157163
LL | while let Some(..) = it.next() {
158164
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
159165

160-
error: aborting due to 26 previous errors
166+
error: aborting due to 27 previous errors
161167

0 commit comments

Comments
 (0)