mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 12:36:47 +00:00
Auto merge of #115308 - chenyukang:yukang-fix-62387-iter-mut, r=davidtwco
suggest iter_mut() where trying to modify elements from .iter() Fixes https://github.com/rust-lang/rust/issues/115259 Fixes https://github.com/rust-lang/rust/issues/62387
This commit is contained in:
commit
68c2f5ba0f
@ -1,9 +1,10 @@
|
||||
use hir::ExprKind;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
|
||||
use rustc_middle::{
|
||||
hir::place::PlaceBase,
|
||||
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
|
||||
@ -491,6 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
),
|
||||
);
|
||||
|
||||
self.suggest_using_iter_mut(&mut err);
|
||||
self.suggest_make_local_mut(&mut err, local, name);
|
||||
}
|
||||
_ => {
|
||||
@ -953,6 +955,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) {
|
||||
let source = self.body.source;
|
||||
let hir = self.infcx.tcx.hir();
|
||||
if let InstanceDef::Item(def_id) = source.instance
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id)
|
||||
&& let ExprKind::Closure(closure) = kind && closure.movability == None
|
||||
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) {
|
||||
let mut cur_expr = expr;
|
||||
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
|
||||
if path_segment.ident.name == sym::iter {
|
||||
// check `_ty` has `iter_mut` method
|
||||
let res = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(path_segment.hir_id.owner.def_id)
|
||||
.type_dependent_def_id(cur_expr.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.filter_by_name_unhygienic(sym::iter_mut).peekable()
|
||||
});
|
||||
|
||||
if let Some(mut res) = res && res.peek().is_some() {
|
||||
err.span_suggestion_verbose(
|
||||
path_segment.ident.span,
|
||||
"you may want to use `iter_mut` here",
|
||||
"iter_mut",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
cur_expr = recv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_make_local_mut(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
|
20
tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed
Normal file
20
tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed
Normal file
@ -0,0 +1,20 @@
|
||||
// run-rustfix
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub trait Layer {
|
||||
fn process(&mut self) -> u32;
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
layers: Vec<Box<dyn Layer>>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn process(&mut self) -> u32 {
|
||||
self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process())
|
||||
//~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
tests/ui/borrowck/issue-115259-suggest-iter-mut.rs
Normal file
20
tests/ui/borrowck/issue-115259-suggest-iter-mut.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// run-rustfix
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub trait Layer {
|
||||
fn process(&mut self) -> u32;
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
layers: Vec<Box<dyn Layer>>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn process(&mut self) -> u32 {
|
||||
self.layers.iter().fold(0, |result, mut layer| result + layer.process())
|
||||
//~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
16
tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr
Normal file
16
tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` reference
|
||||
--> $DIR/issue-115259-suggest-iter-mut.rs:15:65
|
||||
|
|
||||
LL | self.layers.iter().fold(0, |result, mut layer| result + layer.process())
|
||||
| --------- ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
||||
| |
|
||||
| consider changing this binding's type to be: `&mut Box<dyn Layer>`
|
||||
|
|
||||
help: you may want to use `iter_mut` here
|
||||
|
|
||||
LL | self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process())
|
||||
| ~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
36
tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed
Normal file
36
tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed
Normal file
@ -0,0 +1,36 @@
|
||||
// run-rustfix
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Container {
|
||||
things: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn things(&mut self) -> &[PathBuf] {
|
||||
&self.things
|
||||
}
|
||||
}
|
||||
|
||||
// contains containers
|
||||
struct ContainerContainer {
|
||||
contained: Vec<Container>,
|
||||
}
|
||||
|
||||
impl ContainerContainer {
|
||||
fn contained(&self) -> &[Container] {
|
||||
&self.contained
|
||||
}
|
||||
|
||||
fn all_the_things(&mut self) -> &[PathBuf] {
|
||||
let mut vec = self.contained.clone();
|
||||
let _a =
|
||||
vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
|
||||
//~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
36
tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs
Normal file
36
tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// run-rustfix
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Container {
|
||||
things: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn things(&mut self) -> &[PathBuf] {
|
||||
&self.things
|
||||
}
|
||||
}
|
||||
|
||||
// contains containers
|
||||
struct ContainerContainer {
|
||||
contained: Vec<Container>,
|
||||
}
|
||||
|
||||
impl ContainerContainer {
|
||||
fn contained(&self) -> &[Container] {
|
||||
&self.contained
|
||||
}
|
||||
|
||||
fn all_the_things(&mut self) -> &[PathBuf] {
|
||||
let mut vec = self.contained.clone();
|
||||
let _a =
|
||||
vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
|
||||
//~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
16
tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr
Normal file
16
tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference
|
||||
--> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45
|
||||
|
|
||||
LL | vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
|
||||
| --------- ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
||||
| |
|
||||
| consider changing this binding's type to be: `&mut Container`
|
||||
|
|
||||
help: you may want to use `iter_mut` here
|
||||
|
|
||||
LL | vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
|
||||
| ~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
30
tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed
Normal file
30
tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed
Normal file
@ -0,0 +1,30 @@
|
||||
// run-rustfix
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
struct A {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
impl A {
|
||||
fn double(&mut self) {
|
||||
self.a += self.a
|
||||
}
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
let mut v = [A { a: 4 }];
|
||||
v.iter_mut().for_each(|a| a.double());
|
||||
//~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
|
||||
println!("{:?}", v);
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let mut v = [A { a: 4 }];
|
||||
v.iter_mut().rev().rev().for_each(|a| a.double());
|
||||
//~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
|
||||
println!("{:?}", v);
|
||||
}
|
||||
|
||||
fn main() {}
|
30
tests/ui/borrowck/issue-62387-suggest-iter-mut.rs
Normal file
30
tests/ui/borrowck/issue-62387-suggest-iter-mut.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// run-rustfix
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
struct A {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
impl A {
|
||||
fn double(&mut self) {
|
||||
self.a += self.a
|
||||
}
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
let mut v = [A { a: 4 }];
|
||||
v.iter().for_each(|a| a.double());
|
||||
//~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
|
||||
println!("{:?}", v);
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let mut v = [A { a: 4 }];
|
||||
v.iter().rev().rev().for_each(|a| a.double());
|
||||
//~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference
|
||||
println!("{:?}", v);
|
||||
}
|
||||
|
||||
fn main() {}
|
29
tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr
Normal file
29
tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
|
||||
--> $DIR/issue-62387-suggest-iter-mut.rs:18:27
|
||||
|
|
||||
LL | v.iter().for_each(|a| a.double());
|
||||
| - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
||||
| |
|
||||
| consider changing this binding's type to be: `&mut A`
|
||||
|
|
||||
help: you may want to use `iter_mut` here
|
||||
|
|
||||
LL | v.iter_mut().for_each(|a| a.double());
|
||||
| ~~~~~~~~
|
||||
|
||||
error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
|
||||
--> $DIR/issue-62387-suggest-iter-mut.rs:25:39
|
||||
|
|
||||
LL | v.iter().rev().rev().for_each(|a| a.double());
|
||||
| - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
||||
| |
|
||||
| consider changing this binding's type to be: `&mut A`
|
||||
|
|
||||
help: you may want to use `iter_mut` here
|
||||
|
|
||||
LL | v.iter_mut().rev().rev().for_each(|a| a.double());
|
||||
| ~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
Loading…
Reference in New Issue
Block a user