@@ -30,7 +30,7 @@ use crate::{MirBorrowckCtxt, WriteKind};
3030
3131#[ derive( Debug ) ]
3232pub ( crate ) enum BorrowExplanation < ' tcx > {
33- UsedLater ( LaterUseKind , Span , Option < Span > ) ,
33+ UsedLater ( Local , LaterUseKind , Span , Option < Span > ) ,
3434 UsedLaterInLoop ( LaterUseKind , Span , Option < Span > ) ,
3535 UsedLaterWhenDropped {
3636 drop_loc : Location ,
@@ -99,17 +99,39 @@ impl<'tcx> BorrowExplanation<'tcx> {
9999 }
100100 }
101101 match * self {
102- BorrowExplanation :: UsedLater ( later_use_kind, var_or_use_span, path_span) => {
102+ BorrowExplanation :: UsedLater (
103+ dropped_local,
104+ later_use_kind,
105+ var_or_use_span,
106+ path_span,
107+ ) => {
103108 let message = match later_use_kind {
104109 LaterUseKind :: TraitCapture => "captured here by trait object" ,
105110 LaterUseKind :: ClosureCapture => "captured here by closure" ,
106111 LaterUseKind :: Call => "used by call" ,
107112 LaterUseKind :: FakeLetRead => "stored here" ,
108113 LaterUseKind :: Other => "used here" ,
109114 } ;
110- // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
111- if path_span. map ( |path_span| path_span == var_or_use_span) . unwrap_or ( true ) {
112- if borrow_span. map ( |sp| !sp. overlaps ( var_or_use_span) ) . unwrap_or ( true ) {
115+ let local_decl = & body. local_decls [ dropped_local] ;
116+
117+ if let & LocalInfo :: IfThenRescopeTemp { if_then } = local_decl. local_info ( )
118+ && let Some ( ( _, hir:: Node :: Expr ( expr) ) ) = tcx. hir ( ) . parent_iter ( if_then) . next ( )
119+ && let hir:: ExprKind :: If ( cond, conseq, alt) = expr. kind
120+ && let hir:: ExprKind :: Let ( & hir:: LetExpr {
121+ span : _,
122+ pat,
123+ init,
124+ // FIXME(#101728): enable rewrite when type ascription is stabilized again
125+ ty : None ,
126+ recovered : _,
127+ } ) = cond. kind
128+ && pat. span . can_be_used_for_suggestions ( )
129+ && let Ok ( pat) = tcx. sess . source_map ( ) . span_to_snippet ( pat. span )
130+ {
131+ suggest_rewrite_if_let ( expr, & pat, init, conseq, alt, err) ;
132+ } else if path_span. map_or ( true , |path_span| path_span == var_or_use_span) {
133+ // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
134+ if borrow_span. map_or ( true , |sp| !sp. overlaps ( var_or_use_span) ) {
113135 err. span_label (
114136 var_or_use_span,
115137 format ! ( "{borrow_desc}borrow later {message}" ) ,
@@ -255,6 +277,22 @@ impl<'tcx> BorrowExplanation<'tcx> {
255277 Applicability :: MaybeIncorrect ,
256278 ) ;
257279 } ;
280+ } else if let & LocalInfo :: IfThenRescopeTemp { if_then } =
281+ local_decl. local_info ( )
282+ && let hir:: Node :: Expr ( expr) = tcx. hir_node ( if_then)
283+ && let hir:: ExprKind :: If ( cond, conseq, alt) = expr. kind
284+ && let hir:: ExprKind :: Let ( & hir:: LetExpr {
285+ span : _,
286+ pat,
287+ init,
288+ // FIXME(#101728): enable rewrite when type ascription is stabilized again
289+ ty : None ,
290+ recovered : _,
291+ } ) = cond. kind
292+ && pat. span . can_be_used_for_suggestions ( )
293+ && let Ok ( pat) = tcx. sess . source_map ( ) . span_to_snippet ( pat. span )
294+ {
295+ suggest_rewrite_if_let ( expr, & pat, init, conseq, alt, err) ;
258296 }
259297 }
260298 }
@@ -390,6 +428,38 @@ impl<'tcx> BorrowExplanation<'tcx> {
390428 }
391429}
392430
431+ fn suggest_rewrite_if_let < ' tcx > (
432+ expr : & hir:: Expr < ' tcx > ,
433+ pat : & str ,
434+ init : & hir:: Expr < ' tcx > ,
435+ conseq : & hir:: Expr < ' tcx > ,
436+ alt : Option < & hir:: Expr < ' tcx > > ,
437+ err : & mut Diag < ' _ > ,
438+ ) {
439+ err. span_note (
440+ conseq. span . shrink_to_hi ( ) ,
441+ "lifetime for temporaries generated in `if let`s have been shorted in Edition 2024" ,
442+ ) ;
443+ if expr. span . can_be_used_for_suggestions ( ) && conseq. span . can_be_used_for_suggestions ( ) {
444+ let mut sugg = vec ! [
445+ ( expr. span. shrink_to_lo( ) . between( init. span) , "match " . into( ) ) ,
446+ ( conseq. span. shrink_to_lo( ) , format!( " {{ {pat} => " ) ) ,
447+ ] ;
448+ let expr_end = expr. span . shrink_to_hi ( ) ;
449+ if let Some ( alt) = alt {
450+ sugg. push ( ( conseq. span . between ( alt. span ) , format ! ( " _ => " ) ) ) ;
451+ sugg. push ( ( expr_end, "}" . into ( ) ) ) ;
452+ } else {
453+ sugg. push ( ( expr_end, " _ => {} }" . into ( ) ) ) ;
454+ }
455+ err. multipart_suggestion (
456+ "consider rewriting the `if` into `match` which preserves the extended lifetime" ,
457+ sugg,
458+ Applicability :: MachineApplicable ,
459+ ) ;
460+ }
461+ }
462+
393463impl < ' tcx > MirBorrowckCtxt < ' _ , ' _ , ' tcx > {
394464 fn free_region_constraint_info (
395465 & self ,
@@ -465,14 +535,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
465535 . or_else ( || self . borrow_spans ( span, location) ) ;
466536
467537 if use_in_later_iteration_of_loop {
468- let later_use = self . later_use_kind ( borrow, spans, use_location) ;
469- BorrowExplanation :: UsedLaterInLoop ( later_use. 0 , later_use. 1 , later_use. 2 )
538+ let ( later_use_kind, var_or_use_span, path_span) =
539+ self . later_use_kind ( borrow, spans, use_location) ;
540+ BorrowExplanation :: UsedLaterInLoop ( later_use_kind, var_or_use_span, path_span)
470541 } else {
471542 // Check if the location represents a `FakeRead`, and adapt the error
472543 // message to the `FakeReadCause` it is from: in particular,
473544 // the ones inserted in optimized `let var = <expr>` patterns.
474- let later_use = self . later_use_kind ( borrow, spans, location) ;
475- BorrowExplanation :: UsedLater ( later_use. 0 , later_use. 1 , later_use. 2 )
545+ let ( later_use_kind, var_or_use_span, path_span) =
546+ self . later_use_kind ( borrow, spans, location) ;
547+ BorrowExplanation :: UsedLater (
548+ borrow. borrowed_place . local ,
549+ later_use_kind,
550+ var_or_use_span,
551+ path_span,
552+ )
476553 }
477554 }
478555
0 commit comments