Skip to content

Commit 82045ca

Browse files
committed
auto merge of #18264 : jakub-/rust/var-ids-in-error-messages, r=nikomatsakis
This PR aims to improve the readability of diagnostic messages that involve unresolved type variables. Currently, messages like the following: ```rust mismatched types: expected `core::result::Result<uint,()>`, found `core::option::Option<<generic #1>>` <anon>:6 let a: Result<uint, ()> = None; ^~~~ mismatched types: expected `&mut <generic #2>`, found `uint` <anon>:7 f(42u); ^~~ ``` tend to appear unapproachable to new users. [0] While specific type var IDs are valuable in diagnostics that deal with more than one such variable, in practice many messages only mention one. In those cases, leaving out the specific number makes the messages slightly less terrifying. ```rust mismatched types: expected `core::result::Result<uint, ()>`, found `core::option::Option<_>` <anon>:6 let a: Result<uint, ()> = None; ^~~~ mismatched types: expected `&mut _`, found `uint` <anon>:7 f(42u); ^~~ ``` As you can see, I also tweaked the aesthetics slightly by changing type variables to use the type hole syntax _. For integer variables, the syntax used is: ```rust mismatched types: expected `core::result::Result<uint, ()>`, found `core::option::Option<_#1i>` <anon>:6 let a: Result<uint, ()> = Some(1); ``` and float variables: ```rust mismatched types: expected `core::result::Result<uint, ()>`, found `core::option::Option<_#1f>` <anon>:6 let a: Result<uint, ()> = Some(0.5); ``` [0] https://twitter.com/coda/status/517713085465772032 Closes #2632. Closes #3404. Closes #18426.
2 parents 065caf3 + a2624fc commit 82045ca

29 files changed

+240
-194
lines changed

src/librustc/middle/ty.rs

+17-22
Original file line numberDiff line numberDiff line change
@@ -1032,10 +1032,8 @@ pub enum type_err {
10321032
terr_ref_mutability,
10331033
terr_vec_mutability,
10341034
terr_tuple_size(expected_found<uint>),
1035+
terr_fixed_array_size(expected_found<uint>),
10351036
terr_ty_param_size(expected_found<uint>),
1036-
terr_record_size(expected_found<uint>),
1037-
terr_record_mutability,
1038-
terr_record_fields(expected_found<Ident>),
10391037
terr_arg_count,
10401038
terr_regions_does_not_outlive(Region, Region),
10411039
terr_regions_not_same(Region, Region),
@@ -3790,8 +3788,8 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
37903788

37913789
ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
37923790
ty_uniq(_) => "box".to_string(),
3793-
ty_vec(_, Some(_)) => "array".to_string(),
3794-
ty_vec(_, None) => "unsized array".to_string(),
3791+
ty_vec(_, Some(n)) => format!("array of {} elements", n),
3792+
ty_vec(_, None) => "slice".to_string(),
37953793
ty_ptr(_) => "*-ptr".to_string(),
37963794
ty_rptr(_, _) => "&-ptr".to_string(),
37973795
ty_bare_fn(_) => "extern fn".to_string(),
@@ -3874,27 +3872,18 @@ pub fn type_err_to_str(cx: &ctxt, err: &type_err) -> String {
38743872
values.expected,
38753873
values.found)
38763874
}
3877-
terr_tuple_size(values) => {
3878-
format!("expected a tuple with {} elements, \
3875+
terr_fixed_array_size(values) => {
3876+
format!("expected an array with a fixed size of {} elements, \
38793877
found one with {} elements",
38803878
values.expected,
38813879
values.found)
38823880
}
3883-
terr_record_size(values) => {
3884-
format!("expected a record with {} fields, \
3885-
found one with {} fields",
3881+
terr_tuple_size(values) => {
3882+
format!("expected a tuple with {} elements, \
3883+
found one with {} elements",
38863884
values.expected,
38873885
values.found)
38883886
}
3889-
terr_record_mutability => {
3890-
"record elements differ in mutability".to_string()
3891-
}
3892-
terr_record_fields(values) => {
3893-
format!("expected a record with field `{}`, found one \
3894-
with field `{}`",
3895-
token::get_ident(values.expected),
3896-
token::get_ident(values.found))
3897-
}
38983887
terr_arg_count => {
38993888
"incorrect number of function parameters".to_string()
39003889
}
@@ -3923,9 +3912,15 @@ pub fn type_err_to_str(cx: &ctxt, err: &type_err) -> String {
39233912
trait_store_to_string(cx, (*values).found))
39243913
}
39253914
terr_sorts(values) => {
3926-
format!("expected {}, found {}",
3927-
ty_sort_string(cx, values.expected),
3928-
ty_sort_string(cx, values.found))
3915+
// A naive approach to making sure that we're not reporting silly errors such as:
3916+
// (expected closure, found closure).
3917+
let expected_str = ty_sort_string(cx, values.expected);
3918+
let found_str = ty_sort_string(cx, values.found);
3919+
if expected_str == found_str {
3920+
format!("expected {}, found a different {}", expected_str, found_str)
3921+
} else {
3922+
format!("expected {}, found {}", expected_str, found_str)
3923+
}
39293924
}
39303925
terr_traits(values) => {
39313926
format!("expected trait `{}`, found trait `{}`",

src/librustc/middle/typeck/infer/combine.rs

+10
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,16 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
515515
Ok(ty::mk_rptr(tcx, r, mt))
516516
}
517517

518+
(&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => {
519+
this.tys(a_t, b_t).and_then(|t| {
520+
if sz_a == sz_b {
521+
Ok(ty::mk_vec(tcx, t, Some(sz_a)))
522+
} else {
523+
Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b)))
524+
}
525+
})
526+
}
527+
518528
(&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
519529
this.tys(a_t, b_t).and_then(|t| {
520530
if sz_a == sz_b {

src/librustc/middle/typeck/infer/error_reporting.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub trait ErrorReporting {
111111

112112
fn values_str(&self, values: &ValuePairs) -> Option<String>;
113113

114-
fn expected_found_str<T:UserString+Resolvable>(
114+
fn expected_found_str<T: UserString + Resolvable>(
115115
&self,
116116
exp_found: &ty::expected_found<T>)
117117
-> Option<String>;
@@ -396,16 +396,12 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> {
396396
* or None if this is a derived error.
397397
*/
398398
match *values {
399-
infer::Types(ref exp_found) => {
400-
self.expected_found_str(exp_found)
401-
}
402-
infer::TraitRefs(ref exp_found) => {
403-
self.expected_found_str(exp_found)
404-
}
399+
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
400+
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found)
405401
}
406402
}
407403

408-
fn expected_found_str<T:UserString+Resolvable>(
404+
fn expected_found_str<T: UserString + Resolvable>(
409405
&self,
410406
exp_found: &ty::expected_found<T>)
411407
-> Option<String>

src/librustc/middle/typeck/infer/mod.rs

+26-39
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ use syntax::ast;
3636
use syntax::codemap;
3737
use syntax::codemap::Span;
3838
use util::common::indent;
39-
use util::ppaux::{bound_region_to_string, ty_to_string, trait_ref_to_string, Repr};
39+
use util::ppaux::{bound_region_to_string, ty_to_string};
40+
use util::ppaux::{trait_ref_to_string, Repr};
4041

4142
use self::coercion::Coerce;
4243
use self::combine::{Combine, CombineFields};
@@ -900,32 +901,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
900901
err: Option<&ty::type_err>) {
901902
debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty);
902903

903-
let error_str = err.map_or("".to_string(), |t_err| {
904-
format!(" ({})", ty::type_err_to_str(self.tcx, t_err))
905-
});
906904
let resolved_expected = expected_ty.map(|e_ty| {
907905
self.resolve_type_vars_if_possible(e_ty)
908906
});
909-
if !resolved_expected.map_or(false, |e| { ty::type_is_error(e) }) {
910-
match resolved_expected {
911-
None => {
912-
self.tcx
913-
.sess
914-
.span_err(sp,
915-
format!("{}{}",
916-
mk_msg(None, actual_ty),
917-
error_str).as_slice())
918-
}
919-
Some(e) => {
920-
self.tcx.sess.span_err(sp,
921-
format!("{}{}",
922-
mk_msg(Some(self.ty_to_string(e)), actual_ty),
923-
error_str).as_slice());
907+
908+
match resolved_expected {
909+
Some(t) if ty::type_is_error(t) => (),
910+
_ => {
911+
let error_str = err.map_or("".to_string(), |t_err| {
912+
format!(" ({})", ty::type_err_to_str(self.tcx, t_err))
913+
});
914+
915+
self.tcx.sess.span_err(sp, format!("{}{}",
916+
mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
917+
error_str).as_slice());
918+
919+
for err in err.iter() {
920+
ty::note_and_explain_type_err(self.tcx, *err)
924921
}
925922
}
926-
for err in err.iter() {
927-
ty::note_and_explain_type_err(self.tcx, *err)
928-
}
929923
}
930924
}
931925

@@ -945,25 +939,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
945939
}
946940

947941
pub fn report_mismatched_types(&self,
948-
sp: Span,
949-
e: ty::t,
950-
a: ty::t,
942+
span: Span,
943+
expected: ty::t,
944+
actual: ty::t,
951945
err: &ty::type_err) {
952-
let resolved_expected =
953-
self.resolve_type_vars_if_possible(e);
954-
let mk_msg = match ty::get(resolved_expected).sty {
955-
// Don't report an error if expected is ty_err
956-
ty::ty_err => return,
957-
_ => {
958-
// if I leave out : String, it infers &str and complains
959-
|actual: String| {
960-
format!("mismatched types: expected `{}`, found `{}`",
961-
self.ty_to_string(resolved_expected),
962-
actual)
963-
}
964-
}
946+
let trace = TypeTrace {
947+
origin: Misc(span),
948+
values: Types(ty::expected_found {
949+
expected: expected,
950+
found: actual
951+
})
965952
};
966-
self.type_error_message(sp, mk_msg, a, Some(err));
953+
self.report_and_explain_type_error(trace, err);
967954
}
968955

969956
pub fn replace_late_bound_regions_with_fresh_regions(&self,

0 commit comments

Comments
 (0)