Skip to content

Commit

Permalink
Fix ICE for mismatched args on target without span
Browse files Browse the repository at this point in the history
Commit 7ed00ca 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 removing all of the labels and suggestions related to the target
span when it's not found.

Fixes #48046
  • Loading branch information
etaoins committed Feb 7, 2018
1 parent 4f93357 commit daaa9a4
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 47 deletions.
93 changes: 49 additions & 44 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,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,
Expand Down Expand Up @@ -855,7 +857,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,
Expand Down Expand Up @@ -893,48 +895,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);
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/mismatched_types/closure-arg-count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down
12 changes: 9 additions & 3 deletions src/test/ui/mismatched_types/closure-arg-count.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

0 comments on commit daaa9a4

Please sign in to comment.