From d3c4dbd85d63c8bdfa362d7cac8b3e8cbca51272 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 28 Jan 2021 18:14:26 +0900 Subject: [PATCH 1/2] Add suggest mu method for loop --- .../diagnostics/mutability_errors.rs | 94 +++++++++++++++++-- 1 file changed, 85 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 333ac0738d4..0467bf76afe 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -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)); From 90c9b57211ce6104660b93d64f18e0c9736f5a99 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 28 Jan 2021 18:14:35 +0900 Subject: [PATCH 2/2] Add test --- .../suggestions/suggest-mut-method-for-loop.rs | 17 +++++++++++++++++ .../suggest-mut-method-for-loop.stderr | 15 +++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/suggestions/suggest-mut-method-for-loop.rs create mode 100644 src/test/ui/suggestions/suggest-mut-method-for-loop.stderr diff --git a/src/test/ui/suggestions/suggest-mut-method-for-loop.rs b/src/test/ui/suggestions/suggest-mut-method-for-loop.rs new file mode 100644 index 00000000000..756768bce46 --- /dev/null +++ b/src/test/ui/suggestions/suggest-mut-method-for-loop.rs @@ -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 + } +} diff --git a/src/test/ui/suggestions/suggest-mut-method-for-loop.stderr b/src/test/ui/suggestions/suggest-mut-method-for-loop.stderr new file mode 100644 index 00000000000..6ab08197441 --- /dev/null +++ b/src/test/ui/suggestions/suggest-mut-method-for-loop.stderr @@ -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`.