about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-02-10 14:23:58 +0800
committerGitHub <noreply@github.com>2018-02-10 14:23:58 +0800
commitc04ec2c3f966f989b2d1ce80846fca5dbd00b174 (patch)
treebfd4d5ef13dae8ee135e4992ba303b794362076f
parent077979f4a284ff6d3725a6933896330692b9d468 (diff)
parentdaaa9a440ccbdcf12165165ca38eb80bdb9a6eff (diff)
downloadrust-c04ec2c3f966f989b2d1ce80846fca5dbd00b174.tar.gz
rust-c04ec2c3f966f989b2d1ce80846fca5dbd00b174.zip
Rollup merge of #48047 - etaoins:fix-ice-for-mismatched-args-on-target-without-span, r=estebank
Fix ICE for mismatched args on target without span

Commit 7ed00caacc improved our error reporting by including the target function in our error messages when there is an argument count mismatch. A simple example from the UI tests is:

```
error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 0 arguments
  --> $DIR/closure-arg-count.rs:32:53
   |
32 |     let _it = vec![1, 2, 3].into_iter().enumerate().map(foo);
   |                                                     ^^^ expected function that takes a single 2-tuple as argument
...
44 | fn foo() {}
   | -------- takes 0 arguments
```

However, this assumed the target span was always available. This does not hold true if the target function is in `std` or another crate. A simple example from #48046 is assigning `str::split` to a function type with a different number of arguments.

Fix by omitting all of the labels and suggestions related to the target span when it's not found.

Fixes #48046

r? @estebank
-rw-r--r--src/librustc/traits/error_reporting.rs93
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.rs3
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.stderr12
3 files changed, 61 insertions, 47 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index d4bcf00be80..a290839425e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -764,8 +764,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 } else {
                     let (closure_span, found) = found_did
                         .and_then(|did| self.tcx.hir.get_if_local(did))
-                        .map(|node| self.get_fn_like_arguments(node))
-                        .unwrap_or((found_span.unwrap(), found));
+                        .map(|node| {
+                            let (found_span, found) = self.get_fn_like_arguments(node);
+                            (Some(found_span), found)
+                        }).unwrap_or((found_span, found));
 
                     self.report_arg_count_mismatch(span,
                                                    closure_span,
@@ -875,7 +877,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn report_arg_count_mismatch(
         &self,
         span: Span,
-        found_span: Span,
+        found_span: Option<Span>,
         expected_args: Vec<ArgKind>,
         found_args: Vec<ArgKind>,
         is_closure: bool,
@@ -913,48 +915,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         );
 
         err.span_label(span, format!( "expected {} that takes {}", kind, expected_str));
-        err.span_label(found_span, format!("takes {}", found_str));
-
-        if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
-            if fields.len() == expected_args.len() {
-                let sugg = fields.iter()
-                    .map(|(name, _)| name.to_owned())
-                    .collect::<Vec<String>>().join(", ");
-                err.span_suggestion(found_span,
-                                    "change the closure to take multiple arguments instead of \
-                                     a single tuple",
-                                    format!("|{}|", sugg));
+
+        if let Some(found_span) = found_span {
+            err.span_label(found_span, format!("takes {}", found_str));
+
+            if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
+                if fields.len() == expected_args.len() {
+                    let sugg = fields.iter()
+                        .map(|(name, _)| name.to_owned())
+                        .collect::<Vec<String>>().join(", ");
+                    err.span_suggestion(found_span,
+                                        "change the closure to take multiple arguments instead of \
+                                         a single tuple",
+                                        format!("|{}|", sugg));
+                }
             }
-        }
-        if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
-            if fields.len() == found_args.len() && is_closure {
-                let sugg = format!(
-                    "|({}){}|",
-                    found_args.iter()
-                        .map(|arg| match arg {
-                            ArgKind::Arg(name, _) => name.to_owned(),
-                            _ => "_".to_owned(),
-                        })
-                        .collect::<Vec<String>>()
-                        .join(", "),
-                    // add type annotations if available
-                    if found_args.iter().any(|arg| match arg {
-                        ArgKind::Arg(_, ty) => ty != "_",
-                        _ => false,
-                    }) {
-                        format!(": ({})",
-                                fields.iter()
-                                    .map(|(_, ty)| ty.to_owned())
-                                    .collect::<Vec<String>>()
-                                    .join(", "))
-                    } else {
-                        "".to_owned()
-                    },
-                );
-                err.span_suggestion(found_span,
-                                    "change the closure to accept a tuple instead of individual \
-                                     arguments",
-                                    sugg);
+            if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
+                if fields.len() == found_args.len() && is_closure {
+                    let sugg = format!(
+                        "|({}){}|",
+                        found_args.iter()
+                            .map(|arg| match arg {
+                                ArgKind::Arg(name, _) => name.to_owned(),
+                                _ => "_".to_owned(),
+                            })
+                            .collect::<Vec<String>>()
+                            .join(", "),
+                        // add type annotations if available
+                        if found_args.iter().any(|arg| match arg {
+                            ArgKind::Arg(_, ty) => ty != "_",
+                            _ => false,
+                        }) {
+                            format!(": ({})",
+                                    fields.iter()
+                                        .map(|(_, ty)| ty.to_owned())
+                                        .collect::<Vec<String>>()
+                                        .join(", "))
+                        } else {
+                            "".to_owned()
+                        },
+                    );
+                    err.span_suggestion(found_span,
+                                        "change the closure to accept a tuple instead of \
+                                         individual arguments",
+                                        sugg);
+                }
             }
         }
 
diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs
index 96e5201716c..34232e81cbd 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.rs
+++ b/src/test/ui/mismatched_types/closure-arg-count.rs
@@ -36,6 +36,9 @@ fn main() {
     //~^ ERROR closure is expected to take
     let _it = vec![1, 2, 3].into_iter().enumerate().map(qux);
     //~^ ERROR function is expected to take
+
+    let _it = vec![1, 2, 3].into_iter().map(usize::checked_add);
+    //~^ ERROR function is expected to take
 }
 
 fn foo() {}
diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr
index be00ee4d74e..d2a6d6da814 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-count.stderr
@@ -90,7 +90,7 @@ error[E0593]: function is expected to take a single 2-tuple as argument, but it
 32 |     let _it = vec![1, 2, 3].into_iter().enumerate().map(foo);
    |                                                     ^^^ expected function that takes a single 2-tuple as argument
 ...
-41 | fn foo() {}
+44 | fn foo() {}
    | -------- takes 0 arguments
 
 error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments
@@ -107,8 +107,14 @@ error[E0593]: function is expected to take a single 2-tuple as argument, but it
 37 |     let _it = vec![1, 2, 3].into_iter().enumerate().map(qux);
    |                                                     ^^^ expected function that takes a single 2-tuple as argument
 ...
-42 | fn qux(x: usize, y: usize) {}
+45 | fn qux(x: usize, y: usize) {}
    | -------------------------- takes 2 distinct arguments
 
-error: aborting due to 11 previous errors
+error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
+  --> $DIR/closure-arg-count.rs:40:41
+   |
+40 |     let _it = vec![1, 2, 3].into_iter().map(usize::checked_add);
+   |                                         ^^^ expected function that takes 1 argument
+
+error: aborting due to 12 previous errors