Skip to content

Commit

Permalink
Improve display of error E0308 for structs
Browse files Browse the repository at this point in the history
Improve the display of error E0308 for structs by adding a "did you
mean" span label.
  • Loading branch information
Josh Leeb-du Toit committed Oct 31, 2017
1 parent 875ec8d commit 87c951d
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 13 deletions.
53 changes: 40 additions & 13 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -673,14 +673,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
values: Option<ValuePairs<'tcx>>,
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)),
Expand All @@ -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) => {
Expand All @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/issue-35241.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}
15 changes: 15 additions & 0 deletions src/test/ui/issue-35241.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 87c951d

Please sign in to comment.