From 7748bc665d012042d2fe8bbda416ab4682ae45ba Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Wed, 24 May 2017 16:23:02 +0100 Subject: [PATCH 1/5] Include context info into closure_kinds --- src/librustc/infer/mod.rs | 6 +++- src/librustc/ty/context.rs | 6 ++-- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/upvar.rs | 36 +++++++++++++++-------- 6 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 270430f40df..a6dbbee79a4 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1682,7 +1682,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let InferTables::InProgress(tables) = self.tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - return tables.borrow().closure_kinds.get(&id).cloned(); + return tables.borrow() + .closure_kinds + .get(&id) + .cloned() + .map(|(kind, _)| kind); } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5ee0b1c9e5e..bc9fd1147b6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -58,6 +58,7 @@ use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::symbol::{Symbol, keywords}; +use syntax_pos::Span; use hir; @@ -229,8 +230,9 @@ pub struct TypeckTables<'tcx> { /// Records the type of each closure. pub closure_tys: NodeMap>, - /// Records the kind of each closure. - pub closure_kinds: 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)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 4c3d5c8aaca..c2e8269aafe 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().closure_tys.insert(expr.id, sig); match opt_kind { Some(kind) => { - self.tables.borrow_mut().closure_kinds.insert(expr.id, kind); + self.tables.borrow_mut().closure_kinds.insert(expr.id, (kind, None)); } None => {} } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9ad72b2a137..7981df9211a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -802,7 +802,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let closure_kinds = &self.tables.borrow().closure_kinds; let closure_kind = match closure_kinds.get(&closure_id) { - Some(&k) => k, + Some(&(k, _)) => k, None => { return Err(MethodError::ClosureAmbiguity(trait_def_id)); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 24a88140cf0..06af22b9a41 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -702,7 +702,7 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureKind { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.typeck_tables_of(def_id).closure_kinds[&node_id] + tcx.typeck_tables_of(def_id).closure_kinds[&node_id].0 } fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 9bfc5f3f0ea..3d5cb13b0ee 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { @@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { capture_clause: hir::CaptureClause) { if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) { - self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn); + self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None)); debug!("check_closure: adding closure {:?} as Fn", expr.id); } @@ -143,12 +143,12 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, } impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap) + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>) -> AdjustBorrowKind<'a, 'gcx, 'tcx> { AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } } @@ -211,8 +211,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // If we are also inferred the closure kind here, update the // main table and process any deferred resolutions. - if let Some(&kind) = self.temp_closure_kinds.get(&id) { - self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind); + if let Some(&(kind, span)) = self.temp_closure_kinds.get(&id) { + self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, span)); let closure_def_id = self.fcx.tcx.hir.local_def_id(id); debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); @@ -276,6 +276,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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 { @@ -289,7 +290,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // to move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind(upvar_id.closure_expr_id, - ty::ClosureKind::FnOnce); + ty::ClosureKind::FnOnce, + tcx.hir.span(upvar_id.var_id)); let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; @@ -303,7 +305,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // to be a FnOnce closure to permit moves out // of the environment. self.adjust_closure_kind(upvar_id.closure_expr_id, - ty::ClosureKind::FnOnce); + ty::ClosureKind::FnOnce, + tcx.hir.span(upvar_id.var_id)); } mc::NoteNone => { } @@ -394,6 +397,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { ty::ImmBorrow => false, }); + let tcx = self.fcx.tcx; + match *note { mc::NoteUpvarRef(upvar_id) => { // if this is an implicit deref of an @@ -407,7 +412,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } // 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); + self.adjust_closure_kind(upvar_id.closure_expr_id, + ty::ClosureKind::FnMut, + tcx.hir.span(upvar_id.var_id)); true } @@ -415,7 +422,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // this kind of deref occurs in a `move` closure, or // for a by-value upvar; in either case, to mutate an // upvar, we need to be an FnMut closure - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); + self.adjust_closure_kind(upvar_id.closure_expr_id, + ty::ClosureKind::FnMut, + tcx.hir.span(upvar_id.var_id)); true } @@ -462,11 +471,12 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, - new_kind: ty::ClosureKind) { + new_kind: ty::ClosureKind, + upvar_span: Span) { debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", closure_id, new_kind); - if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) { + if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", closure_id, existing_kind, new_kind); @@ -482,7 +492,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { (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); + self.temp_closure_kinds.insert(closure_id, (new_kind, Some(upvar_span))); } } } From bf25b5eb823c3cbbacc06d33a3ff539de325be6a Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Wed, 24 May 2017 17:30:27 +0100 Subject: [PATCH 2/5] Explain why a closure is `FnOnce` in closure errors --- src/librustc_borrowck/borrowck/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f7c20542cbf..297df4978a5 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -597,6 +597,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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"); + } false } else { true From ee88a870b6738232c34aa4e1049d94099648386b Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Sun, 28 May 2017 22:08:51 +0100 Subject: [PATCH 3/5] 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::middle::free_region::RegionRelations; 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 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } fn try_adjust_upvar_deref(&mut self, - note: &mc::Note, + cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool { @@ -399,7 +402,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { (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))) + ); } } } From 31bfdd7f178767294427e6257fbbd104e068a510 Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Tue, 30 May 2017 10:47:51 +0100 Subject: [PATCH 4/5] Update fn_once-moved test --- src/test/ui/fn_once-moved.rs | 3 ++- src/test/ui/fn_once-moved.stderr | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/ui/fn_once-moved.rs b/src/test/ui/fn_once-moved.rs index 781d3885eae..409964082f2 100644 --- a/src/test/ui/fn_once-moved.rs +++ b/src/test/ui/fn_once-moved.rs @@ -20,5 +20,6 @@ fn main() { debug_dump_dict(); debug_dump_dict(); //~^ ERROR use of moved value: `debug_dump_dict` - //~| NOTE closure was moved because it only implements `FnOnce` + //~| NOTE closure cannot be invoked more than once because it moves the + //~| variable `dict` out of its environment } diff --git a/src/test/ui/fn_once-moved.stderr b/src/test/ui/fn_once-moved.stderr index 322ab64ebd4..dfee5931da7 100644 --- a/src/test/ui/fn_once-moved.stderr +++ b/src/test/ui/fn_once-moved.stderr @@ -1,12 +1,15 @@ error[E0382]: use of moved value: `debug_dump_dict` --> $DIR/fn_once-moved.rs:21:5 | +16 | for (key, value) in dict { + | ---- dict moved here +... 20 | debug_dump_dict(); | --------------- value moved here 21 | debug_dump_dict(); | ^^^^^^^^^^^^^^^ value used here after move | - = help: closure was moved because it only implements `FnOnce` + = help: closure cannot be invoked more than once because it moves the variable `dict` out of its environment error: aborting due to previous error From c2f7e945526bff3b7d812137d81b235263060ee8 Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Wed, 31 May 2017 00:07:09 +0100 Subject: [PATCH 5/5] Update closure errors to use `span_note` --- src/librustc_borrowck/borrowck/mod.rs | 9 +++++---- src/test/ui/fn_once-moved.stderr | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index b25252eef8c..2089a49ad37 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -596,10 +596,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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)); + err.span_note(span, &format!( + "closure cannot be invoked more than once because \ + it moves the variable `{}` out of its environment", + name + )); false } else { true diff --git a/src/test/ui/fn_once-moved.stderr b/src/test/ui/fn_once-moved.stderr index dfee5931da7..acb52651bcd 100644 --- a/src/test/ui/fn_once-moved.stderr +++ b/src/test/ui/fn_once-moved.stderr @@ -1,15 +1,16 @@ error[E0382]: use of moved value: `debug_dump_dict` --> $DIR/fn_once-moved.rs:21:5 | -16 | for (key, value) in dict { - | ---- dict moved here -... 20 | debug_dump_dict(); | --------------- value moved here 21 | debug_dump_dict(); | ^^^^^^^^^^^^^^^ value used here after move | - = help: closure cannot be invoked more than once because it moves the variable `dict` out of its environment +note: closure cannot be invoked more than once because it moves the variable `dict` out of its environment + --> $DIR/fn_once-moved.rs:16:29 + | +16 | for (key, value) in dict { + | ^^^^ error: aborting due to previous error