|
| 1 | +use hir::ExprKind; |
1 | 2 | use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
2 | 3 | use rustc_hir as hir;
|
3 | 4 | use rustc_hir::intravisit::Visitor;
|
4 | 5 | use rustc_hir::Node;
|
5 | 6 | use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
6 |
| -use rustc_middle::ty::{self, Ty, TyCtxt}; |
| 7 | +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; |
7 | 8 | use rustc_middle::{
|
8 | 9 | hir::place::PlaceBase,
|
9 | 10 | mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
|
@@ -491,6 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
491 | 492 | ),
|
492 | 493 | );
|
493 | 494 |
|
| 495 | + self.suggest_using_iter_mut(&mut err); |
494 | 496 | self.suggest_make_local_mut(&mut err, local, name);
|
495 | 497 | }
|
496 | 498 | _ => {
|
@@ -953,6 +955,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
953 | 955 | }
|
954 | 956 | }
|
955 | 957 |
|
| 958 | + fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) { |
| 959 | + let source = self.body.source; |
| 960 | + let hir = self.infcx.tcx.hir(); |
| 961 | + if let InstanceDef::Item(def_id) = source.instance |
| 962 | + && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id) |
| 963 | + && let ExprKind::Closure(closure) = kind && closure.movability == None |
| 964 | + && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { |
| 965 | + let mut cur_expr = expr; |
| 966 | + while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { |
| 967 | + if path_segment.ident.name == sym::iter { |
| 968 | + // check `_ty` has `iter_mut` method |
| 969 | + let res = self |
| 970 | + .infcx |
| 971 | + .tcx |
| 972 | + .typeck(path_segment.hir_id.owner.def_id) |
| 973 | + .type_dependent_def_id(cur_expr.hir_id) |
| 974 | + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) |
| 975 | + .map(|def_id| self.infcx.tcx.associated_items(def_id)) |
| 976 | + .map(|assoc_items| { |
| 977 | + assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() |
| 978 | + }); |
| 979 | + |
| 980 | + if let Some(mut res) = res && res.peek().is_some() { |
| 981 | + err.span_suggestion_verbose( |
| 982 | + path_segment.ident.span, |
| 983 | + "you may want to use `iter_mut` here", |
| 984 | + "iter_mut", |
| 985 | + Applicability::MaybeIncorrect, |
| 986 | + ); |
| 987 | + } |
| 988 | + break; |
| 989 | + } else { |
| 990 | + cur_expr = recv; |
| 991 | + } |
| 992 | + } |
| 993 | + } |
| 994 | + } |
| 995 | + |
956 | 996 | fn suggest_make_local_mut(
|
957 | 997 | &self,
|
958 | 998 | err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
|
0 commit comments