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](https://github.com/rust-lang/rust/issues/49839#issuecomment-761930746)
This commit is contained in:
Yuki Okushi 2021-02-10 12:24:21 +09:00 committed by GitHub
commit 3f09418cbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 9 deletions

View File

@ -376,15 +376,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
match opt_desugaring_kind {
// on for loops, RHS points to the iterator part
Some(DesugaringKind::ForLoop(_)) => Some((
false,
opt_assignment_rhs_span.unwrap(),
format!(
"this iterator yields `{SIGIL}` {DESC}s",
SIGIL = pointer_sigil,
DESC = pointer_desc
),
)),
Some(DesugaringKind::ForLoop(_)) => {
self.suggest_similar_mut_method_for_for_loop(&mut err);
Some((
false,
opt_assignment_rhs_span.unwrap(),
format!(
"this iterator yields `{SIGIL}` {DESC}s",
SIGIL = pointer_sigil,
DESC = pointer_desc
),
))
}
// don't create labels for compiler-generated spans
Some(_) => None,
None => {
@ -537,6 +540,79 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
);
}
// Attempt to search similar mutable assosiated items for suggestion.
// In the future, attempt in all path but initially for RHS of for_loop
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) {
let hir = self.infcx.tcx.hir();
let node = hir.item(self.mir_hir_id());
use hir::{
Expr,
ExprKind::{Block, Call, DropTemps, Match, MethodCall},
};
if let hir::ItemKind::Fn(_, _, body_id) = node.kind {
if let Block(
hir::Block {
expr:
Some(Expr {
kind:
DropTemps(Expr {
kind:
Match(
Expr {
kind:
Call(
_,
[Expr {
kind: MethodCall(path_segment, ..),
hir_id,
..
}, ..],
),
..
},
..,
),
..
}),
..
}),
..
},
_,
) = hir.body(body_id).value.kind
{
let opt_suggestions = path_segment
.hir_id
.map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
.and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
assoc_items
.in_definition_order()
.map(|assoc_item_def| assoc_item_def.ident)
.filter(|&ident| {
let original_method_ident = path_segment.ident;
original_method_ident != ident
&& ident
.as_str()
.starts_with(&original_method_ident.name.to_string())
})
.map(|ident| format!("{}()", ident))
});
if let Some(suggestions) = opt_suggestions {
err.span_suggestions(
path_segment.ident.span,
&format!("use mutable method"),
suggestions,
Applicability::MaybeIncorrect,
);
}
}
};
}
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
err.span_label(sp, format!("cannot {}", act));

View File

@ -0,0 +1,17 @@
use std::collections::HashMap;
struct X(usize);
struct Y {
v: u32
}
fn main() {
let mut buzz = HashMap::new();
buzz.insert("a", Y { v: 0 });
for mut t in buzz.values() {
//~^ HELP
//~| SUGGESTION values_mut()
t.v += 1;
//~^ ERROR cannot assign
}
}

View File

@ -0,0 +1,15 @@
error[E0594]: cannot assign to `t.v` which is behind a `&` reference
--> $DIR/suggest-mut-method-for-loop.rs:14:9
|
LL | for mut t in buzz.values() {
| -------------
| | |
| | help: use mutable method: `values_mut()`
| this iterator yields `&` references
...
LL | t.v += 1;
| ^^^^^^^^ `t` is a `&` reference, so the data it refers to cannot be written
error: aborting due to previous error
For more information about this error, try `rustc --explain E0594`.