Skip to content

Commit 3f09418

Browse files
authored
Rollup merge of #81466 - sasurau4:fix/enhance-sugget-mut-method-for-loop, r=oli-obk
Add suggest mut method for loop Part of #49839 This PR focus on [the comment case](#49839 (comment))
2 parents a28f2af + 90c9b57 commit 3f09418

File tree

3 files changed

+117
-9
lines changed

3 files changed

+117
-9
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs

+85-9
Original file line numberDiff line numberDiff line change
@@ -376,15 +376,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
376376
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
377377
match opt_desugaring_kind {
378378
// on for loops, RHS points to the iterator part
379-
Some(DesugaringKind::ForLoop(_)) => Some((
380-
false,
381-
opt_assignment_rhs_span.unwrap(),
382-
format!(
383-
"this iterator yields `{SIGIL}` {DESC}s",
384-
SIGIL = pointer_sigil,
385-
DESC = pointer_desc
386-
),
387-
)),
379+
Some(DesugaringKind::ForLoop(_)) => {
380+
self.suggest_similar_mut_method_for_for_loop(&mut err);
381+
Some((
382+
false,
383+
opt_assignment_rhs_span.unwrap(),
384+
format!(
385+
"this iterator yields `{SIGIL}` {DESC}s",
386+
SIGIL = pointer_sigil,
387+
DESC = pointer_desc
388+
),
389+
))
390+
}
388391
// don't create labels for compiler-generated spans
389392
Some(_) => None,
390393
None => {
@@ -537,6 +540,79 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
537540
);
538541
}
539542

543+
// Attempt to search similar mutable assosiated items for suggestion.
544+
// In the future, attempt in all path but initially for RHS of for_loop
545+
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) {
546+
let hir = self.infcx.tcx.hir();
547+
let node = hir.item(self.mir_hir_id());
548+
use hir::{
549+
Expr,
550+
ExprKind::{Block, Call, DropTemps, Match, MethodCall},
551+
};
552+
if let hir::ItemKind::Fn(_, _, body_id) = node.kind {
553+
if let Block(
554+
hir::Block {
555+
expr:
556+
Some(Expr {
557+
kind:
558+
DropTemps(Expr {
559+
kind:
560+
Match(
561+
Expr {
562+
kind:
563+
Call(
564+
_,
565+
[Expr {
566+
kind: MethodCall(path_segment, ..),
567+
hir_id,
568+
..
569+
}, ..],
570+
),
571+
..
572+
},
573+
..,
574+
),
575+
..
576+
}),
577+
..
578+
}),
579+
..
580+
},
581+
_,
582+
) = hir.body(body_id).value.kind
583+
{
584+
let opt_suggestions = path_segment
585+
.hir_id
586+
.map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
587+
.and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
588+
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
589+
.map(|def_id| self.infcx.tcx.associated_items(def_id))
590+
.map(|assoc_items| {
591+
assoc_items
592+
.in_definition_order()
593+
.map(|assoc_item_def| assoc_item_def.ident)
594+
.filter(|&ident| {
595+
let original_method_ident = path_segment.ident;
596+
original_method_ident != ident
597+
&& ident
598+
.as_str()
599+
.starts_with(&original_method_ident.name.to_string())
600+
})
601+
.map(|ident| format!("{}()", ident))
602+
});
603+
604+
if let Some(suggestions) = opt_suggestions {
605+
err.span_suggestions(
606+
path_segment.ident.span,
607+
&format!("use mutable method"),
608+
suggestions,
609+
Applicability::MaybeIncorrect,
610+
);
611+
}
612+
}
613+
};
614+
}
615+
540616
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
541617
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
542618
err.span_label(sp, format!("cannot {}", act));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::collections::HashMap;
2+
struct X(usize);
3+
struct Y {
4+
v: u32
5+
}
6+
7+
fn main() {
8+
let mut buzz = HashMap::new();
9+
buzz.insert("a", Y { v: 0 });
10+
11+
for mut t in buzz.values() {
12+
//~^ HELP
13+
//~| SUGGESTION values_mut()
14+
t.v += 1;
15+
//~^ ERROR cannot assign
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0594]: cannot assign to `t.v` which is behind a `&` reference
2+
--> $DIR/suggest-mut-method-for-loop.rs:14:9
3+
|
4+
LL | for mut t in buzz.values() {
5+
| -------------
6+
| | |
7+
| | help: use mutable method: `values_mut()`
8+
| this iterator yields `&` references
9+
...
10+
LL | t.v += 1;
11+
| ^^^^^^^^ `t` is a `&` reference, so the data it refers to cannot be written
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0594`.

0 commit comments

Comments
 (0)