about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-05-02 09:41:39 +0000
committerbors <bors@rust-lang.org>2017-05-02 09:41:39 +0000
commit50517d58a2f43779c27478baf77f938c0b3ebba0 (patch)
tree17b4c23fd04ca5324a0f00b06a024a4ff8b264ec /src
parent33535afda497e1de8a831e8270ae8099434f662b (diff)
parentb10e2933d939a8412b1358c235f39cb87ae1a450 (diff)
downloadrust-50517d58a2f43779c27478baf77f938c0b3ebba0.tar.gz
rust-50517d58a2f43779c27478baf77f938c0b3ebba0.zip
Auto merge of #41488 - estebank:closure-args, r=arielb1
Clean up callable type mismatch errors

```rust
error[E0593]: closure takes 1 argument but 2 arguments are required here
  --> ../../src/test/ui/mismatched_types/closure-arg-count.rs:13:15
   |
13 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
   |               ^^^^^^^ -------------------------- takes 1 argument
   |               |
   |               expected closure that takes 2 arguments
```

instead of

```rust
error[E0281]: type mismatch: the type `[closure@../../src/test/ui/mismatched_types/closure-arg-count.rs:13:23: 13:49]` implements the trait `for<'r> std::ops::FnMut<(&'r {integer},)>`, but the trait `for<'r, 'r> std::ops::FnMut<(&'r {integer}, &'r {integer})>` is required (expected a tuple with 2 elements, found one with 1 elements)
  --> ../../src/test/ui/mismatched_types/closure-arg-count.rs:13:15
   |
13 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
   |               ^^^^^^^
```

Fix #21857, re #24680.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/diagnostics.rs27
-rw-r--r--src/librustc/traits/error_reporting.rs111
-rw-r--r--src/librustc/ty/error.rs12
-rw-r--r--src/librustc/ty/sty.rs16
-rw-r--r--src/test/ui/mismatched_types/E0281.rs25
-rw-r--r--src/test/ui/mismatched_types/E0281.stderr24
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.rs15
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.stderr59
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.rs (renamed from src/test/compile-fail/E0281.rs)11
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr24
-rw-r--r--src/test/ui/mismatched_types/fn-variance-1.rs (renamed from src/test/compile-fail/fn-variance-1.rs)8
-rw-r--r--src/test/ui/mismatched_types/fn-variance-1.stderr18
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.rs (renamed from src/test/compile-fail/issue-36053-2.rs)7
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr28
-rw-r--r--src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs (renamed from src/test/compile-fail/unboxed-closures-vtable-mismatch.rs)8
-rw-r--r--src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr30
16 files changed, 399 insertions, 24 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 30e9f502abc..8ef42826fac 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1049,18 +1049,19 @@ which expected that trait. This error typically occurs when working with
 `Fn`-based types. Erroneous code example:
 
 ```compile_fail,E0281
-fn foo<F: Fn()>(x: F) { }
+fn foo<F: Fn(usize)>(x: F) { }
 
 fn main() {
-    // type mismatch: the type ... implements the trait `core::ops::Fn<(_,)>`,
-    // but the trait `core::ops::Fn<()>` is required (expected (), found tuple
+    // type mismatch: ... implements the trait `core::ops::Fn<(String,)>`,
+    // but the trait `core::ops::Fn<(usize,)>` is required
     // [E0281]
-    foo(|y| { });
+    foo(|y: String| { });
 }
 ```
 
-The issue in this case is that `foo` is defined as accepting a `Fn` with no
-arguments, but the closure we attempted to pass to it requires one argument.
+The issue in this case is that `foo` is defined as accepting a `Fn` with one
+argument of type `String`, but the closure we attempted to pass to it requires
+one arguments of type `usize`.
 "##,
 
 E0282: r##"
