about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/diagnostics.rs2
-rw-r--r--src/librustc/traits/error_reporting.rs66
-rw-r--r--src/librustc/ty/sty.rs16
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.rs14
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.stderr43
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.rs19
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr21
7 files changed, 173 insertions, 8 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 30e9f502abc..6f9d9817a44 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1850,4 +1850,6 @@ register_diagnostics! {
     E0495, // cannot infer an appropriate lifetime due to conflicting requirements
     E0566, // conflicting representation hints
     E0587, // conflicting packed and align representation hints
+    E0593, // closure argument count mismatch
+    E0594  // closure mismatch
 }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index ba340a40692..dc7e18f8172 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -35,7 +35,7 @@ use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use std::fmt;
 use syntax::ast::{self, NodeId};
 use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar};
-use ty::error::ExpectedFound;
+use ty::error::{ExpectedFound, TypeError};
 use ty::fast_reject;
 use ty::fold::TypeFolder;
 use ty::subst::Subst;
@@ -663,13 +663,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 if actual_trait_ref.self_ty().references_error() {
                     return;
                 }
-                struct_span_err!(self.tcx.sess, span, E0281,
-                    "type mismatch: the type `{}` implements the trait `{}`, \
-                     but the trait `{}` is required ({})",
-                    expected_trait_ref.self_ty(),
-                    expected_trait_ref,
-                    actual_trait_ref,
-                    e)
+                let expected_trait_ty = expected_trait_ref.self_ty();
+                if expected_trait_ty.is_closure() {
+                    if let &TypeError::TupleSize(ref expected_found) = e {
+                        let mut err = struct_span_err!(self.tcx.sess, span, E0593,
+                            "closure takes {} parameter{} but {} parameter{} are required here",
+                            expected_found.found,
+                            if expected_found.found == 1 { "" } else { "s" },
+                            expected_found.expected,
+                            if expected_found.expected == 1 { "" } else { "s" });
+
+                        err.span_label(span, &format!("expected closure that takes {} parameter{}",
+                                                      expected_found.expected,
+                                                      if expected_found.expected == 1 {
+                                                          ""
+                                                      } else {
+                                                          "s"
+                                                      }));
+                        let closure_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
+                            self.tcx.hir.span_if_local(did)
+                        });
+                        if let Some(span) = closure_span {
+                            err.span_label(span, &format!("takes {} parameter{}",
+                                                          expected_found.found,
+                                                          if expected_found.found == 1 {
+                                                              ""
+                                                          } else {
+                                                              "s"
+                                                          }));
+                        }
+                        err
+                    } else {
+                        let mut err = struct_span_err!(self.tcx.sess, span, E0594,
+                            "closure mismatch: `{}` implements the trait `{}`, \
+                             but the trait `{}` is required",
+                            expected_trait_ty,
+                            expected_trait_ref,
+                            actual_trait_ref);
+
+                        let closure_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
+                            self.tcx.hir.span_if_local(did)
+                        });
+                        if let Some(span) = closure_span {
+                            err.span_label(span, &format!("{}", e));
+                        } else {
+                            err.note(&format!("{}", e));
+                        }
+                        err
+                    }
+                } else {
+                    struct_span_err!(self.tcx.sess, span, E0281,
+                        "type mismatch: the type `{}` implements the trait `{}`, \
+                         but the trait `{}` is required ({})",
+                        expected_trait_ty,
+                        expected_trait_ref,
+                        actual_trait_ref,
+                        e)
+                }
             }
 
             TraitNotObjectSafe(did) => {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index d5924817034..be56ac48d3e 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -68,6 +68,15 @@ pub enum BoundRegion {
     BrEnv,
 }
 
+impl BoundRegion {
+    pub fn is_named(&self) -> bool {
+        match *self {
+            BoundRegion::BrNamed(..) => true,
+            _ => false,
+        }
+    }
+}
+
 /// When a region changed from late-bound to early-bound when #32330
 /// was fixed, its `RegionParameterDef` will have one of these
 /// structures that we can use to give nicer errors.
@@ -1193,6 +1202,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
+    pub fn is_closure(&self) -> bool {
+        match self.sty {
+            TyClosure(..) => true,
+            _ => false,
+        }
+    }
+
     pub fn is_integral(&self) -> bool {
         match self.sty {
             TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs
new file mode 100644
index 00000000000..fbe36cd8fd2
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-count.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    [1, 2, 3].sort_by(|tuple| panic!());
+    [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+}
diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr
new file mode 100644
index 00000000000..f45734d675b
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-count.stderr
@@ -0,0 +1,43 @@
+error[E0593]: closure takes 1 parameter but 2 parameters are required here
+  --> $DIR/closure-arg-count.rs:12:15
+   |
+12 |     [1, 2, 3].sort_by(|tuple| panic!());
+   |               ^^^^^^^ ---------------- takes 1 parameter
+   |               |
+   |               expected closure that takes 2 parameters
+
+error[E0593]: closure takes 1 parameter but 2 parameters are required here
+  --> $DIR/closure-arg-count.rs:12:15
+   |
+12 |     [1, 2, 3].sort_by(|tuple| panic!());
+   |               ^^^^^^^ ---------------- takes 1 parameter
+   |               |
+   |               expected closure that takes 2 parameters
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-count.rs:13:24
+   |
+13 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+   |                        ^^^^^^^^^^^^^^^ expected &{integer}, found tuple
+   |
+   = note: expected type `&{integer}`
+              found type `(_, _)`
+
+error[E0593]: closure takes 1 parameter but 2 parameters are required here
+  --> $DIR/closure-arg-count.rs:13:15
+   |
+13 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+   |               ^^^^^^^ -------------------------- takes 1 parameter
+   |               |
+   |               expected closure that takes 2 parameters
+
+error[E0593]: closure takes 1 parameter but 2 parameters are required here
+  --> $DIR/closure-arg-count.rs:13:15
+   |
+13 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+   |               ^^^^^^^ -------------------------- takes 1 parameter
+   |               |
+   |               expected closure that takes 2 parameters
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs
new file mode 100644
index 00000000000..91298cb2bbd
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-mismatch.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {}
+
+impl<T: Fn(&())> Foo for T {}
+
+fn baz<T: Foo>(_: T) {}
+
+fn main() {
+    baz(|_| ());
+}
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
new file mode 100644
index 00000000000..09e31b263bc
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -0,0 +1,21 @@
+error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:18:9: 18:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
+  --> $DIR/closure-mismatch.rs:18:5
+   |
+18 |     baz(|_| ());
+   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |
+   = note: concrete lifetime that was found is lifetime '_#0r
+   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]`
+   = note: required by `baz`
+
+error[E0594]: closure mismatch: `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r (),)>` is required
+  --> $DIR/closure-mismatch.rs:18:5
+   |
+18 |     baz(|_| ());
+   |     ^^^ ------ expected concrete lifetime, found bound lifetime parameter
+   |
+   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]`
+   = note: required by `baz`
+
+error: aborting due to 2 previous errors
+