1
1
use rustc_errors:: Applicability ;
2
2
use 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 } ;
4
4
use rustc_lint:: { LateContext , LateLintPass } ;
5
5
use rustc_session:: declare_lint_pass;
6
6
use rustc_span:: Span ;
@@ -70,12 +70,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
70
70
&& has_iter_method ( cx, cx. typeck_results ( ) . expr_ty ( iter_recv) ) . is_some ( )
71
71
// Skip the lint if the body is not block because this is simpler than `for` loop.
72
72
// 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
74
74
&& let body = cx. tcx . hir_body ( body)
75
75
// Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
76
76
// and suggesting `for … in … { unsafe { } }` is a little ugly.
77
77
&& !matches ! ( body. value. kind, ExprKind :: Block ( Block { rules: BlockCheckMode :: UnsafeBlock ( _) , .. } , ..) )
78
78
{
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
+
79
91
let mut ret_collector = RetCollector :: default ( ) ;
80
92
ret_collector. visit_expr ( body. value ) ;
81
93
@@ -84,18 +96,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
84
96
return ;
85
97
}
86
98
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
89
101
} 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 ( ) ,
99
109
)
100
110
} ;
101
111
0 commit comments