about summary refs log tree commit diff
path: root/compiler/rustc_borrowck/src/diagnostics
diff options
context:
space:
mode:
authorDing Xiang Fei <dingxiangfei2009@protonmail.ch>2023-01-24 16:06:35 +0800
committerDing Xiang Fei <dingxiangfei2009@protonmail.ch>2024-09-11 04:10:00 +0800
commitf93df1f7dcea3588620b77e2a0eaac12b46a7678 (patch)
tree6f11422d01bb8a063a3e71ecbf0fb8d2490e02ae /compiler/rustc_borrowck/src/diagnostics
parent33855f80d4393bff5d1226eabf8e61f348179cee (diff)
downloadrust-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.rs29
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs95
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,
+                    )
                 }
             }