@@ -30,7 +30,7 @@ use crate::{MirBorrowckCtxt, WriteKind};
30
30
31
31
#[ derive( Debug ) ]
32
32
pub ( crate ) enum BorrowExplanation < ' tcx > {
33
- UsedLater ( LaterUseKind , Span , Option < Span > ) ,
33
+ UsedLater ( Local , LaterUseKind , Span , Option < Span > ) ,
34
34
UsedLaterInLoop ( LaterUseKind , Span , Option < Span > ) ,
35
35
UsedLaterWhenDropped {
36
36
drop_loc : Location ,
@@ -99,17 +99,39 @@ impl<'tcx> BorrowExplanation<'tcx> {
99
99
}
100
100
}
101
101
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
+ ) => {
103
108
let message = match later_use_kind {
104
109
LaterUseKind :: TraitCapture => "captured here by trait object" ,
105
110
LaterUseKind :: ClosureCapture => "captured here by closure" ,
106
111
LaterUseKind :: Call => "used by call" ,
107
112
LaterUseKind :: FakeLetRead => "stored here" ,
108
113
LaterUseKind :: Other => "used here" ,
109
114
} ;
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) ) {
113
135
err. span_label (
114
136
var_or_use_span,
115
137
format ! ( "{borrow_desc}borrow later {message}" ) ,
@@ -255,6 +277,22 @@ impl<'tcx> BorrowExplanation<'tcx> {
255
277
Applicability :: MaybeIncorrect ,
256
278
) ;
257
279
} ;
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) ;
258
296
}
259
297
}
260
298
}
@@ -390,6 +428,53 @@ impl<'tcx> BorrowExplanation<'tcx> {
390
428
}
391
429
}
392
430
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
+
393
478
impl < ' tcx > MirBorrowckCtxt < ' _ , ' _ , ' tcx > {
394
479
fn free_region_constraint_info (
395
480
& self ,
@@ -465,14 +550,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
465
550
. or_else ( || self . borrow_spans ( span, location) ) ;
466
551
467
552
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)
470
556
} else {
471
557
// Check if the location represents a `FakeRead`, and adapt the error
472
558
// message to the `FakeReadCause` it is from: in particular,
473
559
// 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
+ )
476
568
}
477
569
}
478
570
0 commit comments