Skip to content

Commit abb512e

Browse files
committed
Fix 'assign to data in an index of' collection suggestions
splits the large triple suggestion into three sets them to MaybeIncorrect automatically determines the required borrowing to use.
1 parent 5d04477 commit abb512e

1 file changed

Lines changed: 80 additions & 57 deletions

File tree

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 80 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
668668
err: &'a mut Diag<'infcx>,
669669
ty: Ty<'tcx>,
670670
suggested: bool,
671+
infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
671672
}
673+
672674
impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
673675
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
674676
hir::intravisit::walk_stmt(self, stmt);
@@ -679,81 +681,101 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
679681
return;
680682
}
681683
};
684+
685+
/// Taken straight from https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/fn.peel_hir_ty_refs.html
686+
/// Adapted to mid using https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs
687+
/// Simplified to counting only
688+
/// Peels off all references on the type. Returns the number of references
689+
/// removed.
690+
fn count_ty_refs<'tcx>(ty: Ty<'tcx>) -> usize {
691+
let mut count = 0;
692+
let mut ty = ty;
693+
while let ty::Ref(_, inner_ty, _) = ty.kind() {
694+
ty = *inner_ty;
695+
count += 1;
696+
}
697+
count
698+
}
682699
if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
683700
&& let hir::ExprKind::Index(val, index, _) = place.kind
684701
&& (expr.span == self.assign_span || place.span == self.assign_span)
685702
{
686-
// val[index] = rv;
687-
// ---------- place
688-
self.err.multipart_suggestions(
703+
let ref_depth_difference: usize;
704+
let _index_is_copy_clone: bool;
705+
706+
if let Some(index_ty) =
707+
self.infcx.tcx.typeck(val.hir_id.owner.def_id).expr_ty_opt(index)
708+
{
709+
// we know ty is a map, with a key type at walk distance 2.
710+
let key_type = self.ty.walk().nth(1).unwrap().expect_ty();
711+
let key_ref_depth = count_ty_refs(key_type);
712+
713+
let index_ref_depth = count_ty_refs(index_ty);
714+
ref_depth_difference = index_ref_depth - key_ref_depth; //index should
715+
//be deeper than key
716+
} else {
717+
// no type ?
718+
return;
719+
};
720+
721+
// remove the exessive referencing if necessary, but get_mut requires a ref
722+
let (prefix, gm_prefix) = match ref_depth_difference {
723+
0 => (String::new(), String::from("&")),
724+
n => ("*".repeat(n), "*".repeat(n - 1)),
725+
};
726+
727+
self.err.multipart_suggestion(
728+
format!("use `.insert()` to insert a value into a `{}`", self.ty),
729+
vec![
730+
// val.insert(index, rv);
731+
(
732+
val.span.shrink_to_hi().with_hi(index.span.lo()),
733+
format!(".insert({prefix}"),
734+
),
735+
(index.span.shrink_to_hi().with_hi(rv.span.lo()), ", ".to_string()),
736+
(rv.span.shrink_to_hi(), ")".to_string()),
737+
],
738+
Applicability::MaybeIncorrect,
739+
);
740+
self.err.multipart_suggestion(
689741
format!(
690-
"use `.insert()` to insert a value into a `{}`, `.get_mut()` \
691-
to modify it, or the entry API for more flexibility",
742+
"use `.get_mut()` to modify an existing key in a `{}`",
692743
self.ty,
693744
),
694745
vec![
695-
vec![
696-
// val.insert(index, rv);
697-
(
698-
val.span.shrink_to_hi().with_hi(index.span.lo()),
699-
".insert(".to_string(),
700-
),
701-
(
702-
index.span.shrink_to_hi().with_hi(rv.span.lo()),
703-
", ".to_string(),
704-
),
705-
(rv.span.shrink_to_hi(), ")".to_string()),
706-
],
707-
vec![
708-
// if let Some(v) = val.get_mut(index) { *v = rv; }
709-
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
710-
(
711-
val.span.shrink_to_hi().with_hi(index.span.lo()),
712-
".get_mut(".to_string(),
713-
),
714-
(
715-
index.span.shrink_to_hi().with_hi(place.span.hi()),
716-
") { *val".to_string(),
717-
),
718-
(rv.span.shrink_to_hi(), "; }".to_string()),
719-
],
720-
vec![
721-
// let x = val.entry(index).or_insert(rv);
722-
(val.span.shrink_to_lo(), "let val = ".to_string()),
723-
(
724-
val.span.shrink_to_hi().with_hi(index.span.lo()),
725-
".entry(".to_string(),
726-
),
727-
(
728-
index.span.shrink_to_hi().with_hi(rv.span.lo()),
729-
").or_insert(".to_string(),
730-
),
731-
(rv.span.shrink_to_hi(), ")".to_string()),
732-
],
746+
// if let Some(v) = val.get_mut(index) { *v = rv; }
747+
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
748+
(
749+
val.span.shrink_to_hi().with_hi(index.span.lo()),
750+
format!(".get_mut({gm_prefix}"),
751+
),
752+
(
753+
index.span.shrink_to_hi().with_hi(place.span.hi()),
754+
") { *val".to_string(),
755+
),
756+
(rv.span.shrink_to_hi(), "; }".to_string()),
733757
],
734-
Applicability::MachineApplicable,
758+
Applicability::MaybeIncorrect,
735759
);
736-
self.suggested = true;
737-
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
738-
&& let hir::ExprKind::Index(val, index, _) = receiver.kind
739-
&& receiver.span == self.assign_span
740-
{
741-
// val[index].path(args..);
742760
self.err.multipart_suggestion(
743-
format!("to modify a `{}` use `.get_mut()`", self.ty),
761+
format!(
762+
"use the entry API to modify a `{}` for more flexibility",
763+
self.ty
764+
),
744765
vec![
745-
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
766+
// let x = val.entry(index).insert_entry(rv);
767+
(val.span.shrink_to_lo(), "let val = ".to_string()),
746768
(
747769
val.span.shrink_to_hi().with_hi(index.span.lo()),
748-
".get_mut(".to_string(),
770+
format!(".entry({prefix}"),
749771
),
750772
(
751-
index.span.shrink_to_hi().with_hi(receiver.span.hi()),
752-
") { val".to_string(),
773+
index.span.shrink_to_hi().with_hi(rv.span.lo()),
774+
").insert_entry(".to_string(),
753775
),
754-
(sp.shrink_to_hi(), "; }".to_string()),
776+
(rv.span.shrink_to_hi(), ")".to_string()),
755777
],
756-
Applicability::MachineApplicable,
778+
Applicability::MaybeIncorrect,
757779
);
758780
self.suggested = true;
759781
}
@@ -768,6 +790,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
768790
err,
769791
ty,
770792
suggested: false,
793+
infcx: self.infcx,
771794
};
772795
v.visit_body(&body);
773796
if !v.suggested {

0 commit comments

Comments
 (0)