@@ -1807,6 +1808,20 @@ makes a difference in practice.)
 [rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
 "##,
 
+E0593: r##"
+You tried to supply an `Fn`-based type with an incorrect number of arguments
+than what was expected. Erroneous code example:
+
+```compile_fail,E0593
+fn foo<F: Fn()>(x: F) { }
+
+fn main() {
+    // [E0593] closure takes 1 argument but 0 arguments are required
+    foo(|y| { });
+}
+```
+"##,
+
 }
 
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 353677f4f2b..e846d74febf 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,54 @@ 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();
+                let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
+                    self.tcx.hir.span_if_local(did)
+                });
+
+                if let &TypeError::TupleSize(ref expected_found) = e {
+                    // Expected `|x| { }`, found `|x, y| { }`
+                    self.report_arg_count_mismatch(span,
+                                                   found_span,
+                                                   expected_found.expected,
+                                                   expected_found.found,
+                                                   expected_trait_ty.is_closure())
+                } else if let &TypeError::Sorts(ref expected_found) = e {
+                    let expected = if let ty::TyTuple(tys, _) = expected_found.expected.sty {
+                        tys.len()
+                    } else {
+                        1
+                    };
+                    let found = if let ty::TyTuple(tys, _) = expected_found.found.sty {
+                        tys.len()
+                    } else {
+                        1
+                    };
+
+                    if expected != found {
+                        // Expected `|| { }`, found `|x, y| { }`
+                        // Expected `fn(x) -> ()`, found `|| { }`
+                        self.report_arg_count_mismatch(span,
+                                                       found_span,
+                                                       expected,
+                                                       found,
+                                                       expected_trait_ty.is_closure())
+                    } else {
+                        self.report_type_argument_mismatch(span,
+                                                            found_span,
+                                                            expected_trait_ty,
+                                                            expected_trait_ref,
+                                                            actual_trait_ref,
+                                                            e)
+                    }
+                } else {
+                    self.report_type_argument_mismatch(span,
+                                                        found_span,
+                                                        expected_trait_ty,
+                                                        expected_trait_ref,
+                                                        actual_trait_ref,
+                                                        e)
+                }
             }
 
             TraitNotObjectSafe(did) => {
@@ -681,6 +722,60 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.note_obligation_cause(&mut err, obligation);
         err.emit();
     }
