mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-24 05:33:27 +00:00
Suggest flatten
instead of is_some
-> unwrap
This commit is contained in:
parent
0e06b3c5f3
commit
56fbbf7b8f
8 changed files with 282 additions and 72 deletions
|
@ -2389,6 +2389,7 @@ Released 2018-09-13
|
|||
[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
|
||||
[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
|
||||
[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
|
||||
[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
|
||||
[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
|
||||
[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
|
||||
[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
||||
|
||||
[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
[There are over 450 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
|
||||
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
|
||||
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
|
||||
|
|
|
@ -804,6 +804,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&methods::NEW_RET_NO_SELF,
|
||||
&methods::OK_EXPECT,
|
||||
&methods::OPTION_AS_REF_DEREF,
|
||||
&methods::OPTION_FILTER_MAP,
|
||||
&methods::OPTION_MAP_OR_NONE,
|
||||
&methods::OR_FUN_CALL,
|
||||
&methods::RESULT_MAP_OR_INTO_OPTION,
|
||||
|
@ -1596,6 +1597,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&methods::NEW_RET_NO_SELF),
|
||||
LintId::of(&methods::OK_EXPECT),
|
||||
LintId::of(&methods::OPTION_AS_REF_DEREF),
|
||||
LintId::of(&methods::OPTION_FILTER_MAP),
|
||||
LintId::of(&methods::OPTION_MAP_OR_NONE),
|
||||
LintId::of(&methods::OR_FUN_CALL),
|
||||
LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
|
||||
|
@ -1891,6 +1893,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&methods::MANUAL_FILTER_MAP),
|
||||
LintId::of(&methods::MANUAL_FIND_MAP),
|
||||
LintId::of(&methods::OPTION_AS_REF_DEREF),
|
||||
LintId::of(&methods::OPTION_FILTER_MAP),
|
||||
LintId::of(&methods::SEARCH_IS_SOME),
|
||||
LintId::of(&methods::SKIP_WHILE_NEXT),
|
||||
LintId::of(&methods::SUSPICIOUS_MAP),
|
||||
|
|
|
@ -1,87 +1,166 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, SpanlessEq};
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, UnOp};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::TyS;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::MANUAL_FILTER_MAP;
|
||||
use super::MANUAL_FIND_MAP;
|
||||
use super::OPTION_FILTER_MAP;
|
||||
|
||||
fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
|
||||
match &expr.kind {
|
||||
hir::ExprKind::Path(QPath::TypeRelative(_, ref mname)) => mname.ident.name == method_name,
|
||||
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);
|
||||
let closure_expr = remove_blocks(&body.value);
|
||||
let arg_id = body.params[0].pat.hir_id;
|
||||
match closure_expr.kind {
|
||||
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, ref args, _) => {
|
||||
if_chain! {
|
||||
if ident.name == method_name;
|
||||
if let hir::ExprKind::Path(path) = &args[0].kind;
|
||||
if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
|
||||
then {
|
||||
return arg_id == *local
|
||||
}
|
||||
}
|
||||
false
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_option_filter_map<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
filter_arg: &'tcx hir::Expr<'_>,
|
||||
map_arg: &'tcx hir::Expr<'_>,
|
||||
) -> bool {
|
||||
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
|
||||
}
|
||||
|
||||
/// lint use of `filter().map()` for `Iterators`
|
||||
fn lint_filter_some_map_unwrap<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
filter_recv: &'tcx hir::Expr<'_>,
|
||||
filter_arg: &'tcx hir::Expr<'_>,
|
||||
map_arg: &'tcx hir::Expr<'_>,
|
||||
target_span: Span,
|
||||
methods_span: Span,
|
||||
) {
|
||||
let iterator = is_trait_method(cx, expr, sym::Iterator);
|
||||
let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&filter_recv), sym::option_type);
|
||||
if (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) {
|
||||
let msg = "`filter` for `Some` followed by `unwrap`";
|
||||
let help = "consider using `flatten` instead";
|
||||
let sugg = format!(
|
||||
"{}",
|
||||
reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, target_span),)
|
||||
);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
OPTION_FILTER_MAP,
|
||||
methods_span,
|
||||
msg,
|
||||
help,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `filter().map()` or `find().map()` for `Iterators`
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool, target_span: Span) {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind;
|
||||
if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind;
|
||||
if is_trait_method(cx, map_recv, sym::Iterator);
|
||||
if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind;
|
||||
if let ExprKind::MethodCall(_, _, [filter_recv, filter_arg], filter_span) = map_recv.kind;
|
||||
then {
|
||||
lint_filter_some_map_unwrap(cx, expr, filter_recv, filter_arg,
|
||||
map_arg, target_span, filter_span.to(map_span));
|
||||
if_chain! {
|
||||
if is_trait_method(cx, map_recv, sym::Iterator);
|
||||
|
||||
// filter(|x| ...is_some())...
|
||||
if let ExprKind::Closure(_, _, 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| ..)`
|
||||
let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||
(ref_pat, true)
|
||||
} else {
|
||||
(filter_param.pat, false)
|
||||
};
|
||||
// closure ends with is_some() or is_ok()
|
||||
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
|
||||
if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind;
|
||||
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
|
||||
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) {
|
||||
Some(false)
|
||||
} else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
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;
|
||||
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;
|
||||
// closure ends with expect() or unwrap()
|
||||
if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind;
|
||||
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
|
||||
|
||||
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
|
||||
// in `filter(|x| ..)`, replace `*x` with `x`
|
||||
let a_path = if_chain! {
|
||||
if !is_filter_param_ref;
|
||||
if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
|
||||
then { expr_path } else { a }
|
||||
};
|
||||
// let the filter closure arg and the map closure arg be equal
|
||||
if_chain! {
|
||||
if path_to_local_id(a_path, filter_param_id);
|
||||
if path_to_local_id(b, map_param_id);
|
||||
if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b));
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
|
||||
then {
|
||||
let span = filter_span.to(map_span);
|
||||
let (filter_name, lint) = if is_find {
|
||||
("find", MANUAL_FIND_MAP)
|
||||
// filter(|x| ...is_some())...
|
||||
if let ExprKind::Closure(_, _, 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| ..)`
|
||||
let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||
(ref_pat, true)
|
||||
} else {
|
||||
("filter", MANUAL_FILTER_MAP)
|
||||
(filter_param.pat, false)
|
||||
};
|
||||
let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name);
|
||||
let to_opt = if is_result { ".ok()" } else { "" };
|
||||
let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident,
|
||||
snippet(cx, map_arg.span, ".."), to_opt);
|
||||
span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
|
||||
// closure ends with is_some() or is_ok()
|
||||
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
|
||||
if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind;
|
||||
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
|
||||
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) {
|
||||
Some(false)
|
||||
} else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
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;
|
||||
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;
|
||||
// closure ends with expect() or unwrap()
|
||||
if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind;
|
||||
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
|
||||
|
||||
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
|
||||
// in `filter(|x| ..)`, replace `*x` with `x`
|
||||
let a_path = if_chain! {
|
||||
if !is_filter_param_ref;
|
||||
if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
|
||||
then { expr_path } else { a }
|
||||
};
|
||||
// let the filter closure arg and the map closure arg be equal
|
||||
if_chain! {
|
||||
if path_to_local_id(a_path, filter_param_id);
|
||||
if path_to_local_id(b, map_param_id);
|
||||
if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b));
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
|
||||
then {
|
||||
let span = filter_span.to(map_span);
|
||||
let (filter_name, lint) = if is_find {
|
||||
("find", MANUAL_FIND_MAP)
|
||||
} else {
|
||||
("filter", MANUAL_FILTER_MAP)
|
||||
};
|
||||
let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name);
|
||||
let to_opt = if is_result { ".ok()" } else { "" };
|
||||
let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident,
|
||||
snippet(cx, map_arg.span, ".."), to_opt);
|
||||
span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -896,6 +896,28 @@ declare_clippy_lint! {
|
|||
"using `Iterator::step_by(0)`, which will panic at runtime"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for indirect collection of populated `Option`
|
||||
///
|
||||
/// **Why is this bad?** `Option` is like a collection of 0-1 things, so `flatten`
|
||||
/// automatically does this without suspicious-looking `unwrap` calls.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let _ = std::iter::empty::<Option<i32>>().flatten();
|
||||
/// ```
|
||||
pub OPTION_FILTER_MAP,
|
||||
complexity,
|
||||
"filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for the use of `iter.nth(0)`.
|
||||
///
|
||||
|
@ -1651,6 +1673,7 @@ impl_lint_pass!(Methods => [
|
|||
FILTER_MAP_IDENTITY,
|
||||
MANUAL_FILTER_MAP,
|
||||
MANUAL_FIND_MAP,
|
||||
OPTION_FILTER_MAP,
|
||||
FILTER_MAP_NEXT,
|
||||
FLAT_MAP_IDENTITY,
|
||||
MAP_FLATTEN,
|
||||
|
@ -1720,10 +1743,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]),
|
||||
["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]),
|
||||
["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]),
|
||||
["map", "filter"] => filter_map::check(cx, expr, false),
|
||||
["map", "filter"] => filter_map::check(cx, expr, false, method_spans[0]),
|
||||
["map", "filter_map"] => filter_map_map::check(cx, expr),
|
||||
["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()),
|
||||
["map", "find"] => filter_map::check(cx, expr, true),
|
||||
["map", "find"] => filter_map::check(cx, expr, true, method_spans[0]),
|
||||
["flat_map", "filter"] => filter_flat_map::check(cx, expr),
|
||||
["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr),
|
||||
["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]),
|
||||
|
|
23
tests/ui/option_filter_map.fixed
Normal file
23
tests/ui/option_filter_map.fixed
Normal file
|
@ -0,0 +1,23 @@
|
|||
#![warn(clippy::option_filter_map)]
|
||||
// run-rustfix
|
||||
fn odds_out(x: i32) -> Option<i32> {
|
||||
if x % 2 == 0 { Some(x) } else { None }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Some(Some(1)).flatten();
|
||||
let _ = Some(Some(1)).flatten();
|
||||
let _ = Some(1).map(odds_out).flatten();
|
||||
let _ = Some(1).map(odds_out).flatten();
|
||||
|
||||
let _ = vec![Some(1)].into_iter().flatten();
|
||||
let _ = vec![Some(1)].into_iter().flatten();
|
||||
let _ = vec![1]
|
||||
.into_iter()
|
||||
.map(odds_out)
|
||||
.flatten();
|
||||
let _ = vec![1]
|
||||
.into_iter()
|
||||
.map(odds_out)
|
||||
.flatten();
|
||||
}
|
25
tests/ui/option_filter_map.rs
Normal file
25
tests/ui/option_filter_map.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
#![warn(clippy::option_filter_map)]
|
||||
// run-rustfix
|
||||
fn odds_out(x: i32) -> Option<i32> {
|
||||
if x % 2 == 0 { Some(x) } else { None }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
|
||||
let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
|
||||
let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
|
||||
let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
|
||||
|
||||
let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
|
||||
let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
|
||||
let _ = vec![1]
|
||||
.into_iter()
|
||||
.map(odds_out)
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap);
|
||||
let _ = vec![1]
|
||||
.into_iter()
|
||||
.map(odds_out)
|
||||
.filter(|o| o.is_some())
|
||||
.map(|o| o.unwrap());
|
||||
}
|
56
tests/ui/option_filter_map.stderr
Normal file
56
tests/ui/option_filter_map.stderr
Normal file
|
@ -0,0 +1,56 @@
|
|||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:8:27
|
||||
|
|
||||
LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||
|
|
||||
= note: `-D clippy::option-filter-map` implied by `-D warnings`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:9:27
|
||||
|
|
||||
LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:10:35
|
||||
|
|
||||
LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:11:35
|
||||
|
|
||||
LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:13:39
|
||||
|
|
||||
LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:14:39
|
||||
|
|
||||
LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:18:10
|
||||
|
|
||||
LL | .filter(Option::is_some)
|
||||
| __________^
|
||||
LL | | .map(Option::unwrap);
|
||||
| |____________________________^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: `filter` for `Some` followed by `unwrap`
|
||||
--> $DIR/option_filter_map.rs:23:10
|
||||
|
|
||||
LL | .filter(|o| o.is_some())
|
||||
| __________^
|
||||
LL | | .map(|o| o.unwrap());
|
||||
| |____________________________^ help: consider using `flatten` instead: `flatten()`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
Loading…
Reference in a new issue