Skip to content

Commit c74bda1

Browse files
committed
Add suggestion
1 parent b6eef82 commit c74bda1

File tree

3 files changed

+126
-39
lines changed

3 files changed

+126
-39
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 100 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -764,23 +764,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
764764
// // found_trait_ref: std::ops::FnMut<(&i32,)>
765765
// ```
766766

767-
let closure_args_span = found_did.and_then(|did| self.tcx.hir.get_if_local(did))
767+
let (closure_span, closure_args) = found_did
768+
.and_then(|did| self.tcx.hir.get_if_local(did))
768769
.and_then(|node| {
769770
if let hir::map::NodeExpr(
770-
&hir::Expr { node: hir::ExprClosure(_, _, _, span, _), .. }) = node
771+
&hir::Expr {
772+
node: hir::ExprClosure(_, ref decl, id, span, _),
773+
..
774+
}) = node
771775
{
772-
Some(span)
776+
let ty_snips = decl.inputs.iter()
777+
.map(|ty| {
778+
self.tcx.sess.codemap().span_to_snippet(ty.span).ok()
779+
.and_then(|snip| {
780+
// filter out dummy spans
781+
if snip == "," || snip == "|" {
782+
None
783+
} else {
784+
Some(snip)
785+
}
786+
})
787+
})
788+
.collect::<Vec<Option<String>>>();
789+
790+
let body = self.tcx.hir.body(id);
791+
let pat_snips = body.arguments.iter()
792+
.map(|arg|
793+
self.tcx.sess.codemap().span_to_snippet(arg.pat.span).ok())
794+
.collect::<Option<Vec<String>>>();
795+
796+
Some((span, pat_snips, ty_snips))
773797
} else {
774798
None
775799
}
776-
});
800+
})
801+
.map(|(span, pat, ty)| (Some(span), Some((pat, ty))))
802+
.unwrap_or((None, None));
803+
let closure_args = closure_args.and_then(|(pat, ty)| Some((pat?, ty)));
777804

778805
self.report_arg_count_mismatch(
779806
span,
780-
closure_args_span.or(found_span),
807+
closure_span.or(found_span),
781808
expected_ty_count,
782809
expected_tuple,
783810
found_ty_count,
811+
closure_args,
784812
found_trait_ty.is_closure()
785813
)
786814
}
@@ -803,44 +831,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
803831
err.emit();
804832
}
805833

