use rustc_hir as hir;
use rustc_hir::Node;
-use rustc_index::vec::Idx;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
- mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
+ mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
- let name = self.upvars[upvar_index.index()].name;
+ let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx);
reason = format!(", as `{}` is not declared as mutable", name);
}
}
}
}
PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
- if the_place_err.local == Local::new(1)
+ if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
item_msg = format!("`{}`", access_place_desc.unwrap());
- debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+ debug_assert!(
+ self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
+ );
debug_assert!(is_closure_or_generator(
Place::ty_from(
the_place_err.local,
"mutable borrow occurs due to use of {} in closure",
self.describe_any_place(access_place.as_ref()),
),
+ "mutable",
);
borrow_span
}
match label {
Some((true, err_help_span, suggested_code)) => {
- err.span_suggestion(
- err_help_span,
- &format!(
- "consider changing this to be a mutable {}",
- pointer_desc
- ),
- suggested_code,
- Applicability::MachineApplicable,
- );
+ let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
+ if !is_trait_sig {
+ err.span_suggestion(
+ err_help_span,
+ &format!(
+ "consider changing this to be a mutable {}",
+ pointer_desc
+ ),
+ suggested_code,
+ Applicability::MachineApplicable,
+ );
+ } else if let Some(x) = local_trait {
+ err.span_suggestion(
+ x,
+ &format!(
+ "consider changing that to be a mutable {}",
+ pointer_desc
+ ),
+ suggested_code,
+ Applicability::MachineApplicable,
+ );
+ }
}
Some((false, err_label_span, message)) => {
err.span_label(err_label_span, &message);
}
}
- PlaceRef {
- local,
- projection: [ProjectionElem::Deref],
- // FIXME document what is this 1 magic number about
- } if local == Local::new(1) && !self.upvars.is_empty() => {
+ 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.buffer(&mut self.errors_buffer);
}
+ /// User cannot make signature of a trait mutable without changing the
+ /// trait. So we find if this error belongs to a trait and if so we move
+ /// suggestion to the trait or disable it if it is out of scope of this crate
+ fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
+ if self.body.local_kind(local) != LocalKind::Arg {
+ return (false, None);
+ }
+ let hir_map = self.infcx.tcx.hir();
+ let my_def = self.body.source.def_id();
+ let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap());
+ let td = if let Some(a) =
+ self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
+ {
+ a
+ } else {
+ return (false, None);
+ };
+ (
+ true,
+ td.as_local().and_then(|tld| {
+ let h = hir_map.local_def_id_to_hir_id(tld);
+ match hir_map.find(h) {
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(_, _, _, _, items),
+ ..
+ })) => {
+ let mut f_in_trait_opt = None;
+ for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
+ let hi = fi.hir_id();
+ if !matches!(k, hir::AssocItemKind::Fn { .. }) {
+ continue;
+ }
+ if hir_map.name(hi) != hir_map.name(my_hir) {
+ continue;
+ }
+ f_in_trait_opt = Some(hi);
+ break;
+ }
+ f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
+ Some(Node::TraitItem(hir::TraitItem {
+ kind:
+ hir::TraitItemKind::Fn(
+ hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
+ _,
+ ),
+ ..
+ })) => {
+ let hir::Ty { span, .. } = inputs[local.index() - 1];
+ Some(span)
+ }
+ _ => None,
+ })
+ }
+ _ => None,
+ }
+ }),
+ )
+ }
+
// point to span of upvar making closure call require mutable borrow
fn show_mutating_upvar(
&self,
{
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
- return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+ if !ty.trim_start().starts_with("mut") {
+ return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+ }
} else if let Some(stripped) = src.strip_prefix('&') {
- return (assignment_rhs_span, format!("&mut {}", stripped));
+ if !stripped.trim_start().starts_with("mut") {
+ return (assignment_rhs_span, format!("&mut {}", stripped));
+ }
}
}
}