@@ -2569,17 +2569,35 @@ fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Ex
25692569fn lint_map_flatten < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > , map_args : & ' tcx [ hir:: Expr < ' _ > ] ) {
25702570 // lint if caller of `.map().flatten()` is an Iterator
25712571 if match_trait_method ( cx, expr, & paths:: ITERATOR ) {
2572- let msg = "called `map(..).flatten()` on an `Iterator`. \
2573- This is more succinctly expressed by calling `.flat_map(..)`";
2572+ let map_closure_ty = cx. typeck_results ( ) . expr_ty ( & map_args[ 1 ] ) ;
2573+ let is_map_to_option = if let ty:: Closure ( _def_id, substs) = map_closure_ty. kind {
2574+ let map_closure_return_ty = cx. tcx . erase_late_bound_regions ( & substs. as_closure ( ) . sig ( ) . output ( ) ) ;
2575+ is_type_diagnostic_item ( cx, map_closure_return_ty, sym ! ( option_type) )
2576+ } else {
2577+ false
2578+ } ;
2579+
2580+ let method_to_use = if is_map_to_option {
2581+ // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
2582+ "filter_map"
2583+ } else {
2584+ // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
2585+ "flat_map"
2586+ } ;
2587+ let msg = & format ! (
2588+ "called `map(..).flatten()` on an `Iterator`. \
2589+ This is more succinctly expressed by calling `.{}(..)`",
2590+ method_to_use
2591+ ) ;
25742592 let self_snippet = snippet ( cx, map_args[ 0 ] . span , ".." ) ;
25752593 let func_snippet = snippet ( cx, map_args[ 1 ] . span , ".." ) ;
2576- let hint = format ! ( "{0}.flat_map( {1})" , self_snippet, func_snippet) ;
2594+ let hint = format ! ( "{0}.{1}({2} )" , self_snippet, method_to_use , func_snippet) ;
25772595 span_lint_and_sugg (
25782596 cx,
25792597 MAP_FLATTEN ,
25802598 expr. span ,
25812599 msg,
2582- "try using `flat_map ` instead" ,
2600+ & format ! ( "try using `{} ` instead" , method_to_use ) ,
25832601 hint,
25842602 Applicability :: MachineApplicable ,
25852603 ) ;
0 commit comments