11use rustc_errors:: Applicability ;
22use rustc_hir:: intravisit:: { Visitor , walk_expr} ;
3- use rustc_hir:: { Block , BlockCheckMode , Closure , Expr , ExprKind , Stmt , StmtKind } ;
3+ use rustc_hir:: { Block , BlockCheckMode , Closure , Expr , ExprKind , Stmt , StmtKind , TyKind } ;
44use rustc_lint:: { LateContext , LateLintPass } ;
55use rustc_session:: declare_lint_pass;
66use rustc_span:: Span ;
@@ -70,12 +70,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
7070 && has_iter_method ( cx, cx. typeck_results ( ) . expr_ty ( iter_recv) ) . is_some ( )
7171 // Skip the lint if the body is not block because this is simpler than `for` loop.
7272 // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
73- && let ExprKind :: Closure ( & Closure { body, .. } ) = for_each_arg. kind
73+ && let ExprKind :: Closure ( & Closure { body, fn_decl , .. } ) = for_each_arg. kind
7474 && let body = cx. tcx . hir_body ( body)
7575 // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
7676 // and suggesting `for … in … { unsafe { } }` is a little ugly.
7777 && !matches ! ( body. value. kind, ExprKind :: Block ( Block { rules: BlockCheckMode :: UnsafeBlock ( _) , .. } , ..) )
7878 {
79+ let mut applicability = Applicability :: MachineApplicable ;
80+
81+ // If any closure parameter has an explicit type specified, applying the lint would necessarily
82+ // remove that specification, possibly breaking type inference
83+ if fn_decl
84+ . inputs
85+ . iter ( )
86+ . any ( |input| matches ! ( input. kind, TyKind :: Infer ( ..) ) )
87+ {
88+ applicability = Applicability :: MaybeIncorrect ;
89+ }
90+
7991 let mut ret_collector = RetCollector :: default ( ) ;
8092 ret_collector. visit_expr ( body. value ) ;
8193
@@ -84,18 +96,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
8496 return ;
8597 }
8698
87- let ( mut applicability , ret_suggs) = if ret_collector. spans . is_empty ( ) {
88- ( Applicability :: MachineApplicable , None )
99+ let ret_suggs = if ret_collector. spans . is_empty ( ) {
100+ None
89101 } else {
90- (
91- Applicability :: MaybeIncorrect ,
92- Some (
93- ret_collector
94- . spans
95- . into_iter ( )
96- . map ( |span| ( span, "continue" . to_string ( ) ) )
97- . collect ( ) ,
98- ) ,
102+ applicability = Applicability :: MaybeIncorrect ;
103+ Some (
104+ ret_collector
105+ . spans
106+ . into_iter ( )
107+ . map ( |span| ( span, "continue" . to_string ( ) ) )
108+ . collect ( ) ,
99109 )
100110 } ;
101111
0 commit comments