|
1 | 1 | use rustc_hir as hir;
|
2 | 2 | use rustc_hir::Node;
|
3 | 3 | use rustc_index::vec::Idx;
|
4 |
| -use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location}; |
5 | 4 | use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
6 | 5 | use rustc_middle::ty::{self, Ty, TyCtxt};
|
| 6 | +use rustc_middle::{ |
| 7 | + hir::place::PlaceBase, |
| 8 | + mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location}, |
| 9 | +}; |
7 | 10 | use rustc_span::source_map::DesugaringKind;
|
8 | 11 | use rustc_span::symbol::{kw, Symbol};
|
9 | 12 | use rustc_span::Span;
|
@@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
241 | 244 | format!("mut {}", self.local_names[local].unwrap()),
|
242 | 245 | Applicability::MachineApplicable,
|
243 | 246 | );
|
| 247 | + let tcx = self.infcx.tcx; |
| 248 | + if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() { |
| 249 | + self.show_mutating_upvar(tcx, id, the_place_err, &mut err); |
| 250 | + } |
244 | 251 | }
|
245 | 252 |
|
246 | 253 | // Also suggest adding mut for upvars
|
@@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
271 | 278 | );
|
272 | 279 | }
|
273 | 280 | }
|
| 281 | + |
| 282 | + let tcx = self.infcx.tcx; |
| 283 | + if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind() |
| 284 | + { |
| 285 | + if let ty::Closure(id, _) = ty.kind() { |
| 286 | + self.show_mutating_upvar(tcx, id, the_place_err, &mut err); |
| 287 | + } |
| 288 | + } |
274 | 289 | }
|
275 | 290 |
|
276 | 291 | // complete hack to approximate old AST-borrowck
|
@@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
463 | 478 | err.buffer(&mut self.errors_buffer);
|
464 | 479 | }
|
465 | 480 |
|
| 481 | + // point to span of upvar making closure call require mutable borrow |
| 482 | + fn show_mutating_upvar( |
| 483 | + &self, |
| 484 | + tcx: TyCtxt<'_>, |
| 485 | + id: &hir::def_id::DefId, |
| 486 | + the_place_err: PlaceRef<'tcx>, |
| 487 | + err: &mut DiagnosticBuilder<'_>, |
| 488 | + ) { |
| 489 | + let id = id.expect_local(); |
| 490 | + let tables = tcx.typeck(id); |
| 491 | + let hir_id = tcx.hir().local_def_id_to_hir_id(id); |
| 492 | + let (span, place) = &tables.closure_kind_origins()[hir_id]; |
| 493 | + let reason = if let PlaceBase::Upvar(upvar_id) = place.base { |
| 494 | + let upvar = ty::place_to_string_for_capture(tcx, place); |
| 495 | + match tables.upvar_capture(upvar_id) { |
| 496 | + ty::UpvarCapture::ByRef(ty::UpvarBorrow { |
| 497 | + kind: ty::BorrowKind::MutBorrow, |
| 498 | + .. |
| 499 | + }) => { |
| 500 | + format!("mutable borrow of `{}`", upvar) |
| 501 | + } |
| 502 | + ty::UpvarCapture::ByValue(_) => { |
| 503 | + format!("possible mutation of `{}`", upvar) |
| 504 | + } |
| 505 | + _ => bug!("upvar `{}` borrowed, but not mutably", upvar), |
| 506 | + } |
| 507 | + } else { |
| 508 | + bug!("not an upvar") |
| 509 | + }; |
| 510 | + err.span_label( |
| 511 | + *span, |
| 512 | + format!( |
| 513 | + "calling `{}` requires mutable binding due to {}", |
| 514 | + self.describe_place(the_place_err).unwrap(), |
| 515 | + reason |
| 516 | + ), |
| 517 | + ); |
| 518 | + } |
| 519 | + |
466 | 520 | /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
|
467 | 521 | fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
|
468 | 522 | err.span_label(sp, format!("cannot {}", act));
|
|
0 commit comments