Fix error message with non-tupled bare fn trait
This commit is contained in:
parent
40336865fe
commit
8b64988575
10 changed files with 101 additions and 38 deletions
|
@ -1750,6 +1750,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
||||||
&& let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
|
&& let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
|
||||||
&& let Some(def_id) = def_id.as_local()
|
&& let Some(def_id) = def_id.as_local()
|
||||||
|
&& terr.involves_regions()
|
||||||
{
|
{
|
||||||
let span = self.tcx.def_span(def_id);
|
let span = self.tcx.def_span(def_id);
|
||||||
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
|
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
|
||||||
|
|
|
@ -1935,6 +1935,18 @@ impl<'tcx> TypeTrace<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn poly_trait_refs(
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
|
a_is_expected: bool,
|
||||||
|
a: ty::PolyTraitRef<'tcx>,
|
||||||
|
b: ty::PolyTraitRef<'tcx>,
|
||||||
|
) -> TypeTrace<'tcx> {
|
||||||
|
TypeTrace {
|
||||||
|
cause: cause.clone(),
|
||||||
|
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn consts(
|
pub fn consts(
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
|
|
|
@ -74,6 +74,18 @@ pub enum TypeError<'tcx> {
|
||||||
TargetFeatureCast(DefId),
|
TargetFeatureCast(DefId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypeError<'_> {
|
||||||
|
pub fn involves_regions(self) -> bool {
|
||||||
|
match self {
|
||||||
|
TypeError::RegionsDoesNotOutlive(_, _)
|
||||||
|
| TypeError::RegionsInsufficientlyPolymorphic(_, _)
|
||||||
|
| TypeError::RegionsOverlyPolymorphic(_, _)
|
||||||
|
| TypeError::RegionsPlaceholderMismatch => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
|
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
|
||||||
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
|
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
|
||||||
/// afterwards to present additional details, particularly when it comes to lifetime-related
|
/// afterwards to present additional details, particularly when it comes to lifetime-related
|
||||||
|
|
|
@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::GenericParam;
|
use rustc_hir::GenericParam;
|
||||||
use rustc_hir::Item;
|
use rustc_hir::Item;
|
||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
|
use rustc_infer::infer::TypeTrace;
|
||||||
use rustc_infer::traits::TraitEngine;
|
use rustc_infer::traits::TraitEngine;
|
||||||
use rustc_middle::traits::select::OverflowError;
|
use rustc_middle::traits::select::OverflowError;
|
||||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||||
|
@ -941,9 +942,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
|
self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
|
||||||
|
|
||||||
|
let mut not_tupled = false;
|
||||||
|
|
||||||
let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
|
let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
|
||||||
ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
|
ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
|
||||||
_ => vec![ArgKind::empty()],
|
_ => {
|
||||||
|
not_tupled = true;
|
||||||
|
vec![ArgKind::empty()]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
|
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
|
||||||
|
@ -951,10 +957,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
ty::Tuple(ref tys) => {
|
ty::Tuple(ref tys) => {
|
||||||
tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
|
tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
|
||||||
}
|
}
|
||||||
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
|
_ => {
|
||||||
|
not_tupled = true;
|
||||||
|
vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if found.len() == expected.len() {
|
// If this is a `Fn` family trait and either the expected or found
|
||||||
|
// is not tupled, then fall back to just a regular mismatch error.
|
||||||
|
// This shouldn't be common unless manually implementing one of the
|
||||||
|
// traits manually, but don't make it more confusing when it does
|
||||||
|
// happen.
|
||||||
|
if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
|
||||||
|
self.report_and_explain_type_error(
|
||||||
|
TypeTrace::poly_trait_refs(
|
||||||
|
&obligation.cause,
|
||||||
|
true,
|
||||||
|
expected_trait_ref,
|
||||||
|
found_trait_ref,
|
||||||
|
),
|
||||||
|
ty::error::TypeError::Mismatch,
|
||||||
|
)
|
||||||
|
} else if found.len() == expected.len() {
|
||||||
self.report_closure_arg_mismatch(
|
self.report_closure_arg_mismatch(
|
||||||
span,
|
span,
|
||||||
found_span,
|
found_span,
|
||||||
|
|
|
@ -5,7 +5,7 @@ fn bar<F: Fn<usize>>(_: F) {}
|
||||||
fn main() {
|
fn main() {
|
||||||
fn f(_: u64) {}
|
fn f(_: u64) {}
|
||||||
foo(|_: isize| {}); //~ ERROR type mismatch
|
foo(|_: isize| {}); //~ ERROR type mismatch
|
||||||
bar(|_: isize| {}); //~ ERROR type mismatch
|
bar(|_: isize| {}); //~ ERROR mismatched types
|
||||||
foo(f); //~ ERROR type mismatch
|
foo(f); //~ ERROR type mismatch
|
||||||
bar(f); //~ ERROR type mismatch
|
bar(f); //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,16 +14,14 @@ note: required by a bound in `foo`
|
||||||
LL | fn foo<F: Fn(usize)>(_: F) {}
|
LL | fn foo<F: Fn(usize)>(_: F) {}
|
||||||
| ^^^^^^^^^ required by this bound in `foo`
|
| ^^^^^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
error[E0631]: type mismatch in closure arguments
|
error[E0308]: mismatched types
|
||||||
--> $DIR/E0631.rs:8:5
|
--> $DIR/E0631.rs:8:5
|
||||||
|
|
|
|
||||||
LL | bar(|_: isize| {});
|
LL | bar(|_: isize| {});
|
||||||
| ^^^ ---------- found signature defined here
|
| ^^^ types differ
|
||||||
| |
|
|
||||||
| expected due to this
|
|
||||||
|
|
|
|
||||||
= note: expected closure signature `fn(usize) -> _`
|
= note: expected trait `Fn<usize>`
|
||||||
found closure signature `fn(isize) -> _`
|
found trait `Fn<(isize,)>`
|
||||||
note: required by a bound in `bar`
|
note: required by a bound in `bar`
|
||||||
--> $DIR/E0631.rs:4:11
|
--> $DIR/E0631.rs:4:11
|
||||||
|
|
|
|
||||||
|
@ -49,19 +47,16 @@ note: required by a bound in `foo`
|
||||||
LL | fn foo<F: Fn(usize)>(_: F) {}
|
LL | fn foo<F: Fn(usize)>(_: F) {}
|
||||||
| ^^^^^^^^^ required by this bound in `foo`
|
| ^^^^^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
error[E0631]: type mismatch in function arguments
|
error[E0308]: mismatched types
|
||||||
--> $DIR/E0631.rs:10:9
|
--> $DIR/E0631.rs:10:9
|
||||||
|
|
|
|
||||||
LL | fn f(_: u64) {}
|
|
||||||
| ------------ found signature defined here
|
|
||||||
...
|
|
||||||
LL | bar(f);
|
LL | bar(f);
|
||||||
| --- ^ expected due to this
|
| --- ^ types differ
|
||||||
| |
|
| |
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= note: expected function signature `fn(usize) -> _`
|
= note: expected trait `Fn<usize>`
|
||||||
found function signature `fn(u64) -> _`
|
found trait `Fn<(u64,)>`
|
||||||
note: required by a bound in `bar`
|
note: required by a bound in `bar`
|
||||||
--> $DIR/E0631.rs:4:11
|
--> $DIR/E0631.rs:4:11
|
||||||
|
|
|
|
||||||
|
@ -70,4 +65,5 @@ LL | fn bar<F: Fn<usize>>(_: F) {}
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0631`.
|
Some errors have detailed explanations: E0308, E0631.
|
||||||
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -11,9 +11,9 @@ fn main() {
|
||||||
[1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!());
|
[1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!());
|
||||||
//~^ ERROR closure is expected to take
|
//~^ ERROR closure is expected to take
|
||||||
f(|| panic!());
|
f(|| panic!());
|
||||||
//~^ ERROR closure is expected to take
|
//~^ ERROR mismatched types
|
||||||
f( move || panic!());
|
f( move || panic!());
|
||||||
//~^ ERROR closure is expected to take
|
//~^ ERROR mismatched types
|
||||||
|
|
||||||
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
|
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
|
||||||
//~^ ERROR closure is expected to take
|
//~^ ERROR closure is expected to take
|
||||||
|
|
|
@ -45,41 +45,33 @@ help: change the closure to take multiple arguments instead of a single tuple
|
||||||
LL | [1, 2, 3].sort_by(|tuple, tuple2| panic!());
|
LL | [1, 2, 3].sort_by(|tuple, tuple2| panic!());
|
||||||
| ~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
|
error[E0308]: mismatched types
|
||||||
--> $DIR/closure-arg-count.rs:13:5
|
--> $DIR/closure-arg-count.rs:13:5
|
||||||
|
|
|
|
||||||
LL | f(|| panic!());
|
LL | f(|| panic!());
|
||||||
| ^ -- takes 0 arguments
|
| ^ types differ
|
||||||
| |
|
|
||||||
| expected closure that takes 1 argument
|
|
||||||
|
|
|
|
||||||
|
= note: expected trait `Fn<usize>`
|
||||||
|
found trait `Fn<()>`
|
||||||
note: required by a bound in `f`
|
note: required by a bound in `f`
|
||||||
--> $DIR/closure-arg-count.rs:3:9
|
--> $DIR/closure-arg-count.rs:3:9
|
||||||
|
|
|
|
||||||
LL | fn f<F: Fn<usize>>(_: F) {}
|
LL | fn f<F: Fn<usize>>(_: F) {}
|
||||||
| ^^^^^^^^^ required by this bound in `f`
|
| ^^^^^^^^^ required by this bound in `f`
|
||||||
help: consider changing the closure to take and ignore the expected argument
|
|
||||||
|
|
|
||||||
LL | f(|_| panic!());
|
|
||||||
| ~~~
|
|
||||||
|
|
||||||
error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
|
error[E0308]: mismatched types
|
||||||
--> $DIR/closure-arg-count.rs:15:5
|
--> $DIR/closure-arg-count.rs:15:5
|
||||||
|
|
|
|
||||||
LL | f( move || panic!());
|
LL | f( move || panic!());
|
||||||
| ^ ---------- takes 0 arguments
|
| ^ types differ
|
||||||
| |
|
|
||||||
| expected closure that takes 1 argument
|
|
||||||
|
|
|
|
||||||
|
= note: expected trait `Fn<usize>`
|
||||||
|
found trait `Fn<()>`
|
||||||
note: required by a bound in `f`
|
note: required by a bound in `f`
|
||||||
--> $DIR/closure-arg-count.rs:3:9
|
--> $DIR/closure-arg-count.rs:3:9
|
||||||
|
|
|
|
||||||
LL | fn f<F: Fn<usize>>(_: F) {}
|
LL | fn f<F: Fn<usize>>(_: F) {}
|
||||||
| ^^^^^^^^^ required by this bound in `f`
|
| ^^^^^^^^^ required by this bound in `f`
|
||||||
help: consider changing the closure to take and ignore the expected argument
|
|
||||||
|
|
|
||||||
LL | f( move |_| panic!());
|
|
||||||
| ~~~
|
|
||||||
|
|
||||||
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
|
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
|
||||||
--> $DIR/closure-arg-count.rs:18:53
|
--> $DIR/closure-arg-count.rs:18:53
|
||||||
|
@ -198,4 +190,5 @@ LL | fn call<F, R>(_: F) where F: FnOnce() -> R {}
|
||||||
|
|
||||||
error: aborting due to 14 previous errors
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0593`.
|
Some errors have detailed explanations: E0308, E0593.
|
||||||
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
8
src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
Normal file
8
src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
|
||||||
|
fn a<F: Fn<usize>>(f: F) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a(|_: usize| {});
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
17
src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
Normal file
17
src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/non-tupled-arg-mismatch.rs:6:5
|
||||||
|
|
|
||||||
|
LL | a(|_: usize| {});
|
||||||
|
| ^ types differ
|
||||||
|
|
|
||||||
|
= note: expected trait `Fn<usize>`
|
||||||
|
found trait `Fn<(usize,)>`
|
||||||
|
note: required by a bound in `a`
|
||||||
|
--> $DIR/non-tupled-arg-mismatch.rs:3:9
|
||||||
|
|
|
||||||
|
LL | fn a<F: Fn<usize>>(f: F) {}
|
||||||
|
| ^^^^^^^^^ required by this bound in `a`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue