Skip to content

Commit 1bfbfb2

Browse files
committed
Print fn signature when there is closure argument type mismatch
Fixes rust-lang#42143. E0281 is totally replaced by E0631. UI tests are updated accordingly.
1 parent 3eb19bf commit 1bfbfb2

14 files changed

+245
-119
lines changed

Diff for: src/librustc/diagnostics.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1139,11 +1139,13 @@ already specify all requirements that will be used for every type parameter.
11391139
"##,
11401140

11411141
E0281: r##"
1142+
#### Note: this error code is no longer emitted by the compiler.
1143+
11421144
You tried to supply a type which doesn't implement some trait in a location
11431145
which expected that trait. This error typically occurs when working with
11441146
`Fn`-based types. Erroneous code example:
11451147
1146-
```compile_fail,E0281
1148+
```compile-fail
11471149
fn foo<F: Fn(usize)>(x: F) { }
11481150
11491151
fn main() {
@@ -2086,5 +2088,6 @@ register_diagnostics! {
20862088
E0566, // conflicting representation hints
20872089
E0623, // lifetime mismatch where both parameters are anonymous regions
20882090
E0628, // generators cannot have explicit arguments
2091+
E0631, // type mismatch in closure arguments
20892092
E0637, // "'_" is not a valid lifetime bound
20902093
}

Diff for: src/librustc/traits/error_reporting.rs

+75-66
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
3737
use std::fmt;
3838
use syntax::ast;
3939
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
40-
use ty::error::{ExpectedFound, TypeError};
40+
use ty::error::ExpectedFound;
4141
use ty::fast_reject;
4242
use ty::fold::TypeFolder;
4343
use ty::subst::Subst;
@@ -711,7 +711,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
711711
}
712712
}
713713

714-
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
714+
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, _) => {
715715
let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref);
716716
let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref);
717717
if actual_trait_ref.self_ty().references_error() {
@@ -722,48 +722,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
722722
self.tcx.hir.span_if_local(did)
723723
});
724724

