]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / compiler / rustc_mir / src / borrow_check / diagnostics / conflict_errors.rs
index 8b0761889b83453b9d205d5418a57f4e14bb01e5..2e854ea5be7df7046321a33dde452c5a84a38d30 100644 (file)
@@ -9,10 +9,11 @@ use rustc_middle::mir::{
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_trait_selection::infer::InferCtxtExt;
 
 use crate::dataflow::drop_flag_effects;
 use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
@@ -65,7 +66,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
         let span = use_spans.args_or_use();
 
-        let move_site_vec = self.get_moved_indexes(location, mpi);
+        let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);
         debug!(
             "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
             move_site_vec, use_spans
@@ -138,6 +139,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.describe_place_with_options(moved_place, IncludingDowncast(true)),
             );
 
+            let reinit_spans = maybe_reinitialized_locations
+                .iter()
+                .take(3)
+                .map(|loc| {
+                    self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)
+                        .args_or_use()
+                })
+                .collect::<Vec<Span>>();
+            let reinits = maybe_reinitialized_locations.len();
+            if reinits == 1 {
+                err.span_label(reinit_spans[0], "this reinitialization might get skipped");
+            } else if reinits > 1 {
+                err.span_note(
+                    MultiSpan::from_spans(reinit_spans),
+                    &if reinits <= 3 {
+                        format!("these {} reinitializations might get skipped", reinits)
+                    } else {
+                        format!(
+                            "these 3 reinitializations and {} other{} might get skipped",
+                            reinits - 3,
+                            if reinits == 4 { "" } else { "s" }
+                        )
+                    },
+                );
+            }
+
             self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
 
             let mut is_loop_move = false;
@@ -218,7 +245,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     ),
                                 );
                             }
-                            if is_option_or_result {
+                            if is_option_or_result && maybe_reinitialized_locations.is_empty() {
                                 err.span_suggestion_verbose(
                                     fn_call_span.shrink_to_lo(),
                                     "consider calling `.as_ref()` to borrow the type's contents",
@@ -259,19 +286,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     }
                 }
 
-                if let UseSpans::PatUse(span) = move_spans {
-                    err.span_suggestion_verbose(
-                        span.shrink_to_lo(),
-                        &format!(
-                            "borrow this field in the pattern to avoid moving {}",
-                            self.describe_place(moved_place.as_ref())
-                                .map(|n| format!("`{}`", n))
-                                .unwrap_or_else(|| "the value".to_string())
-                        ),
-                        "ref ".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                    in_pattern = true;
+                if let (UseSpans::PatUse(span), []) =
+                    (move_spans, &maybe_reinitialized_locations[..])
+                {
+                    if maybe_reinitialized_locations.is_empty() {
+                        err.span_suggestion_verbose(
+                            span.shrink_to_lo(),
+                            &format!(
+                                "borrow this field in the pattern to avoid moving {}",
+                                self.describe_place(moved_place.as_ref())
+                                    .map(|n| format!("`{}`", n))
+                                    .unwrap_or_else(|| "the value".to_string())
+                            ),
+                            "ref ".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                        in_pattern = true;
+                    }
                 }
 
                 if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
@@ -453,6 +484,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 &mut err,
                 "",
                 Some(borrow_span),
+                None,
             );
         err.buffer(&mut self.errors_buffer);
     }
@@ -498,6 +530,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 &mut err,
                 "",
                 None,
+                None,
             );
         err
     }
@@ -718,6 +751,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             &mut err,
             first_borrow_desc,
             None,
+            Some((issued_span, span)),
         );
 
         err
@@ -1076,6 +1110,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     &mut err,
                     "",
                     None,
+                    None,
                 );
             }
         } else {
@@ -1093,6 +1128,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 &mut err,
                 "",
                 None,
+                None,
             );
         }
 
@@ -1158,6 +1194,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             &mut err,
             "",
             None,
+            None,
         );
 
         err.buffer(&mut self.errors_buffer);
@@ -1236,6 +1273,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             &mut err,
             "",
             None,
+            None,
         );
 
         let within = if borrow_spans.for_generator() { " by generator" } else { "" };
@@ -1322,18 +1360,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let return_ty = tcx.erase_regions(return_ty);
 
             // to avoid panics
-            if !return_ty.has_infer_types() {
-                if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
-                    if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
-                    {
-                        if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
-                            err.span_suggestion_hidden(
-                                return_span,
-                                "use `.collect()` to allocate the iterator",
-                                format!("{}{}", snippet, ".collect::<Vec<_>>()"),
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
+            if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
+                if self
+                    .infcx
+                    .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env)
+                    .must_apply_modulo_regions()
+                {
+                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
+                        err.span_suggestion_hidden(
+                            return_span,
+                            "use `.collect()` to allocate the iterator",
+                            format!("{}{}", snippet, ".collect::<Vec<_>>()"),
+                            Applicability::MaybeIncorrect,
+                        );
                     }
                 }
             }
@@ -1456,7 +1495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err
     }
 
-    fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
+    fn get_moved_indexes(
+        &mut self,
+        location: Location,
+        mpi: MovePathIndex,
+    ) -> (Vec<MoveSite>, Vec<Location>) {
         fn predecessor_locations(
             body: &'a mir::Body<'tcx>,
             location: Location,
@@ -1479,6 +1522,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }));
 
         let mut visited = FxHashSet::default();
+        let mut move_locations = FxHashSet::default();
+        let mut reinits = vec![];
         let mut result = vec![];
 
         'dfs: while let Some((location, is_back_edge)) = stack.pop() {
@@ -1520,6 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             move_paths[path].place
                         );
                         result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
+                        move_locations.insert(location);
 
                         // Strictly speaking, we could continue our DFS here. There may be
                         // other moves that can reach the point of error. But it is kind of
@@ -1556,6 +1602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 },
             );
             if any_match {
+                reinits.push(location);
                 continue 'dfs;
             }
 
@@ -1565,7 +1612,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }));
         }
 
-        result
+        // Check if we can reach these reinits from a move location.
+        let reinits_reachable = reinits
+            .into_iter()
+            .filter(|reinit| {
+                let mut visited = FxHashSet::default();
+                let mut stack = vec![*reinit];
+                while let Some(location) = stack.pop() {
+                    if !visited.insert(location) {
+                        continue;
+                    }
+                    if move_locations.contains(&location) {
+                        return true;
+                    }
+                    stack.extend(predecessor_locations(self.body, location));
+                }
+                false
+            })
+            .collect::<Vec<Location>>();
+        (result, reinits_reachable)
     }
 
     pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
@@ -1614,6 +1679,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             &mut err,
             "",
             None,
+            None,
         );
 
         self.explain_deref_coercion(loan, &mut err);