-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Friendlier error message for closure argument type mismatch #44735
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @nikomatsakis (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
@@ -730,40 +730,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { | |||
expected_found.found, | |||
expected_trait_ty.is_closure()) | |||
} else if let &TypeError::Sorts(ref expected_found) = e { | |||
let expected = if let ty::TyTuple(tys, _) = expected_found.expected.sty { |
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.
You're still matching against the expected/found, which could lead to this bogusly triggering when one of the arguments is a tuple - when you have something like fn((u32, u32)): Fn((u32,))
.
There's no reason to do so - you have the trait-refs in expected_trait_ref
and actual_trait_ref
.
You can get the argument length of each argument in this way:
// skipping the binder is ok because we only care if this is a tuple
let arg_len = match X_trait_ref.skip_binder().substs.type_at(1) {
ty::TyTuple(ref tys) => Some(tys.len()),
_ => None
};
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.
I have a few questions. I've contributed to Rust a little, but still not sure how to write compiler code...
ty::TyTuple(args, _) => { | ||
let len = args.len(); | ||
if len == 0 { | ||
return String::from("no arguments"); |
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.
Is this code unreachable? I mean, will report_closure_arg_mismatch
be called even when one of the Fn
traits has zero arguments?
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.
Why aren't you calling report_type_argument_mismatch
?
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.
ok I see
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.
I think you won't see this error message - no arguments, no place for a type error.
if len == 1 { "" } else { "s" }, | ||
type_list_string) | ||
}, | ||
_ => panic!(), |
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.
Is it fine to use standard panic macro like panic!
or unreachable!
to signal compiler bugs? (panic!
here is a mistake, I should have used unreachable!
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.
An unreachable!()
is ok-ish for local things, but it is recommended to use bug!
or span_bug!(span, "error")
- span_bug
also displays the span of the error, which makes for easier debugging.
move |trait_ref| build_args_type_string(span, trait_ref) | ||
); | ||
err.span_label(span, format!("expected {}", found_arg_list.skip_binder())); | ||
if let Some(sp) = found_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.
You should display the "takes" even when you don't have a span - aka fn pointers:
fn foo(f: fn((u32, u32))) {
a.iter().map(f)
}
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.
I think you should add a test for each case with fn pointer - arg count mismatch, same arg count but type-error, higher-ranked error, F: Fn<u32>
bad bound.
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.
Higher-ranked test for fn pointers:
fn foo<F: Fn(*mut &u32)>(_f: F) {}
fn bar<'a>(f: fn(*mut &'a u32)) { foo(f); }
Higher-ranked test for closures: src/test/ui/mismatched_types/closure-mismatch.rs (already exists)
Just check that the error message is sane.
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.
Can I use note
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.
With respect to the span specifically, probably just something like this would be fine:
let found_span = found_span.unwrap_or(span);
i.e., if we don't have a better span, display both messages at the same place.
@tirr-c this looks awesome btw! |
Tried @arielb1's test code, and I get two errors. #![feature(unboxed_closures)]
fn main() {}
fn foo<F: Fn(*mut &u32)>(_f: F) {}
fn bar<'a>(f: fn(*mut &'a u32)) { foo(f); } (ignore
Is this okay? |
Your error message says "closure" for the function pointer. You should make it say "function" (you can use |
Other than that the error messages look sane. Just be sure to add a UI test so I can see them before giving the r+. Otherwise LGTM. |
I've removed the test |
@@ -1,25 +0,0 @@ | |||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
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.
If E0281 still exists, please write a test that reproduces it. That's the Fn<usize>
test.
@@ -7,14 +7,13 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.r | |||
= note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` | |||
= note: required by `baz` | |||
|
|||
error[E0281]: type mismatch: `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r (),)>` is required | |||
error[E0631]: type mismatch in closure arguments |
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 erases the binder. I don't like this error message.
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.
@arielb1 the expected and found signatures are in the labels now, I'm not sure if that was the case when you left this comment.
Please add the test for E0281 back - all error codes are supposed to have a test for them, and you can similarly add a test for E0631 with the name |
there's another doctest for E0281 in rust/src/librustc/diagnostics.rs Line 1141 in 1b55d19
|
r? @arielb1 |
Should pass the test, but the documentation needs to be rewritten now I think... |
now you just need to use |
|
Error message from the test for Before:
After:
|
E0281, the original error code, is totally replaced by E0631. I left E0281 in the error code index, though. |
☔ The latest upstream changes (presumably #44691) made this pull request unmergeable. Please resolve the merge conflicts. |
--> $DIR/issue-36053-2.rs:17:32 | ||
| | ||
17 | once::<&str>("str").fuse().filter(|a: &str| true).count(); | ||
| ^^^^^^ -------------- implements `for<'r> std::ops::FnMut<(&'r str,)>` | ||
| ^^^^^^ -------------- found signature of for<'r> fn(&'r str) -> _ |
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: we should enclose the signature in backticks:
+ | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
Fixes rust-lang#42143. E0281 is totally replaced by E0631. UI tests are updated accordingly.
That's cool. @bors r+ |
📌 Commit 1bfbfb2 has been approved by |
Friendlier error message for closure argument type mismatch Rebased #42270. Fixes #42143. --- `test.rs`: ```rust fn main() { foo(|_: i32, _: usize| ()); } fn foo<F>(_: F) where F: Fn(&str, usize) {} ``` Before: ``` error[E0281]: type mismatch: `[[email protected]:2:9: 2:30]` implements the trait `std::ops::Fn<(i32, usize)>`, but the trait `for<'r> std::ops::Fn<(&'r str, usize)>` is required --> test.rs:2:5 | 2 | foo(|_: i32, _: usize| ()); | ^^^ --------------------- implements `std::ops::Fn<(i32, usize)>` | | | expected &str, found i32 | requires `for<'r> std::ops::Fn<(&'r str, usize)>` | = note: required by `foo` ``` After (early): ``` error[E0631]: type mismatch in closure arguments --> test.rs:2:5 | 2 | foo(|_: i32, _: usize| ()); | ^^^ --------------------- takes arguments of type `i32` and `usize` | | | expected arguments of type `&str` and `usize` | = note: required by `foo` ``` After (current): ``` error[E0631]: type mismatch in closure arguments --> test.rs:2:5 | 2 | foo(|_: i32, _: usize| ()); | ^^^ --------------------- found signature of `fn(i32, usize) -> _` | | | expected signature of `for<'r> fn(&'r str, usize) -> _` | = note: required by `foo` ``` ~~Compiler output has been changed, and a few tests are failing. Help me writing/fixing tests!~~ r? @nikomatsakis
☀️ Test successful - status-appveyor, status-travis |
Rebased #42270.
Fixes #42143.
test.rs
:Before:
After (early):
After (current):
Compiler output has been changed, and a few tests are failing. Help me writing/fixing tests!r? @nikomatsakis