Skip to content

Commit b851d1c

Browse files
Rollup merge of #42196 - tommyip:explain_closure_err, r=nikomatsakis
Explain why a closure is `FnOnce` in closure errors. Issue: #42065 @nikomatsakis Am I going the right direction with this? ~~I am stuck in a few bits:~~ ~~1. How to trace the code to get the upvar instead of the original variable's span?~~ ~~2. How to find the node id of the upvar where the move occured?~~
2 parents d5a7fd5 + c2f7e94 commit b851d1c

File tree

9 files changed

+66
-32
lines changed

9 files changed

+66
-32
lines changed

src/librustc/infer/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1682,7 +1682,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
16821682
{
16831683
if let InferTables::InProgress(tables) = self.tables {
16841684
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
1685-
return tables.borrow().closure_kinds.get(&id).cloned();
1685+
return tables.borrow()
1686+
.closure_kinds
1687+
.get(&id)
1688+
.cloned()
1689+
.map(|(kind, _)| kind);
16861690
}
16871691
}
16881692

src/librustc/ty/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use syntax::abi;
5858
use syntax::ast::{self, Name, NodeId};
5959
use syntax::attr;
6060
use syntax::symbol::{Symbol, keywords};
61+
use syntax_pos::Span;
6162

6263
use hir;
6364

@@ -229,8 +230,9 @@ pub struct TypeckTables<'tcx> {
229230
/// Records the type of each closure.
230231
pub closure_tys: NodeMap<ty::PolyFnSig<'tcx>>,
231232

232-
/// Records the kind of each closure.
233-
pub closure_kinds: NodeMap<ty::ClosureKind>,
233+
/// Records the kind of each closure and the span and name of the variable
234+
/// that caused the closure to be this kind.
235+
pub closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
234236

235237
/// For each fn, records the "liberated" types of its arguments
236238
/// and return type. Liberated means that all bound regions

src/librustc_borrowck/borrowck/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ use rustc::middle::free_region::RegionRelations;
3939
use rustc::ty::{self, TyCtxt};
4040
use rustc::ty::maps::Providers;
4141

42-
use syntax_pos::DUMMY_SP;
43-
4442
use std::fmt;
4543
use std::rc::Rc;
4644
use std::hash::{Hash, Hasher};
@@ -587,9 +585,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
587585
verb, msg, nl);
588586
let need_note = match lp.ty.sty {
589587
ty::TypeVariants::TyClosure(id, _) => {
590-
if let Ok(ty::ClosureKind::FnOnce) =
591-
ty::queries::closure_kind::try_get(self.tcx, DUMMY_SP, id) {
592-
err.help("closure was moved because it only implements `FnOnce`");
588+
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
589+
if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) =
590+
self.tables.closure_kinds.get(&node_id)
591+
{
592+
err.span_note(span, &format!(
593+
"closure cannot be invoked more than once because \
594+
it moves the variable `{}` out of its environment",
595+
name
596+
));
593597
false
594598
} else {
595599
true

src/librustc_typeck/check/closure.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
103103
self.tables.borrow_mut().closure_tys.insert(expr.id, sig);
104104
match opt_kind {
105105
Some(kind) => {
106-
self.tables.borrow_mut().closure_kinds.insert(expr.id, kind);
106+
self.tables.borrow_mut().closure_kinds.insert(expr.id, (kind, None));
107107
}
108108
None => {}
109109
}

src/librustc_typeck/check/method/probe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
814814

815815
let closure_kinds = &self.tables.borrow().closure_kinds;
816816
let closure_kind = match closure_kinds.get(&closure_id) {
817-
Some(&k) => k,
817+
Some(&(k, _)) => k,
818818
None => {
819819
return Err(MethodError::ClosureAmbiguity(trait_def_id));
820820
}

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
702702
def_id: DefId)
703703
-> ty::ClosureKind {
704704
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
705-
tcx.typeck_tables_of(def_id).closure_kinds[&node_id]
705+
tcx.typeck_tables_of(def_id).closure_kinds[&node_id].0
706706
}
707707

708708
fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

src/librustc_typeck/check/upvar.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
7474

7575
struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
7676
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
77-
temp_closure_kinds: NodeMap<ty::ClosureKind>,
77+
temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
7878
}
7979

8080
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
@@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
107107
capture_clause: hir::CaptureClause)
108108
{
109109
if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) {
110-
self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn);
110+
self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None));
111111
debug!("check_closure: adding closure {:?} as Fn", expr.id);
112112
}
113113

@@ -143,12 +143,12 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
143143

144144
struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
145145
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
146-
temp_closure_kinds: NodeMap<ty::ClosureKind>,
146+
temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
147147
}
148148

149149
impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
150150
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
151-
temp_closure_kinds: NodeMap<ty::ClosureKind>)
151+
temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>)
152152
-> AdjustBorrowKind<'a, 'gcx, 'tcx> {
153153
AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds }
154154
}
@@ -211,8 +211,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
211211

212212
// If we are also inferred the closure kind here, update the
213213
// main table and process any deferred resolutions.
214-
if let Some(&kind) = self.temp_closure_kinds.get(&id) {
215-
self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind);
214+
if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) {
215+
self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context));
216216
let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
217217
debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
218218

@@ -272,6 +272,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
272272
euv::Move(_) => { }
273273
}
274274

