diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs index fd8700042c6..147ea64a9c2 100644 --- a/src/rustc/middle/infer.rs +++ b/src/rustc/middle/infer.rs @@ -493,7 +493,7 @@ impl unify_methods for infer_ctxt { if b == r { self.uok() } else { - err(ty::terr_regions_differ(false, b, a)) + err(ty::terr_regions_differ(b, a)) } } } @@ -521,21 +521,23 @@ impl unify_methods for infer_ctxt { } } - /* mk_subty passes the "smaller" type as the first argument - and the "bigger" type as the second -- so the first arg - is the actual type, and the second is the expected type */ - fn flds(a: ty::field, e: ty::field) -> ures { - if e.ident != a.ident { - ret self.uerr(ty::terr_record_fields(e.ident, a.ident)); + fn flds(a: ty::field, b: ty::field) -> ures { + if b.ident != a.ident { + // Note: the error object expects the "expected" field to + // come first, which is generally the supertype (b). + ret self.uerr(ty::terr_record_fields(b.ident, a.ident)); + } + + self.mts(a.mt, b.mt).chain_err {|err| + self.uerr(ty::terr_in_field(@err, a.ident)) } - self.mts(a.mt, e.mt) } fn tps(as: [ty::t], bs: [ty::t]) -> ures { if check vec::same_length(as, bs) { iter2(as, bs) {|a, b| self.tys(a, b) } } else { - self.uerr(ty::terr_ty_param_size(as.len(), bs.len())) + self.uerr(ty::terr_ty_param_size(bs.len(), as.len())) } } @@ -544,7 +546,7 @@ impl unify_methods for infer_ctxt { (_, ast::proto_any) { self.uok() } (ast::proto_bare, _) { self.uok() } (_, _) if a == b { self.uok() } - _ { self.uerr(ty::terr_proto_mismatch(a, b)) } + _ { self.uerr(ty::terr_proto_mismatch(b, a)) } } } @@ -558,7 +560,7 @@ impl unify_methods for infer_ctxt { this check is necessary to ensure that the annotation in an object method matches the declared object type */ - self.uerr(ty::terr_ret_style_mismatch(a_ret_style, b_ret_style)) + self.uerr(ty::terr_ret_style_mismatch(b_ret_style, a_ret_style)) } else { self.uok() } @@ -672,7 +674,7 @@ impl unify_methods for infer_ctxt { self.constrs(a, b) } } else { - self.uerr(ty::terr_constr_len(as.len(), bs.len())) + self.uerr(ty::terr_constr_len(bs.len(), as.len())) } } @@ -713,7 +715,7 @@ impl unify_methods for infer_ctxt { if ty::mach_sty(cfg, a) == ty::mach_sty(cfg, b) { self.uok() } else { - self.uerr(ty::terr_mismatch) + self.uerr(ty::terr_sorts(b, a)) } } @@ -757,8 +759,8 @@ impl unify_methods for infer_ctxt { self.flds(a, b) } } else { - ret self.uerr(ty::terr_record_size(a_fields.len(), - b_fields.len())); + ret self.uerr(ty::terr_record_size(b_fields.len(), + a_fields.len())); } } @@ -766,7 +768,7 @@ impl unify_methods for infer_ctxt { if check vec::same_length(a_tys, b_tys) { iter2(a_tys, b_tys) {|a,b| self.tys(a,b) } } else { - self.uerr(ty::terr_tuple_size(a_tys.len(), b_tys.len())) + self.uerr(ty::terr_tuple_size(b_tys.len(), a_tys.len())) } } @@ -780,7 +782,7 @@ impl unify_methods for infer_ctxt { } } - _ { self.uerr(ty::terr_mismatch) } + _ { self.uerr(ty::terr_sorts(b, a)) } } } } @@ -1066,7 +1068,7 @@ fn c_tuptys(self: C, as: [ty::t], bs: [ty::t]) if check vec::same_length(as, bs) { map2(as, bs) {|a, b| self.c_tys(a, b) } } else { - err(ty::terr_tuple_size(as.len(), bs.len())) + err(ty::terr_tuple_size(bs.len(), as.len())) } } @@ -1077,7 +1079,7 @@ fn c_tps(self: C, _did: ast::def_id, as: [ty::t], bs: [ty::t]) if check vec::same_length(as, bs) { map2(as, bs) {|a,b| self.c_tys(a, b) } } else { - err(ty::terr_ty_param_size(as.len(), bs.len())) + err(ty::terr_ty_param_size(bs.len(), as.len())) } } @@ -1087,17 +1089,17 @@ fn c_fieldvecs(self: C, as: [ty::field], bs: [ty::field]) if check vec::same_length(as, bs) { map2(as, bs) {|a,b| c_flds(self, a, b) } } else { - err(ty::terr_record_size(as.len(), bs.len())) + err(ty::terr_record_size(bs.len(), as.len())) } } -fn c_flds(self: C, e: ty::field, a: ty::field) -> cres { - if e.ident == a.ident { - self.c_mts(e.mt, a.mt).chain {|mt| - ok({ident: e.ident, mt: mt}) +fn c_flds(self: C, a: ty::field, b: ty::field) -> cres { + if a.ident == b.ident { + self.c_mts(a.mt, b.mt).chain {|mt| + ok({ident: a.ident, mt: mt}) } } else { - err(ty::terr_record_fields(e.ident, a.ident)) + err(ty::terr_record_fields(b.ident, a.ident)) } } @@ -1196,7 +1198,7 @@ fn c_tys( if ty::mach_sty(cfg, a) == ty::mach_sty(cfg, b) { ok(a) } else { - err(ty::terr_mismatch) + err(ty::terr_sorts(b, a)) } } @@ -1293,7 +1295,7 @@ fn c_tys( } } - _ { err(ty::terr_mismatch) } + _ { err(ty::terr_sorts(b, a)) } } } } @@ -1350,14 +1352,14 @@ fn c_regions( #debug["... no, %s != %s.", a.to_str(self.infcx()), b.to_str(self.infcx())]; - err(ty::terr_regions_differ(false, b, a)) + err(ty::terr_regions_differ(b, a)) } } (ty::re_default, _) | (_, ty::re_default) { // actually a compiler bug, I think. - err(ty::terr_regions_differ(false, b, a)) + err(ty::terr_regions_differ(b, a)) } } } @@ -1480,7 +1482,7 @@ impl of combine for lub { let rm = self.infcx().tcx.region_map; alt region::nearest_common_ancestor(rm, a_id, b_id) { some(r_id) { ok(ty::re_scope(r_id)) } - _ { err(ty::terr_regions_differ(false, b, a)) } + _ { err(ty::terr_regions_differ(b, a)) } } } } @@ -1623,7 +1625,7 @@ impl of combine for glb { alt region::nearest_common_ancestor(rm, a_id, b_id) { some(r_id) if a_id == r_id { ok(b) } some(r_id) if b_id == r_id { ok(a) } - _ { err(ty::terr_regions_differ(false, b, a)) } + _ { err(ty::terr_regions_differ(b, a)) } } } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 70173de4f05..de4dddc7390 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -341,7 +341,9 @@ enum type_err { terr_mode_mismatch(mode, mode), terr_constr_len(uint, uint), terr_constr_mismatch(@type_constr, @type_constr), - terr_regions_differ(bool /* variance */, region, region), + terr_regions_differ(region, region), + terr_in_field(@type_err, str), + terr_sorts(t, t) } enum param_bound { @@ -1837,6 +1839,33 @@ fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) { } } +fn ty_sort_str(cx: ctxt, t: t) -> str { + alt get(t).struct { + ty_nil | ty_bot | ty_bool | ty_int(_) | + ty_uint(_) | ty_float(_) | ty_str | ty_type | ty_opaque_box | + ty_opaque_closure_ptr(_) { + ty_to_str(cx, t) + } + + ty_enum(_, _) { "enum" } + ty_box(_) { "@-ptr" } + ty_uniq(_) { "~-ptr" } + ty_vec(_) { "vector" } + ty_ptr(_) { "*-ptr" } + ty_rptr(_, _) { "&-ptr" } + ty_rec(_) { "record" } + ty_fn(_) { "fn" } + ty_iface(_, _) { "iface" } + ty_class(_, _) { "class" } + ty_res(_, _, _) { "resource" } + ty_tup(_) { "tuple" } + ty_var(_) { "variable" } + ty_param(_, _) { "type parameter" } + ty_self(_) { "self" } + ty_constr(t, _) { ty_sort_str(cx, t) } + } +} + fn type_err_to_str(cx: ctxt, err: type_err) -> str { alt err { terr_mismatch { ret "types differ"; } @@ -1876,8 +1905,8 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> str { } terr_record_mutability { ret "record elements differ in mutability"; } terr_record_fields(e_fld, a_fld) { - ret "expected a record with field '" + e_fld + - "' but found one with field '" + a_fld + "'"; + ret "expected a record with field `" + e_fld + + "` but found one with field `" + a_fld + "`"; } terr_arg_count { ret "incorrect number of function parameters"; } terr_mode_mismatch(e_mode, a_mode) { @@ -1894,16 +1923,18 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> str { " but found one with constraint " + ty_constr_to_str(a_constr); } - terr_regions_differ(true, region_a, region_b) { - ret #fmt("reference lifetime %s does not match reference lifetime %s", - region_to_str(cx, region_a), region_to_str(cx, region_b)); - } - terr_regions_differ(false, subregion, superregion) { + terr_regions_differ(subregion, superregion) { ret #fmt("references with lifetime %s do not outlive references with \ lifetime %s", region_to_str(cx, subregion), region_to_str(cx, superregion)); } + terr_in_field(err, fname) { + ret #fmt("in field `%s`, %s", fname, type_err_to_str(cx, *err)); + } + terr_sorts(exp, act) { + ret #fmt("%s vs %s", ty_sort_str(cx, exp), ty_sort_str(cx, act)); + } } } diff --git a/src/test/compile-fail/bad-bang-ann-3.rs b/src/test/compile-fail/bad-bang-ann-3.rs index ded6f62a6dd..bab121bd6d3 100644 --- a/src/test/compile-fail/bad-bang-ann-3.rs +++ b/src/test/compile-fail/bad-bang-ann-3.rs @@ -3,7 +3,7 @@ fn bad_bang(i: uint) -> ! { ret 7u; - //!^ ERROR expected `_|_` but found `uint` (types differ) + //!^ ERROR expected `_|_` but found `uint` } fn main() { bad_bang(5u); } diff --git a/src/test/compile-fail/bad-bang-ann.rs b/src/test/compile-fail/bad-bang-ann.rs index f5ec75c59fa..b6e2dea4e5a 100644 --- a/src/test/compile-fail/bad-bang-ann.rs +++ b/src/test/compile-fail/bad-bang-ann.rs @@ -3,7 +3,7 @@ fn bad_bang(i: uint) -> ! { if i < 0u { } else { fail; } - //!^ ERROR expected `_|_` but found `()` (types differ) + //!^ ERROR expected `_|_` but found `()` } fn main() { bad_bang(5u); } diff --git a/src/test/compile-fail/bang-tailexpr.rs b/src/test/compile-fail/bang-tailexpr.rs index 20b147cb5e3..bdb543ed19b 100644 --- a/src/test/compile-fail/bang-tailexpr.rs +++ b/src/test/compile-fail/bang-tailexpr.rs @@ -1,4 +1,4 @@ fn f() -> ! { - 3 //! ERROR expected `_|_` but found `int` (types differ) + 3 //! ERROR expected `_|_` but found `int` } fn main() { } diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs index 9b8f85fc668..75d8c4a37df 100644 --- a/src/test/compile-fail/issue-897-2.rs +++ b/src/test/compile-fail/issue-897-2.rs @@ -1,6 +1,6 @@ fn g() -> ! { fail; } fn f() -> ! { - ret 42; //! ERROR expected `_|_` but found `int` (types differ) + ret 42; //! ERROR expected `_|_` but found `int` g(); //! WARNING unreachable statement } fn main() { } diff --git a/src/test/compile-fail/issue-897.rs b/src/test/compile-fail/issue-897.rs index 6521f5159a9..58e8ef4fe53 100644 --- a/src/test/compile-fail/issue-897.rs +++ b/src/test/compile-fail/issue-897.rs @@ -1,5 +1,5 @@ fn f() -> ! { - ret 42; //! ERROR expected `_|_` but found `int` (types differ) + ret 42; //! ERROR expected `_|_` but found `int` fail; //! WARNING unreachable statement } fn main() { } diff --git a/src/test/compile-fail/loop-does-not-diverge.rs b/src/test/compile-fail/loop-does-not-diverge.rs index eaaa4ecc9fb..d2015e10698 100644 --- a/src/test/compile-fail/loop-does-not-diverge.rs +++ b/src/test/compile-fail/loop-does-not-diverge.rs @@ -4,7 +4,7 @@ fn forever() -> ! { loop { break; } - ret 42; //! ERROR expected `_|_` but found `int` (types differ) + ret 42; //! ERROR expected `_|_` but found `int` } fn main() { diff --git a/src/test/compile-fail/rec-expected.rs b/src/test/compile-fail/rec-expected.rs new file mode 100644 index 00000000000..acbb7f03531 --- /dev/null +++ b/src/test/compile-fail/rec-expected.rs @@ -0,0 +1,9 @@ +type foo = {a: int}; +type bar = {b: int}; + +fn want_foo(f: foo) {} +fn have_bar(b: bar) { + want_foo(b); //! ERROR expected a record with field `a` +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/terr-in-field.rs b/src/test/compile-fail/terr-in-field.rs new file mode 100644 index 00000000000..0b676e35db7 --- /dev/null +++ b/src/test/compile-fail/terr-in-field.rs @@ -0,0 +1,9 @@ +type foo = {a: int, b: int}; +type bar = {a: int, b: uint}; + +fn want_foo(f: foo) {} +fn have_bar(b: bar) { + want_foo(b); //! ERROR (in field `b`, int vs uint) +} + +fn main() {} diff --git a/src/test/compile-fail/terr-sorts.rs b/src/test/compile-fail/terr-sorts.rs new file mode 100644 index 00000000000..6ab384673c1 --- /dev/null +++ b/src/test/compile-fail/terr-sorts.rs @@ -0,0 +1,9 @@ +type foo = {a: int, b: int}; +type bar = @foo; + +fn want_foo(f: foo) {} +fn have_bar(b: bar) { + want_foo(b); //! ERROR (record vs @-ptr) +} + +fn main() {}