Suggest using a temporary variable to fix borrowck errors
In Rust, nesting method calls with both require `&mut` access to `self` produces a borrow-check error: error[E0499]: cannot borrow `*self` as mutable more than once at a time --> src/lib.rs:7:14 | 7 | self.foo(self.bar()); | ---------^^^^^^^^^^- | | | | | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here That's because Rust has a left-to-right evaluation order, and the method receiver is passed first. Thus, the argument to the method cannot then mutate `self`. There's an easy solution to this error: just extract a local variable for the inner argument: let tmp = self.bar(); self.foo(tmp); However, the error doesn't give any suggestion of how to solve the problem. As a result, new users may assume that it's impossible to express their code correctly and get stuck. This commit adds a (non-structured) suggestion to extract a local variable for the inner argument to solve the error. The suggestion uses heuristics that eliminate most false positives, though there are a few false negatives (cases where the suggestion should be emitted but is not). Those other cases can be implemented in a future change.
This commit is contained in:
parent
0b42deaccc
commit
e27315268b
11 changed files with 309 additions and 2 deletions
|
@ -12,6 +12,7 @@ use crate::ty::print::{FmtPrinter, Printer};
|
|||
use crate::ty::subst::{Subst, SubstsRef};
|
||||
use crate::ty::{self, List, Ty, TyCtxt};
|
||||
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
|
||||
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_hir::{self, GeneratorKind};
|
||||
|
@ -30,6 +31,9 @@ use rustc_serialize::{Decodable, Encodable};
|
|||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
|
||||
use either::Either;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||
|
@ -503,6 +507,16 @@ impl<'tcx> Body<'tcx> {
|
|||
Location { block: bb, statement_index: self[bb].statements.len() }
|
||||
}
|
||||
|
||||
pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> {
|
||||
let Location { block, statement_index } = location;
|
||||
let block_data = &self.basic_blocks[block];
|
||||
block_data
|
||||
.statements
|
||||
.get(statement_index)
|
||||
.map(Either::Left)
|
||||
.unwrap_or_else(|| Either::Right(block_data.terminator()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn predecessors(&self) -> &Predecessors {
|
||||
self.predecessor_cache.compute(&self.basic_blocks)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue