diff options
| author | Ding Xiang Fei <dingxiangfei2009@protonmail.ch> | 2023-01-24 16:06:35 +0800 |
|---|---|---|
| committer | Ding Xiang Fei <dingxiangfei2009@protonmail.ch> | 2024-09-11 04:10:00 +0800 |
| commit | f93df1f7dcea3588620b77e2a0eaac12b46a7678 (patch) | |
| tree | 6f11422d01bb8a063a3e71ecbf0fb8d2490e02ae /compiler/rustc_borrowck/src/diagnostics | |
| parent | 33855f80d4393bff5d1226eabf8e61f348179cee (diff) | |
| download | rust-f93df1f7dcea3588620b77e2a0eaac12b46a7678.tar.gz rust-f93df1f7dcea3588620b77e2a0eaac12b46a7678.zip | |
rescope temp lifetime in let-chain into IfElse
apply rules by span edition
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics')
| -rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 29 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs | 95 |
2 files changed, 107 insertions, 17 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a47518fca3f..215e0476f01 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1999,19 +1999,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { let used_in_call = matches!( explanation, - BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) + BorrowExplanation::UsedLater( + _, + LaterUseKind::Call | LaterUseKind::Other, + _call_span, + _ + ) ); if !used_in_call { debug!("not later used in call"); return; } + if matches!( + self.body.local_decls[issued_borrow.borrowed_place.local].local_info(), + LocalInfo::IfThenRescopeTemp { .. } + ) { + // A better suggestion will be issued by the `if_let_rescope` lint + return; + } - let use_span = - if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { - Some(use_span) - } else { - None - }; + let use_span = if let BorrowExplanation::UsedLater(_, LaterUseKind::Other, use_span, _) = + explanation + { + Some(use_span) + } else { + None + }; let outer_call_loc = if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { @@ -2862,7 +2875,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // and `move` will not help here. ( Some(name), - BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _), + BorrowExplanation::UsedLater(_, LaterUseKind::ClosureCapture, var_or_use_span, _), ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self .report_escaping_closure_capture( borrow_spans, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 419e72df00b..22327d2ba0d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -30,7 +30,7 @@ use crate::{MirBorrowckCtxt, WriteKind}; #[derive(Debug)] pub(crate) enum BorrowExplanation<'tcx> { - UsedLater(LaterUseKind, Span, Option<Span>), + UsedLater(Local, LaterUseKind, Span, Option<Span>), UsedLaterInLoop(LaterUseKind, Span, Option<Span>), UsedLaterWhenDropped { drop_loc: Location, @@ -99,7 +99,12 @@ impl<'tcx> BorrowExplanation<'tcx> { } } match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { + BorrowExplanation::UsedLater( + dropped_local, + later_use_kind, + var_or_use_span, + path_span, + ) => { let message = match later_use_kind { LaterUseKind::TraitCapture => "captured here by trait object", LaterUseKind::ClosureCapture => "captured here by closure", @@ -107,9 +112,26 @@ impl<'tcx> BorrowExplanation<'tcx> { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + let local_decl = &body.local_decls[dropped_local]; + + if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info() + && let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(if_then).next() + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is stabilized again + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(expr, &pat, init, conseq, alt, err); + } else if path_span.map_or(true, |path_span| path_span == var_or_use_span) { + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) { err.span_label( var_or_use_span, format!("{borrow_desc}borrow later {message}"), @@ -255,6 +277,22 @@ impl<'tcx> BorrowExplanation<'tcx> { Applicability::MaybeIncorrect, ); }; + } else if let &LocalInfo::IfThenRescopeTemp { if_then } = + local_decl.local_info() + && let hir::Node::Expr(expr) = tcx.hir_node(if_then) + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is stabilized again + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(expr, &pat, init, conseq, alt, err); } } } @@ -390,6 +428,38 @@ impl<'tcx> BorrowExplanation<'tcx> { } } +fn suggest_rewrite_if_let<'tcx>( + expr: &hir::Expr<'tcx>, + pat: &str, + init: &hir::Expr<'tcx>, + conseq: &hir::Expr<'tcx>, + alt: Option<&hir::Expr<'tcx>>, + err: &mut Diag<'_>, +) { + err.span_note( + conseq.span.shrink_to_hi(), + "lifetime for temporaries generated in `if let`s have been shorted in Edition 2024", + ); + if expr.span.can_be_used_for_suggestions() && conseq.span.can_be_used_for_suggestions() { + let mut sugg = vec![ + (expr.span.shrink_to_lo().between(init.span), "match ".into()), + (conseq.span.shrink_to_lo(), format!(" {{ {pat} => ")), + ]; + let expr_end = expr.span.shrink_to_hi(); + if let Some(alt) = alt { + sugg.push((conseq.span.between(alt.span), format!(" _ => "))); + sugg.push((expr_end, "}".into())); + } else { + sugg.push((expr_end, " _ => {} }".into())); + } + err.multipart_suggestion( + "consider rewriting the `if` into `match` which preserves the extended lifetime", + sugg, + Applicability::MachineApplicable, + ); + } +} + impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { fn free_region_constraint_info( &self, @@ -465,14 +535,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { .or_else(|| self.borrow_spans(span, location)); if use_in_later_iteration_of_loop { - let later_use = self.later_use_kind(borrow, spans, use_location); - BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) + let (later_use_kind, var_or_use_span, path_span) = + self.later_use_kind(borrow, spans, use_location); + BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = <expr>` patterns. - let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) + let (later_use_kind, var_or_use_span, path_span) = + self.later_use_kind(borrow, spans, location); + BorrowExplanation::UsedLater( + borrow.borrowed_place.local, + later_use_kind, + var_or_use_span, + path_span, + ) } } |
