Simplify get_enclosing_loop_or_multi_call_closure
This commit is contained in:
parent
0c42e451d6
commit
b587871e27
@ -113,10 +113,7 @@ use visitors::Visitable;
|
|||||||
|
|
||||||
use crate::consts::{constant, mir_to_const, Constant};
|
use crate::consts::{constant, mir_to_const, Constant};
|
||||||
use crate::higher::Range;
|
use crate::higher::Range;
|
||||||
use crate::ty::{
|
use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
|
||||||
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
|
|
||||||
ty_is_fn_once_param,
|
|
||||||
};
|
|
||||||
use crate::visitors::for_each_expr;
|
use crate::visitors::for_each_expr;
|
||||||
|
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
@ -1345,46 +1342,12 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
|
|||||||
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
|
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
|
||||||
match node {
|
match node {
|
||||||
Node::Expr(e) => match e.kind {
|
Node::Expr(e) => match e.kind {
|
||||||
ExprKind::Closure { .. } => {
|
ExprKind::Closure { .. }
|
||||||
if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
|
if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
|
||||||
&& subs.as_closure().kind() == ClosureKind::FnOnce
|
&& subs.as_closure().kind() == ClosureKind::FnOnce => {},
|
||||||
{
|
|
||||||
continue;
|
// Note: A closure's kind is determined by how it's used, not it's captures.
|
||||||
}
|
ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
|
||||||
let is_once = walk_to_expr_usage(cx, e, |node, id| {
|
|
||||||
let Node::Expr(e) = node else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
match e.kind {
|
|
||||||
ExprKind::Call(f, _) if f.hir_id == id => Some(()),
|
|
||||||
ExprKind::Call(f, args) => {
|
|
||||||
let i = args.iter().position(|arg| arg.hir_id == id)?;
|
|
||||||
let sig = expr_sig(cx, f)?;
|
|
||||||
let predicates = sig
|
|
||||||
.predicates_id()
|
|
||||||
.map_or(cx.param_env, |id| cx.tcx.param_env(id))
|
|
||||||
.caller_bounds();
|
|
||||||
sig.input(i).and_then(|ty| {
|
|
||||||
ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
ExprKind::MethodCall(_, receiver, args, _) => {
|
|
||||||
let i = std::iter::once(receiver)
|
|
||||||
.chain(args.iter())
|
|
||||||
.position(|arg| arg.hir_id == id)?;
|
|
||||||
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
|
|
||||||
let ty = cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i];
|
|
||||||
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.is_some();
|
|
||||||
if !is_once {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ExprKind::Loop(..) => return Some(e),
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
|
Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
|
||||||
|
@ -972,35 +972,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
|
|
||||||
pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [ty::Clause<'_>]) -> bool {
|
|
||||||
let ty::Param(ty) = *ty.kind() else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let lang = tcx.lang_items();
|
|
||||||
let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id)) = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
predicates
|
|
||||||
.iter()
|
|
||||||
.try_fold(false, |found, p| {
|
|
||||||
if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
|
|
||||||
&& let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
|
|
||||||
&& ty.index == self_ty.index
|
|
||||||
{
|
|
||||||
// This should use `super_traits_of`, but that's a private function.
|
|
||||||
if p.trait_ref.def_id == fn_once_id {
|
|
||||||
return Some(true);
|
|
||||||
} else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(found)
|
|
||||||
})
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Comes up with an "at least" guesstimate for the type's size, not taking into
|
/// Comes up with an "at least" guesstimate for the type's size, not taking into
|
||||||
/// account the layout of type parameters.
|
/// account the layout of type parameters.
|
||||||
pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
|
pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
|
||||||
|
@ -406,7 +406,7 @@ fn issue_8113() {
|
|||||||
fn fn_once_closure() {
|
fn fn_once_closure() {
|
||||||
let mut it = 0..10;
|
let mut it = 0..10;
|
||||||
(|| {
|
(|| {
|
||||||
for x in it {
|
for x in it.by_ref() {
|
||||||
if x % 2 == 0 {
|
if x % 2 == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -441,7 +441,19 @@ fn fn_once_closure() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
trait MySpecialFnMut: FnOnce() {}
|
||||||
|
impl<T: FnOnce()> MySpecialFnMut for T {}
|
||||||
|
fn f4(_: impl MySpecialFnMut) {}
|
||||||
|
let mut it = 0..10;
|
||||||
|
f4(|| {
|
||||||
|
for x in it {
|
||||||
|
if x % 2 == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -441,7 +441,19 @@ fn fn_once_closure() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
trait MySpecialFnMut: FnOnce() {}
|
||||||
|
impl<T: FnOnce()> MySpecialFnMut for T {}
|
||||||
|
fn f4(_: impl MySpecialFnMut) {}
|
||||||
|
let mut it = 0..10;
|
||||||
|
f4(|| {
|
||||||
|
while let Some(x) = it.next() {
|
||||||
|
if x % 2 == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -131,7 +131,7 @@ error: this loop could be written as a `for` loop
|
|||||||
--> $DIR/while_let_on_iterator.rs:409:9
|
--> $DIR/while_let_on_iterator.rs:409:9
|
||||||
|
|
|
|
||||||
LL | while let Some(x) = it.next() {
|
LL | while let Some(x) = it.next() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
|
||||||
|
|
||||||
error: this loop could be written as a `for` loop
|
error: this loop could be written as a `for` loop
|
||||||
--> $DIR/while_let_on_iterator.rs:419:9
|
--> $DIR/while_let_on_iterator.rs:419:9
|
||||||
@ -152,10 +152,16 @@ LL | while let Some(x) = it.next() {
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
|
||||||
|
|
||||||
error: this loop could be written as a `for` loop
|
error: this loop could be written as a `for` loop
|
||||||
--> $DIR/while_let_on_iterator.rs:449:5
|
--> $DIR/while_let_on_iterator.rs:451:9
|
||||||
|
|
|
||||||
|
LL | while let Some(x) = it.next() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
|
||||||
|
|
||||||
|
error: this loop could be written as a `for` loop
|
||||||
|
--> $DIR/while_let_on_iterator.rs:461:5
|
||||||
|
|
|
|
||||||
LL | while let Some(..) = it.next() {
|
LL | while let Some(..) = it.next() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
|
||||||
|
|
||||||
error: aborting due to 26 previous errors
|
error: aborting due to 27 previous errors
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user