725-
if let &TypeError::TupleSize(ref expected_found) = e {
726-
// Expected `|x| { }`, found `|x, y| { }`
727-
self.report_arg_count_mismatch(span,
728-
found_span,
729-
expected_found.expected,
730-
expected_found.found,
731-
expected_trait_ty.is_closure())
732-
} else if let &TypeError::Sorts(ref expected_found) = e {
733-
let expected = if let ty::TyTuple(tys, _) = expected_found.expected.sty {
734-
tys.len()
735-
} else {
736-
1
725+
let self_ty_count =
726+
match expected_trait_ref.skip_binder().substs.type_at(1).sty {
727+
ty::TyTuple(ref tys, _) => tys.len(),
728+
_ => 1,
737729
};
738-
let found = if let ty::TyTuple(tys, _) = expected_found.found.sty {
739-
tys.len()
740-
} else {
741-
1
730+
let arg_ty_count =
731+
match actual_trait_ref.skip_binder().substs.type_at(1).sty {
732+
ty::TyTuple(ref tys, _) => tys.len(),
733+
_ => 1,
742734
};
743-
744-
if expected != found {
745-
// Expected `|| { }`, found `|x, y| { }`
746-
// Expected `fn(x) -> ()`, found `|| { }`
747-
self.report_arg_count_mismatch(span,
748-
found_span,
749-
expected,
750-
found,
751-
expected_trait_ty.is_closure())
752-
} else {
753-
self.report_type_argument_mismatch(span,
754-
found_span,
755-
expected_trait_ty,
756-
expected_trait_ref,
757-
actual_trait_ref,
758-
e)
759-
}
735+
if self_ty_count == arg_ty_count {
736+
self.report_closure_arg_mismatch(span,
737+
found_span,
738+
expected_trait_ref,
739+
actual_trait_ref)
760740
} else {
761-
self.report_type_argument_mismatch(span,
762-
found_span,
763-
expected_trait_ty,
764-
expected_trait_ref,
765-
actual_trait_ref,
766-
e)
741+
// Expected `|| { }`, found `|x, y| { }`
742+
// Expected `fn(x) -> ()`, found `|| { }`
743+
self.report_arg_count_mismatch(
744+
span,
745+
found_span,
746+
arg_ty_count,
747+
self_ty_count,
748+
expected_trait_ty.is_closure()
749+
)
767750
}
768751
}
769752

@@ -784,31 +767,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
784767
err.emit();
785768
}
786769

787-
fn report_type_argument_mismatch(&self,
788-
span: Span,
789-
found_span: Option<Span>,
790-
expected_ty: Ty<'tcx>,
791-
expected_ref: ty::PolyTraitRef<'tcx>,
792-
found_ref: ty::PolyTraitRef<'tcx>,
793-
type_error: &TypeError<'tcx>)
794-
-> DiagnosticBuilder<'tcx>
795-
{
796-
let mut err = struct_span_err!(self.tcx.sess, span, E0281,
797-
"type mismatch: `{}` implements the trait `{}`, but the trait `{}` is required",
798-
expected_ty,
799-
expected_ref,
800-
found_ref);
801-
802-
err.span_label(span, format!("{}", type_error));
803-
804-
if let Some(sp) = found_span {
805-
err.span_label(span, format!("requires `{}`", found_ref));
806-
err.span_label(sp, format!("implements `{}`", expected_ref));
807-
}
808-
809-
err
810-
}
811-
812770
fn report_arg_count_mismatch(&self,
813771
span: Span,
814772
found_span: Option<Span>,
@@ -837,6 +795,57 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
837795
}
838796
err
839797
}
798+
799+
fn report_closure_arg_mismatch(&self,
800+
span: Span,
801+
found_span: Option<Span>,
802+
expected_ref: ty::PolyTraitRef<'tcx>,
803+
found: ty::PolyTraitRef<'tcx>)
804+
-> DiagnosticBuilder<'tcx>
805+
{
806+
fn build_fn_sig_string<'a, 'gcx, 'tcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>,
807+
trait_ref: &ty::TraitRef<'tcx>) -> String {
808+
let inputs = trait_ref.substs.type_at(1);
809+
let sig = if let ty::TyTuple(inputs, _) = inputs.sty {
810+
tcx.mk_fn_sig(
811+
inputs.iter().map(|&x| x),
812+
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
813+
false,
814+
hir::Unsafety::Normal,
815+
::syntax::abi::Abi::Rust
816+
)
817+
} else {
818+
tcx.mk_fn_sig(
819+
::std::iter::once(inputs),
820+
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
821+
false,
822+
hir::Unsafety::Normal,
823+
::syntax::abi::Abi::Rust
824+
)
825+
};
826+
format!("{}", ty::Binder(sig))
827+
}
828+
829+
let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure();
830+
let mut err = struct_span_err!(self.tcx.sess, span, E0631,
831+
"type mismatch in {} arguments",
832+
if argument_is_closure { "closure" } else { "function" });
833+
834+
let found_str = format!(
835+
"expected signature of `{}`",
836+
build_fn_sig_string(self.tcx, found.skip_binder())
837+
);
838+
err.span_label(span, found_str);
839+
840+
let found_span = found_span.unwrap_or(span);
841+
let expected_str = format!(
842+
"found signature of `{}`",
843+
build_fn_sig_string(self.tcx, expected_ref.skip_binder())
844+
);
845+
err.span_label(found_span, expected_str);
846+
847+
err
848+
}
840849
}
841850

842851
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {

Diff for: src/librustc/util/ppaux.rs

+6
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,12 @@ impl<'tcx> fmt::Display for ty::Binder<ty::TraitRef<'tcx>> {
676676
}
677677
}
678678

679+
impl<'tcx> fmt::Display for ty::Binder<ty::FnSig<'tcx>> {
680+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
681+
ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
682+
}
683+
}
684+
679685
impl<'tcx> fmt::Display for ty::Binder<ty::TraitPredicate<'tcx>> {
680686
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
681687
ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))

Diff for: src/test/ui/mismatched_types/E0281.stderr

-13
This file was deleted.

Diff for: src/test/ui/mismatched_types/E0281.rs renamed to src/test/ui/mismatched_types/E0631.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
fn foo<F: Fn(usize)>(x: F) { }
11+
#![feature(unboxed_closures)]
1212

13+
fn foo<F: Fn(usize)>(_: F) {}
14+
fn bar<F: Fn<usize>>(_: F) {}
1315
fn main() {
14-
foo(|y: String| { });
15-
//~^ ERROR E0281
16-
//~| ERROR E0281
17-
//~| NOTE implements
18-
//~| NOTE implements
19-
//~| NOTE requires
20-
//~| NOTE requires
21-
//~| NOTE expected usize, found struct `std::string::String`
22-
//~| NOTE expected usize, found struct `std::string::String`
23-
//~| NOTE required by `foo`
24-
//~| NOTE required by `foo`
16+
fn f(_: u64) {}
17+
foo(|_: isize| {});
18+
bar(|_: isize| {});
19+
foo(f);
20+
bar(f);
2521
}

