diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 54bd25d6471..0567bb5a6c9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -775,8 +775,9 @@ pub enum PatKind { #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] #[derive(HashStable_Generic, Encodable, Decodable)] pub enum Mutability { - Mut, + // N.B. Order is deliberate, so that Not < Mut Not, + Mut, } impl Mutability { @@ -787,12 +788,21 @@ impl Mutability { } } + /// Returns `""` (empty string) or `"mut "` depending on the mutability. pub fn prefix_str(&self) -> &'static str { match self { Mutability::Mut => "mut ", Mutability::Not => "", } } + + /// Returns `"&"` or `"&mut "` depending on the mutability. + pub fn ref_prefix_str(&self) -> &'static str { + match self { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + } + } } /// The kind of borrow in an `AddrOf` expression, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5f99d86b4ea..018f606db64 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -571,11 +571,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let moved_place = &self.move_data.move_paths[move_out.path].place; let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); let move_span = move_spans.args_or_use(); - let suggestion = if borrow_level == hir::Mutability::Mut { - "&mut ".to_string() - } else { - "&".to_string() - }; + let suggestion = borrow_level.ref_prefix_str().to_owned(); (move_span.shrink_to_lo(), suggestion) }) .collect(); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7457369aa58..5122f9808ed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -389,13 +389,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // diagnostic: if the span starts with a mutable borrow of // a local variable, then just suggest the user remove it. PlaceRef { local: _, projection: [] } - if { - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - snippet.starts_with("&mut ") - } else { - false - } - } => + if self + .infcx + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map_or(false, |snippet| snippet.starts_with("&mut ")) => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_suggestion( diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 934d1240442..13d7ab372a4 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -19,6 +19,7 @@ use rustc_trait_selection::traits::ObligationCause; use super::method::probe; +use std::cmp::min; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -937,51 +938,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Ok(src) = sm.span_to_snippet(sp) { let derefs = "*".repeat(steps); - if let Some((span, src, applicability)) = match mutbl_b { - hir::Mutability::Mut => { - let new_prefix = "&mut ".to_owned() + &derefs; - match mutbl_a { - hir::Mutability::Mut => { - replace_prefix(&src, "&mut ", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(5); - let sp = sp.with_lo(pos).with_hi(pos); - (sp, derefs, Applicability::MachineApplicable) - }) - } - hir::Mutability::Not => { - replace_prefix(&src, "&", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(1); - let sp = sp.with_lo(pos).with_hi(pos); - ( - sp, - format!("mut {derefs}"), - Applicability::Unspecified, - ) - }) - } - } - } - hir::Mutability::Not => { - let new_prefix = "&".to_owned() + &derefs; - match mutbl_a { - hir::Mutability::Mut => { - replace_prefix(&src, "&mut ", &new_prefix).map(|_| { - let lo = sp.lo() + BytePos(1); - let hi = sp.lo() + BytePos(5); - let sp = sp.with_lo(lo).with_hi(hi); - (sp, derefs, Applicability::MachineApplicable) - }) - } - hir::Mutability::Not => { - replace_prefix(&src, "&", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(1); - let sp = sp.with_lo(pos).with_hi(pos); - (sp, derefs, Applicability::MachineApplicable) - }) - } - } - } - } { + let old_prefix = mutbl_a.ref_prefix_str(); + let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs; + + let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| { + // skip `&` or `&mut ` if both mutabilities are mutable + let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _); + // skip `&` or `&mut ` + let hi = sp.lo() + BytePos(old_prefix.len() as _); + let sp = sp.with_lo(lo).with_hi(hi); + + ( + sp, + format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }), + if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect } + ) + }); + + if let Some((span, src, applicability)) = suggestion { return Some(( span, "consider dereferencing".to_string(), @@ -1005,10 +979,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the expression has `&`, removing it would fix the error prefix_span = prefix_span.with_hi(inner.span.lo()); expr = inner; - remove += match mutbl { - hir::Mutability::Not => "&", - hir::Mutability::Mut => "&mut ", - }; + remove.push_str(mutbl.ref_prefix_str()); steps -= 1; } else { break; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b5aa8cd6e7c..1780226b8e0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -345,8 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if annotation { let suggest_annotation = match expr.peel_drop_temps().kind { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&", - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ", + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, _) => mutbl.ref_prefix_str(), _ => return true, }; let mut tuple_indexes = Vec::new(); diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 89746ce54a6..dea14dd93d6 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -5,7 +5,6 @@ use crate::{ use hir::def_id::DefId; use hir::HirId; use hir::ItemKind; -use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -88,14 +87,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { - Some(probe::AutorefOrPtrAdjustment::Autoref { - mutbl: Mutability::Mut, - .. - }) => "&mut ", - Some(probe::AutorefOrPtrAdjustment::Autoref { - mutbl: Mutability::Not, - .. - }) => "&", + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => { + mutbl.ref_prefix_str() + } Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", }; if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) @@ -386,8 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { - Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ", - Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&", + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(), Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d0ea2b0e664..09101558995 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1147,19 +1147,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && assoc.kind == ty::AssocKind::Fn { let sig = self.tcx.fn_sig(assoc.def_id); - if let Some(first) = sig.inputs().skip_binder().get(0) { - if first.peel_refs() == rcvr_ty.peel_refs() { - None - } else { - Some(if first.is_region_ptr() { - if first.is_mutable_ptr() { "&mut " } else { "&" } - } else { - "" - }) - } - } else { + sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() { None - } + } else { + Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) + }) } else { None }; @@ -2625,11 +2617,7 @@ fn print_disambiguation_help<'tcx>( let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) { let args = format!( "({}{})", - if rcvr_ty.is_region_ptr() { - if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" } - } else { - "" - }, + rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()), std::iter::once(receiver) .chain(args.iter()) .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 7b3178e610f..31235ce1918 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -15,7 +15,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef}; @@ -508,10 +508,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { [ .., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ }, - ] => match mut_ { - AutoBorrowMutability::Mut { .. } => "&mut ", - AutoBorrowMutability::Not => "&", - }, + ] => hir::Mutability::from(*mut_).ref_prefix_str(), _ => "", };