Improve display of error E0308 for structs

Improve the display of error E0308 for structs by adding a "did you
mean" span label.
This commit is contained in:
Josh Leeb-du Toit 2017-10-29 10:44:05 +11:00
parent 875ec8d597
commit 87c951da0f
3 changed files with 70 additions and 13 deletions

View File

@ -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<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)),
@ -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);

View File

@ -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() {}

View File

@ -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