275+
let tcx = self.fcx.tcx;
276+
275277
// watch out for a move of the deref of a borrowed pointer;
276278
// for that to be legal, the upvar would have to be borrowed
277279
// by value instead
@@ -289,7 +291,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
289291

290292
// to move out of an upvar, this must be a FnOnce closure
291293
self.adjust_closure_kind(upvar_id.closure_expr_id,
292-
ty::ClosureKind::FnOnce);
294+
ty::ClosureKind::FnOnce,
295+
guarantor.span,
296+
tcx.hir.name(upvar_id.var_id));
293297

294298
let upvar_capture_map =
295299
&mut self.fcx.tables.borrow_mut().upvar_capture_map;
@@ -303,7 +307,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
303307
// to be a FnOnce closure to permit moves out
304308
// of the environment.
305309
self.adjust_closure_kind(upvar_id.closure_expr_id,
306-
ty::ClosureKind::FnOnce);
310+
ty::ClosureKind::FnOnce,
311+
guarantor.span,
312+
tcx.hir.name(upvar_id.var_id));
307313
}
308314
mc::NoteNone => {
309315
}
@@ -331,7 +337,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
331337

332338
Categorization::Deref(base, _, mc::BorrowedPtr(..)) |
333339
Categorization::Deref(base, _, mc::Implicit(..)) => {
334-
if !self.try_adjust_upvar_deref(&cmt.note, ty::MutBorrow) {
340+
if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) {
335341
// assignment to deref of an `&mut`
336342
// borrowed pointer implies that the
337343
// pointer itself must be unique, but not
@@ -365,7 +371,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
365371

366372
Categorization::Deref(base, _, mc::BorrowedPtr(..)) |
367373
Categorization::Deref(base, _, mc::Implicit(..)) => {
368-
if !self.try_adjust_upvar_deref(&cmt.note, ty::UniqueImmBorrow) {
374+
if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) {
369375
// for a borrowed pointer to be unique, its
370376
// base must be unique
371377
self.adjust_upvar_borrow_kind_for_unique(base);
@@ -382,7 +388,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
382388
}
383389

384390
fn try_adjust_upvar_deref(&mut self,
385-
note: &mc::Note,
391+
cmt: mc::cmt<'tcx>,
386392
borrow_kind: ty::BorrowKind)
387393
-> bool
388394
{
@@ -394,7 +400,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
394400
ty::ImmBorrow => false,
395401
});
396402

397-
match *note {
403+
let tcx = self.fcx.tcx;
404+
405+
match cmt.note {
398406
mc::NoteUpvarRef(upvar_id) => {
399407
// if this is an implicit deref of an
400408
// upvar, then we need to modify the
@@ -407,15 +415,21 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
407415
}
408416

409417
// also need to be in an FnMut closure since this is not an ImmBorrow
410-
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut);
418+
self.adjust_closure_kind(upvar_id.closure_expr_id,
419+
ty::ClosureKind::FnMut,
420+
cmt.span,
421+
tcx.hir.name(upvar_id.var_id));
411422

412423
true
413424
}
414425
mc::NoteClosureEnv(upvar_id) => {
415426
// this kind of deref occurs in a `move` closure, or
416427
// for a by-value upvar; in either case, to mutate an
417428
// upvar, we need to be an FnMut closure
418-
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut);
429+
self.adjust_closure_kind(upvar_id.closure_expr_id,
430+
ty::ClosureKind::FnMut,
431+
cmt.span,
432+
tcx.hir.name(upvar_id.var_id));
419433

420434
true
421435
}
@@ -462,11 +476,13 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
462476

463477
fn adjust_closure_kind(&mut self,
464478
closure_id: ast::NodeId,
465-
new_kind: ty::ClosureKind) {
466-
debug!("adjust_closure_kind(closure_id={}, new_kind={:?})",
467-
closure_id, new_kind);
479+
new_kind: ty::ClosureKind,
480+
upvar_span: Span,
481+
var_name: ast::Name) {
482+
debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})",
483+
closure_id, new_kind, upvar_span, var_name);
468484

469-
if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) {
485+
if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) {
470486
debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
471487
closure_id, existing_kind, new_kind);
472488

@@ -482,7 +498,10 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
482498
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
483499
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
484500
// new kind is stronger than the old kind
485-
self.temp_closure_kinds.insert(closure_id, new_kind);
501+
self.temp_closure_kinds.insert(
502+
closure_id,
503+
(new_kind, Some((upvar_span, var_name)))
504+
);
486505
}
487506
}
488507
}

src/test/ui/fn_once-moved.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ fn main() {
2020
debug_dump_dict();
2121
debug_dump_dict();
2222
//~^ ERROR use of moved value: `debug_dump_dict`
23-
//~| NOTE closure was moved because it only implements `FnOnce`
23+
//~| NOTE closure cannot be invoked more than once because it moves the
24+
//~| variable `dict` out of its environment
2425
}

src/test/ui/fn_once-moved.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ error[E0382]: use of moved value: `debug_dump_dict`
66
21 | debug_dump_dict();
77
| ^^^^^^^^^^^^^^^ value used here after move
88
|
9-
= help: closure was moved because it only implements `FnOnce`
9+
note: closure cannot be invoked more than once because it moves the variable `dict` out of its environment
10+
--> $DIR/fn_once-moved.rs:16:29
11+
|
12+
16 | for (key, value) in dict {
13+
| ^^^^
1014

1115
error: aborting due to previous error(s)
1216

0 commit comments

Comments
 (0)