@@ -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 ( 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 ( expr, & pat, init, conseq, alt, err) ;
258
296
}
259
297
}
260
298
}
@@ -390,6 +428,38 @@ impl<'tcx> BorrowExplanation<'tcx> {
390
428
}
391
429
}
392
430
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
+
393
463
impl < ' tcx > MirBorrowckCtxt < ' _ , ' _ , ' _ , ' tcx > {
394
464
fn free_region_constraint_info (
395
465
& self ,
@@ -465,14 +535,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
465
535
. or_else ( || self . borrow_spans ( span, location) ) ;
466
536
467
537
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)
470
541
} else {
471
542
// Check if the location represents a `FakeRead`, and adapt the error
472
543
// message to the `FakeReadCause` it is from: in particular,
473
544
// 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
+ )
476
553
}
477
554
}
478
555
0 commit comments