Diff for: src/test/ui/mismatched_types/E0631.stderr

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error[E0631]: type mismatch in closure arguments
2+
--> $DIR/E0631.rs:17:5
3+
|
4+
17 | foo(|_: isize| {});
5+
| ^^^ ------------- found signature of `fn(isize) -> _`
6+
| |
7+
| expected signature of `fn(usize) -> _`
8+
|
9+
= note: required by `foo`
10+
11+
error[E0631]: type mismatch in closure arguments
12+
--> $DIR/E0631.rs:18:5
13+
|
14+
18 | bar(|_: isize| {});
15+
| ^^^ ------------- found signature of `fn(isize) -> _`
16+
| |
17+
| expected signature of `fn(usize) -> _`
18+
|
19+
= note: required by `bar`
20+
21+
error[E0631]: type mismatch in function arguments
22+
--> $DIR/E0631.rs:19:5
23+
|
24+
19 | foo(f);
25+
| ^^^
26+
| |
27+
| expected signature of `fn(usize) -> _`
28+
| found signature of `fn(u64) -> _`
29+
|
30+
= note: required by `foo`
31+
32+
error[E0631]: type mismatch in function arguments
33+
--> $DIR/E0631.rs:20:5
34+
|
35+
20 | bar(f);
36+
| ^^^
37+
| |
38+
| expected signature of `fn(usize) -> _`
39+
| found signature of `fn(u64) -> _`
40+
|
41+
= note: required by `bar`
42+
43+
error: aborting due to 4 previous errors
44+

Diff for: src/test/ui/mismatched_types/closure-arg-count.rs

+4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(unboxed_closures)]
12+
13+
fn f<F: Fn<usize>>(_: F) {}
1114
fn main() {
1215
[1, 2, 3].sort_by(|| panic!());
1316
[1, 2, 3].sort_by(|tuple| panic!());
1417
[1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
18+
f(|| panic!());
1519
}
+19-9
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,45 @@
11
error[E0593]: closure takes 0 arguments but 2 arguments are required
2-
--> $DIR/closure-arg-count.rs:12:15
2+
--> $DIR/closure-arg-count.rs:15:15
33
|
4-
12 | [1, 2, 3].sort_by(|| panic!());
4+
15 | [1, 2, 3].sort_by(|| panic!());
55
| ^^^^^^^ ----------- takes 0 arguments
66
| |
77
| expected closure that takes 2 arguments
88

99
error[E0593]: closure takes 1 argument but 2 arguments are required
10-
--> $DIR/closure-arg-count.rs:13:15
10+
--> $DIR/closure-arg-count.rs:16:15
1111
|
12-
13 | [1, 2, 3].sort_by(|tuple| panic!());
12+
16 | [1, 2, 3].sort_by(|tuple| panic!());
1313
| ^^^^^^^ ---------------- takes 1 argument
1414
| |
1515
| expected closure that takes 2 arguments
1616

1717
error[E0308]: mismatched types
18-
--> $DIR/closure-arg-count.rs:14:24
18+
--> $DIR/closure-arg-count.rs:17:24
1919
|
20-
14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
20+
17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
2121
| ^^^^^^^^^^^^^^^ expected &{integer}, found tuple
2222
|
2323
= note: expected type `&{integer}`
2424
found type `(_, _)`
2525

2626
error[E0593]: closure takes 1 argument but 2 arguments are required
27-
--> $DIR/closure-arg-count.rs:14:15
27+
--> $DIR/closure-arg-count.rs:17:15
2828
|
29-
14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
29+
17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
3030
| ^^^^^^^ -------------------------- takes 1 argument
3131
| |
3232
| expected closure that takes 2 arguments
3333

34-
error: aborting due to 4 previous errors
34+
error[E0593]: closure takes 0 arguments but 1 argument is required
35+
--> $DIR/closure-arg-count.rs:18:5
36+
|
37+
18 | f(|| panic!());
38+
| ^ ----------- takes 0 arguments
39+
| |
40+
| expected closure that takes 1 argument
41+
|
42+
= note: required by `f`
43+
44+
error: aborting due to 5 previous errors
3545

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let a = [(1u32, 2u32)];
13+
a.iter().map(|_: (u32, u32)| 45);
14+
a.iter().map(|_: &(u16, u16)| 45);
15+
a.iter().map(|_: (u16, u16)| 45);
16+
}
17+
18+
fn baz<F: Fn(*mut &u32)>(_: F) {}
19+
fn _test<'a>(f: fn(*mut &'a u32)) {
20+
baz(f);
21+
}

0 commit comments

Comments
 (0)