From 87c951da0f36405ee9d7226f63a7208c58a16d07 Mon Sep 17 00:00:00 2001 From: Josh Leeb-du Toit Date: Sun, 29 Oct 2017 10:44:05 +1100 Subject: [PATCH] Improve display of error E0308 for structs Improve the display of error E0308 for structs by adding a "did you mean" span label. --- src/librustc/infer/error_reporting/mod.rs | 53 +++++++++++++++++------ src/test/ui/issue-35241.rs | 15 +++++++ src/test/ui/issue-35241.stderr | 15 +++++++ 3 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/issue-35241.rs create mode 100644 src/test/ui/issue-35241.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 895894a0bb2..aac67b528c2 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -66,7 +66,7 @@ use hir::map as hir_map; use hir::def_id::DefId; use middle::region; use traits::{ObligationCause, ObligationCauseCode}; -use ty::{self, Region, Ty, TyCtxt, TypeFoldable}; +use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::error::TypeError; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; @@ -673,14 +673,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { values: Option>, terr: &TypeError<'tcx>) { - let (expected_found, is_simple_error) = match values { - None => (None, false), + let (expected_found, exp_found, is_simple_error) = match values { + None => (None, None, false), Some(values) => { - let is_simple_error = match values { + let (is_simple_error, exp_found) = match values { ValuePairs::Types(exp_found) => { - exp_found.expected.is_primitive() && exp_found.found.is_primitive() + let is_simple_err = exp_found.expected.is_primitive() + && exp_found.found.is_primitive(); + + (is_simple_err, Some(exp_found)) } - _ => false, + _ => (false, None), }; let vals = match self.values_str(&values) { Some((expected, found)) => Some((expected, found)), @@ -690,12 +693,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return } }; - (vals, is_simple_error) + (vals, exp_found, is_simple_error) } }; let span = cause.span; + diag.span_label(span, terr.to_string()); + if let Some((sp, msg)) = secondary_span { + diag.span_label(sp, msg); + } + if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { (&TypeError::Sorts(ref values), false, true) => { @@ -704,18 +712,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &format!(" ({})", values.expected.sort_string(self.tcx)), &format!(" ({})", values.found.sort_string(self.tcx))); } - (_, false, _) => { + (_, false, _) => { + if let Some(exp_found) = exp_found { + let (def_id, ret_ty) = match exp_found.found.sty { + TypeVariants::TyFnDef(def, _) => { + (Some(def), Some(self.tcx.fn_sig(def).output())) + } + _ => (None, None) + }; + + let exp_is_struct = match exp_found.expected.sty { + TypeVariants::TyAdt(def, _) => def.is_struct(), + _ => false + }; + + if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { + if exp_is_struct && exp_found.expected == ret_ty.0 { + let message = format!( + "did you mean `{}(/* fields */)`?", + self.tcx.item_path_str(def_id) + ); + diag.span_label(cause.span, message); + } + } + } + diag.note_expected_found(&"type", expected, found); } _ => (), } } - diag.span_label(span, terr.to_string()); - if let Some((sp, msg)) = secondary_span { - diag.span_label(sp, msg); - } - self.note_error_origin(diag, &cause); self.check_and_note_conflicting_crates(diag, terr, span); self.tcx.note_and_explain_type_err(diag, terr, span); diff --git a/src/test/ui/issue-35241.rs b/src/test/ui/issue-35241.rs new file mode 100644 index 00000000000..7ec3974854b --- /dev/null +++ b/src/test/ui/issue-35241.rs @@ -0,0 +1,15 @@ +// 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. + +struct Foo(u32); + +fn test() -> Foo { Foo } + +fn main() {} diff --git a/src/test/ui/issue-35241.stderr b/src/test/ui/issue-35241.stderr new file mode 100644 index 00000000000..bb1bba152bb --- /dev/null +++ b/src/test/ui/issue-35241.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-35241.rs:13:20 + | +13 | fn test() -> Foo { Foo } + | --- ^^^ + | | | + | | expected struct `Foo`, found fn item + | | did you mean `Foo(/* fields */)`? + | expected `Foo` because of return type + | + = note: expected type `Foo` + found type `fn(u32) -> Foo {Foo::{{constructor}}}` + +error: aborting due to previous error +