From 1020e3036badebc56b02661666b09a62112d04ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 31 May 2016 18:23:22 -0700 Subject: [PATCH] Show types of all args when missing args When there're missing arguments in a function call, present a list of all the expected types: ```rust fn main() { t(""); } fn t(a: &str, x: String) {} ``` ```bash % rustc file.rs file.rs:3:5: 2:8 error: this function takes 2 parameters but 0 parameters were supplied [E0061] file.rs:3 t(); ^~~ file.rs:3:5: 2:8 help: run `rustc --explain E0061` to see a detailed explanation file.rs:3:5: 2:8 note: the following parameter types were expected: &str, std::string::String error: aborting due to previous error ``` Fixes #33649 --- src/librustc_typeck/check/mod.rs | 71 ++++++++++--------- src/test/compile-fail/issue-18819.rs | 1 + src/test/compile-fail/issue-3044.rs | 1 + src/test/compile-fail/issue-4935.rs | 1 + src/test/compile-fail/method-call-err-msg.rs | 3 + src/test/compile-fail/not-enough-arguments.rs | 1 + src/test/compile-fail/overloaded-calls-bad.rs | 8 ++- src/test/compile-fail/variadic-ffi-3.rs | 2 + 8 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index de45883c872..41339c3ff1d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2407,29 +2407,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut expected_arg_tys = expected_arg_tys; let expected_arg_count = fn_inputs.len(); + + fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'tcx>], + expected_count: usize, arg_count: usize, error_code: &str, + variadic: bool) { + let mut err = sess.struct_span_err_with_code(sp, + &format!("this function takes {}{} parameter{} but {} parameter{} supplied", + if variadic {"at least "} else {""}, + expected_count, + if expected_count == 1 {""} else {"s"}, + arg_count, + if arg_count == 1 {" was"} else {"s were"}), + error_code); + let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::>(); + if input_types.len() > 0 { + err.note(&format!("the following parameter type{} expected: {}", + if expected_count == 1 {" was"} else {"s were"}, + input_types.join(", "))); + } + err.emit(); + } + let formal_tys = if tuple_arguments == TupleArguments { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { + ty::TyTuple(arg_types) if arg_types.len() != args.len() => { + parameter_count_error(tcx.sess, sp, fn_inputs, arg_types.len(), args.len(), + "E0057", false); + expected_arg_tys = &[]; + self.err_args(args.len()) + } ty::TyTuple(arg_types) => { - if arg_types.len() != args.len() { - span_err!(tcx.sess, sp, E0057, - "this function takes {} parameter{} but {} parameter{} supplied", - arg_types.len(), - if arg_types.len() == 1 {""} else {"s"}, - args.len(), - if args.len() == 1 {" was"} else {"s were"}); - expected_arg_tys = &[]; - self.err_args(args.len()) - } else { - expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.sty { - ty::TyTuple(ref tys) => &tys, - _ => &[] - }, - None => &[] - }; - arg_types.to_vec() - } + expected_arg_tys = match expected_arg_tys.get(0) { + Some(&ty) => match ty.sty { + ty::TyTuple(ref tys) => &tys, + _ => &[] + }, + None => &[] + }; + arg_types.to_vec() } _ => { span_err!(tcx.sess, sp, E0059, @@ -2445,23 +2461,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if supplied_arg_count >= expected_arg_count { fn_inputs.to_vec() } else { - span_err!(tcx.sess, sp, E0060, - "this function takes at least {} parameter{} \ - but {} parameter{} supplied", - expected_arg_count, - if expected_arg_count == 1 {""} else {"s"}, - supplied_arg_count, - if supplied_arg_count == 1 {" was"} else {"s were"}); + parameter_count_error(tcx.sess, sp, fn_inputs, expected_arg_count, + supplied_arg_count, "E0060", true); expected_arg_tys = &[]; self.err_args(supplied_arg_count) } } else { - span_err!(tcx.sess, sp, E0061, - "this function takes {} parameter{} but {} parameter{} supplied", - expected_arg_count, - if expected_arg_count == 1 {""} else {"s"}, - supplied_arg_count, - if supplied_arg_count == 1 {" was"} else {"s were"}); + parameter_count_error(tcx.sess, sp, fn_inputs, expected_arg_count, supplied_arg_count, + "E0061", false); expected_arg_tys = &[]; self.err_args(supplied_arg_count) }; diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index d89b2c6ce8c..3591b982414 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -24,4 +24,5 @@ fn print_x(_: &Foo, extra: &str) { fn main() { print_x(X); //~error this function takes 2 parameters but 1 parameter was supplied + //~^ NOTE the following parameter types were expected: &Foo, &str } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index 0f7cc2cb72b..68046056fb3 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -14,6 +14,7 @@ fn main() { needlesArr.iter().fold(|x, y| { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied + //~^^^ NOTE the following parameter types were expected // // the first error is, um, non-ideal. } diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs index b37b8e237ed..438d238b6fe 100644 --- a/src/test/compile-fail/issue-4935.rs +++ b/src/test/compile-fail/issue-4935.rs @@ -12,3 +12,4 @@ fn foo(a: usize) {} fn main() { foo(5, 6) } //~ ERROR this function takes 1 parameter but 2 parameters were supplied +//~^ NOTE the following parameter type was expected diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs index 3434cf96fce..212c09364cf 100644 --- a/src/test/compile-fail/method-call-err-msg.rs +++ b/src/test/compile-fail/method-call-err-msg.rs @@ -21,10 +21,13 @@ fn main() { let x = Foo; x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied + //~^ NOTE the following parameter type was expected .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied + //~^ NOTE the following parameter types were expected let y = Foo; y.zero() .take() //~ ERROR no method named `take` found for type `Foo` in the current scope + //~^ NOTE the method `take` exists but the following trait bounds were not satisfied .one(0); } diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs index c952906e5e8..1f5a54477dd 100644 --- a/src/test/compile-fail/not-enough-arguments.rs +++ b/src/test/compile-fail/not-enough-arguments.rs @@ -19,4 +19,5 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 parameters but 3 + //~^^ NOTE the following parameter types were expected } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 77ac97bc8b8..8763fb0913a 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -36,7 +36,13 @@ fn main() { y: 3, }; let ans = s("what"); //~ ERROR mismatched types - let ans = s(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied + //~^ NOTE expected isize, found &-ptr + //~| NOTE expected type + //~| NOTE found type + let ans = s(); + //~^ ERROR this function takes 1 parameter but 0 parameters were supplied + //~| NOTE the following parameter type was expected let ans = s("burma", "shave"); //~^ ERROR this function takes 1 parameter but 2 parameters were supplied + //~| NOTE the following parameter type was expected } diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index b43159b0d96..d8620ead836 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -17,7 +17,9 @@ extern "C" fn bar(f: isize, x: u8) {} fn main() { unsafe { foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied + //~^ NOTE the following parameter types were expected foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied + //~^ NOTE the following parameter types were expected let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types