+
+    fn report_type_argument_mismatch(&self,
+                                      span: Span,
+                                      found_span: Option<Span>,
+                                      expected_ty: Ty<'tcx>,
+                                      expected_ref: ty::PolyTraitRef<'tcx>,
+                                      found_ref: ty::PolyTraitRef<'tcx>,
+                                      type_error: &TypeError<'tcx>)
+        -> DiagnosticBuilder<'tcx>
+    {
+        let mut err = struct_span_err!(self.tcx.sess, span, E0281,
+            "type mismatch: `{}` implements the trait `{}`, but the trait `{}` is required",
+            expected_ty,
+            expected_ref,
+            found_ref);
+
+        err.span_label(span, &format!("{}", type_error));
+
+        if let Some(sp) = found_span {
+            err.span_label(span, &format!("requires `{}`", found_ref));
+            err.span_label(sp, &format!("implements `{}`", expected_ref));
+        }
+
+        err
+    }
+
+    fn report_arg_count_mismatch(&self,
+                                 span: Span,
+                                 found_span: Option<Span>,
+                                 expected: 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" });
+
+        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
+    }
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 73d9c8b00ae..e41202771cc 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -117,12 +117,16 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                 write!(f, "lifetimes do not intersect")
             }
             RegionsInsufficientlyPolymorphic(br, _, _) => {
-                write!(f, "expected bound lifetime parameter {}, \
-                           found concrete lifetime", br)
+                write!(f,
+                       "expected bound lifetime parameter{}{}, found concrete lifetime",
+                       if br.is_named() { " " } else { "" },
+                       br)
             }
             RegionsOverlyPolymorphic(br, _, _) => {
-                write!(f, "expected concrete lifetime, \
-                           found bound lifetime parameter {}", br)
+                write!(f,
+                       "expected concrete lifetime, found bound lifetime parameter{}{}",
+                       if br.is_named() { " " } else { "" },
+                       br)
             }
             Sorts(values) => ty::tls::with(|tcx| {
                 report_maybe_different(f, values.expected.sort_string(tcx),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 7857d07ed09..b82e2dc0c8d 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/E0281.rs b/src/test/ui/mismatched_types/E0281.rs
new file mode 100644
index 00000000000..abb66c99fab
--- /dev/null
+++ b/src/test/ui/mismatched_types/E0281.rs
@@ -0,0 +1,25 @@
+// Copyright 2016 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 foo<F: Fn(usize)>(x: F) { }
+
+fn main() {
+    foo(|y: String| { });
+    //~^ ERROR E0281
+    //~| ERROR E0281
+    //~| NOTE implements
+    //~| NOTE implements
+    //~| NOTE requires
+    //~| NOTE requires
+    //~| NOTE expected usize, found struct `std::string::String`
+    //~| NOTE expected usize, found struct `std::string::String`
+    //~| NOTE required by `foo`
+    //~| NOTE required by `foo`
+}
diff --git a/src/test/ui/mismatched_types/E0281.stderr b/src/test/ui/mismatched_types/E0281.stderr
new file mode 100644
index 00000000000..28a649d4c91
--- /dev/null
+++ b/src/test/ui/mismatched_types/E0281.stderr
@@ -0,0 +1,24 @@
+error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements the trait `std::ops::Fn<(std::string::String,)>`, but the trait `std::ops::Fn<(usize,)>` is required
+  --> $DIR/E0281.rs:14:5
+   |
+14 |     foo(|y: String| { });
+   |     ^^^ --------------- implements `std::ops::Fn<(std::string::String,)>`
+   |     |
+   |     requires `std::ops::Fn<(usize,)>`
+   |     expected usize, found struct `std::string::String`
+   |
+   = note: required by `foo`
+
+error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements the trait `std::ops::FnOnce<(std::string::String,)>`, but the trait `std::ops::FnOnce<(usize,)>` is required
+  --> $DIR/E0281.rs:14:5
+   |
+14 |     foo(|y: String| { });
+   |     ^^^ --------------- implements `std::ops::FnOnce<(std::string::String,)>`
+   |     |
+   |     requires `std::ops::FnOnce<(usize,)>`
+   |     expected usize, found struct `std::string::String`
+   |
+   = note: required by `foo`
+
+error: aborting due to 2 previous errors
+
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..284f82d86eb
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-count.rs
@@ -0,0 +1,15 @@
+// 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(|| panic!());
+    [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..c1b880b6162
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-count.stderr
@@ -0,0 +1,59 @@
+error[E0593]: closure takes 0 arguments but 2 arguments are required
+  --> $DIR/closure-arg-count.rs:12:15
+   |
+12 |     [1, 2, 3].sort_by(|| panic!());
+   |               ^^^^^^^ ----------- takes 0 arguments
+   |               |
+   |               expected closure that takes 2 arguments
+
+error[E0593]: closure takes 0 arguments but 2 arguments are required
+  --> $DIR/closure-arg-count.rs:12:15
+   |
+12 |     [1, 2, 3].sort_by(|| panic!());
+   |               ^^^^^^^ ----------- takes 0 arguments
+   |               |
+   |               expected closure that takes 2 arguments
+
+error[E0593]: closure takes 1 argument but 2 arguments are required
+  --> $DIR/closure-arg-count.rs:13:15
+   |
+13 |     [1, 2, 3].sort_by(|tuple| panic!());
+   |               ^^^^^^^ ---------------- takes 1 argument
+   |               |
+   |               expected closure that takes 2 arguments
+
+error[E0593]: closure takes 1 argument but 2 arguments are required
+  --> $DIR/closure-arg-count.rs:13:15
+   |
+13 |     [1, 2, 3].sort_by(|tuple| panic!());
+   |               ^^^^^^^ ---------------- takes 1 argument
+   |               |
+   |               expected closure that takes 2 arguments
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-count.rs:14:24
+   |
+14 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+   |                        ^^^^^^^^^^^^^^^ expected &{integer}, found tuple
+   |
+   = note: expected type `&{integer}`
+              found type `(_, _)`
+
+error[E0593]: closure takes 1 argument but 2 arguments are required
+  --> $DIR/closure-arg-count.rs:14:15
+   |
+14 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+   |               ^^^^^^^ -------------------------- takes 1 argument
+   |               |
+   |               expected closure that takes 2 arguments
+
+error[E0593]: closure takes 1 argument but 2 arguments are required
+  --> $DIR/closure-arg-count.rs:14:15
+   |
+14 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
+   |               ^^^^^^^ -------------------------- takes 1 argument
+   |               |
+   |               expected closure that takes 2 arguments
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/compile-fail/E0281.rs b/src/test/ui/mismatched_types/closure-mismatch.rs
index d468cd3ff1b..91298cb2bbd 100644
--- a/src/test/compile-fail/E0281.rs
+++ b/src/test/ui/mismatched_types/closure-mismatch.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,9 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn foo<F: Fn()>(x: F) { }
+trait Foo {}
+
+impl<T: Fn(&())> Foo for T {}
+
+fn baz<T: Foo>(_: T) {}
 
 fn main() {
-    foo(|y| { }); //~ ERROR E0281
-                  //~^ ERROR E0281
+    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..5b3eb593189
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -0,0 +1,24 @@
+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[E0281]: type 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(|_| ());
+   |     ^^^ ------ implements `std::ops::Fn<(_,)>`
+   |     |
+   |     requires `for<'r> std::ops::Fn<(&'r (),)>`
+   |     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
+
diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/ui/mismatched_types/fn-variance-1.rs
index d0d911b6eb9..4bea8177b7c 100644
--- a/src/test/compile-fail/fn-variance-1.rs
+++ b/src/test/ui/mismatched_types/fn-variance-1.rs
@@ -19,9 +19,13 @@ fn apply<T, F>(t: T, f: F) where F: FnOnce(T) {
 fn main() {
     apply(&3, takes_imm);
     apply(&3, takes_mut);
-    //~^ ERROR (types differ in mutability)
+    //~^ ERROR type mismatch
+    //~| NOTE types differ in mutability
+    //~| NOTE required by `apply`
 
     apply(&mut 3, takes_mut);
     apply(&mut 3, takes_imm);
-    //~^ ERROR (types differ in mutability)
+    //~^ ERROR type mismatch
+    //~| NOTE types differ in mutability
+    //~| NOTE required by `apply`
 }
diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr
new file mode 100644
index 00000000000..120fb87cdc8
--- /dev/null
+++ b/src/test/ui/mismatched_types/fn-variance-1.stderr
@@ -0,0 +1,18 @@
+error[E0281]: type mismatch: `fn(&mut isize) {takes_mut}` implements the trait `for<'r> std::ops::FnOnce<(&'r mut isize,)>`, but the trait `std::ops::FnOnce<(&{integer},)>` is required
+  --> $DIR/fn-variance-1.rs:21:5
+   |
+21 |     apply(&3, takes_mut);
+   |     ^^^^^ types differ in mutability
+   |
+   = note: required by `apply`
+
+error[E0281]: type mismatch: `fn(&isize) {takes_imm}` implements the trait `for<'r> std::ops::FnOnce<(&'r isize,)>`, but the trait `std::ops::FnOnce<(&mut {integer},)>` is required
+  --> $DIR/fn-variance-1.rs:27:5
+   |
+27 |     apply(&mut 3, takes_imm);
+   |     ^^^^^ types differ in mutability
+   |
+   = note: required by `apply`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/compile-fail/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs
index 7da529487aa..7e489621e21 100644
--- a/src/test/compile-fail/issue-36053-2.rs
+++ b/src/test/ui/mismatched_types/issue-36053-2.rs
@@ -18,4 +18,11 @@ fn main() {
     //~^ ERROR no method named `count`
     //~| ERROR E0281
     //~| ERROR E0281
+    //~| NOTE expected &str, found str
+    //~| NOTE expected &str, found str
+    //~| NOTE implements
+    //~| NOTE implements
+    //~| NOTE requires
+    //~| NOTE requires
+    //~| NOTE the method `count` exists but the following trait bounds
 }
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
new file mode 100644
index 00000000000..adc229aaacc
--- /dev/null
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -0,0 +1,28 @@
+error: no method named `count` found for type `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]>` in the current scope
+  --> $DIR/issue-36053-2.rs:17:55
+   |
+17 |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                                       ^^^^^
+   |
+   = note: the method `count` exists but the following trait bounds were not satisfied: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>`, `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator`
+
+error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnMut<(&'r str,)>`, but the trait `for<'r> std::ops::FnMut<(&'r &str,)>` is required
+  --> $DIR/issue-36053-2.rs:17:32
+   |
+17 |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- implements `for<'r> std::ops::FnMut<(&'r str,)>`
+   |                                |
+   |                                requires `for<'r> std::ops::FnMut<(&'r &str,)>`
+   |                                expected &str, found str
+
+error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnOnce<(&'r str,)>`, but the trait `for<'r> std::ops::FnOnce<(&'r &str,)>` is required
+  --> $DIR/issue-36053-2.rs:17:32
+   |
+17 |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- implements `for<'r> std::ops::FnOnce<(&'r str,)>`
+   |                                |
+   |                                requires `for<'r> std::ops::FnOnce<(&'r &str,)>`
+   |                                expected &str, found str
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
index 28e8b8db2a4..7400a27fb6b 100644
--- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
+++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
@@ -20,8 +20,16 @@ fn call_it<F:FnMut(isize,isize)->isize>(y: isize, mut f: F) -> isize {
 
 pub fn main() {
     let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
+    //~^ NOTE implements
+    //~| NOTE implements
     let z = call_it(3, f);
     //~^ ERROR type mismatch
     //~| ERROR type mismatch
+    //~| NOTE expected isize, found usize
+    //~| NOTE expected isize, found usize
+    //~| NOTE requires
+    //~| NOTE requires
+    //~| NOTE required by `call_it`
+    //~| NOTE required by `call_it`
     println!("{}", z);
 }
diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
new file mode 100644
index 00000000000..e100520e561
--- /dev/null
+++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
@@ -0,0 +1,30 @@
+error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:22:23: 22:73]` implements the trait `std::ops::FnMut<(usize, isize)>`, but the trait `std::ops::FnMut<(isize, isize)>` is required
+  --> $DIR/unboxed-closures-vtable-mismatch.rs:25:13
+   |
+22 |     let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
+   |                       -------------------------------------------------- implements `std::ops::FnMut<(usize, isize)>`
+...
+25 |     let z = call_it(3, f);
+   |             ^^^^^^^
+   |             |
+   |             requires `std::ops::FnMut<(isize, isize)>`
+   |             expected isize, found usize
+   |
+   = note: required by `call_it`
+
+error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:22:23: 22:73]` implements the trait `std::ops::FnOnce<(usize, isize)>`, but the trait `std::ops::FnOnce<(isize, isize)>` is required
+  --> $DIR/unboxed-closures-vtable-mismatch.rs:25:13
+   |
+22 |     let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
+   |                       -------------------------------------------------- implements `std::ops::FnOnce<(usize, isize)>`
+...
+25 |     let z = call_it(3, f);
+   |             ^^^^^^^
+   |             |
+   |             requires `std::ops::FnOnce<(isize, isize)>`
+   |             expected isize, found usize
+   |
+   = note: required by `call_it`
+
+error: aborting due to 2 previous errors
+