From ee88a870b6738232c34aa4e1049d94099648386b Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Sun, 28 May 2017 22:08:51 +0100 Subject: [PATCH] Explain why closure is moved in error message --- src/librustc/ty/context.rs | 6 ++-- src/librustc_borrowck/borrowck/mod.rs | 16 +++++----- src/librustc_typeck/check/upvar.rs | 45 ++++++++++++++++----------- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index bc9fd1147b6..8deeb35270d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -230,9 +230,9 @@ pub struct TypeckTables<'tcx> { /// Records the type of each closure. pub closure_tys: NodeMap>, - /// Records the kind of each closure and the span of the variable that - /// cause the closure to be this kind. - pub closure_kinds: NodeMap<(ty::ClosureKind, Option)>, + /// Records the kind of each closure and the span and name of the variable + /// that caused the closure to be this kind. + pub closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 297df4978a5..b25252eef8c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -39,8 +39,6 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::Providers; -use syntax_pos::DUMMY_SP; - use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; @@ -594,12 +592,14 @@ pub fn report_use_of_moved_value(&self, verb, msg, nl); let need_note = match lp.ty.sty { ty::TypeVariants::TyClosure(id, _) => { - if let Ok(ty::ClosureKind::FnOnce) = - ty::queries::closure_kind::try_get(self.tcx, DUMMY_SP, id) { - err.help("closure was moved because it only implements `FnOnce`"); - if let Some(&(_kind, Some(span))) = self.tables.closure_kinds.get( ) { - err.span_label(span, "move occured here"); - } + let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); + if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = + self.tables.closure_kinds.get(&node_id) + { + err.help(&format!("closure cannot be invoked more than once because \ + it moves the variable `{}` out of its environment", + name)); + err.span_label(span, format!("{} moved here", name)); false } else { true diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 3d5cb13b0ee..114290c52d1 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -74,7 +74,7 @@ pub fn closure_analyze(&self, body: &'gcx hir::Body) { struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { @@ -143,12 +143,12 @@ fn check_closure(&mut self, struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, } impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>) + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>) -> AdjustBorrowKind<'a, 'gcx, 'tcx> { AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } } @@ -211,8 +211,8 @@ fn analyze_closure(&mut self, // If we are also inferred the closure kind here, update the // main table and process any deferred resolutions. - if let Some(&(kind, span)) = self.temp_closure_kinds.get(&id) { - self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, span)); + if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) { + self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context)); let closure_def_id = self.fcx.tcx.hir.local_def_id(id); debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); @@ -272,11 +272,12 @@ fn adjust_upvar_borrow_kind_for_consume(&mut self, euv::Move(_) => { } } + let tcx = self.fcx.tcx; + // watch out for a move of the deref of a borrowed pointer; // for that to be legal, the upvar would have to be borrowed // by value instead let guarantor = cmt.guarantor(); - let tcx = self.fcx.tcx; debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", guarantor); match guarantor.cat { @@ -291,7 +292,8 @@ fn adjust_upvar_borrow_kind_for_consume(&mut self, // to move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - tcx.hir.span(upvar_id.var_id)); + guarantor.span, + tcx.hir.name(upvar_id.var_id)); let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; @@ -306,7 +308,8 @@ fn adjust_upvar_borrow_kind_for_consume(&mut self, // of the environment. self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - tcx.hir.span(upvar_id.var_id)); + guarantor.span, + tcx.hir.name(upvar_id.var_id)); } mc::NoteNone => { } @@ -334,7 +337,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { Categorization::Deref(base, _, mc::BorrowedPtr(..)) | Categorization::Deref(base, _, mc::Implicit(..)) => { - if !self.try_adjust_upvar_deref(&cmt.note, ty::MutBorrow) { + if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) { // assignment to deref of an `&mut` // borrowed pointer implies that the // pointer itself must be unique, but not @@ -368,7 +371,7 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { Categorization::Deref(base, _, mc::BorrowedPtr(..)) | Categorization::Deref(base, _, mc::Implicit(..)) => { - if !self.try_adjust_upvar_deref(&cmt.note, ty::UniqueImmBorrow) { + if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique self.adjust_upvar_borrow_kind_for_unique(base); @@ -385,7 +388,7 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { } fn try_adjust_upvar_deref(&mut self, - note: &mc::Note, + cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool { @@ -399,7 +402,7 @@ fn try_adjust_upvar_deref(&mut self, let tcx = self.fcx.tcx; - match *note { + match cmt.note { mc::NoteUpvarRef(upvar_id) => { // if this is an implicit deref of an // upvar, then we need to modify the @@ -414,7 +417,8 @@ fn try_adjust_upvar_deref(&mut self, // also need to be in an FnMut closure since this is not an ImmBorrow self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut, - tcx.hir.span(upvar_id.var_id)); + cmt.span, + tcx.hir.name(upvar_id.var_id)); true } @@ -424,7 +428,8 @@ fn try_adjust_upvar_deref(&mut self, // upvar, we need to be an FnMut closure self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut, - tcx.hir.span(upvar_id.var_id)); + cmt.span, + tcx.hir.name(upvar_id.var_id)); true } @@ -472,9 +477,10 @@ fn adjust_upvar_borrow_kind(&mut self, fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, new_kind: ty::ClosureKind, - upvar_span: Span) { - debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", - closure_id, new_kind); + upvar_span: Span, + var_name: ast::Name) { + debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})", + closure_id, new_kind, upvar_span, var_name); if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", @@ -492,7 +498,10 @@ fn adjust_closure_kind(&mut self, (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind - self.temp_closure_kinds.insert(closure_id, (new_kind, Some(upvar_span))); + self.temp_closure_kinds.insert( + closure_id, + (new_kind, Some((upvar_span, var_name))) + ); } } } -- 2.44.0