From e8cf5f366263533bd739c4dda9bc8a57ec55b8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Apr 2017 15:36:35 -0700 Subject: [PATCH] Clean up closure type mismatch errors --- src/librustc/diagnostics.rs | 2 + src/librustc/traits/error_reporting.rs | 66 ++++++++++++++++--- src/librustc/ty/sty.rs | 16 +++++ .../ui/mismatched_types/closure-arg-count.rs | 14 ++++ .../mismatched_types/closure-arg-count.stderr | 43 ++++++++++++ .../ui/mismatched_types/closure-mismatch.rs | 19 ++++++ .../mismatched_types/closure-mismatch.stderr | 21 ++++++ 7 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/mismatched_types/closure-arg-count.rs create mode 100644 src/test/ui/mismatched_types/closure-arg-count.stderr create mode 100644 src/test/ui/mismatched_types/closure-mismatch.rs create mode 100644 src/test/ui/mismatched_types/closure-mismatch.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 30e9f502abc..6f9d9817a44 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1850,4 +1850,6 @@ 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 } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba340a40692..dc7e18f8172 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,63 @@ 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(); + 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" }); + + 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 + } 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); + + 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 + } + } 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) + } } TraitNotObjectSafe(did) => { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d5924817034..be56ac48d3e 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/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs new file mode 100644 index 00000000000..fbe36cd8fd2 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -0,0 +1,14 @@ +// 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() { + [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..f45734d675b --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -0,0 +1,43 @@ +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:12:15 + | +12 | [1, 2, 3].sort_by(|tuple| panic!()); + | ^^^^^^^ ---------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:12:15 + | +12 | [1, 2, 3].sort_by(|tuple| panic!()); + | ^^^^^^^ ---------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error[E0308]: mismatched types + --> $DIR/closure-arg-count.rs:13:24 + | +13 | [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 + | +13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^ -------------------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:13:15 + | +13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^ -------------------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs new file mode 100644 index 00000000000..91298cb2bbd --- /dev/null +++ b/src/test/ui/mismatched_types/closure-mismatch.rs @@ -0,0 +1,19 @@ +// 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. + +trait Foo {} + +impl Foo for T {} + +fn baz(_: T) {} + +fn main() { + 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..09e31b263bc --- /dev/null +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -0,0 +1,21 @@ +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[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 + --> $DIR/closure-mismatch.rs:18:5 + | +18 | baz(|_| ()); + | ^^^ ------ 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 +