11use crate :: { LateContext , LateLintPass , LintContext } ;
22
33use hir:: { Expr , Pat } ;
4+ use rustc_errors:: Applicability ;
45use rustc_hir as hir;
56use rustc_middle:: ty;
67use rustc_span:: sym;
@@ -65,18 +66,24 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopOverFallibles {
6566 _ => return ,
6667 } ;
6768
68- let Ok ( pat_snip) = cx. sess ( ) . source_map ( ) . span_to_snippet ( pat. span ) else { return } ;
6969 let Ok ( arg_snip) = cx. sess ( ) . source_map ( ) . span_to_snippet ( arg. span ) else { return } ;
7070
71- let help_string = format ! (
72- "consider replacing `for {pat_snip} in {arg_snip}` with `if let {var}({pat_snip}) = {arg_snip}`"
73- ) ;
7471 let msg = format ! (
7572 "for loop over `{arg_snip}`, which is {article} `{ty}`. This is more readably written as an `if let` statement" ,
7673 ) ;
7774
7875 cx. struct_span_lint ( FOR_LOOP_OVER_FALLIBLES , arg. span , |diag| {
79- diag. build ( msg) . help ( help_string) . emit ( )
76+ diag. build ( msg)
77+ . multipart_suggestion_verbose (
78+ "consider using `if let` to clear intent" ,
79+ vec ! [
80+ // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
81+ ( expr. span. with_hi( pat. span. lo( ) ) , format!( "if let {var}(" ) ) ,
82+ ( pat. span. between( arg. span) , format!( ") = " ) ) ,
83+ ] ,
84+ Applicability :: MachineApplicable ,
85+ )
86+ . emit ( )
8087 } )
8188 }
8289}
@@ -89,11 +96,10 @@ fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx E
8996 && let [ stmt] = block. stmts
9097 && let hir:: StmtKind :: Expr ( e) = stmt. kind
9198 && let hir:: ExprKind :: Match ( _, [ _, some_arm] , _) = e. kind
92- && let hir:: PatKind :: Struct ( _, [ field] , _) = some_arm. pat . kind
99+ && let hir:: PatKind :: Struct ( _, [ field] , _) = some_arm. pat . kind
93100 {
94101 Some ( ( field. pat , arg) )
95102 } else {
96103 None
97104 }
98-
99- }
105+ }
0 commit comments