Point to span of upvar making closure FnMut
Add expected error Add comment Tweak comment wording Fix after rebase to updated master Fix after rebase to updated master Distinguish mutation in normal and move closures Tweak error message Fix error message for nested closures Refactor code showing mutated upvar in closure Remove debug assert B
This commit is contained in:
parent
66eb982166
commit
26b4baf46e
13 changed files with 152 additions and 4 deletions
|
@ -1,9 +1,12 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::Node;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
|
||||
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{
|
||||
hir::place::PlaceBase,
|
||||
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
|
||||
};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
format!("mut {}", self.local_names[local].unwrap()),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
|
||||
// Also suggest adding mut for upvars
|
||||
|
@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
|
||||
{
|
||||
if let ty::Closure(id, _) = ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// complete hack to approximate old AST-borrowck
|
||||
|
@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
// point to span of upvar making closure call require mutable borrow
|
||||
fn show_mutating_upvar(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
id: &hir::def_id::DefId,
|
||||
the_place_err: PlaceRef<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
let id = id.expect_local();
|
||||
let tables = tcx.typeck(id);
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
|
||||
let (span, place) = &tables.closure_kind_origins()[hir_id];
|
||||
let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
|
||||
let upvar = ty::place_to_string_for_capture(tcx, place);
|
||||
match tables.upvar_capture(upvar_id) {
|
||||
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
|
||||
kind: ty::BorrowKind::MutBorrow,
|
||||
..
|
||||
}) => {
|
||||
format!("mutable borrow of `{}`", upvar)
|
||||
}
|
||||
ty::UpvarCapture::ByValue(_) => {
|
||||
format!("possible mutation of `{}`", upvar)
|
||||
}
|
||||
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
|
||||
}
|
||||
} else {
|
||||
bug!("not an upvar")
|
||||
};
|
||||
err.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"calling `{}` requires mutable binding due to {}",
|
||||
self.describe_place(the_place_err).unwrap(),
|
||||
reason
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue