diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 39ec33eef1fec..93d736eccad79 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1440,8 +1440,13 @@ pub struct Ty { impl fmt::Debug for Ty { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "type({})", - print::to_string(print::NO_ANN, |s| s.print_type(self))) + write!(f, "type({})", print::to_string(print::NO_ANN, |s| s.print_type(self))) + } +} + +impl fmt::Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", print::to_string(print::NO_ANN, |s| s.print_type(self))) } } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 514b29120a96a..87015d6c3ecf0 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -588,6 +588,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { s.push_normal(format!("{}", tnm.ty)); } + fn push_closure<'tcx>(capture: &hir::CaptureClause, + fn_decl: &hir::FnDecl, + s: &mut DiagnosticStyledString) { + let args = fn_decl.inputs.iter() + .map(|arg| format!("{}", arg)) + .collect::>() + .join(", "); + s.push_highlighted( + format!("{}|{}| -> {}", + if capture == &hir::CaptureByValue { + "move " + } else { + "" + }, + args, + if let hir::Return(ref r_ty) = fn_decl.output { + format!("{}", r_ty) + } else { + "_".to_string() + })); + } + match (&t1.sty, &t2.sty) { (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); @@ -723,8 +745,67 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // When encountering &T != &mut T, highlight only the borrow (&ty::TyRef(r1, ref tnm1), &ty::TyRef(r2, ref tnm2)) if equals(&tnm1.ty, &tnm2.ty) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, tnm1, &mut values.0); - push_ty_ref(&r2, tnm2, &mut values.1); + push_ty_ref(& r1, tnm1, & mut values.0); + push_ty_ref( & r2, tnm2, &mut values.1); + values + } + // When comparing against a closure, print its signature without location + (&ty::TyClosure(did1, _), &ty::TyClosure(did2, _)) => { + let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); + let mut success = false; + if let Some(node_id) = self.tcx.hir.as_local_node_id(did1) { + if let Some(hir::map::NodeExpr(expr)) = self.tcx.hir.find(node_id) { + if let hir::ExprClosure(capture, ref fn_decl, _, _, _) = expr.node { + push_closure(&capture, fn_decl, &mut values.0); + success = true; + } + } + } + if !success { // fallback + values.0.push_highlighted(format!("{}", t1)); + } + success = false; + if let Some(node_id) = self.tcx.hir.as_local_node_id(did2) { + if let Some(hir::map::NodeExpr(expr)) = self.tcx.hir.find(node_id) { + if let hir::ExprClosure(capture, ref fn_decl, _, _, _) = expr.node { + push_closure(&capture, fn_decl, &mut values.1); + success = true; + } + } + } + if !success { // fallback + values.1.push_highlighted(format!("{}", t2)); + } + values + } + (_, &ty::TyClosure(did, _)) => { + let mut values = (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::new()); + if let Some(node_id) = self.tcx.hir.as_local_node_id(did) { + if let Some(hir::map::NodeExpr(expr)) = self.tcx.hir.find(node_id) { + if let hir::ExprClosure(capture, ref fn_decl, _, _, _) = expr.node { + push_closure(&capture, fn_decl, &mut values.1); + return values; + } + } + } + // fallback + values.1.push_highlighted(format!("{}", t2)); + values + } + (&ty::TyClosure(did, _), _) => { + let mut values = (DiagnosticStyledString::new(), + DiagnosticStyledString::highlighted(format!("{}", t2))); + if let Some(node_id) = self.tcx.hir.as_local_node_id(did) { + if let Some(hir::map::NodeExpr(expr)) = self.tcx.hir.find(node_id) { + if let hir::ExprClosure(capture, ref fn_decl, _, _, _) = expr.node { + push_closure(&capture, fn_decl, &mut values.0); + return values; + } + } + } + // fallback + values.0.push_highlighted(format!("{}", t1)); values } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5703c5c870e88..eb3ce0bc2f3ab 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -938,36 +938,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } + fn build_fn_sig_string(&self, trait_ref: &ty::TraitRef<'tcx>) -> String { + let inputs = trait_ref.substs.type_at(1); + let sig = if let ty::TyTuple(inputs, _) = inputs.sty { + self.tcx.mk_fn_sig( + inputs.iter().map(|&x| x), + self.tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), + false, + hir::Unsafety::Normal, + ::syntax::abi::Abi::Rust + ) + } else { + self.tcx.mk_fn_sig( + ::std::iter::once(inputs), + self.tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), + false, + hir::Unsafety::Normal, + ::syntax::abi::Abi::Rust + ) + }; + format!("{}", ty::Binder(sig)) + } + fn report_closure_arg_mismatch(&self, - span: Span, - found_span: Option, - expected_ref: ty::PolyTraitRef<'tcx>, - found: ty::PolyTraitRef<'tcx>) + 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", @@ -975,14 +974,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let found_str = format!( "expected signature of `{}`", - build_fn_sig_string(self.tcx, found.skip_binder()) + self.build_fn_sig_string(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()) + self.build_fn_sig_string(expected_ref.skip_binder()) ); err.span_label(found_span, expected_str); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index cb68e576e5af9..8e09f1835d583 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -246,6 +246,22 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyError => "type error".to_string(), } } + + pub fn span(&self, tcx: &TyCtxt<'a, 'gcx, 'lcx>) -> Option { + match self.sty { + ty::TyClosure(def, _) => { + if let Some(node_id) = tcx.hir.as_local_node_id(def) { + if let Some(hir::map::NodeExpr(expr)) = tcx.hir.find(node_id) { + if let hir::ExprClosure(_, _, _, sp, _) = expr.node { + return Some(sp); + } + } + } + None + } + _ => None, + } + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -260,10 +276,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let expected_str = values.expected.sort_string(self); let found_str = values.found.sort_string(self); if expected_str == found_str && expected_str == "closure" { - db.span_note(sp, - "no two closures, even if identical, have the same type"); - db.span_help(sp, - "consider boxing your closure and/or using it as a trait object"); + db.note("no two closures, even if identical, have the same type"); + if let Some(sp) = values.expected.span(&self) { + db.span_label(sp, "this closure was expected"); + } + db.help("consider boxing your closure and/or using it as a trait object"); } }, TyParamDefaultMismatch(values) => { diff --git a/src/test/compile-fail/issue-24036.rs b/src/test/compile-fail/issue-24036.rs index ac7e0f2e9a867..0366a8f320e3a 100644 --- a/src/test/compile-fail/issue-24036.rs +++ b/src/test/compile-fail/issue-24036.rs @@ -10,28 +10,29 @@ fn closure_to_loc() { let mut x = |c| c + 1; + //~^ NOTE this closure was expected x = |c| c + 1; //~^ ERROR mismatched types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object //~| expected closure, found a different closure - //~| expected type `[closure - //~| found type `[closure + //~| expected type `|_| -> _` + //~| found type `|_| -> _` } fn closure_from_match() { let x = match 1usize { + //~^ ERROR match arms have incompatible types + //~| NOTE no two closures, even if identical, have the same type + //~| HELP consider boxing your closure and/or using it as a trait object + //~| NOTE expected closure, found a different closure + //~| NOTE expected type `|_| -> _` (closure) 1 => |c| c + 1, + //~^ NOTE this closure was expected 2 => |c| c - 1, //~^ NOTE match arm with an incompatible type _ => |c| c - 1 }; - //~^^^^^^ ERROR match arms have incompatible types - //~| NOTE no two closures, even if identical, have the same type - //~| HELP consider boxing your closure and/or using it as a trait object - //~| expected closure, found a different closure - //~| expected type `[closure - //~| found type `[closure } fn main() { } diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index 7c88d789fd36e..4c6976f3f6f04 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types | ^^^^^^^^^ expected (), found closure | = note: expected type `()` - found type `[closure@$DIR/issue-20862.rs:12:5: 12:14 x:_]` + found type `|_| -> _` error[E0618]: expected function, found `()` --> $DIR/issue-20862.rs:17:13 diff --git a/src/test/ui/span/move-closure.stderr b/src/test/ui/span/move-closure.stderr index 9135a26bbaf77..415fc0408a194 100644 --- a/src/test/ui/span/move-closure.stderr +++ b/src/test/ui/span/move-closure.stderr @@ -5,7 +5,7 @@ error[E0308]: mismatched types | ^^^^^^^^^^ expected (), found closure | = note: expected type `()` - found type `[closure@$DIR/move-closure.rs:15:17: 15:27]` + found type `move || -> _` error: aborting due to previous error