Skip to content

Commit

Permalink
Auto merge of rust-lang#42443 - tommyip:better_closure_msg, r=nikomat…
Browse files Browse the repository at this point in the history
…sakis

Better closure error message

Use tracked data introduced in rust-lang#42196 to provide a better closure
error message by showing why a closure implements `FnOnce`.

```
error[E0525]: expected a closure that implements the `Fn` trait, but
this closure only implements `FnOnce`
 --> $DIR/issue_26046.rs:4:19
  |
4 |       let closure = move || {
  |  ___________________^
5 | |         vec
6 | |     };
  | |_____^
  |
note: closure is `FnOnce` because it moves the variable `vec` out of
its environment
 --> $DIR/issue_26046.rs:5:9
  |
5 |         vec
  |         ^^^

error: aborting due to previous error(s)
```

Fixes rust-lang#26046

r? @nikomatsakis
cc @doomrobo
  • Loading branch information
bors committed Jun 8, 2017
2 parents 76eea74 + 345b833 commit f09576c
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 6 deletions.
36 changes: 32 additions & 4 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use hir::{self, intravisit, Local, Pat, Body};
use hir::intravisit::{Visitor, NestedVisitorMap};
use hir::map::NodeExpr;
use hir::def_id::DefId;
use infer::{self, InferCtxt};
use infer::{self, InferCtxt, InferTables, InferTablesRef};
use infer::type_variable::TypeVariableOrigin;
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
use std::fmt;
Expand Down Expand Up @@ -640,16 +640,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::ClosureKind(closure_def_id, kind) => {
let found_kind = self.closure_kind(closure_def_id).unwrap();
let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
let mut err = struct_span_err!(
self.tcx.sess, closure_span, E0525,
"expected a closure that implements the `{}` trait, \
but this closure only implements `{}`",
kind,
found_kind);
err.span_note(

err.span_label(
obligation.cause.span,
&format!("the requirement to implement \
`{}` derives from here", kind));
format!("the requirement to implement `{}` derives from here", kind));

let infer_tables = match self.tables {
InferTables::Interned(tables) =>
Some(InferTablesRef::Interned(tables)),
InferTables::InProgress(tables) =>
Some(InferTablesRef::InProgress(tables.borrow())),
InferTables::Missing => None,
};

// Additional context information explaining why the closure only implements
// a particular trait.
if let Some(tables) = infer_tables {
match tables.closure_kinds.get(&node_id) {
Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => {
err.span_note(span, &format!(
"closure is `FnOnce` because it moves the \
variable `{}` out of its environment", name));
},
Some(&(ty::ClosureKind::FnMut, Some((span, name)))) => {
err.span_note(span, &format!(
"closure is `FnMut` because it mutates the \
variable `{}` here", name));
},
_ => {}
}
}

err.emit();
return;
}
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/closure_context/issue-26046-fn-mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn foo() -> Box<Fn()> {
let num = 5;

let closure = || {
num += 1;
};

Box::new(closure)
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/closure_context/issue-26046-fn-mut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> $DIR/issue-26046-fn-mut.rs:14:19
|
14 | let closure = || {
| ___________________^
15 | | num += 1;
16 | | };
| |_____^
17 |
18 | Box::new(closure)
| ----------------- the requirement to implement `Fn` derives from here
|
note: closure is `FnMut` because it mutates the variable `num` here
--> $DIR/issue-26046-fn-mut.rs:15:9
|
15 | num += 1;
| ^^^

error: aborting due to previous error(s)

21 changes: 21 additions & 0 deletions src/test/ui/closure_context/issue-26046-fn-once.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn get_closure() -> Box<Fn() -> Vec<u8>> {
let vec = vec![1u8, 2u8];

let closure = move || {
vec
};

Box::new(closure)
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/closure_context/issue-26046-fn-once.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> $DIR/issue-26046-fn-once.rs:14:19
|
14 | let closure = move || {
| ___________________^
15 | | vec
16 | | };
| |_____^
17 |
18 | Box::new(closure)
| ----------------- the requirement to implement `Fn` derives from here
|
note: closure is `FnOnce` because it moves the variable `vec` out of its environment
--> $DIR/issue-26046-fn-once.rs:15:9
|
15 | vec
| ^^^

error: aborting due to previous error(s)

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0382]: use of moved value: `debug_dump_dict`
--> $DIR/fn_once-moved.rs:21:5
--> $DIR/issue-42065.rs:21:5
|
20 | debug_dump_dict();
| --------------- value moved here
21 | debug_dump_dict();
| ^^^^^^^^^^^^^^^ value used here after move
|
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
--> $DIR/issue-42065.rs:16:29
|
16 | for (key, value) in dict {
| ^^^^
Expand Down

0 comments on commit f09576c

Please sign in to comment.