Add suggestion
This commit is contained in:
parent
b6eef82c68
commit
c74bda1075
3 changed files with 126 additions and 39 deletions
|
|
@ -764,23 +764,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// // found_trait_ref: std::ops::FnMut<(&i32,)>
|
||||
// ```
|
||||
|
||||
let closure_args_span = found_did.and_then(|did| self.tcx.hir.get_if_local(did))
|
||||
let (closure_span, closure_args) = found_did
|
||||
.and_then(|did| self.tcx.hir.get_if_local(did))
|
||||
.and_then(|node| {
|
||||
if let hir::map::NodeExpr(
|
||||
&hir::Expr { node: hir::ExprClosure(_, _, _, span, _), .. }) = node
|
||||
&hir::Expr {
|
||||
node: hir::ExprClosure(_, ref decl, id, span, _),
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
Some(span)
|
||||
let ty_snips = decl.inputs.iter()
|
||||
.map(|ty| {
|
||||
self.tcx.sess.codemap().span_to_snippet(ty.span).ok()
|
||||
.and_then(|snip| {
|
||||
// filter out dummy spans
|
||||
if snip == "," || snip == "|" {
|
||||
None
|
||||
} else {
|
||||
Some(snip)
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<Vec<Option<String>>>();
|
||||
|
||||
let body = self.tcx.hir.body(id);
|
||||
let pat_snips = body.arguments.iter()
|
||||
.map(|arg|
|
||||
self.tcx.sess.codemap().span_to_snippet(arg.pat.span).ok())
|
||||
.collect::<Option<Vec<String>>>();
|
||||
|
||||
Some((span, pat_snips, ty_snips))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
})
|
||||
.map(|(span, pat, ty)| (Some(span), Some((pat, ty))))
|
||||
.unwrap_or((None, None));
|
||||
let closure_args = closure_args.and_then(|(pat, ty)| Some((pat?, ty)));
|
||||
|
||||
self.report_arg_count_mismatch(
|
||||
span,
|
||||
closure_args_span.or(found_span),
|
||||
closure_span.or(found_span),
|
||||
expected_ty_count,
|
||||
expected_tuple,
|
||||
found_ty_count,
|
||||
closure_args,
|
||||
found_trait_ty.is_closure()
|
||||
)
|
||||
}
|
||||
|
|
@ -803,44 +831,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
err.emit();
|
||||
}
|
||||
|
||||
fn report_arg_count_mismatch(&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected: usize,
|
||||
expected_tuple: Option<usize>,
|
||||
found: usize,
|
||||
is_closure: bool)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
fn report_arg_count_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected: usize,
|
||||
expected_tuple: Option<usize>,
|
||||
found: usize,
|
||||
closure_args: Option<(Vec<String>, Vec<Option<String>>)>,
|
||||
is_closure: bool
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
use std::borrow::Cow;
|
||||
|
||||
let kind = if is_closure { "closure" } else { "function" };
|
||||
|
||||
let tuple_or_args = |tuple, args| if let Some(n) = tuple {
|
||||
format!("a {}-tuple", n)
|
||||
} else {
|
||||
format!(
|
||||
let args_str = |n| format!(
|
||||
"{} argument{}",
|
||||
args,
|
||||
if args == 1 { "" } else { "s" }
|
||||
)
|
||||
};
|
||||
|
||||
let found_str = tuple_or_args(None, found);
|
||||
let expected_str = tuple_or_args(expected_tuple, expected);
|
||||
n,
|
||||
if n == 1 { "" } else { "s" }
|
||||
);
|
||||
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0593,
|
||||
"{} takes {} but {} {} required",
|
||||
"{} takes {}, but {} {} required",
|
||||
kind,
|
||||
found_str,
|
||||
expected_str,
|
||||
if expected_tuple.is_some() || expected == 1 { "is" } else { "are" });
|
||||
if expected_tuple.is_some() {
|
||||
Cow::from("multiple arguments")
|
||||
} else {
|
||||
Cow::from(args_str(found))
|
||||
},
|
||||
if expected_tuple.is_some() {
|
||||
Cow::from("a tuple argument")
|
||||
} else {
|
||||
Cow::from(args_str(expected))
|
||||
},
|
||||
if expected == 1 { "is" } else { "are" });
|
||||
|
||||
err.span_label(
|
||||
span,
|
||||
format!("expected {} that takes {}", kind, expected_str)
|
||||
format!(
|
||||
"expected {} that takes {}{}",
|
||||
kind,
|
||||
args_str(expected),
|
||||
if let Some(n) = expected_tuple {
|
||||
assert!(expected == 1);
|
||||
Cow::from(format!(", a {}-tuple", n))
|
||||
} else {
|
||||
Cow::from("")
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
if let Some(span) = found_span {
|
||||
err.span_label(span, format!("takes {}", found_str));
|
||||
if let (Some(expected_tuple), Some((pats, tys))) = (expected_tuple, closure_args) {
|
||||
if expected_tuple != found || pats.len() != found {
|
||||
err.span_label(span, format!("takes {}", args_str(found)));
|
||||
} else {
|
||||
let sugg = format!(
|
||||
"|({}){}|",
|
||||
pats.join(", "),
|
||||
|
||||
// add type annotations if available
|
||||
if tys.iter().any(|ty| ty.is_some()) {
|
||||
Cow::from(format!(
|
||||
": ({})",
|
||||
tys.into_iter().map(|ty| if let Some(ty) = ty {
|
||||
ty
|
||||
} else {
|
||||
"_".to_string()
|
||||
}).collect::<Vec<String>>().join(", ")
|
||||
))
|
||||
} else {
|
||||
Cow::from("")
|
||||
},
|
||||
);
|
||||
|
||||
err.span_suggestion(span, "consider changing to", sugg);
|
||||
}
|
||||
} else {
|
||||
err.span_label(span, format!("takes {}", args_str(found)));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
|
|
|
|||
|
|
@ -18,4 +18,6 @@ fn main() {
|
|||
f(|| panic!());
|
||||
|
||||
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
|
||||
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
|
||||
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error[E0593]: closure takes 0 arguments but 2 arguments are required
|
||||
error[E0593]: closure takes 0 arguments, but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:15:15
|
||||
|
|
||||
15 | [1, 2, 3].sort_by(|| panic!());
|
||||
|
|
@ -6,7 +6,7 @@ error[E0593]: closure takes 0 arguments but 2 arguments are required
|
|||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error[E0593]: closure takes 1 argument but 2 arguments are required
|
||||
error[E0593]: closure takes 1 argument, but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:16:15
|
||||
|
|
||||
16 | [1, 2, 3].sort_by(|tuple| panic!());
|
||||
|
|
@ -23,7 +23,7 @@ error[E0308]: mismatched types
|
|||
= note: expected type `&{integer}`
|
||||
found type `(_, _)`
|
||||
|
||||
error[E0593]: closure takes 1 argument but 2 arguments are required
|
||||
error[E0593]: closure takes 1 argument, but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:17:15
|
||||
|
|
||||
17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
|
||||
|
|
@ -31,7 +31,7 @@ error[E0593]: closure takes 1 argument but 2 arguments are required
|
|||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error[E0593]: closure takes 0 arguments but 1 argument is required
|
||||
error[E0593]: closure takes 0 arguments, but 1 argument is required
|
||||
--> $DIR/closure-arg-count.rs:18:5
|
||||
|
|
||||
18 | f(|| panic!());
|
||||
|
|
@ -41,13 +41,29 @@ error[E0593]: closure takes 0 arguments but 1 argument is required
|
|||
|
|
||||
= note: required by `f`
|
||||
|
||||
error[E0593]: closure takes 2 arguments but a 2-tuple is required
|
||||
error[E0593]: closure takes multiple arguments, but a tuple argument is required
|
||||
--> $DIR/closure-arg-count.rs:20:53
|
||||
|
|
||||
20 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
|
||||
| ^^^ ------ takes 2 arguments
|
||||
| ^^^ ------ help: consider changing to: `|(i, x)|`
|
||||
| |
|
||||
| expected closure that takes a 2-tuple
|
||||
| expected closure that takes 1 argument, a 2-tuple
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error[E0593]: closure takes multiple arguments, but a tuple argument is required
|
||||
--> $DIR/closure-arg-count.rs:21:53
|
||||
|
|
||||
21 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
|
||||
| ^^^ ------------- help: consider changing to: `|(i, x): (usize, _)|`
|
||||
| |
|
||||
| expected closure that takes 1 argument, a 2-tuple
|
||||
|
||||
error[E0593]: closure takes multiple arguments, but a tuple argument is required
|
||||
--> $DIR/closure-arg-count.rs:22:53
|
||||
|
|
||||
22 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
|
||||
| ^^^ --------- takes 3 arguments
|
||||
| |
|
||||
| expected closure that takes 1 argument, a 2-tuple
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue