diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 6e0f49bba90..0b0c1bba387 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1139,11 +1139,13 @@ already specify all requirements that will be used for every type parameter. "##, E0281: r##" +#### Note: this error code is no longer emitted by the compiler. + You tried to supply a type which doesn't implement some trait in a location which expected that trait. This error typically occurs when working with `Fn`-based types. Erroneous code example: -```compile_fail,E0281 +```compile-fail fn foo(x: F) { } fn main() { @@ -2086,5 +2088,6 @@ register_diagnostics! { E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions E0628, // generators cannot have explicit arguments + E0631, // type mismatch in closure arguments E0637, // "'_" is not a valid lifetime bound } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b491baadd7c..c7c8141f4f7 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -37,7 +37,7 @@ use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use ty::error::{ExpectedFound, TypeError}; +use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; @@ -711,7 +711,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { + OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, _) => { let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref); let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref); if actual_trait_ref.self_ty().references_error() { @@ -722,48 +722,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 self_ty_count = + match expected_trait_ref.skip_binder().substs.type_at(1).sty { + ty::TyTuple(ref tys, _) => tys.len(), + _ => 1, }; - let found = if let ty::TyTuple(tys, _) = expected_found.found.sty { - tys.len() - } else { - 1 + let arg_ty_count = + match actual_trait_ref.skip_binder().substs.type_at(1).sty { + ty::TyTuple(ref tys, _) => tys.len(), + _ => 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) - } + if self_ty_count == arg_ty_count { + self.report_closure_arg_mismatch(span, + found_span, + expected_trait_ref, + actual_trait_ref) } else { - self.report_type_argument_mismatch(span, - found_span, - expected_trait_ty, - expected_trait_ref, - actual_trait_ref, - e) + // Expected `|| { }`, found `|x, y| { }` + // Expected `fn(x) -> ()`, found `|| { }` + self.report_arg_count_mismatch( + span, + found_span, + arg_ty_count, + self_ty_count, + expected_trait_ty.is_closure() + ) } } @@ -784,31 +767,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.emit(); } - fn report_type_argument_mismatch(&self, - span: Span, - found_span: Option, - 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, @@ -837,6 +795,57 @@ 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> + { + fn build_fn_sig_string<'a, 'gcx, 'tcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, + trait_ref: &ty::TraitRef<'tcx>) -> String { + let inputs = trait_ref.substs.type_at(1); + let sig = if let ty::TyTuple(inputs, _) = inputs.sty { + tcx.mk_fn_sig( + inputs.iter().map(|&x| x), + tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), + false, + hir::Unsafety::Normal, + ::syntax::abi::Abi::Rust + ) + } else { + tcx.mk_fn_sig( + ::std::iter::once(inputs), + tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), + false, + hir::Unsafety::Normal, + ::syntax::abi::Abi::Rust + ) + }; + format!("{}", ty::Binder(sig)) + } + + let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); + let mut err = struct_span_err!(self.tcx.sess, span, E0631, + "type mismatch in {} arguments", + if argument_is_closure { "closure" } else { "function" }); + + let found_str = format!( + "expected signature of `{}`", + build_fn_sig_string(self.tcx, found.skip_binder()) + ); + err.span_label(span, found_str); + + let found_span = found_span.unwrap_or(span); + let expected_str = format!( + "found signature of `{}`", + build_fn_sig_string(self.tcx, expected_ref.skip_binder()) + ); + err.span_label(found_span, expected_str); + + err + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index cf7a29d2845..168eecf9b08 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -676,6 +676,12 @@ impl<'tcx> fmt::Display for ty::Binder> { } } +impl<'tcx> fmt::Display for ty::Binder> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) + } +} + impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) diff --git a/src/test/ui/mismatched_types/E0281.stderr b/src/test/ui/mismatched_types/E0281.stderr deleted file mode 100644 index 744e8c30939..00000000000 --- a/src/test/ui/mismatched_types/E0281.stderr +++ /dev/null @@ -1,13 +0,0 @@ -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,)>` - | | - | expected usize, found struct `std::string::String` - | requires `std::ops::Fn<(usize,)>` - | - = note: required by `foo` - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/E0281.rs b/src/test/ui/mismatched_types/E0631.rs similarity index 55% rename from src/test/ui/mismatched_types/E0281.rs rename to src/test/ui/mismatched_types/E0631.rs index abb66c99fab..e28f15ab0b6 100644 --- a/src/test/ui/mismatched_types/E0281.rs +++ b/src/test/ui/mismatched_types/E0631.rs @@ -8,18 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(x: F) { } +#![feature(unboxed_closures)] +fn foo(_: F) {} +fn bar>(_: 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` + fn f(_: u64) {} + foo(|_: isize| {}); + bar(|_: isize| {}); + foo(f); + bar(f); } diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr new file mode 100644 index 00000000000..235e7a10063 --- /dev/null +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -0,0 +1,44 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/E0631.rs:17:5 + | +17 | foo(|_: isize| {}); + | ^^^ ------------- found signature of `fn(isize) -> _` + | | + | expected signature of `fn(usize) -> _` + | + = note: required by `foo` + +error[E0631]: type mismatch in closure arguments + --> $DIR/E0631.rs:18:5 + | +18 | bar(|_: isize| {}); + | ^^^ ------------- found signature of `fn(isize) -> _` + | | + | expected signature of `fn(usize) -> _` + | + = note: required by `bar` + +error[E0631]: type mismatch in function arguments + --> $DIR/E0631.rs:19:5 + | +19 | foo(f); + | ^^^ + | | + | expected signature of `fn(usize) -> _` + | found signature of `fn(u64) -> _` + | + = note: required by `foo` + +error[E0631]: type mismatch in function arguments + --> $DIR/E0631.rs:20:5 + | +20 | bar(f); + | ^^^ + | | + | expected signature of `fn(usize) -> _` + | found signature of `fn(u64) -> _` + | + = note: required by `bar` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index 284f82d86eb..f94471a73ca 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + +fn f>(_: F) {} fn main() { [1, 2, 3].sort_by(|| panic!()); [1, 2, 3].sort_by(|tuple| panic!()); [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + f(|| panic!()); } diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index ca71154e872..3031a77b1e8 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -1,35 +1,45 @@ error[E0593]: closure takes 0 arguments but 2 arguments are required - --> $DIR/closure-arg-count.rs:12:15 + --> $DIR/closure-arg-count.rs:15:15 | -12 | [1, 2, 3].sort_by(|| panic!()); +15 | [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 + --> $DIR/closure-arg-count.rs:16:15 | -13 | [1, 2, 3].sort_by(|tuple| panic!()); +16 | [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 + --> $DIR/closure-arg-count.rs:17:24 | -14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); +17 | [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 + --> $DIR/closure-arg-count.rs:17:15 | -14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); +17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); | ^^^^^^^ -------------------------- takes 1 argument | | | expected closure that takes 2 arguments -error: aborting due to 4 previous errors +error[E0593]: closure takes 0 arguments but 1 argument is required + --> $DIR/closure-arg-count.rs:18:5 + | +18 | f(|| panic!()); + | ^ ----------- takes 0 arguments + | | + | expected closure that takes 1 argument + | + = note: required by `f` + +error: aborting due to 5 previous errors 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 00000000000..aa9dba4c3f4 --- /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. + +fn main() { + let a = [(1u32, 2u32)]; + a.iter().map(|_: (u32, u32)| 45); + a.iter().map(|_: &(u16, u16)| 45); + a.iter().map(|_: (u16, u16)| 45); +} + +fn baz(_: F) {} +fn _test<'a>(f: fn(*mut &'a u32)) { + baz(f); +} 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 00000000000..866a024ab08 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -0,0 +1,45 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:13:14 + | +13 | a.iter().map(|_: (u32, u32)| 45); + | ^^^ ------------------ found signature of `fn((u32, u32)) -> _` + | | + | expected signature of `fn(&(u32, u32)) -> _` + +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:14:14 + | +14 | a.iter().map(|_: &(u16, u16)| 45); + | ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _` + | | + | expected signature of `fn(&(u32, u32)) -> _` + +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:15:14 + | +15 | a.iter().map(|_: (u16, u16)| 45); + | ^^^ ------------------ found signature of `fn((u16, u16)) -> _` + | | + | expected signature of `fn(&(u32, u32)) -> _` + +error[E0631]: type mismatch in function arguments + --> $DIR/closure-arg-type-mismatch.rs:20:5 + | +20 | baz(f); + | ^^^ + | | + | expected signature of `for<'r> fn(*mut &'r u32) -> _` + | found signature of `fn(*mut &'a u32) -> _` + | + = note: required by `baz` + +error[E0271]: type mismatch resolving `for<'r> >::Output == ()` + --> $DIR/closure-arg-type-mismatch.rs:20:5 + | +20 | baz(f); + | ^^^ expected bound lifetime parameter, found concrete lifetime + | + = note: required by `baz` + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index d928a6a0a8e..a54fd118cc5 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -7,14 +7,13 @@ 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[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 +error[E0631]: type mismatch in closure arguments --> $DIR/closure-mismatch.rs:18:5 | 18 | baz(|_| ()); - | ^^^ ------ implements `std::ops::Fn<(_,)>` + | ^^^ ------ found signature of `fn(_) -> _` | | - | expected concrete lifetime, found bound lifetime parameter - | requires `for<'r> std::ops::Fn<(&'r (),)>` + | expected signature of `for<'r> fn(&'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` diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr index 120fb87cdc8..09a90ef3d6b 100644 --- a/src/test/ui/mismatched_types/fn-variance-1.stderr +++ b/src/test/ui/mismatched_types/fn-variance-1.stderr @@ -1,16 +1,22 @@ -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 +error[E0631]: type mismatch in function arguments --> $DIR/fn-variance-1.rs:21:5 | 21 | apply(&3, takes_mut); - | ^^^^^ types differ in mutability + | ^^^^^ + | | + | expected signature of `fn(&{integer}) -> _` + | found signature of `for<'r> fn(&'r mut isize) -> _` | = 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 +error[E0631]: type mismatch in function arguments --> $DIR/fn-variance-1.rs:27:5 | 27 | apply(&mut 3, takes_imm); - | ^^^^^ types differ in mutability + | ^^^^^ + | | + | expected signature of `fn(&mut {integer}) -> _` + | found signature of `for<'r> fn(&'r isize) -> _` | = note: required by `apply` diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index e2e2019307f..71a3a0a5714 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -8,14 +8,13 @@ error[E0599]: no method named `count` found for type `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` `&mut std::iter::Filter>, [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 +error[E0631]: type mismatch in closure arguments --> $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,)>` + | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` | | - | expected &str, found str - | requires `for<'r> std::ops::FnMut<(&'r &str,)>` + | expected signature of `for<'r> fn(&'r &str) -> _` error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index f14e711b23a..59883649280 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -1,14 +1,11 @@ -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 +error[E0631]: type mismatch in closure arguments --> $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)>` + | -------------------------------------------------- found signature of `fn(usize, isize) -> _` ... 25 | let z = call_it(3, f); - | ^^^^^^^ - | | - | expected isize, found usize - | requires `std::ops::FnMut<(isize, isize)>` + | ^^^^^^^ expected signature of `fn(isize, isize) -> _` | = note: required by `call_it`