806-
fn report_arg_count_mismatch(&self,
807-
span: Span,
808-
found_span: Option<Span>,
809-
expected: usize,
810-
expected_tuple: Option<usize>,
811-
found: usize,
812-
is_closure: bool)
813-
-> DiagnosticBuilder<'tcx>
814-
{
834+
fn report_arg_count_mismatch(
835+
&self,
836+
span: Span,
837+
found_span: Option<Span>,
838+
expected: usize,
839+
expected_tuple: Option<usize>,
840+
found: usize,
841+
closure_args: Option<(Vec<String>, Vec<Option<String>>)>,
842+
is_closure: bool
843+
) -> DiagnosticBuilder<'tcx> {
844+
use std::borrow::Cow;
845+
815846
let kind = if is_closure { "closure" } else { "function" };
816847

817-
let tuple_or_args = |tuple, args| if let Some(n) = tuple {
818-
format!("a {}-tuple", n)
819-
} else {
820-
format!(
848+
let args_str = |n| format!(
821849
"{} 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);
850+
n,
851+
if n == 1 { "" } else { "s" }
852+
);
829853

830854
let mut err = struct_span_err!(self.tcx.sess, span, E0593,
831-
"{} takes {} but {} {} required",
855+
"{} takes {}, but {} {} required",
832856
kind,
833-
found_str,
834-
expected_str,
835-
if expected_tuple.is_some() || expected == 1 { "is" } else { "are" });
857+
if expected_tuple.is_some() {
858+
Cow::from("multiple arguments")
859+
} else {
860+
Cow::from(args_str(found))
861+
},
862+
if expected_tuple.is_some() {
863+
Cow::from("a tuple argument")
864+
} else {
865+
Cow::from(args_str(expected))
866+
},
867+
if expected == 1 { "is" } else { "are" });
836868

837869
err.span_label(
838870
span,
839-
format!("expected {} that takes {}", kind, expected_str)
871+
format!(
872+
"expected {} that takes {}{}",
873+
kind,
874+
args_str(expected),
875+
if let Some(n) = expected_tuple {
876+
assert!(expected == 1);
877+
Cow::from(format!(", a {}-tuple", n))
878+
} else {
879+
Cow::from("")
880+
}
881+
)
840882
);
841883

842884
if let Some(span) = found_span {
843-
err.span_label(span, format!("takes {}", found_str));
885+
if let (Some(expected_tuple), Some((pats, tys))) = (expected_tuple, closure_args) {
886+
if expected_tuple != found || pats.len() != found {
887+
err.span_label(span, format!("takes {}", args_str(found)));
888+
} else {
889+
let sugg = format!(
890+
"|({}){}|",
891+
pats.join(", "),
892+
893+
// add type annotations if available
894+
if tys.iter().any(|ty| ty.is_some()) {
895+
Cow::from(format!(
896+
": ({})",
897+
tys.into_iter().map(|ty| if let Some(ty) = ty {
898+
ty
899+
} else {
900+
"_".to_string()
901+
}).collect::<Vec<String>>().join(", ")
902+
))
903+
} else {
904+
Cow::from("")
905+
},
906+
);
907+
908+
err.span_suggestion(span, "consider changing to", sugg);
909+
}
910+
} else {
911+
err.span_label(span, format!("takes {}", args_str(found)));
912+
}
844913
}
845914

846915
err

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ fn main() {
1818
f(|| panic!());
1919

2020
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
21+
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
22+
let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
2123
}

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error[E0593]: closure takes 0 arguments but 2 arguments are required
1+
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!());
55
| ^^^^^^^ -- takes 0 arguments
66
| |
77
| expected closure that takes 2 arguments
88

9-
error[E0593]: closure takes 1 argument but 2 arguments are required
9+
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!());
@@ -23,15 +23,15 @@ error[E0308]: mismatched types
2323
= note: expected type `&{integer}`
2424
found type `(_, _)`
2525

26-
error[E0593]: closure takes 1 argument but 2 arguments are required
26+
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!());
3030
| ^^^^^^^ ----------------- takes 1 argument
3131
| |
3232
| expected closure that takes 2 arguments
3333

34-
error[E0593]: closure takes 0 arguments but 1 argument is required
34+
error[E0593]: closure takes 0 arguments, but 1 argument is required
3535
--> $DIR/closure-arg-count.rs:18:5
3636
|
3737
18 | f(|| panic!());
@@ -41,13 +41,29 @@ error[E0593]: closure takes 0 arguments but 1 argument is required
4141
|
4242
= note: required by `f`
4343

44-
error[E0593]: closure takes 2 arguments but a 2-tuple is required
44+
error[E0593]: closure takes multiple arguments, but a tuple argument is required
4545
--> $DIR/closure-arg-count.rs:20:53
4646
|
4747
20 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
48-
| ^^^ ------ takes 2 arguments
48+
| ^^^ ------ help: consider changing to: `|(i, x)|`
4949
| |
50-
| expected closure that takes a 2-tuple
50+
| expected closure that takes 1 argument, a 2-tuple
5151

52-
error: aborting due to 6 previous errors
52+
error[E0593]: closure takes multiple arguments, but a tuple argument is required
53+
--> $DIR/closure-arg-count.rs:21:53
54+
|
55+
21 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
56+
| ^^^ ------------- help: consider changing to: `|(i, x): (usize, _)|`
57+
| |
58+
| expected closure that takes 1 argument, a 2-tuple
59+
60+
error[E0593]: closure takes multiple arguments, but a tuple argument is required
61+
--> $DIR/closure-arg-count.rs:22:53
62+
|
63+
22 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
64+
| ^^^ --------- takes 3 arguments
65+
| |
66+
| expected closure that takes 1 argument, a 2-tuple
67+
68+
error: aborting due to 8 previous errors
5369

0 commit comments

Comments
 (0)