Skip to content

Commit 2371906

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 cf16cd9 commit 2371906

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
@@ -611,7 +611,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
611611
err: &'a mut Diag<'infcx>,
612612
ty: Ty<'tcx>,
613613
suggested: bool,
614+
infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
614615
}
616+
615617
impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
616618
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
617619
hir::intravisit::walk_stmt(self, stmt);
@@ -622,81 +624,101 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
622624
return;
623625
}
624626
};
627+
628+
/// Taken straight from https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/fn.peel_hir_ty_refs.html
629+
/// Adapted to mid using https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs
630+
/// Simplified to counting only
631+
/// Peels off all references on the type. Returns the number of references
632+
/// removed.
633+
fn count_ty_refs<'tcx>(ty: Ty<'tcx>) -> usize {
634+
let mut count = 0;
635+
let mut ty = ty;
636+
while let ty::Ref(_, inner_ty, _) = ty.kind() {
637+
ty = *inner_ty;
638+
count += 1;
639+
}
640+
count
641+
}
625642
if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
626643
&& let hir::ExprKind::Index(val, index, _) = place.kind
627644
&& (expr.span == self.assign_span || place.span == self.assign_span)
628645
{
629-
// val[index] = rv;
630-
// ---------- place
631-
self.err.multipart_suggestions(
646+
let ref_depth_difference: usize;
647+
let _index_is_copy_clone: bool;
648+
649+
if let Some(index_ty) =
650+
self.infcx.tcx.typeck(val.hir_id.owner.def_id).expr_ty_opt(index)
651+
{
652+
// we know ty is a map, with a key type at walk distance 2.
653+
let key_type = self.ty.walk().nth(1).unwrap().expect_ty();
654+
let key_ref_depth = count_ty_refs(key_type);
655+
656+
let index_ref_depth = count_ty_refs(index_ty);
657+
ref_depth_difference = index_ref_depth - key_ref_depth; //index should
658+
//be deeper than key
659+
} else {
660+
// no type ?
661+
return;
662+
};
663+
664+
// remove the exessive referencing if necessary, but get_mut requires a ref
665+
let (prefix, gm_prefix) = match ref_depth_difference {
666+
0 => (String::new(), String::from("&")),
667+
n => ("*".repeat(n), "*".repeat(n - 1)),
668+
};
669+
670+
self.err.multipart_suggestion(
671+
format!("use `.insert()` to insert a value into a `{}`", self.ty),
672+
vec![
673+
// val.insert(index, rv);
674+
(
675+
val.span.shrink_to_hi().with_hi(index.span.lo()),
676+
format!(".insert({prefix}"),
677+
),
678+
(index.span.shrink_to_hi().with_hi(rv.span.lo()), ", ".to_string()),
679+
(rv.span.shrink_to_hi(), ")".to_string()),
680+
],
681+
Applicability::MaybeIncorrect,
682+
);
683+
self.err.multipart_suggestion(
632684
format!(
633-
"use `.insert()` to insert a value into a `{}`, `.get_mut()` \
634-
to modify it, or the entry API for more flexibility",
685+
"use `.get_mut()` to modify an existing key in a `{}`",
635686
self.ty,
636687
),
637688
vec![
638-
vec![
639-
// val.insert(index, rv);
640-
(
641-
val.span.shrink_to_hi().with_hi(index.span.lo()),
642-
".insert(".to_string(),
643-
),
644-
(
645-
index.span.shrink_to_hi().with_hi(rv.span.lo()),
646-
", ".to_string(),
647-
),
648-
(rv.span.shrink_to_hi(), ")".to_string()),
649-
],
650-
vec![
651-
// if let Some(v) = val.get_mut(index) { *v = rv; }
652-
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
653-
(
654-
val.span.shrink_to_hi().with_hi(index.span.lo()),
655-
".get_mut(".to_string(),
656-
),
657-
(
658-
index.span.shrink_to_hi().with_hi(place.span.hi()),
659-
") { *val".to_string(),
660-
),
661-
(rv.span.shrink_to_hi(), "; }".to_string()),
662-
],
663-
vec![
664-
// let x = val.entry(index).or_insert(rv);
665-
(val.span.shrink_to_lo(), "let val = ".to_string()),
666-
(
667-
val.span.shrink_to_hi().with_hi(index.span.lo()),
668-
".entry(".to_string(),
669-
),
670-
(
671-
index.span.shrink_to_hi().with_hi(rv.span.lo()),
672-
").or_insert(".to_string(),
673-
),
674-
(rv.span.shrink_to_hi(), ")".to_string()),
675-
],
689+
// if let Some(v) = val.get_mut(index) { *v = rv; }
690+
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
691+
(
692+
val.span.shrink_to_hi().with_hi(index.span.lo()),
693+
format!(".get_mut({gm_prefix}"),
694+
),
695+
(
696+
index.span.shrink_to_hi().with_hi(place.span.hi()),
697+
") { *val".to_string(),
698+
),
699+
(rv.span.shrink_to_hi(), "; }".to_string()),
676700
],
677-
Applicability::MachineApplicable,
701+
Applicability::MaybeIncorrect,
678702
);
679-
self.suggested = true;
680-
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
681-
&& let hir::ExprKind::Index(val, index, _) = receiver.kind
682-
&& receiver.span == self.assign_span
683-
{
684-
// val[index].path(args..);
685703
self.err.multipart_suggestion(
686-
format!("to modify a `{}` use `.get_mut()`", self.ty),
704+
format!(
705+
"use the entry API to modify a `{}` for more flexibility",
706+
self.ty
707+
),
687708
vec![
688-
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
709+
// let x = val.entry(index).insert_entry(rv);
710+
(val.span.shrink_to_lo(), "let val = ".to_string()),
689711
(
690712
val.span.shrink_to_hi().with_hi(index.span.lo()),
691-
".get_mut(".to_string(),
713+
format!(".entry({prefix}"),
692714
),
693715
(
694-
index.span.shrink_to_hi().with_hi(receiver.span.hi()),
695-
") { val".to_string(),
716+
index.span.shrink_to_hi().with_hi(rv.span.lo()),
717+
").insert_entry(".to_string(),
696718
),
697-
(sp.shrink_to_hi(), "; }".to_string()),
719+
(rv.span.shrink_to_hi(), ")".to_string()),
698720
],
699-
Applicability::MachineApplicable,
721+
Applicability::MaybeIncorrect,
700722
);
701723
self.suggested = true;
702724
}
@@ -711,6 +733,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
711733
err,
712734
ty,
713735
suggested: false,
736+
infcx: self.infcx,
714737
};
715738
v.visit_body(&body);
716739
if !v.suggested {

0 commit comments

Comments
 (0)