Skip to content

Commit

Permalink
Fix wrong report on closure args mismatch
Browse files Browse the repository at this point in the history
when a ref is expected but not found.

Adds new error E0622

Fixes rust-lang#42143
  • Loading branch information
Emilgardis committed Jul 7, 2017
1 parent 54fc9e4 commit 994d76d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
64 changes: 39 additions & 25 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -825,6 +820,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
err
}

fn report_closure_arg_mismatch(&self,
span: Span,
found_span: Option<Span>,
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> {
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
Original file line number Diff line number Diff line change
@@ -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 <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.

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<F>(m: F) where F: Fn(usize) {}
36 changes: 36 additions & 0 deletions src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 994d76d

Please sign in to comment.