Skip to content

Commit 070de4b

Browse files
authored
Rollup merge of #99942 - compiler-errors:nonsense-un-tupled-fn-trait-error, r=cjgillot
Fix nonsense non-tupled `Fn` trait error Given this code: ```rust #![feature(unboxed_closures)] fn a<F: Fn<usize>>(f: F) {} fn main() { a(|_: usize| {}); } ``` We currently emit this error: ``` error[E0631]: type mismatch in closure arguments --> src/main.rs:6:5 | 6 | a(|_: usize| {}); | ^ ---------- found signature of `fn(usize) -> _` | | | expected signature of `fn(usize) -> _` | note: required by a bound in `a` --> src/main.rs:3:9 | 3 | fn a<F: Fn<usize>>(f: F) {} | ^^^^^^^^^ required by this bound in `a` For more information about this error, try `rustc --explain E0631`. error: could not compile `playground` due to previous error ``` Notably, it says the same thing for "expected" and "found"! Fix the output so that we instead emit: ``` error[E0308]: mismatched types --> /home/gh-compiler-errors/test.rs:6:5 | 6 | a(|_: usize| {}); | ^ types differ | = note: expected trait `Fn<usize>` found trait `Fn<(usize,)>` note: required by a bound in `a` --> /home/gh-compiler-errors/test.rs:3:9 | 3 | fn a<F: Fn<usize>>(f: F) {} | ^^^^^^^^^ required by this bound in `a` error: aborting due to previous error ``` The error could still use some work, namely the "mismatched types" part, but I'm leaving it a bit rough since the only way you'd ever get this error is when you're messing with `#![feature(unboxed_closures)]`. Simply making sure we actually print out the difference in trait-refs is good enough for me. I could probably factor in some additional improvements if those are desired.
2 parents 14a459b + 1c084f1 commit 070de4b

File tree

10 files changed

+87
-13
lines changed

10 files changed

+87
-13
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17501750
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
17511751
&& let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
17521752
&& let Some(def_id) = def_id.as_local()
1753+
&& terr.involves_regions()
17531754
{
17541755
let span = self.tcx.def_span(def_id);
17551756
diag.span_note(span, "this closure does not fulfill the lifetime requirements");

compiler/rustc_infer/src/infer/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,18 @@ impl<'tcx> TypeTrace<'tcx> {
19351935
}
19361936
}
19371937

1938+
pub fn poly_trait_refs(
1939+
cause: &ObligationCause<'tcx>,
1940+
a_is_expected: bool,
1941+
a: ty::PolyTraitRef<'tcx>,
1942+
b: ty::PolyTraitRef<'tcx>,
1943+
) -> TypeTrace<'tcx> {
1944+
TypeTrace {
1945+
cause: cause.clone(),
1946+
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
1947+
}
1948+
}
1949+
19381950
pub fn consts(
19391951
cause: &ObligationCause<'tcx>,
19401952
a_is_expected: bool,

compiler/rustc_middle/src/ty/error.rs

+12
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ pub enum TypeError<'tcx> {
7474
TargetFeatureCast(DefId),
7575
}
7676

77+
impl TypeError<'_> {
78+
pub fn involves_regions(self) -> bool {
79+
match self {
80+
TypeError::RegionsDoesNotOutlive(_, _)
81+
| TypeError::RegionsInsufficientlyPolymorphic(_, _)
82+
| TypeError::RegionsOverlyPolymorphic(_, _)
83+
| TypeError::RegionsPlaceholderMismatch => true,
84+
_ => false,
85+
}
86+
}
87+
}
88+
7789
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
7890
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
7991
/// afterwards to present additional details, particularly when it comes to lifetime-related

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor;
2222
use rustc_hir::GenericParam;
2323
use rustc_hir::Item;
2424
use rustc_hir::Node;
25+
use rustc_infer::infer::TypeTrace;
2526
use rustc_infer::traits::TraitEngine;
2627
use rustc_middle::traits::select::OverflowError;
2728
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -941,20 +942,43 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
941942

942943
self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
943944

945+
let mut not_tupled = false;
946+
944947
let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
945948
ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
946-
_ => vec![ArgKind::empty()],
949+
_ => {
950+
not_tupled = true;
951+
vec![ArgKind::empty()]
952+
}
947953
};
948954

949955
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
950956
let expected = match expected_ty.kind() {
951957
ty::Tuple(ref tys) => {
952958
tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
953959
}
954-
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
960+
_ => {
961+
not_tupled = true;
962+
vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
963+
}
955964
};
956965

