From 639f4d999787bcd7331ea23c8c4a0e5535eaeac7 Mon Sep 17 00:00:00 2001 From: AndyJado <101876416+AndyJado@users.noreply.github.com> Date: Thu, 25 May 2023 13:05:02 +0800 Subject: [PATCH] E0596 & E0594 diagnose migration --- compiler/rustc_borrowck/messages.ftl | 106 +++++++- .../rustc_borrowck/src/borrowck_errors.rs | 157 +++++++++++- .../rustc_borrowck/src/diagnostics/mod.rs | 16 +- .../src/diagnostics/mutability_errors.rs | 153 ++++++------ .../rustc_borrowck/src/session_diagnostics.rs | 228 +++++++++++++++++- 5 files changed, 566 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index dbe8c32978261..afe3f2806dbfe 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -382,8 +382,11 @@ borrowck_require_mutable_binding = *[mutation] possible mutation of `{$upvar}` } -borrowck_cannot_act = - cannot {$act} +borrowck_cannot_assign = + cannot assign + +borrowck_cannot_borrow_mut = + cannot borrow as mutable borrowck_expects_fnmut_not_fn = change this to accept `FnMut` instead of `Fn` @@ -582,3 +585,102 @@ borrowck_cannot_reassign_immutable_arg = borrowck_cannot_reassign_immutable_var = cannot assign twice to immutable variable {$place} + +borrowck_modify_ty_methods_help = + to modify a `{$ty}`, use `.get_mut()`, `.insert()` or the entry API + +borrowck_upvar_need_mut_due_to_borrow = + calling `{$place}` requires mutable binding due to mutable borrow of `{$upvar}` + +borrowck_upvar_need_mut_due_to_mutation = + calling `{$place}` requires mutable binding due to possible mutation of `{$upvar}` + +borrowck_mut_borrow_place_declared_immute = + cannot borrow {$any_place} as mutable, as it is not declared as mutable + +borrowck_mut_borrow_symbol_declared_immute = + cannot borrow {$any_place} as mutable, as `{$name}` is not declared as mutable + +borrowck_mut_borrow_place_in_pattern_guard_immute = + cannot borrow {$path} as mutable, as it is immutable for the pattern guard + +borrowck_mut_borrow_place_static = + cannot borrow immutable static item {$path} as mutable + +borrowck_mut_borrow_symbol_static = + cannot borrow {$path} as mutable, as `{$static_name}` is an immutable static item + +borrowck_mut_borrow_self_in_fn = + cannot borrow {$path} as mutable, as it is a captured variable in a `Fn` closure + +borrowck_mut_borrow_upvar_in_fn = + cannot borrow {$path} as mutable, as `Fn` closures cannot mutate their captured variables + +borrowck_mut_borrow_self_behind_const_pointer = + cannot borrow {$place} as mutable, as it is behind a `*const` pointer + +borrowck_mut_borrow_self_behind_ref = + cannot borrow {$place} as mutable, as it is behind a `&` reference + +borrowck_mut_borrow_self_behind_deref = + cannot borrow {$place} as mutable, as it is behind {$name} + +borrowck_mut_borrow_self_behind_index = + cannot borrow {$place} as mutable, as it is behind an index of {$name} + +borrowck_mut_borrow_data_behind_const_pointer = + cannot borrow data in a `*const` pointer as mutable + +borrowck_mut_borrow_data_behind_ref = + cannot borrow data in a `&` reference as mutable + +borrowck_mut_borrow_data_behind_deref = + cannot borrow data in {$name} as mutable + +borrowck_mut_borrow_data_behind_index = + cannot borrow data in an index of {$name} as mutable + +borrowck_assign_place_declared_immute = + cannot assign to {$any_place}, as it is not declared as mutable + +borrowck_assign_symbol_declared_immute = + cannot assign to {$any_place}, as `{$name}` is not declared as mutable + +borrowck_assign_place_in_pattern_guard_immute = + cannot assign to {$path}, as it is immutable for the pattern guard + +borrowck_assign_place_static = + cannot assign to immutable static item {$path} + +borrowck_assign_symbol_static = + cannot assign to {$path}, as `{$static_name}` is an immutable static item + +borrowck_assign_place_in_fn = + cannot assign to {$path}, as it is a captured variable in a `Fn` closure + +borrowck_assign_upvar_in_fn = + cannot assign to {$path}, as `Fn` closures cannot mutate their captured variables + +borrowck_assign_place_behind_const_pointer = + cannot assign to {$place}, which is behind a `*const` pointer + +borrowck_assign_place_behind_ref = + cannot assign to {$place}, which is behind a `&` reference + +borrowck_assign_place_behind_deref = + cannot assign to {$place}, which is behind {$name} + +borrowck_assign_place_behind_index = + cannot assign to {$place}, which is behind an index of {$ty} + +borrowck_assign_data_behind_const_pointer = + cannot assign to data in a `*const` pointer + +borrowck_assign_data_behind_ref = + cannot assign to data in a `&` reference + +borrowck_assign_data_behind_deref = + cannot assign to data in {$name} + +borrowck_assign_data_behind_index = + cannot assign to data in an index of {$name} diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 1501ef996be63..9f251c4f6f4ef 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,12 +1,18 @@ +// #![deny(rustc::untranslatable_diagnostic)] +// #![deny(rustc::diagnostic_outside_of_impl)] + use rustc_errors::{ struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan, }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; -use crate::session_diagnostics::{ - AssignBorrowErr, BorrowAcrossDestructor, BorrowAcrossGeneratorYield, InteriorDropMoveErr, - PathShortLive, UseMutBorrowErr, +use crate::{ + diagnostics::PlaceAndReason, + session_diagnostics::{ + AssignBorrowErr, AssignErr, BorrowAcrossDestructor, BorrowAcrossGeneratorYield, + InteriorDropMoveErr, MutBorrowErr, PathShortLive, UseMutBorrowErr, + }, }; impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { @@ -215,9 +221,77 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { pub(crate) fn cannot_assign( &self, span: Span, - desc: &str, + path_and_reason: PlaceAndReason<'_>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!(self, span, E0594, "cannot assign to {}", desc) + let diag = match path_and_reason { + PlaceAndReason::DeclaredImmute(place, name) => { + if let Some(name) = name { + AssignErr::SymbolDeclaredImmute { span, any_place: place, name } + } else { + AssignErr::PlaceDeclaredImmute { span, any_place: place } + } + } + PlaceAndReason::InPatternGuard(place) => { + AssignErr::PatternGuardImmute { span, path: place } + } + PlaceAndReason::StaticItem(place, name) => { + if let Some(name) = name { + AssignErr::SymbolStatic { span, path: place, static_name: name } + } else { + AssignErr::PlaceStatic { span, path: place } + } + } + PlaceAndReason::UpvarCaptured(place) => AssignErr::UpvarInFn { span, path: place }, + PlaceAndReason::SelfCaptured(place) => AssignErr::CapturedInFn { span, path: place }, + PlaceAndReason::BehindPointer(place, pointer_ty, name) => { + if let Some(place) = place { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + AssignErr::PlaceBehindRawPointer { span, place } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + AssignErr::PlaceBehindSharedRef { span, place } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + AssignErr::PlaceBehindDeref { + span, + place, + name: name.unwrap_or_default(), + } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + AssignErr::PlaceBehindIndex { + span, + place, + name: name.unwrap_or_default(), + } + } + } + } else { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + AssignErr::DataBehindRawPointer { span } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + AssignErr::DataBehindSharedRef { span } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + AssignErr::DataBehindDeref { span, name: name.unwrap_or_default() } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + AssignErr::DataBehindIndex { span, name: name.unwrap_or_default() } + } + } + } + } + }; + self.infcx.tcx.sess.create_err(diag) } pub(crate) fn cannot_move_out_of( @@ -285,10 +359,77 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { pub(crate) fn cannot_borrow_path_as_mutable_because( &self, span: Span, - path: &str, - reason: &str, + path_and_reason: PlaceAndReason<'_>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) + let diag = match path_and_reason { + PlaceAndReason::DeclaredImmute(place, name) => { + if let Some(name) = name { + MutBorrowErr::SymbolDeclaredImmute { span, any_place: place, name } + } else { + MutBorrowErr::PlaceDeclaredImmute { span, any_place: place } + } + } + PlaceAndReason::InPatternGuard(place) => { + MutBorrowErr::PatternGuardImmute { span, path: place } + } + PlaceAndReason::StaticItem(place, name) => { + if let Some(name) = name { + MutBorrowErr::SymbolStatic { span, path: place, static_name: name } + } else { + MutBorrowErr::PlaceStatic { span, path: place } + } + } + PlaceAndReason::UpvarCaptured(place) => MutBorrowErr::UpvarInFn { span, path: place }, + PlaceAndReason::SelfCaptured(place) => MutBorrowErr::CapturedInFn { span, path: place }, + PlaceAndReason::BehindPointer(place, pointer_ty, name) => { + if let Some(place) = place { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + MutBorrowErr::SelfBehindRawPointer { span, place } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + MutBorrowErr::SelfBehindSharedRef { span, place } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + MutBorrowErr::SelfBehindDeref { + span, + place, + name: name.unwrap_or_default(), + } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + MutBorrowErr::SelfBehindIndex { + span, + place, + name: name.unwrap_or_default(), + } + } + } + } else { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + MutBorrowErr::DataBehindRawPointer { span } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + MutBorrowErr::DataBehindSharedRef { span } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + MutBorrowErr::DataBehindDeref { span, name: name.unwrap_or_default() } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + MutBorrowErr::DataBehindIndex { span, name: name.unwrap_or_default() } + } + } + } + } + }; + self.infcx.tcx.sess.create_err(diag) } pub(crate) fn cannot_mutate_in_immutable_section( diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index c3cf7db32b149..5e6212fdd0eb9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -46,7 +46,7 @@ mod mutability_errors; mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; -pub(crate) use mutability_errors::AccessKind; +pub(crate) use mutability_errors::{AccessKind, PlaceAndReason}; pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder; pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; pub(crate) use region_name::{RegionName, RegionNameSource}; @@ -678,6 +678,7 @@ impl UseSpans<'_> { } } +#[derive(Clone, Copy, Debug)] pub(super) enum BorrowedContentSource<'tcx> { DerefRawPointer, DerefMutableRef, @@ -715,21 +716,22 @@ impl<'tcx> BorrowedContentSource<'tcx> { } } - pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String { + // ready to remove + pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> Option { match *self { - BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(), - BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(), + BorrowedContentSource::DerefRawPointer => None, + BorrowedContentSource::DerefSharedRef => None, BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } BorrowedContentSource::OverloadedDeref(ty) => ty .ty_adt_def() .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? { - name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")), + name @ (sym::Rc | sym::Arc) => Some(Some(format!("an `{name}`"))), _ => None, }) - .unwrap_or_else(|| format!("dereference of `{ty}`")), - BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"), + .unwrap_or_else(|| Some(format!("dereference of `{ty}`"))), + BorrowedContentSource::OverloadedIndex(ty) => Some(format!("`{ty}`")), } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8664f3c07dc7f..d8001c8199502 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,6 +1,5 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use hir::ExprKind; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; @@ -17,7 +16,7 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::diagnostics::BorrowedContentSource; -use crate::session_diagnostics::FnMutBumpFn; +use crate::session_diagnostics::{BorrowMutUpvarLable, FnMutBumpFn, OnModifyTy}; use crate::util::FindAssignments; use crate::MirBorrowckCtxt; @@ -27,6 +26,22 @@ pub(crate) enum AccessKind { Mutate, } +#[derive(Debug)] +pub(crate) enum PlaceAndReason<'a> { + // place, name + DeclaredImmute(String, Option), + // place + InPatternGuard(String), + // place, name + StaticItem(String, Option), + // place + UpvarCaptured(String), + // place + SelfCaptured(String), + // place, pointer_type, name + BehindPointer(Option, BorrowedContentSource<'a>, Option), +} + impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub(crate) fn report_mutability_error( &mut self, @@ -45,7 +60,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut err; let item_msg; - let reason; + let diagnosing: PlaceAndReason<'_>; let mut opt_source = None; let access_place_desc = self.describe_any_place(access_place.as_ref()); debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); @@ -53,12 +68,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match the_place_err { PlaceRef { local, projection: [] } => { item_msg = access_place_desc; - if access_place.as_local().is_some() { - reason = ", as it is not declared as mutable".to_string(); + diagnosing = if access_place.as_local().is_some() { + PlaceAndReason::DeclaredImmute(item_msg.clone(), None) } else { let name = self.local_names[local].expect("immutable unnamed local"); - reason = format!(", as `{name}` is not declared as mutable"); - } + PlaceAndReason::DeclaredImmute(item_msg.clone(), Some(name.to_string())) + }; } PlaceRef { @@ -86,11 +101,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { return; } else { item_msg = access_place_desc; - if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - reason = ", as it is not declared as mutable".to_string(); + diagnosing = if self.is_upvar_field_projection(access_place.as_ref()).is_some() + { + PlaceAndReason::DeclaredImmute(item_msg.clone(), None) } else { let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx); - reason = format!(", as `{name}` is not declared as mutable"); + PlaceAndReason::DeclaredImmute(item_msg.clone(), Some(name)) } } } @@ -99,20 +115,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.body.local_decls[local].is_ref_for_guard() => { item_msg = access_place_desc; - reason = ", as it is immutable for the pattern guard".to_string(); + diagnosing = PlaceAndReason::InPatternGuard(item_msg.clone()) } PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_to_static() => { - if access_place.projection.len() == 1 { - item_msg = format!("immutable static item {access_place_desc}"); - reason = String::new(); + diagnosing = if access_place.projection.len() == 1 { + PlaceAndReason::StaticItem(access_place_desc.clone(), None) } else { item_msg = access_place_desc; let local_info = self.body.local_decls[local].local_info(); if let LocalInfo::StaticRef { def_id, .. } = *local_info { let static_name = &self.infcx.tcx.item_name(def_id); - reason = format!(", as `{static_name}` is an immutable static item"); + PlaceAndReason::StaticItem(item_msg.clone(), Some(static_name.to_string())) } else { bug!("is_ref_to_static return true, but not ref to static?"); } @@ -129,30 +144,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { the_place_err.ty(self.body, self.infcx.tcx).ty )); - reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - ", as it is a captured variable in a `Fn` closure".to_string() + diagnosing = if self.is_upvar_field_projection(access_place.as_ref()).is_some() + { + PlaceAndReason::SelfCaptured(item_msg.clone()) } else { - ", as `Fn` closures cannot mutate their captured variables".to_string() + PlaceAndReason::UpvarCaptured(item_msg.clone()) } } else { let source = self.borrowed_content_source(PlaceRef { local: the_place_err.local, projection: proj_base, }); - let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); - opt_source = Some(source); - if let Some(desc) = self.describe_place(access_place.as_ref()) { + let diag_msg = source.describe_for_immutable_place(self.infcx.tcx); + diagnosing = if let Some(desc) = self.describe_place(access_place.as_ref()) { item_msg = format!("`{desc}`"); - reason = match error_access { - AccessKind::Mutate => format!(", which is behind {pointer_type}"), - AccessKind::MutableBorrow => { - format!(", as it is behind {pointer_type}") - } - } + PlaceAndReason::BehindPointer(Some(item_msg.clone()), source, diag_msg) } else { - item_msg = format!("data in {pointer_type}"); - reason = String::new(); - } + PlaceAndReason::BehindPointer(None, source, diag_msg) + }; + + opt_source = Some(source); } } @@ -171,7 +182,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } => bug!("Unexpected immutable place."), } - debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason); + debug!( + "report_mutability_error: item_msg and reason is moved to a struct due to diagnosing migration: {:?}", + &diagnosing + ); // `act` and `acted_on` are strings that let us abstract over // the verbs used in some diagnostic messages. @@ -181,9 +195,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut mut_error = None; let mut count = 1; + let cant_access_here = |sp: Span| match error_access { + AccessKind::MutableBorrow => FnMutBumpFn::CannotBorrowMut { sp }, + AccessKind::Mutate => FnMutBumpFn::CannotAssign { sp }, + }; let span = match error_access { + // cannot assign only happen in Mutate AccessKind::Mutate => { - err = self.cannot_assign(span, &(item_msg + &reason)); + err = self.cannot_assign(span, diagnosing); act = "assign"; acted_on = "written"; span @@ -213,19 +232,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } 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, diagnosing); } } _ => { - err = self.cannot_borrow_path_as_mutable_because( - borrow_span, - &item_msg, - &reason, - ); + err = self.cannot_borrow_path_as_mutable_because(borrow_span, diagnosing); } } if suggest { @@ -265,7 +277,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ProjectionElem::Deref, ], } => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx); if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) { @@ -287,7 +299,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) => { let decl = &self.body.local_decls[local]; - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); if let Some(mir::Statement { source_info, kind: @@ -372,7 +384,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { assert_eq!(local_decl.mutability, Mutability::Not); if count < 10 { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); } if suggest { self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local); @@ -394,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let captured_place = &self.upvars[upvar_index.index()].place; - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); let upvar_hir_id = captured_place.get_root_variable(); @@ -450,7 +462,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .span_to_snippet(span) .is_ok_and(|snippet| snippet.starts_with("&mut ")) => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); err.span_suggestion( span, "try removing `&mut` here", @@ -462,7 +474,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_for_guard() => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); err.note( "variables bound in patterns are immutable until the end of the pattern guard", ); @@ -506,11 +518,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() => { - self.expected_fn_found_fn_mut_call(&mut err, span, act); + err.subdiagnostic(cant_access_here(span)); + self.expected_fn_found_fn_mut_call(&mut err); } PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); match opt_source { Some(BorrowedContentSource::OverloadedDeref(ty)) => { @@ -531,7 +544,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } _ => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(cant_access_here(span)); } } @@ -650,9 +663,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut v = V { assign_span: span, err, ty, suggested: false }; v.visit_body(body); if !v.suggested { - err.help(format!( - "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API", - )); + err.subdiagnostic(OnModifyTy { ty }); } } } @@ -798,7 +809,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { let tables = tcx.typeck(closure_local_def_id); if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) { - let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { + if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); let root_hir_id = upvar_id.var_path.hir_id; // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here @@ -810,7 +821,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .iter() .map(|proj| proj.kind) .collect::>(); - let mut capture_reason = String::new(); for captured_place in captured_places { let captured_place_kinds = captured_place .place @@ -822,35 +832,34 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &captured_place_kinds, &origin_projection, ) { + let place = self.describe_place(the_place_err).unwrap(); match captured_place.info.capture_kind { ty::UpvarCapture::ByRef( ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, ) => { - capture_reason = format!("mutable borrow of `{upvar}`"); + err.subdiagnostic(BorrowMutUpvarLable::MutBorrow { + span: *span, + upvar, + place, + }); } ty::UpvarCapture::ByValue => { - capture_reason = format!("possible mutation of `{upvar}`"); + err.subdiagnostic(BorrowMutUpvarLable::Mutation { + span: *span, + upvar, + place, + }); } _ => bug!("upvar `{upvar}` borrowed, but not mutably"), } break; + } else { + bug!("upvar `{upvar}` borrowed, but cannot find reason"); } } - if capture_reason.is_empty() { - bug!("upvar `{upvar}` borrowed, but cannot find reason"); - } - capture_reason } else { bug!("not an upvar") }; - err.span_label( - *span, - format!( - "calling `{}` requires mutable binding due to {}", - self.describe_place(the_place_err).unwrap(), - reason - ), - ); } } @@ -941,9 +950,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. - fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) { - err.subdiagnostic(FnMutBumpFn::Cannot { act, sp }); - + fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic) { let hir = self.infcx.tcx.hir(); let closure_id = self.mir_hir_id(); let closure_span = self.infcx.tcx.def_span(self.mir_def_id()); diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index db8889d07e99e..e2e1ed73936fa 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -483,10 +483,14 @@ pub(crate) enum OnLifetimeBound<'a> { } #[derive(Subdiagnostic)] -pub(crate) enum FnMutBumpFn<'a> { - #[label(borrowck_cannot_act)] - Cannot { - act: &'a str, +pub(crate) enum FnMutBumpFn { + #[label(borrowck_cannot_assign)] + CannotAssign { + #[primary_span] + sp: Span, + }, + #[label(borrowck_cannot_borrow_mut)] + CannotBorrowMut { #[primary_span] sp: Span, }, @@ -836,3 +840,219 @@ pub(crate) enum ReassignImmut<'a> { place: &'a str, }, } + +#[derive(Subdiagnostic)] +#[help(borrowck_modify_ty_methods_help)] +pub(crate) struct OnModifyTy<'tcx> { + pub ty: Ty<'tcx>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum BorrowMutUpvarLable { + #[label(borrowck_upvar_need_mut_due_to_borrow)] + MutBorrow { + #[primary_span] + span: Span, + upvar: String, + place: String, + }, + #[label(borrowck_upvar_need_mut_due_to_mutation)] + Mutation { + #[primary_span] + span: Span, + upvar: String, + place: String, + }, +} + +#[derive(Diagnostic)] +pub(crate) enum MutBorrowErr { + #[diag(borrowck_mut_borrow_place_declared_immute, code = "E0596")] + PlaceDeclaredImmute { + #[primary_span] + span: Span, + any_place: String, + }, + #[diag(borrowck_mut_borrow_symbol_declared_immute, code = "E0596")] + SymbolDeclaredImmute { + #[primary_span] + span: Span, + any_place: String, + name: String, + }, + #[diag(borrowck_mut_borrow_place_in_pattern_guard_immute, code = "E0596")] + PatternGuardImmute { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_mut_borrow_symbol_static, code = "E0596")] + SymbolStatic { + #[primary_span] + span: Span, + path: String, + static_name: String, + }, + #[diag(borrowck_mut_borrow_place_static, code = "E0596")] + PlaceStatic { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_mut_borrow_self_in_fn, code = "E0596")] + CapturedInFn { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_mut_borrow_upvar_in_fn, code = "E0596")] + UpvarInFn { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_mut_borrow_self_behind_const_pointer, code = "E0596")] + SelfBehindRawPointer { + #[primary_span] + span: Span, + place: String, + }, + #[diag(borrowck_mut_borrow_self_behind_ref, code = "E0596")] + SelfBehindSharedRef { + #[primary_span] + span: Span, + place: String, + }, + #[diag(borrowck_mut_borrow_self_behind_deref, code = "E0596")] + SelfBehindDeref { + #[primary_span] + span: Span, + place: String, + name: String, + }, + #[diag(borrowck_mut_borrow_self_behind_index, code = "E0596")] + SelfBehindIndex { + #[primary_span] + span: Span, + place: String, + name: String, + }, + #[diag(borrowck_mut_borrow_data_behind_const_pointer, code = "E0596")] + DataBehindRawPointer { + #[primary_span] + span: Span, + }, + #[diag(borrowck_mut_borrow_data_behind_ref, code = "E0596")] + DataBehindSharedRef { + #[primary_span] + span: Span, + }, + #[diag(borrowck_mut_borrow_data_behind_deref, code = "E0596")] + DataBehindDeref { + #[primary_span] + span: Span, + name: String, + }, + #[diag(borrowck_mut_borrow_data_behind_index, code = "E0596")] + DataBehindIndex { + #[primary_span] + span: Span, + name: String, + }, +} + +#[derive(Diagnostic)] +pub(crate) enum AssignErr { + #[diag(borrowck_assign_place_declared_immute, code = "E0594")] + PlaceDeclaredImmute { + #[primary_span] + span: Span, + any_place: String, + }, + #[diag(borrowck_assign_symbol_declared_immute, code = "E0594")] + SymbolDeclaredImmute { + #[primary_span] + span: Span, + any_place: String, + name: String, + }, + #[diag(borrowck_assign_place_in_pattern_guard_immute, code = "E0594")] + PatternGuardImmute { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_assign_symbol_static, code = "E0594")] + SymbolStatic { + #[primary_span] + span: Span, + path: String, + static_name: String, + }, + #[diag(borrowck_assign_place_static, code = "E0594")] + PlaceStatic { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_assign_place_in_fn, code = "E0594")] + CapturedInFn { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_assign_upvar_in_fn, code = "E0594")] + UpvarInFn { + #[primary_span] + span: Span, + path: String, + }, + #[diag(borrowck_assign_place_behind_const_pointer, code = "E0594")] + PlaceBehindRawPointer { + #[primary_span] + span: Span, + place: String, + }, + #[diag(borrowck_assign_place_behind_ref, code = "E0594")] + PlaceBehindSharedRef { + #[primary_span] + span: Span, + place: String, + }, + #[diag(borrowck_assign_place_behind_deref, code = "E0594")] + PlaceBehindDeref { + #[primary_span] + span: Span, + place: String, + name: String, + }, + #[diag(borrowck_assign_place_behind_index, code = "E0594")] + PlaceBehindIndex { + #[primary_span] + span: Span, + place: String, + name: String, + }, + #[diag(borrowck_assign_data_behind_const_pointer, code = "E0594")] + DataBehindRawPointer { + #[primary_span] + span: Span, + }, + #[diag(borrowck_assign_data_behind_ref, code = "E0594")] + DataBehindSharedRef { + #[primary_span] + span: Span, + }, + #[diag(borrowck_assign_data_behind_deref, code = "E0594")] + DataBehindDeref { + #[primary_span] + span: Span, + name: String, + }, + #[diag(borrowck_assign_data_behind_index, code = "E0594")] + DataBehindIndex { + #[primary_span] + span: Span, + name: String, + }, +}