Better error for missing tuple pattern in args (#44150)
This commit is contained in:
parent
3ed8b69842
commit
8782d0fe78
3 changed files with 87 additions and 27 deletions
|
|
@ -718,7 +718,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
let expected_trait_ty = expected_trait_ref.self_ty();
|
||||
let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
|
||||
|
||||
let found_did = expected_trait_ty.ty_to_def_id();
|
||||
let found_span = found_did.and_then(|did| {
|
||||
self.tcx.hir.span_if_local(did)
|
||||
});
|
||||
|
||||
|
|
@ -727,10 +729,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
ty::TyTuple(ref tys, _) => tys.len(),
|
||||
_ => 1,
|
||||
};
|
||||
let arg_ty_count =
|
||||
let (arg_tys, arg_ty_count) =
|
||||
match actual_trait_ref.skip_binder().substs.type_at(1).sty {
|
||||
ty::TyTuple(ref tys, _) => tys.len(),
|
||||
_ => 1,
|
||||
ty::TyTuple(ref tys, _) =>
|
||||
(tys.iter().map(|t| &t.sty).collect(), tys.len()),
|
||||
ref sty => (vec![sty], 1),
|
||||
};
|
||||
if self_ty_count == arg_ty_count {
|
||||
self.report_closure_arg_mismatch(span,
|
||||
|
|
@ -738,12 +741,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
expected_trait_ref,
|
||||
actual_trait_ref)
|
||||
} else {
|
||||
// Expected `|| { }`, found `|x, y| { }`
|
||||
// Expected `fn(x) -> ()`, found `|| { }`
|
||||
let arg_tuple = if arg_ty_count == 1 {
|
||||
arg_tys.first().and_then(|t| {
|
||||
if let &&ty::TyTuple(ref tuptys, _) = t {
|
||||
Some(tuptys.len())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// FIXME(#44150): Expand this to "N args expected bug a N-tuple found".
|
||||
// Type of the 1st expected argument is somehow provided as type of a
|
||||
// found one in that case.
|
||||
//
|
||||
// ```
|
||||
// [1i32, 2, 3].sort_by(|(a, b)| ..)
|
||||
// // ^^^^^^^^
|
||||
// // actual_trait_ref: std::ops::FnMut<(&i32, &i32)>
|
||||
// // expected_trait_ref: std::ops::FnMut<(&i32,)>
|
||||
// ```
|
||||
|
||||
let closure_args_span = 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
|
||||
{
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
self.report_arg_count_mismatch(
|
||||
span,
|
||||
found_span,
|
||||
closure_args_span.or(found_span),
|
||||
arg_ty_count,
|
||||
arg_tuple,
|
||||
self_ty_count,
|
||||
expected_trait_ty.is_closure()
|
||||
)
|
||||
|
|
@ -771,28 +807,42 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected: usize,
|
||||
expected_tuple: Option<usize>,
|
||||
found: usize,
|
||||
is_closure: bool)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0593,
|
||||
"{} takes {} argument{} but {} argument{} {} required",
|
||||
if is_closure { "closure" } else { "function" },
|
||||
found,
|
||||
if found == 1 { "" } else { "s" },
|
||||
expected,
|
||||
if expected == 1 { "" } else { "s" },
|
||||
if expected == 1 { "is" } else { "are" });
|
||||
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!(
|
||||
"{} argument{}",
|
||||
args,
|
||||
if args == 1 { "" } else { "s" }
|
||||
)
|
||||
};
|
||||
|
||||
let found_str = tuple_or_args(None, found);
|
||||
let expected_str = tuple_or_args(expected_tuple, expected);
|
||||
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0593,
|
||||
"{} takes {} but {} {} required",
|
||||
kind,
|
||||
found_str,
|
||||
expected_str,
|
||||
if expected_tuple.is_some() || expected == 1 { "is" } else { "are" });
|
||||
|
||||
err.span_label(
|
||||
span,
|
||||
format!("expected {} that takes {}", kind, expected_str)
|
||||
);
|
||||
|
||||
err.span_label(span, format!("expected {} that takes {} argument{}",
|
||||
if is_closure { "closure" } else { "function" },
|
||||
expected,
|
||||
if expected == 1 { "" } else { "s" }));
|
||||
if let Some(span) = found_span {
|
||||
err.span_label(span, format!("takes {} argument{}",
|
||||
found,
|
||||
if found == 1 { "" } else { "s" }));
|
||||
err.span_label(span, format!("takes {}", found_str));
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@ fn main() {
|
|||
[1, 2, 3].sort_by(|tuple| panic!());
|
||||
[1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
|
||||
f(|| panic!());
|
||||
|
||||
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ 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!());
|
||||
| ^^^^^^^ ----------- takes 0 arguments
|
||||
| ^^^^^^^ -- takes 0 arguments
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ 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!());
|
||||
| ^^^^^^^ ---------------- takes 1 argument
|
||||
| ^^^^^^^ ------- takes 1 argument
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ 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!());
|
||||
| ^^^^^^^ -------------------------- takes 1 argument
|
||||
| ^^^^^^^ ----------------- takes 1 argument
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
|
|
@ -35,11 +35,19 @@ error[E0593]: closure takes 0 arguments but 1 argument is required
|
|||
--> $DIR/closure-arg-count.rs:18:5
|
||||
|
|
||||
18 | f(|| panic!());
|
||||
| ^ ----------- takes 0 arguments
|
||||
| ^ -- takes 0 arguments
|
||||
| |
|
||||
| expected closure that takes 1 argument
|
||||
|
|
||||
= note: required by `f`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0593]: closure takes 2 arguments but a 2-tuple 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
|
||||
| |
|
||||
| expected closure that takes a 2-tuple
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue