@@ -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 ( tcx, 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 ( tcx, expr, & pat, init, conseq, alt, err) ;
258296 }
259297 }
260298 }
@@ -390,6 +428,53 @@ impl<'tcx> BorrowExplanation<'tcx> {
390428 }
391429}
392430
431+ fn suggest_rewrite_if_let (
432+ tcx : TyCtxt < ' _ > ,
433+ expr : & hir:: Expr < ' _ > ,
434+ pat : & str ,
435+ init : & hir:: Expr < ' _ > ,
436+ conseq : & hir:: Expr < ' _ > ,
437+ alt : Option < & hir:: Expr < ' _ > > ,
438+ err : & mut Diag < ' _ > ,
439+ ) {
440+ let source_map = tcx. sess . source_map ( ) ;
441+ err. span_note (
442+ source_map. end_point ( conseq. span ) ,
443+ "lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead" ,
444+ ) ;
445+ if expr. span . can_be_used_for_suggestions ( ) && conseq. span . can_be_used_for_suggestions ( ) {
446+ let needs_block = if let Some ( hir:: Node :: Expr ( expr) ) =
447+ alt. and_then ( |alt| tcx. hir ( ) . parent_iter ( alt. hir_id ) . next ( ) ) . map ( |( _, node) | node)
448+ {
449+ matches ! ( expr. kind, hir:: ExprKind :: If ( ..) )
450+ } else {
451+ false
452+ } ;
453+ let mut sugg = vec ! [
454+ (
455+ expr. span. shrink_to_lo( ) . between( init. span) ,
456+ if needs_block { "{ match " . into( ) } else { "match " . into( ) } ,
457+ ) ,
458+ ( conseq. span. shrink_to_lo( ) , format!( " {{ {pat} => " ) ) ,
459+ ] ;
460+ let expr_end = expr. span . shrink_to_hi ( ) ;
461+ let mut expr_end_code;
462+ if let Some ( alt) = alt {
463+ sugg. push ( ( conseq. span . between ( alt. span ) , " _ => " . into ( ) ) ) ;
464+ expr_end_code = "}" . to_string ( ) ;
465+ } else {
466+ expr_end_code = " _ => {} }" . into ( ) ;
467+ }
468+ expr_end_code. push ( '}' ) ;
469+ sugg. push ( ( expr_end, expr_end_code) ) ;
470+ err. multipart_suggestion (
471+ "consider rewriting the `if` into `match` which preserves the extended lifetime" ,
472+ sugg,
473+ Applicability :: MaybeIncorrect ,
474+ ) ;
475+ }
476+ }
477+
393478impl < ' tcx > MirBorrowckCtxt < ' _ , ' _ , ' tcx > {
394479 fn free_region_constraint_info (
395480 & self ,
@@ -465,14 +550,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
465550 . or_else ( || self . borrow_spans ( span, location) ) ;
466551
467552 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 )
553+ let ( later_use_kind, var_or_use_span, path_span) =
554+ self . later_use_kind ( borrow, spans, use_location) ;
555+ BorrowExplanation :: UsedLaterInLoop ( later_use_kind, var_or_use_span, path_span)
470556 } else {
471557 // Check if the location represents a `FakeRead`, and adapt the error
472558 // message to the `FakeReadCause` it is from: in particular,
473559 // 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 )
560+ let ( later_use_kind, var_or_use_span, path_span) =
561+ self . later_use_kind ( borrow, spans, location) ;
562+ BorrowExplanation :: UsedLater (
563+ borrow. borrowed_place . local ,
564+ later_use_kind,
565+ var_or_use_span,
566+ path_span,
567+ )
476568 }
477569 }
478570
0 commit comments