-
-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Explain why a closure is FnOnce in closure errors.
#42196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
7748bc6
bf25b5e
ee88a87
31bfdd7
c2f7e94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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>, | ||
| temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<Span>)>, | ||
| } | ||
|
|
||
| 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<ty::ClosureKind>, | ||
| temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<Span>)>, | ||
| } | ||
|
|
||
| impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { | ||
| fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, | ||
| temp_closure_kinds: NodeMap<ty::ClosureKind>) | ||
| temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<Span>)>) | ||
| -> 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,15 +412,19 @@ 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 | ||
| } | ||
| mc::NoteClosureEnv(upvar_id) => { | ||
| // 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))); | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think what we want is to include the span of a variable, but perhaps more than that we would prefer to include the name as well, for later use in the error message (including just the node-id of the reference could suffice, but I'm a bit wary of including a node-id in this value, since it will make life harder later as we handle incremental etc).