]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Rollup merge of #106157 - LeSeulArtichaut:106126-thir-unsafeck-good-path-bug-2, r...
[rust.git] / compiler / rustc_borrowck / src / diagnostics / mutability_errors.rs
index 3319a80681fde277dc0fd3f361c2656adfafe6b6..6f6d1b01bd4294a7f95195f858e0266a8a6f9c45 100644 (file)
@@ -180,6 +180,9 @@ pub(crate) fn report_mutability_error(
         // the verbs used in some diagnostic messages.
         let act;
         let acted_on;
+        let mut suggest = true;
+        let mut mut_error = None;
+        let mut count = 1;
 
         let span = match error_access {
             AccessKind::Mutate => {
@@ -194,15 +197,50 @@ pub(crate) fn report_mutability_error(
 
                 let borrow_spans = self.borrow_spans(span, location);
                 let borrow_span = borrow_spans.args_or_use();
-                err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
-                borrow_spans.var_span_label(
-                    &mut err,
-                    format!(
-                        "mutable borrow occurs due to use of {} in closure",
-                        self.describe_any_place(access_place.as_ref()),
-                    ),
-                    "mutable",
-                );
+                match the_place_err {
+                    PlaceRef { local, projection: [] }
+                        if self.body.local_decls[local].can_be_made_mutable() =>
+                    {
+                        let span = self.body.local_decls[local].source_info.span;
+                        mut_error = Some(span);
+                        if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+                            // We've encountered a second (or more) attempt to mutably borrow an
+                            // immutable binding, so the likely problem is with the binding
+                            // declaration, not the use. We collect these in a single diagnostic
+                            // and make the binding the primary span of the error.
+                            err = buffer;
+                            count = c + 1;
+                            if count == 2 {
+                                err.replace_span_with(span, false);
+                                err.span_label(span, "not mutable");
+                            }
+                            suggest = false;
+                        } else {
+                            err = self.cannot_borrow_path_as_mutable_because(
+                                borrow_span,
+                                &item_msg,
+                                &reason,
+                            );
+                        }
+                    }
+                    _ => {
+                        err = self.cannot_borrow_path_as_mutable_because(
+                            borrow_span,
+                            &item_msg,
+                            &reason,
+                        );
+                    }
+                }
+                if suggest {
+                    borrow_spans.var_span_label(
+                        &mut err,
+                        format!(
+                            "mutable borrow occurs due to use of {} in closure",
+                            self.describe_any_place(access_place.as_ref()),
+                        ),
+                        "mutable",
+                    );
+                }
                 borrow_span
             }
         };
@@ -276,7 +314,9 @@ pub(crate) fn report_mutability_error(
                                 pat_span: _,
                             },
                         )))) => {
-                            err.span_note(sp, "the binding is already a mutable borrow");
+                            if suggest {
+                                err.span_note(sp, "the binding is already a mutable borrow");
+                            }
                         }
                         _ => {
                             err.span_note(
@@ -333,16 +373,20 @@ pub(crate) fn report_mutability_error(
                 let local_decl = &self.body.local_decls[local];
                 assert_eq!(local_decl.mutability, Mutability::Not);
 
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.span_suggestion(
-                    local_decl.source_info.span,
-                    "consider changing this to be mutable",
-                    format!("mut {}", self.local_names[local].unwrap()),
-                    Applicability::MachineApplicable,
-                );
-                let tcx = self.infcx.tcx;
-                if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
-                    self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+                if count < 10 {
+                    err.span_label(span, format!("cannot {act}"));
+                }
+                if suggest {
+                    err.span_suggestion_verbose(
+                        local_decl.source_info.span.shrink_to_lo(),
+                        "consider changing this to be mutable",
+                        "mut ".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                    let tcx = self.infcx.tcx;
+                    if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+                        self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+                    }
                 }
             }
 
@@ -357,7 +401,7 @@ pub(crate) fn report_mutability_error(
 
                 let captured_place = &self.upvars[upvar_index.index()].place;
 
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
 
                 let upvar_hir_id = captured_place.get_root_variable();
 
@@ -397,7 +441,7 @@ pub(crate) fn report_mutability_error(
                     .span_to_snippet(span)
                     .map_or(false, |snippet| snippet.starts_with("&mut ")) =>
             {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
                 err.span_suggestion(
                     span,
                     "try removing `&mut` here",
@@ -409,7 +453,7 @@ pub(crate) fn report_mutability_error(
             PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[local].is_ref_for_guard() =>
             {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
                 err.note(
                     "variables bound in patterns are immutable until the end of the pattern guard",
                 );
@@ -537,7 +581,7 @@ pub(crate) fn report_mutability_error(
                             Some((true, err_help_span, suggested_code)) => {
                                 let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
                                 if !is_trait_sig {
-                                    err.span_suggestion(
+                                    err.span_suggestion_verbose(
                                         err_help_span,
                                         &format!(
                                             "consider changing this to be a mutable {pointer_desc}"
@@ -546,7 +590,7 @@ pub(crate) fn report_mutability_error(
                                         Applicability::MachineApplicable,
                                     );
                                 } else if let Some(x) = local_trait {
-                                    err.span_suggestion(
+                                    err.span_suggestion_verbose(
                                         x,
                                         &format!(
                                             "consider changing that to be a mutable {pointer_desc}"
@@ -569,24 +613,15 @@ pub(crate) fn report_mutability_error(
                         err.span_label(
                             span,
                             format!(
-                                "`{NAME}` is a `{SIGIL}` {DESC}, \
-                                so the data it refers to cannot be {ACTED_ON}",
-                                NAME = name,
-                                SIGIL = pointer_sigil,
-                                DESC = pointer_desc,
-                                ACTED_ON = acted_on
+                                "`{name}` is a `{pointer_sigil}` {pointer_desc}, \
+                                 so the data it refers to cannot be {acted_on}",
                             ),
                         );
                     }
                     _ => {
                         err.span_label(
                             span,
-                            format!(
-                                "cannot {ACT} through `{SIGIL}` {DESC}",
-                                ACT = act,
-                                SIGIL = pointer_sigil,
-                                DESC = pointer_desc
-                            ),
+                            format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"),
                         );
                     }
                 }
@@ -605,13 +640,13 @@ pub(crate) fn report_mutability_error(
                     Some(BorrowedContentSource::OverloadedDeref(ty)) => {
                         err.help(&format!(
                             "trait `DerefMut` is required to modify through a dereference, \
-                                but it is not implemented for `{ty}`",
+                             but it is not implemented for `{ty}`",
                         ));
                     }
                     Some(BorrowedContentSource::OverloadedIndex(ty)) => {
                         err.help(&format!(
                             "trait `IndexMut` is required to modify indexed content, \
-                                but it is not implemented for `{ty}`",
+                             but it is not implemented for `{ty}`",
                         ));
                         self.suggest_map_index_mut_alternatives(ty, &mut err, span);
                     }
@@ -620,11 +655,15 @@ pub(crate) fn report_mutability_error(
             }
 
             _ => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
             }
         }
 
-        self.buffer_error(err);
+        if let Some(span) = mut_error {
+            self.buffer_mut_error(span, err, count);
+        } else {
+            self.buffer_error(err);
+        }
     }
 
     fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
@@ -1209,7 +1248,7 @@ fn get_mut_span_in_struct_field<'tcx>(
         // Now we're dealing with the actual struct that we're going to suggest a change to,
         // we can expect a field that is an immutable reference to a type.
         && let hir::Node::Field(field) = node
-        && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
+        && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
     {
         return Some(lt.ident.span.between(ty.span));
     }