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:
commit
3f09418cbe
3 changed files with 117 additions and 9 deletions
|
@ -376,7 +376,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
|
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
|
||||||
match opt_desugaring_kind {
|
match opt_desugaring_kind {
|
||||||
// on for loops, RHS points to the iterator part
|
// on for loops, RHS points to the iterator part
|
||||||
Some(DesugaringKind::ForLoop(_)) => Some((
|
Some(DesugaringKind::ForLoop(_)) => {
|
||||||
|
self.suggest_similar_mut_method_for_for_loop(&mut err);
|
||||||
|
Some((
|
||||||
false,
|
false,
|
||||||
opt_assignment_rhs_span.unwrap(),
|
opt_assignment_rhs_span.unwrap(),
|
||||||
format!(
|
format!(
|
||||||
|
@ -384,7 +386,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
SIGIL = pointer_sigil,
|
SIGIL = pointer_sigil,
|
||||||
DESC = pointer_desc
|
DESC = pointer_desc
|
||||||
),
|
),
|
||||||
)),
|
))
|
||||||
|
}
|
||||||
// don't create labels for compiler-generated spans
|
// don't create labels for compiler-generated spans
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
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.
|
/// 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) {
|
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
|
||||||
err.span_label(sp, format!("cannot {}", act));
|
err.span_label(sp, format!("cannot {}", act));
|
||||||
|
|
17
src/test/ui/suggestions/suggest-mut-method-for-loop.rs
Normal file
17
src/test/ui/suggestions/suggest-mut-method-for-loop.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
15
src/test/ui/suggestions/suggest-mut-method-for-loop.stderr
Normal file
15
src/test/ui/suggestions/suggest-mut-method-for-loop.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue