Skip to content

Commit a7d98c7

Browse files
committed
Auto merge of #45630 - joshleeb:iss35241, r=estebank
Improve display of error E0308 Ref. Forgetting to call a variant constructor causes a confusing error message #35241. This PR modifies [`note_type_err`](https://github.com/rust-lang/rust/blob/b7041bfab3a83702a8026fb7a18d8ea7d54cc648/src/librustc/infer/error_reporting/mod.rs#L669-L674) to display a `help` message when a `TyFnPtr` or `TyFnDef` are found and the return type, of the function or function pointer, is the same as the type that is expected. The output of compiling ```rust struct Foo(u32); fn test() -> Foo { Foo } fn main() {} ``` is now ```bash $ rustc src/test/ui/issue-35241.rs error[E0308]: mismatched types --> src/test/ui/issue-35241.rs:13:20 | 13 | fn test() -> Foo { Foo } | --- ^^^ expected struct `Foo`, found fn item | | | expected `Foo` because of return type | = help: did you mean `Foo { /* fields */ }`? = note: expected type `Foo` found type `fn(u32) -> Foo {Foo::{{constructor}}}` error: aborting due to previous error ```
2 parents 2379faa + 87c951d commit a7d98c7

File tree

3 files changed

+70
-13
lines changed

3 files changed

+70
-13
lines changed

src/librustc/infer/error_reporting/mod.rs

+40-13
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use hir::map as hir_map;
6666
use hir::def_id::DefId;
6767
use middle::region;
6868
use traits::{ObligationCause, ObligationCauseCode};
69-
use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
69+
use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
7070
use ty::error::TypeError;
7171
use syntax::ast::DUMMY_NODE_ID;
7272
use syntax_pos::{Pos, Span};
@@ -673,14 +673,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
673673
values: Option<ValuePairs<'tcx>>,
674674
terr: &TypeError<'tcx>)
675675
{
676-
let (expected_found, is_simple_error) = match values {
677-
None => (None, false),
676+
let (expected_found, exp_found, is_simple_error) = match values {
677+
None => (None, None, false),
678678
Some(values) => {
679-
let is_simple_error = match values {
679+
let (is_simple_error, exp_found) = match values {
680680
ValuePairs::Types(exp_found) => {
681-
exp_found.expected.is_primitive() && exp_found.found.is_primitive()
681+
let is_simple_err = exp_found.expected.is_primitive()
682+
&& exp_found.found.is_primitive();
683+
684+
(is_simple_err, Some(exp_found))
682685
}
683-
_ => false,
686+
_ => (false, None),
684687
};
685688
let vals = match self.values_str(&values) {
686689
Some((expected, found)) => Some((expected, found)),
@@ -690,12 +693,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
690693
return
691694
}
692695
};
693-
(vals, is_simple_error)
696+
(vals, exp_found, is_simple_error)
694697
}
695698
};
696699

697700
let span = cause.span;
698701

702+
diag.span_label(span, terr.to_string());
703+
if let Some((sp, msg)) = secondary_span {
704+
diag.span_label(sp, msg);
705+
}
706+
699707
if let Some((expected, found)) = expected_found {
700708
match (terr, is_simple_error, expected == found) {
701709
(&TypeError::Sorts(ref values), false, true) => {
@@ -704,18 +712,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
704712
&format!(" ({})", values.expected.sort_string(self.tcx)),
705713
&format!(" ({})", values.found.sort_string(self.tcx)));
706714
}
707-
(_, false, _) => {
715+
(_, false, _) => {
716+
if let Some(exp_found) = exp_found {
717+
let (def_id, ret_ty) = match exp_found.found.sty {
718+
TypeVariants::TyFnDef(def, _) => {
719+
(Some(def), Some(self.tcx.fn_sig(def).output()))
720+
}
721+
_ => (None, None)
722+
};
723+
724+
let exp_is_struct = match exp_found.expected.sty {
725+
TypeVariants::TyAdt(def, _) => def.is_struct(),
726+
_ => false
727+
};
728+
729+
if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) {
730+
if exp_is_struct && exp_found.expected == ret_ty.0 {
731+
let message = format!(
732+
"did you mean `{}(/* fields */)`?",
733+
self.tcx.item_path_str(def_id)
734+
);
735+
diag.span_label(cause.span, message);
736+
}
737+
}
738+
}
739+
708740
diag.note_expected_found(&"type", expected, found);
709741
}
710742
_ => (),
711743
}
712744
}
713745

714-
diag.span_label(span, terr.to_string());
715-
if let Some((sp, msg)) = secondary_span {
716-
diag.span_label(sp, msg);
717-
}
718-
719746
self.note_error_origin(diag, &cause);
720747
self.check_and_note_conflicting_crates(diag, terr, span);
721748
self.tcx.note_and_explain_type_err(diag, terr, span);

src/test/ui/issue-35241.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Foo(u32);
12+
13+
fn test() -> Foo { Foo }
14+
15+
fn main() {}

src/test/ui/issue-35241.stderr

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-35241.rs:13:20
3+
|
4+
13 | fn test() -> Foo { Foo }
5+
| --- ^^^
6+
| | |
7+
| | expected struct `Foo`, found fn item
8+
| | did you mean `Foo(/* fields */)`?
9+
| expected `Foo` because of return type
10+
|
11+
= note: expected type `Foo`
12+
found type `fn(u32) -> Foo {Foo::{{constructor}}}`
13+
14+
error: aborting due to previous error
15+

0 commit comments

Comments
 (0)