impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- if let ExprKind::Closure(_, _, eid, _, _) = expr.kind {
+ if let ExprKind::Closure { body, .. } = expr.kind {
// do not lint if the closure is called using an iterator (see #1141)
if_chain! {
if let Some(parent) = get_parent_expr(self.cx, expr);
}
}
- let body = self.cx.tcx.hir().body(eid);
+ let body = self.cx.tcx.hir().body(body);
let ex = &body.value;
if let ExprKind::Block(block, _) = ex.kind {
if !body.value.span.from_expansion() && !block.stmts.is_empty() {
if count.ident.name == sym::count;
if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind;
if filter.ident.name == sym!(filter);
- if let ExprKind::Closure(_, _, body_id, _, _) = filter_arg.kind;
- let body = cx.tcx.hir().body(body_id);
+ if let ExprKind::Closure { body, .. } = filter_arg.kind;
+ let body = cx.tcx.hir().body(body);
if let [param] = body.params;
if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
if let ExprKind::Binary(ref op, l, r) = body.value.kind;
| ExprKind::Loop(..)
| ExprKind::Match(..)
| ExprKind::Let(..)
- | ExprKind::Closure(..)
+ | ExprKind::Closure{..}
| ExprKind::Block(..)
| ExprKind::Assign(..)
| ExprKind::AssignOp(..)
return;
}
let body = match expr.kind {
- ExprKind::Closure(_, _, id, _, _) => cx.tcx.hir().body(id),
+ ExprKind::Closure { body, .. } => cx.tcx.hir().body(body),
_ => return,
};
if body.value.span.from_expansion() {
}
}
if method.ident.name == sym!(flat_map) && args.len() == 2 {
- if let ExprKind::Closure(_, _, body_id, _, _) = args[1].kind {
- let body = cx.tcx.hir().body(body_id);
+ if let ExprKind::Closure { body, .. } = args[1].kind {
+ let body = cx.tcx.hir().body(body);
return is_infinite(cx, &body.value);
}
}
self.visit_expr(expr);
}
},
- ExprKind::Closure(_, _, body_id, ..) => {
- let body = self.cx.tcx.hir().body(body_id);
+ ExprKind::Closure { body, .. } => {
+ let body = self.cx.tcx.hir().body(body);
self.visit_expr(&body.value);
},
_ => walk_expr(self, expr),
.fold(NeverLoopResult::Otherwise, combine_both),
ExprKind::Struct(_, _, None)
| ExprKind::Yield(_, _)
- | ExprKind::Closure(_, _, _, _, _)
+ | ExprKind::Closure { .. }
| ExprKind::Path(_)
| ExprKind::ConstBlock(_)
| ExprKind::Lit(_)
if let Some(e) = e {
self.visit_expr(e);
}
- } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+ } else if let ExprKind::Closure { body: id, .. } = e.kind {
if is_res_used(self.cx, self.iter_expr.path, id) {
self.uses_iter = true;
}
if let Some(e) = e {
self.visit_expr(e);
}
- } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+ } else if let ExprKind::Closure { body: id, .. } = e.kind {
self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
} else {
walk_expr(self, e);
if let Some(e) = e {
self.visit_expr(e);
}
- } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+ } else if let ExprKind::Closure { body: id, .. } = e.kind {
self.used_after = is_res_used(self.cx, self.iter_expr.path, id);
} else {
walk_expr(self, e);
if let Some(block_expr) = block.expr;
if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
if args.len() == 1;
- if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0];
- let closure_body = cx.tcx.hir().body(body_id);
+ if let Expr{kind: ExprKind::Closure { body, .. }, ..} = args[0];
+ let closure_body = cx.tcx.hir().body(body);
if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
then {
return Some(closure_body);
}
}
if_chain! {
- if let ExprKind::Closure(_, _, body_id, ..) = map_expr.kind;
- let body = cx.tcx.hir().body(body_id);
+ if let ExprKind::Closure { body, .. } = map_expr.kind;
+ let body = cx.tcx.hir().body(body);
if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
if is_lang_ctor(cx, ok_path, ResultOk);
if method.ident.name == sym::map;
let ty = cx.typeck_results().expr_ty(&args[0]);
if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator);
- if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
+ if let hir::ExprKind::Closure { body, .. } = args[1].kind;
then {
- let closure_body = cx.tcx.hir().body(body_id);
+ let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
match closure_body.params[0].pat.kind {
hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
// only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
// Enum::Variant[2]))
if method.ident.as_str() == "map_err" && args.len() == 2 {
- // make sure the first argument is a closure, and grab the CaptureRef, body_id, and body_span fields
- if let ExprKind::Closure(capture, _, body_id, body_span, _) = args[1].kind {
+ // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
+ // fields
+ if let ExprKind::Closure {
+ capture_clause,
+ body,
+ fn_decl_span,
+ ..
+ } = args[1].kind
+ {
// check if this is by Reference (meaning there's no move statement)
- if capture == CaptureBy::Ref {
+ if capture_clause == CaptureBy::Ref {
// Get the closure body to check the parameters and values
- let closure_body = cx.tcx.hir().body(body_id);
+ let closure_body = cx.tcx.hir().body(body);
// make sure there's only one parameter (`|_|`)
if closure_body.params.len() == 1 {
// make sure that parameter is the wild token (`_`)
span_lint_and_help(
cx,
MAP_ERR_IGNORE,
- body_span,
+ fn_decl_span,
"`map_err(|_|...` wildcard pattern discards the original error",
None,
"consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
expr: &hir::Expr<'_>,
) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
if_chain! {
- if let hir::ExprKind::Closure(_, decl, inner_expr_id, _, _) = expr.kind;
- let body = cx.tcx.hir().body(inner_expr_id);
+ if let hir::ExprKind::Closure { fn_decl, body, .. } = expr.kind;
+ let body = cx.tcx.hir().body(body);
let body_expr = &body.value;
- if decl.inputs.len() == 1;
+ if fn_decl.inputs.len() == 1;
if is_unit_expression(cx, body_expr);
- if let Some(binding) = iter_input_pats(decl, body).next();
+ if let Some(binding) = iter_input_pats(fn_decl, body).next();
then {
return Some((binding, body_expr));
}
let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new());
if let Some(parent_expr) = get_parent_expr(cx, match_expr) {
- if let ExprKind::Closure(..) = parent_expr.kind {
+ if let ExprKind::Closure { .. } = parent_expr.kind {
cbrace_end = format!("\n{}}}", indent);
// Fix body indent due to the closure
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
ExprKind::Break(_, _) |
ExprKind::Cast(_, _) |
// Don't want to check the closure itself, only invocation, which is covered by MethodCall
- ExprKind::Closure(_, _, _, _, _) |
+ ExprKind::Closure { .. } |
ExprKind::ConstBlock(_) |
ExprKind::Continue(_) |
ExprKind::DropTemps(_) |
}
match arg.kind {
- hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
- let closure_body = cx.tcx.hir().body(body_id);
+ hir::ExprKind::Closure { body, fn_decl_span, .. } => {
+ let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
- if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
+ if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
true
} else {
Self::lint_closure(cx, expr, closure_expr)
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
segments.segments.last().unwrap().ident.name == method_name
},
- hir::ExprKind::Closure(_, _, c, _, _) => {
- let body = cx.tcx.hir().body(*c);
+ hir::ExprKind::Closure { body, .. } => {
+ let body = cx.tcx.hir().body(*body);
let closure_expr = peel_blocks(&body.value);
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
if is_trait_method(cx, map_recv, sym::Iterator);
// filter(|x| ...is_some())...
- if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind;
+ if let ExprKind::Closure { body: filter_body_id, .. } = filter_arg.kind;
let filter_body = cx.tcx.hir().body(filter_body_id);
if let [filter_param] = filter_body.params;
// optional ref pattern: `filter(|&x| ..)`
if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
// ...map(|x| ...unwrap())
- if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind;
+ if let ExprKind::Closure { body: map_body_id, .. } = map_arg.kind;
let map_body = cx.tcx.hir().body(map_body_id);
if let [map_param] = map_body.params;
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
.map_or(false, |fun_def_id| {
deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
}),
- hir::ExprKind::Closure(_, _, body_id, _, _) => {
- let closure_body = cx.tcx.hir().body(body_id);
+ hir::ExprKind::Closure { body, .. } => {
+ let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
match &closure_expr.kind {
if is_option {
let self_snippet = snippet(cx, recv.span, "..");
if_chain! {
- if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind;
- let arg_snippet = snippet(cx, span, "..");
- let body = cx.tcx.hir().body(id);
- if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
- if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
- if Some(id) == cx.tcx.lang_items().option_some_variant();
- then {
- let func_snippet = snippet(cx, arg_char.span, "..");
- let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
- `map(..)` instead";
- return span_lint_and_sugg(
- cx,
- OPTION_MAP_OR_NONE,
- expr.span,
- msg,
- "try using `map` instead",
- format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet),
- Applicability::MachineApplicable,
- );
- }
-
+ if let hir::ExprKind::Closure { body, fn_decl_span, .. } = map_arg.kind;
+ let arg_snippet = snippet(cx, fn_decl_span, "..");
+ let body = cx.tcx.hir().body(body);
+ if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
+ if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
+ if Some(id) == cx.tcx.lang_items().option_some_variant();
+ then {
+ let func_snippet = snippet(cx, arg_char.span, "..");
+ let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
+ `map(..)` instead";
+ return span_lint_and_sugg(
+ cx,
+ OPTION_MAP_OR_NONE,
+ expr.span,
+ msg,
+ "try using `map` instead",
+ format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet),
+ Applicability::MachineApplicable,
+ );
+ }
}
let func_snippet = snippet(cx, map_arg.span, "..");
let mut applicability = Applicability::MachineApplicable;
let any_search_snippet = if_chain! {
if search_method == "find";
- if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind;
- let closure_body = cx.tcx.hir().body(body_id);
+ if let hir::ExprKind::Closure { body, .. } = search_arg.kind;
+ let closure_body = cx.tcx.hir().body(body);
if let Some(closure_arg) = closure_body.params.get(0);
then {
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
return;
}
- if let hir::ExprKind::Closure(_, _, body_id, ..) = arg.kind {
- let body = cx.tcx.hir().body(body_id);
+ if let hir::ExprKind::Closure { body, .. } = arg.kind {
+ let body = cx.tcx.hir().body(body);
let arg_id = body.params[0].pat.hir_id;
let mutates_arg =
mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
) {
if_chain! {
// Extract the body of the closure passed to fold
- if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind;
- let closure_body = cx.tcx.hir().body(body_id);
+ if let hir::ExprKind::Closure { body, .. } = acc.kind;
+ let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
// Check if the closure body is of the form `acc <op> some_expr(x)`
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
if is_option || is_result {
- if let hir::ExprKind::Closure(_, _, eid, _, _) = arg.kind {
- let body = cx.tcx.hir().body(eid);
+ if let hir::ExprKind::Closure { body, .. } = arg.kind {
+ let body = cx.tcx.hir().body(body);
let body_expr = &body.value;
if usage::BindingUsageFinder::are_params_used(cx, body) {
impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
match e.kind {
- ExprKind::Closure(..) => {},
+ ExprKind::Closure { .. } => {},
ExprKind::Match(e, arms, _) => {
self.visit_expr(e);
for arm in arms {
walk_expr(vis, expr);
}
},
- ExprKind::Closure(_, _, _, _, _) => {
+ ExprKind::Closure { .. } => {
// Either
//
// * `var` is defined in the closure body, in which case we've reached the top of the enclosing
// We're about to descend a closure. Since we don't know when (or
// if) the closure will be evaluated, any reads in it might not
// occur here (or ever). Like above, bail to avoid false positives.
- ExprKind::Closure(_, _, _, _, _) |
+ ExprKind::Closure{..} |
// We want to avoid a false positive when a variable name occurs
// only to have its address taken, so we stop here. Technically,
if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some();
// Skip the lint if the body is not block because this is simpler than `for` loop.
// e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
- if let ExprKind::Closure(_, _, body_id, ..) = for_each_arg.kind;
- let body = cx.tcx.hir().body(body_id);
+ if let ExprKind::Closure { body, .. } = for_each_arg.kind;
+ let body = cx.tcx.hir().body(body);
if let ExprKind::Block(..) = body.value.kind;
then {
let mut ret_collector = RetCollector::default();
return false;
}
match peel_blocks(expr).kind {
- ExprKind::Lit(..) | ExprKind::Closure(..) => true,
+ ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
},
ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
// since analysing the closure is not easy, just set all variables in it to side-effect
- ExprKind::Closure(_, _, body_id, _, _) => {
- let body = self.tcx.hir().body(body_id);
+ ExprKind::Closure { body, .. } => {
+ let body = self.tcx.hir().body(body);
self.visit_body(body);
let vars = std::mem::take(&mut self.ret_vars);
self.add_side_effect(vars);
if_chain! {
if let hir::StmtKind::Local(local) = w[0].kind;
if let Option::Some(t) = local.init;
- if let hir::ExprKind::Closure(..) = t.kind;
+ if let hir::ExprKind::Closure { .. } = t.kind;
if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind;
if let hir::StmtKind::Semi(second) = w[1].kind;
if let hir::ExprKind::Assign(_, call, _) = second.kind;
fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
if_chain! {
- if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind;
+ if let ExprKind::Closure { body, fn_decl_span, .. } = arg.kind;
if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind();
let ret_ty = substs.as_closure().sig().output();
let ty = cx.tcx.erase_late_bound_regions(ret_ty);
if ty.is_unit();
then {
- let body = cx.tcx.hir().body(body_id);
+ let body = cx.tcx.hir().body(body);
if_chain! {
if let ExprKind::Block(block, _) = body.value.kind;
if block.expr.is_none();
then {
let data = stmt.span.data();
// Make a span out of the semicolon for the help message
- Some((span, Some(data.with_lo(data.hi-BytePos(1)))))
+ Some((fn_decl_span, Some(data.with_lo(data.hi-BytePos(1)))))
} else {
- Some((span, None))
+ Some((fn_decl_span, None))
}
}
} else {
if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
if let name = name_ident.ident.name.to_ident_string();
if name == "sort_by" || name == "sort_unstable_by";
- if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
+ if let [vec, Expr { kind: ExprKind::Closure{ body: closure_body_id, .. }, .. }] = args;
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
if let closure_body = cx.tcx.hir().body(*closure_body_id);
if let &[
self.expr(scrutinee);
self.slice(arms, |arm| self.arm(arm));
},
- ExprKind::Closure(capture_by, fn_decl, body_id, _, movability) => {
+ ExprKind::Closure {
+ capture_clause,
+ fn_decl,
+ body: body_id,
+ movability,
+ ..
+ } => {
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
let ret_ty = match fn_decl.output {
};
bind!(self, fn_decl, body_id);
- kind!("Closure(CaptureBy::{capture_by:?}, {fn_decl}, {body_id}, _, {movability})");
+ kind!("Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})");
out!("if let {ret_ty} = {fn_decl}.output;");
self.body(body_id);
},
| ExprKind::Let(..)
| ExprKind::If(..)
| ExprKind::Match(..)
- | ExprKind::Closure(..)
+ | ExprKind::Closure { .. }
| ExprKind::Field(..)
| ExprKind::Path(_)
| ExprKind::AddrOf(..)
self.hash_expr(e);
self.hash_ty(ty);
},
- ExprKind::Closure(cap, _, eid, _, _) => {
- std::mem::discriminant(&cap).hash(&mut self.s);
+ ExprKind::Closure {
+ capture_clause, body, ..
+ } => {
+ std::mem::discriminant(&capture_clause).hash(&mut self.s);
// closures inherit TypeckResults
- self.hash_expr(&self.cx.tcx.hir().body(eid).value);
+ self.hash_expr(&self.cx.tcx.hir().body(body).value);
},
ExprKind::Field(e, ref f) => {
self.hash_expr(e);
self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
}
},
- ExprKind::Closure(..) => {
+ ExprKind::Closure { .. } => {
let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id).to_def_id();
for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
let local_id = match capture.place.base {
match node {
Node::Expr(
e @ Expr {
- kind: ExprKind::Loop(..) | ExprKind::Closure(..),
+ kind: ExprKind::Loop(..) | ExprKind::Closure { .. },
..
},
) => return Some(e),
_,
&[
Expr {
- kind: ExprKind::Closure(_, _, body, _, _),
+ kind: ExprKind::Closure { body, .. },
..
},
],
}
match expr.kind {
- ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
+ ExprKind::Closure { body, .. } => is_body_identity_function(cx, cx.tcx.hir().body(body)),
_ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
}
}
| hir::ExprKind::Box(..)
| hir::ExprKind::If(..)
| hir::ExprKind::Let(..)
- | hir::ExprKind::Closure(..)
+ | hir::ExprKind::Closure { .. }
| hir::ExprKind::Unary(..)
| hir::ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)),
hir::ExprKind::Continue(..)
match expr.kind {
ast::ExprKind::AddrOf(..)
| ast::ExprKind::Box(..)
- | ast::ExprKind::Closure(..)
+ | ast::ExprKind::Closure { .. }
| ast::ExprKind::If(..)
| ast::ExprKind::Let(..)
| ast::ExprKind::Unary(..)
///
/// note: this only works on single line immutable closures with exactly one input parameter.
pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> {
- if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = closure.kind {
- let closure_body = cx.tcx.hir().body(body_id);
+ if let hir::ExprKind::Closure { fn_decl, body, .. } = closure.kind {
+ let closure_body = cx.tcx.hir().body(body);
// is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
// a type annotation is present if param `kind` is different from `TyKind::Infer`
let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
matches!(
node,
Node::Expr(Expr {
- kind: ExprKind::Loop(..) | ExprKind::Closure(..),
+ kind: ExprKind::Loop(..) | ExprKind::Closure { .. },
..
})
)