about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2016-05-31 18:23:22 -0700
committerEsteban Küber <esteban@kuber.com.ar>2016-06-15 18:40:11 -0700
commit1020e3036badebc56b02661666b09a62112d04ec (patch)
tree175ef1c6bf37cd3afb0704fc180c123ee66f1539
parentad5fbaf57c1f763935175cd217fedfc551d91aac (diff)
downloadrust-1020e3036badebc56b02661666b09a62112d04ec.tar.gz
rust-1020e3036badebc56b02661666b09a62112d04ec.zip
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
-rw-r--r--src/librustc_typeck/check/mod.rs71
-rw-r--r--src/test/compile-fail/issue-18819.rs1
-rw-r--r--src/test/compile-fail/issue-3044.rs1
-rw-r--r--src/test/compile-fail/issue-4935.rs1
-rw-r--r--src/test/compile-fail/method-call-err-msg.rs3
-rw-r--r--src/test/compile-fail/not-enough-arguments.rs1
-rw-r--r--src/test/compile-fail/overloaded-calls-bad.rs8
-rw-r--r--src/test/compile-fail/variadic-ffi-3.rs2
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::<Vec<String>>();
+            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<Item=bool>, 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<Item=bool>, &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