957-
if found.len() == expected.len() {
966+
// If this is a `Fn` family trait and either the expected or found
967+
// is not tupled, then fall back to just a regular mismatch error.
968+
// This shouldn't be common unless manually implementing one of the
969+
// traits manually, but don't make it more confusing when it does
970+
// happen.
971+
if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
972+
self.report_and_explain_type_error(
973+
TypeTrace::poly_trait_refs(
974+
&obligation.cause,
975+
true,
976+
expected_trait_ref,
977+
found_trait_ref,
978+
),
979+
ty::error::TypeError::Mismatch,
980+
)
981+
} else if found.len() == expected.len() {
958982
self.report_closure_arg_mismatch(
959983
span,
960984
found_span,

src/test/ui/mismatched_types/E0631.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![feature(unboxed_closures)]
22

33
fn foo<F: Fn(usize)>(_: F) {}
4-
fn bar<F: Fn<usize>>(_: F) {}
4+
fn bar<F: Fn<(usize,)>>(_: F) {}
55
fn main() {
66
fn f(_: u64) {}
77
foo(|_: isize| {}); //~ ERROR type mismatch

src/test/ui/mismatched_types/E0631.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ LL | bar(|_: isize| {});
2727
note: required by a bound in `bar`
2828
--> $DIR/E0631.rs:4:11
2929
|
30-
LL | fn bar<F: Fn<usize>>(_: F) {}
31-
| ^^^^^^^^^ required by this bound in `bar`
30+
LL | fn bar<F: Fn<(usize,)>>(_: F) {}
31+
| ^^^^^^^^^^^^ required by this bound in `bar`
3232

3333
error[E0631]: type mismatch in function arguments
3434
--> $DIR/E0631.rs:9:9
@@ -65,8 +65,8 @@ LL | bar(f);
6565
note: required by a bound in `bar`
6666
--> $DIR/E0631.rs:4:11
6767
|
68-
LL | fn bar<F: Fn<usize>>(_: F) {}
69-
| ^^^^^^^^^ required by this bound in `bar`
68+
LL | fn bar<F: Fn<(usize,)>>(_: F) {}
69+
| ^^^^^^^^^^^^ required by this bound in `bar`
7070

7171
error: aborting due to 4 previous errors
7272

src/test/ui/mismatched_types/closure-arg-count.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(unboxed_closures)]
22

3-
fn f<F: Fn<usize>>(_: F) {}
3+
fn f<F: Fn<(usize,)>>(_: F) {}
44
fn main() {
55
[1, 2, 3].sort_by(|| panic!());
66
//~^ ERROR closure is expected to take

src/test/ui/mismatched_types/closure-arg-count.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ LL | f(|| panic!());
5656
note: required by a bound in `f`
5757
--> $DIR/closure-arg-count.rs:3:9
5858
|
59-
LL | fn f<F: Fn<usize>>(_: F) {}
60-
| ^^^^^^^^^ required by this bound in `f`
59+
LL | fn f<F: Fn<(usize,)>>(_: F) {}
60+
| ^^^^^^^^^^^^ required by this bound in `f`
6161
help: consider changing the closure to take and ignore the expected argument
6262
|
6363
LL | f(|_| panic!());
@@ -74,8 +74,8 @@ LL | f( move || panic!());
7474
note: required by a bound in `f`
7575
--> $DIR/closure-arg-count.rs:3:9
7676
|
77-
LL | fn f<F: Fn<usize>>(_: F) {}
78-
| ^^^^^^^^^ required by this bound in `f`
77+
LL | fn f<F: Fn<(usize,)>>(_: F) {}
78+
| ^^^^^^^^^^^^ required by this bound in `f`
7979
help: consider changing the closure to take and ignore the expected argument
8080
|
8181
LL | f( move |_| panic!());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(unboxed_closures)]
2+
3+
fn a<F: Fn<usize>>(f: F) {}
4+
5+
fn main() {
6+
a(|_: usize| {});
7+
//~^ ERROR mismatched types
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/non-tupled-arg-mismatch.rs:6:5
3+
|
4+
LL | a(|_: usize| {});
5+
| ^ types differ
6+
|
7+
= note: expected trait `Fn<usize>`
8+
found trait `Fn<(usize,)>`
9+
note: required by a bound in `a`
10+
--> $DIR/non-tupled-arg-mismatch.rs:3:9
11+
|
12+
LL | fn a<F: Fn<usize>>(f: F) {}
13+
| ^^^^^^^^^ required by this bound in `a`
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)