diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 035640b9710e2..54a0bf6faf85c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2027,4 +2027,5 @@ register_diagnostics! { E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints E0587, // conflicting packed and align representation hints + E0622, // type mismatch in closure arguments } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0bf0e21baaf93..51baaa89bc253 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -725,32 +725,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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()) + let mut count_mismatch = None; + if let ty::TyTuple(expected_tys, _) = expected_found.expected.sty { + if let ty::TyTuple(found_tys, _) = expected_found.found.sty { + if expected_tys.len() != found_tys.len() { + // Expected `|| { }`, found `|x, y| { }` + // Expected `fn(x) -> ()`, found `|| { }` + count_mismatch = Some(self.report_arg_count_mismatch(span, + found_span, + expected_tys.len(), + found_tys.len(), + expected_trait_ty.is_closure())); + } + } + } + if let Some(count_mismatch) = count_mismatch { + count_mismatch } else { - self.report_type_argument_mismatch(span, - found_span, - expected_trait_ty, - expected_trait_ref, - actual_trait_ref, - e) + self.report_closure_arg_mismatch(span, + found_span, + expected_trait_ref, + actual_trait_ref) } } else { self.report_type_argument_mismatch(span, @@ -825,6 +820,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } err } + + fn report_closure_arg_mismatch(&self, + span: Span, + found_span: Option, + expected_ref: ty::PolyTraitRef<'tcx>, + found: ty::PolyTraitRef<'tcx>) + -> DiagnosticBuilder<'tcx> + { + let mut err = struct_span_err!(self.tcx.sess, span, E0622, + "type mismatch in closure arguments"); + if let Some(sp) = found_span { + err.span_label(span, format!("expected closure that takes a `{}`", found)); + err.span_label(sp, format!("takes a `{}`", expected_ref)); + } else { + panic!(); + } + + err + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs new file mode 100644 index 0000000000000..d451dc086864b --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::{FnOnce, Fn}; + +pub fn main() { + let a = [(1u32,2u32)]; + let b = a.iter().map(|x: (u32, u32)| 45); + let d1 = a.iter().map(|x: &(u16,u16)| 45); + let d2 = a.iter().map(|x: (u16,u16)| 45); + foo(|y: isize| ()); +} + +fn foo(m: F) where F: Fn(usize) {} \ No newline at end of file diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr new file mode 100644 index 0000000000000..1479282ac3c11 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -0,0 +1,36 @@ +error[E0622]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:15:26 + | +15 | let b = a.iter().map(|x: (u32, u32)| 45); + | ^^^ ------------------ takes a `std::ops::FnMut<((u32, u32),)>` + | | + | expected closure that takes a `std::ops::FnMut<(&(u32, u32),)>` + +error[E0622]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:16:27 + | +16 | let d1 = a.iter().map(|x: &(u16,u16)| 45); + | ^^^ ------------------ takes a `for<'r> std::ops::FnMut<(&'r (u16, u16),)>` + | | + | expected closure that takes a `std::ops::FnMut<(&(u32, u32),)>` + +error[E0622]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:17:27 + | +17 | let d2 = a.iter().map(|x: (u16,u16)| 45); + | ^^^ ----------------- takes a `std::ops::FnMut<((u16, u16),)>` + | | + | expected closure that takes a `std::ops::FnMut<(&(u32, u32),)>` + +error[E0622]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:18:9 + | +18 | foo(|y: isize| ()); + | ^^^ ------------- takes a `std::ops::Fn<(isize,)>` + | | + | expected closure that takes a `std::ops::Fn<(usize,)>` + | + = note: required by `foo` + +error: aborting due to 4 previous errors +