@@ -29,7 +29,7 @@ use crate::{MirBorrowckCtxt, WriteKind};
29
29
30
30
#[ derive( Debug ) ]
31
31
pub ( crate ) enum BorrowExplanation < ' tcx > {
32
- UsedLater ( LaterUseKind , Span , Option < Span > ) ,
32
+ UsedLater ( Local , LaterUseKind , Span , Option < Span > ) ,
33
33
UsedLaterInLoop ( LaterUseKind , Span , Option < Span > ) ,
34
34
UsedLaterWhenDropped {
35
35
drop_loc : Location ,
@@ -98,17 +98,39 @@ impl<'tcx> BorrowExplanation<'tcx> {
98
98
}
99
99
}
100
100
match * self {
101
- BorrowExplanation :: UsedLater ( later_use_kind, var_or_use_span, path_span) => {
101
+ BorrowExplanation :: UsedLater (
102
+ dropped_local,
103
+ later_use_kind,
104
+ var_or_use_span,
105
+ path_span,
106
+ ) => {
102
107
let message = match later_use_kind {
103
108
LaterUseKind :: TraitCapture => "captured here by trait object" ,
104
109
LaterUseKind :: ClosureCapture => "captured here by closure" ,
105
110
LaterUseKind :: Call => "used by call" ,
106
111
LaterUseKind :: FakeLetRead => "stored here" ,
107
112
LaterUseKind :: Other => "used here" ,
108
113
} ;
109
- // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
110
- if path_span. map ( |path_span| path_span == var_or_use_span) . unwrap_or ( true ) {
111
- if borrow_span. map ( |sp| !sp. overlaps ( var_or_use_span) ) . unwrap_or ( true ) {
114
+ let local_decl = & body. local_decls [ dropped_local] ;
115
+
116
+ if let & LocalInfo :: IfThenRescopeTemp { if_then } = local_decl. local_info ( )
117
+ && let Some ( ( _, hir:: Node :: Expr ( expr) ) ) = tcx. hir ( ) . parent_iter ( if_then) . next ( )
118
+ && let hir:: ExprKind :: If ( cond, conseq, alt) = expr. kind
119
+ && let hir:: ExprKind :: Let ( & hir:: LetExpr {
120
+ span : _,
121
+ pat,
122
+ init,
123
+ // FIXME(#101728): enable rewrite when type ascription is stabilized again
124
+ ty : None ,
125
+ recovered : _,
126
+ } ) = cond. kind
127
+ && pat. span . can_be_used_for_suggestions ( )
128
+ && let Ok ( pat) = tcx. sess . source_map ( ) . span_to_snippet ( pat. span )
129
+ {
130
+ suggest_rewrite_if_let ( expr, & pat, init, conseq, alt, err) ;
131
+ } else if path_span. map_or ( true , |path_span| path_span == var_or_use_span) {
132
+ // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
133
+ if borrow_span. map_or ( true , |sp| !sp. overlaps ( var_or_use_span) ) {
112
134
err. span_label (
113
135
var_or_use_span,
114
136
format ! ( "{borrow_desc}borrow later {message}" ) ,
@@ -254,6 +276,22 @@ impl<'tcx> BorrowExplanation<'tcx> {
254
276
Applicability :: MaybeIncorrect ,
255
277
) ;
256
278
} ;
279
+ } else if let & LocalInfo :: IfThenRescopeTemp { if_then } =
280
+ local_decl. local_info ( )
281
+ && let hir:: Node :: Expr ( expr) = tcx. hir_node ( if_then)
282
+ && let hir:: ExprKind :: If ( cond, conseq, alt) = expr. kind
283
+ && let hir:: ExprKind :: Let ( & hir:: LetExpr {
284
+ span : _,
285
+ pat,
286
+ init,
287
+ // FIXME(#101728): enable rewrite when type ascription is stabilized again
288
+ ty : None ,
289
+ recovered : _,
290
+ } ) = cond. kind
291
+ && pat. span . can_be_used_for_suggestions ( )
292
+ && let Ok ( pat) = tcx. sess . source_map ( ) . span_to_snippet ( pat. span )
293
+ {
294
+ suggest_rewrite_if_let ( expr, & pat, init, conseq, alt, err) ;
257
295
}
258
296
}
259
297
}
@@ -389,6 +427,38 @@ impl<'tcx> BorrowExplanation<'tcx> {
389
427
}
390
428
}
391
429
430
+ fn suggest_rewrite_if_let < ' tcx > (
431
+ expr : & hir:: Expr < ' tcx > ,
432
+ pat : & str ,
433
+ init : & hir:: Expr < ' tcx > ,
434
+ conseq : & hir:: Expr < ' tcx > ,
435
+ alt : Option < & hir:: Expr < ' tcx > > ,
436
+ err : & mut Diag < ' _ > ,
437
+ ) {
438
+ err. span_note (
439
+ conseq. span . shrink_to_hi ( ) ,
440
+ "lifetime for temporaries generated in `if let`s have been shorted in Edition 2024" ,
441
+ ) ;
442
+ if expr. span . can_be_used_for_suggestions ( ) && conseq. span . can_be_used_for_suggestions ( ) {
443
+ let mut sugg = vec ! [
444
+ ( expr. span. shrink_to_lo( ) . between( init. span) , "match " . into( ) ) ,
445
+ ( conseq. span. shrink_to_lo( ) , format!( " {{ {pat} => " ) ) ,
446
+ ] ;
447
+ let expr_end = expr. span . shrink_to_hi ( ) ;
448
+ if let Some ( alt) = alt {
449
+ sugg. push ( ( conseq. span . between ( alt. span ) , format ! ( " _ => " ) ) ) ;
450
+ sugg. push ( ( expr_end, "}" . into ( ) ) ) ;
451
+ } else {
452
+ sugg. push ( ( expr_end, " _ => {} }" . into ( ) ) ) ;
453
+ }
454
+ err. multipart_suggestion (
455
+ "consider rewriting the `if` into `match` which preserves the extended lifetime" ,
456
+ sugg,
457
+ Applicability :: MachineApplicable ,
458
+ ) ;
459
+ }
460
+ }
461
+
392
462
impl < ' tcx > MirBorrowckCtxt < ' _ , ' _ , ' _ , ' tcx > {
393
463
fn free_region_constraint_info (
394
464
& self ,
@@ -464,14 +534,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
464
534
. or_else ( || self . borrow_spans ( span, location) ) ;
465
535
466
536
if use_in_later_iteration_of_loop {
467
- let later_use = self . later_use_kind ( borrow, spans, use_location) ;
468
- BorrowExplanation :: UsedLaterInLoop ( later_use. 0 , later_use. 1 , later_use. 2 )
537
+ let ( later_use_kind, var_or_use_span, path_span) =
538
+ self . later_use_kind ( borrow, spans, use_location) ;
539
+ BorrowExplanation :: UsedLaterInLoop ( later_use_kind, var_or_use_span, path_span)
469
540
} else {
470
541
// Check if the location represents a `FakeRead`, and adapt the error
471
542
// message to the `FakeReadCause` it is from: in particular,
472
543
// the ones inserted in optimized `let var = <expr>` patterns.
473
- let later_use = self . later_use_kind ( borrow, spans, location) ;
474
- BorrowExplanation :: UsedLater ( later_use. 0 , later_use. 1 , later_use. 2 )
544
+ let ( later_use_kind, var_or_use_span, path_span) =
545
+ self . later_use_kind ( borrow, spans, location) ;
546
+ BorrowExplanation :: UsedLater (
547
+ borrow. borrowed_place . local ,
548
+ later_use_kind,
549
+ var_or_use_span,
550
+ path_span,
551
+ )
475
552
}
476
553
}
477
554
0 commit comments