Reorder code, fix unittests

This commit is contained in:
Esteban Küber 2017-04-23 17:54:32 -07:00
parent 366dd1bd3f
commit b52c8c2fcf
9 changed files with 192 additions and 86 deletions

View File

@ -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| { });
}
```
"##,
}
@ -1850,6 +1865,4 @@ 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
}

View File

@ -664,61 +664,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
return;
}
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" });
let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
self.tcx.hir.span_if_local(did)
});
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
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 {
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);
1
};
let found = if let ty::TyTuple(tys, _) = expected_found.found.sty {
tys.len()
} else {
1
};
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
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 {
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)
self.report_type_argument_mismatch(span,
found_span,
expected_trait_ty,
expected_trait_ref,
actual_trait_ref,
e)
}
}
@ -731,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> {

View File

@ -8,9 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn foo<F: Fn()>(x: F) { }
fn foo<F: Fn(usize)>(x: F) { }
fn main() {
foo(|y| { }); //~ ERROR E0281
//~^ ERROR E0281
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`
}

View File

@ -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`
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -9,6 +9,7 @@
// 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!());
}

View File

@ -1,43 +1,59 @@
error[E0593]: closure takes 1 parameter but 2 parameters are required here
error[E0593]: closure takes 0 arguments but 2 arguments are required
--> $DIR/closure-arg-count.rs:12:15
|
12 | [1, 2, 3].sort_by(|tuple| panic!());
| ^^^^^^^ ---------------- takes 1 parameter
12 | [1, 2, 3].sort_by(|| panic!());
| ^^^^^^^ ----------- takes 0 arguments
| |
| expected closure that takes 2 parameters
| expected closure that takes 2 arguments
error[E0593]: closure takes 1 parameter but 2 parameters are required here
error[E0593]: closure takes 0 arguments but 2 arguments are required
--> $DIR/closure-arg-count.rs:12:15
|
12 | [1, 2, 3].sort_by(|tuple| panic!());
| ^^^^^^^ ---------------- takes 1 parameter
12 | [1, 2, 3].sort_by(|| panic!());
| ^^^^^^^ ----------- takes 0 arguments
| |
| expected closure that takes 2 parameters
| 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:13:24
--> $DIR/closure-arg-count.rs:14:24
|
13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
14 | [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
error[E0593]: closure takes 1 argument but 2 arguments are required
--> $DIR/closure-arg-count.rs:14:15
|
13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
| ^^^^^^^ -------------------------- takes 1 parameter
14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
| ^^^^^^^ -------------------------- takes 1 argument
| |
| expected closure that takes 2 parameters
| expected closure that takes 2 arguments
error[E0593]: closure takes 1 parameter but 2 parameters are required here
--> $DIR/closure-arg-count.rs:13:15
error[E0593]: closure takes 1 argument but 2 arguments are required
--> $DIR/closure-arg-count.rs:14:15
|
13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
| ^^^^^^^ -------------------------- takes 1 parameter
14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
| ^^^^^^^ -------------------------- takes 1 argument
| |
| expected closure that takes 2 parameters
| expected closure that takes 2 arguments
error: aborting due to 5 previous errors
error: aborting due to 7 previous errors

View File

@ -8,11 +8,14 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.r
= 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
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(|_| ());
| ^^^ ------ expected concrete lifetime, found bound lifetime parameter
| ^^^ ------ 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`