]> git.lizzy.rs Git - rust.git/commitdiff
Better error for missing tuple pattern in args (#44150)
authorsinkuu <sinkuu@sinkuu.xyz>
Fri, 6 Oct 2017 14:57:00 +0000 (23:57 +0900)
committersinkuu <sinkuu@sinkuu.xyz>
Fri, 6 Oct 2017 15:02:54 +0000 (00:02 +0900)
src/librustc/traits/error_reporting.rs
src/test/ui/mismatched_types/closure-arg-count.rs
src/test/ui/mismatched_types/closure-arg-count.stderr

index c7c8141f4f768d06e28ec8e048c11ed98c1b75e8..372f05647261feb655f05eca2dedc43706708396 100644 (file)
@@ -718,7 +718,9 @@ pub fn report_selection_error(&self,
                     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 @@ pub fn report_selection_error(&self,
                         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 @@ pub fn report_selection_error(&self,
                                                      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 @@ 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>
     {
+        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 {} 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" });
-
-        err.span_label(span, format!("expected {} that takes {} argument{}",
-                                      if is_closure { "closure" } else { "function" },
-                                      expected,
-                                      if expected == 1 { "" } else { "s" }));
+            "{} 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)
+        );
+
         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
     }
 
index f94471a73ca271f78fd1f812a0b0587cf80cd867..a2a31d44a499f11b4c23c3de4db5d37232351f0a 100644 (file)
@@ -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);
 }
index 3031a77b1e8288bf4b4c77a41a6e746defce3a27..e59a585149b897790bc1b15af86ff461442335eb 100644 (file)
@@ -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