-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Better closure error message #42443
Better closure error message #42443
Conversation
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
c04d0a3
to
9cbb5f9
Compare
}; | ||
|
||
if let Some(tables) = infer_tables { | ||
if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = |
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.
This message is specific to FnOnce
, but similar scenarios can arise in other situations. For example, we could highlight the x += 1
here and say something like "mutating this variable":
fn foo<F: Fn()>(f: F) { }
fn main() {
let mut x = 0;
foo(|| x += 1); // Error
}
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.
Should we match more cases here or make the error more generic?
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.
Good question. I think it'd be better to match more cases, and keep the message fairly tailored -- there are really only two cases. The closure might be FnOnce
(in which case we can talk about something being moved) or it might be FnMut
(in which case we can talk about something being written to).
It now handles both FnMut and FnOnce case.
This tests the FnMut case.
Updated |
16 | | }; | ||
| |_____^ | ||
| | ||
note: closure is `FnMut` because it mutates the variable `num` here |
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.
slick
"closure is `FnMut` because it mutates the \ | ||
variable `{}` here", name)); | ||
}, | ||
_ => {} |
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.
One minor point -- in this arm, we emit neither the new note nor the old one. Seems like the old one might still be helpful?
Actually, maybe we should always emit the old note -- but instead of a note, just make it a span_label
? Seems like it's useful information either way. In other words, the old note tells you "why it has to be Fn
", and the new note tells you why it cannot be...
If you agree, maybe move the body of the else
below out and above this if
, and convert span_note
to span_label
(so that it prints within one code snippet)
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.
Good point, I didn't think about that!
For some reason
Next to diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 7375338..c8e99c0 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -648,6 +648,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
kind,
found_kind);
+ err.span_label(
+ obligation.cause.span,
+ format!("the requirement to implement `{}` derives from here", kind));
+
let infer_tables = match self.tables {
InferTables::Interned(tables) =>
Some(InferTablesRef::Interned(tables)),
@@ -656,6 +660,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
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)))) => {
@@ -670,11 +676,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
},
_ => {}
}
- } else {
- err.span_note(
- obligation.cause.span,
- &format!("the requirement to implement `{}` \
- derives from here", kind));
}
err.emit(); |
@tommyip perhaps we just always print a trailing space in that scenario? Is that really a problem? |
Er, I guess you didn't push the commits that implement that part yet? |
I'll push them now |
Pushed |
@@ -6,6 +6,9 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closur | |||
15 | | num += 1; | |||
16 | | }; | |||
| |_____^ | |||
17 | |
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.
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.
@nikomatsakis that space is to pad to compensate for the multiline markers. We can add a check for empty lines and avoid it.
@bors r+ |
📌 Commit 345b833 has been approved by |
Better closure error message Use tracked data introduced in #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 #26046 r? @nikomatsakis cc @doomrobo
☀️ Test successful - status-appveyor, status-travis |
this is really cool :) |
Use tracked data introduced in #42196 to provide a better closure
error message by showing why a closure implements
FnOnce
.Fixes #26046
r? @nikomatsakis
cc @doomrobo