Skip to content

Commit 8782d0f

Browse files
committed
Better error for missing tuple pattern in args (#44150)
1 parent 3ed8b69 commit 8782d0f

File tree

3 files changed

+87
-27
lines changed

3 files changed

+87
-27
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
718718
return;
719719
}
720720
let expected_trait_ty = expected_trait_ref.self_ty();
721-
let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
721+
722+
let found_did = expected_trait_ty.ty_to_def_id();
723+
let found_span = found_did.and_then(|did| {
722724
self.tcx.hir.span_if_local(did)
723725
});
724726

@@ -727,23 +729,57 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
727729
ty::TyTuple(ref tys, _) => tys.len(),
728730
_ => 1,
729731
};
730-
let arg_ty_count =
732+
let (arg_tys, arg_ty_count) =
731733
match actual_trait_ref.skip_binder().substs.type_at(1).sty {
732-
ty::TyTuple(ref tys, _) => tys.len(),
733-
_ => 1,
734+
ty::TyTuple(ref tys, _) =>
735+
(tys.iter().map(|t| &t.sty).collect(), tys.len()),
736+
ref sty => (vec![sty], 1),
734737
};
735738
if self_ty_count == arg_ty_count {
736739
self.report_closure_arg_mismatch(span,
737740
found_span,
738741
expected_trait_ref,
739742
actual_trait_ref)
740743
} else {
741-
// Expected `|| { }`, found `|x, y| { }`
742-
// Expected `fn(x) -> ()`, found `|| { }`
744+
let arg_tuple = if arg_ty_count == 1 {
745+
arg_tys.first().and_then(|t| {
746+
if let &&ty::TyTuple(ref tuptys, _) = t {
747+
Some(tuptys.len())
748+
} else {
749+
None
750+
}
751+
})
752+
} else {
753+
None
754+
};
755+
756+
// FIXME(#44150): Expand this to "N args expected bug a N-tuple found".
757+
// Type of the 1st expected argument is somehow provided as type of a
758+
// found one in that case.
759+
//
760+
// ```
761+
// [1i32, 2, 3].sort_by(|(a, b)| ..)
762+
// // ^^^^^^^^
763+
// // actual_trait_ref: std::ops::FnMut<(&i32, &i32)>
764+
// // expected_trait_ref: std::ops::FnMut<(&i32,)>
765+
// ```
766+
767+
let closure_args_span = found_did.and_then(|did| self.tcx.hir.get_if_local(did))
768+
.and_then(|node| {
769+
if let hir::map::NodeExpr(
770+
&hir::Expr { node: hir::ExprClosure(_, _, _, span, _), .. }) = node
771+
{
772+
Some(span)
773+
} else {
774+
None
775+
}
776+
});
777+
743778
self.report_arg_count_mismatch(
744779
span,
745-
found_span,
780+
closure_args_span.or(found_span),
746781
arg_ty_count,
782+
arg_tuple,
747783
self_ty_count,
748784
expected_trait_ty.is_closure()
749785
)
@@ -771,28 +807,42 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
771807
span: Span,
772808
found_span: Option<Span>,
773809
expected: usize,
810+
expected_tuple: Option<usize>,
774811
found: usize,
775812
is_closure: bool)
776813
-> DiagnosticBuilder<'tcx>
777814
{
815+
let kind = if is_closure { "closure" } else { "function" };
816+
817+
let tuple_or_args = |tuple, args| if let Some(n) = tuple {
818+
format!("a {}-tuple", n)
819+
} else {
820+
format!(
821+
"{} argument{}",
822+
args,
823+
if args == 1 { "" } else { "s" }
824+
)
825+
};
826+
827+
let found_str = tuple_or_args(None, found);
828+
let expected_str = tuple_or_args(expected_tuple, expected);
829+
778830
let mut err = struct_span_err!(self.tcx.sess, span, E0593,
779-
"{} takes {} argument{} but {} argument{} {} required",
780-
if is_closure { "closure" } else { "function" },
781-
found,
782-
if found == 1 { "" } else { "s" },
783-
expected,
784-
if expected == 1 { "" } else { "s" },
785-
if expected == 1 { "is" } else { "are" });
786-
787-
err.span_label(span, format!("expected {} that takes {} argument{}",
788-
if is_closure { "closure" } else { "function" },
789-
expected,
790-
if expected == 1 { "" } else { "s" }));
831+
"{} takes {} but {} {} required",
832+
kind,
833+
found_str,
834+
expected_str,
835+
if expected_tuple.is_some() || expected == 1 { "is" } else { "are" });
836+
837+
err.span_label(
838+
span,
839+
format!("expected {} that takes {}", kind, expected_str)
840+
);
841+
791842
if let Some(span) = found_span {
792-
err.span_label(span, format!("takes {} argument{}",
793-
found,
794-
if found == 1 { "" } else { "s" }));
843+
err.span_label(span, format!("takes {}", found_str));
795844
}
845+
796846
err
797847
}
798848

src/test/ui/mismatched_types/closure-arg-count.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ fn main() {
1616
[1, 2, 3].sort_by(|tuple| panic!());
1717
[1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
1818
f(|| panic!());
19+
20+
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
1921
}

src/test/ui/mismatched_types/closure-arg-count.stderr

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ error[E0593]: closure takes 0 arguments but 2 arguments are required
22
--> $DIR/closure-arg-count.rs:15:15
33
|
44
15 | [1, 2, 3].sort_by(|| panic!());
5-
| ^^^^^^^ ----------- takes 0 arguments
5+
| ^^^^^^^ -- takes 0 arguments
66
| |
77
| expected closure that takes 2 arguments
88

99
error[E0593]: closure takes 1 argument but 2 arguments are required
1010
--> $DIR/closure-arg-count.rs:16:15
1111
|
1212
16 | [1, 2, 3].sort_by(|tuple| panic!());
13-
| ^^^^^^^ ---------------- takes 1 argument
13+
| ^^^^^^^ ------- takes 1 argument
1414
| |
1515
| expected closure that takes 2 arguments
1616

@@ -27,19 +27,27 @@ error[E0593]: closure takes 1 argument but 2 arguments are required
2727
--> $DIR/closure-arg-count.rs:17:15
2828
|
2929
17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
30-
| ^^^^^^^ -------------------------- takes 1 argument
30+
| ^^^^^^^ ----------------- takes 1 argument
3131
| |
3232
| expected closure that takes 2 arguments
3333

3434
error[E0593]: closure takes 0 arguments but 1 argument is required
3535
--> $DIR/closure-arg-count.rs:18:5
3636
|
3737
18 | f(|| panic!());
38-
| ^ ----------- takes 0 arguments
38+
| ^ -- takes 0 arguments
3939
| |
4040
| expected closure that takes 1 argument
4141
|
4242
= note: required by `f`
4343

44-
error: aborting due to 5 previous errors
44+
error[E0593]: closure takes 2 arguments but a 2-tuple is required
45+
--> $DIR/closure-arg-count.rs:20:53
46+
|
47+
20 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
48+
| ^^^ ------ takes 2 arguments
49+
| |
50+
| expected closure that takes a 2-tuple
51+
52+
error: aborting due to 6 previous errors
4553

0 commit comments

Comments
 (0)