From a678fb485dabf2528b645a33fc286acb7e3239ea Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 16 Nov 2012 19:22:48 -0800 Subject: [PATCH] Introduce a T_err type for type errors This allows more errors to be non-fatal, as per #1871. I only went through and started changing span_fatal to span_err in check.rs. There are probably more errors that could be made non-fatal. --- src/librustc/metadata/tyencode.rs | 1 + src/librustc/middle/trans/reflect.rs | 1 + src/librustc/middle/trans/type_of.rs | 1 + src/librustc/middle/ty.rs | 42 ++- src/librustc/middle/typeck/check.rs | 287 ++++++++++++--------- src/librustc/middle/typeck/check/method.rs | 2 + src/librustc/middle/typeck/check/vtable.rs | 8 +- src/librustc/middle/typeck/coherence.rs | 4 +- src/librustc/middle/typeck/infer.rs | 38 +++ src/librustc/util/ppaux.rs | 3 +- src/test/compile-fail/cast-from-nil.rs | 2 +- src/test/compile-fail/cast-to-nil.rs | 2 +- src/test/compile-fail/extern-no-call.rs | 2 +- src/test/compile-fail/issue-1871.rs | 7 +- src/test/compile-fail/issue-2149.rs | 2 +- 15 files changed, 256 insertions(+), 146 deletions(-) diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 922fff18e9e59..232fb7c3b3d74 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -318,6 +318,7 @@ fn enc_sty(w: io::Writer, cx: @ctxt, st: ty::sty) { debug!("~~~~ %s", ~"]"); w.write_char(']'); } + ty::ty_err => fail ~"Shouldn't encode error type" } } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 5724c5ada22f3..5c4380ffe85f0 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -266,6 +266,7 @@ impl reflector { // Miscallaneous extra types ty::ty_trait(_, _, _) => self.leaf(~"trait"), ty::ty_infer(_) => self.leaf(~"infer"), + ty::ty_err => self.leaf(~"err"), ty::ty_param(p) => self.visit(~"param", ~[self.c_uint(p.idx)]), ty::ty_self => self.leaf(~"self"), ty::ty_type => self.leaf(~"type"), diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 7b5a912ed7f23..604bad2312f72 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -179,6 +179,7 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef { ty::ty_self => cx.tcx.sess.unimpl(~"type_of: ty_self"), ty::ty_infer(*) => cx.tcx.sess.bug(~"type_of with ty_infer"), ty::ty_param(*) => cx.tcx.sess.bug(~"type_of with ty_param"), + ty::ty_err(*) => cx.tcx.sess.bug(~"type_of with ty_err") }; cx.lltypes.insert(t, llty); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index fe8df3e2ada67..cb567028ac99c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -57,7 +57,7 @@ export lookup_item_type; export lookup_public_fields; export method; export method_idx; -export mk_class; +export mk_class, mk_err; export mk_ctxt; export mk_with_id, type_def_id; export mt; @@ -87,6 +87,7 @@ export ty_fn_proto, ty_fn_purity, ty_fn_ret, ty_fn_ret_style, tys_in_fn_ty; export ty_int, mk_int, mk_mach_int, mk_char; export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64; export mk_f32, mk_f64; +export ty_err; export ty_estr, mk_estr, type_is_str; export ty_evec, mk_evec, type_is_vec; export ty_unboxed_vec, mk_unboxed_vec, mk_mut_unboxed_vec; @@ -127,7 +128,7 @@ export kind_is_owned; export meta_kind, kind_lteq, type_kind; export operators; export type_err, terr_vstore_kind; -export terr_onceness_mismatch; +export terr_mismatch, terr_onceness_mismatch; export type_err_to_str, note_and_explain_type_err; export expected_found; export type_needs_drop; @@ -673,6 +674,9 @@ enum sty { ty_self, // special, implicit `self` type parameter ty_infer(InferTy), // soething used only during inference/typeck + ty_err, // Also only used during inference/typeck, to represent + // the type of an erroneous expression (helps cut down + // on non-useful type error messages) // "Fake" types, used for trans purposes ty_type, // type_desc* @@ -1062,7 +1066,7 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option) -> t { } ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | - ty_opaque_box => (), + ty_opaque_box | ty_err => (), ty_param(_) => flags |= has_params as uint, ty_infer(_) => flags |= needs_infer as uint, ty_self => flags |= has_self as uint, @@ -1094,6 +1098,8 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option) -> t { fn mk_nil(cx: ctxt) -> t { mk_t(cx, ty_nil) } +fn mk_err(cx: ctxt) -> t { mk_t(cx, ty_err) } + fn mk_bot(cx: ctxt) -> t { mk_t(cx, ty_bot) } fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) } @@ -1301,7 +1307,7 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) { match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_estr(_) | ty_type | ty_opaque_box | ty_self | - ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) => { + ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) | ty_err => { } ty_box(tm) | ty_evec(tm, _) | ty_unboxed_vec(tm) | ty_ptr(tm) | ty_rptr(_, tm) => { @@ -1386,7 +1392,7 @@ fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty { ty_class(did, fold_substs(substs, fldop)) } ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | + ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | ty_err | ty_opaque_box | ty_infer(_) | ty_param(*) | ty_self => { *sty } @@ -1794,7 +1800,7 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool { ty_trait(_, _, vstore_fixed(_)) | ty_trait(_, _, vstore_slice(_)) => false, - ty_param(*) | ty_infer(*) => true, + ty_param(*) | ty_infer(*) | ty_err => true, ty_evec(mt, vstore_fixed(_)) => type_needs_drop(cx, mt.ty), ty_unboxed_vec(mt) => type_needs_drop(cx, mt.ty), @@ -2270,7 +2276,7 @@ fn type_kind(cx: ctxt, ty: t) -> Kind { cx.sess.bug(~"Asked to compute kind of a type variable"); } ty_type | ty_opaque_closure_ptr(_) - | ty_opaque_box | ty_unboxed_vec(_) => { + | ty_opaque_box | ty_unboxed_vec(_) | ty_err => { cx.sess.bug(~"Asked to compute kind of fictitious type"); } }; @@ -2341,7 +2347,7 @@ fn type_size(cx: ctxt, ty: t) -> uint { cx.sess.bug(~"Asked to compute kind of a type variable"); } ty_type | ty_opaque_closure_ptr(_) - | ty_opaque_box | ty_unboxed_vec(_) => { + | ty_opaque_box | ty_unboxed_vec(_) | ty_err => { cx.sess.bug(~"Asked to compute kind of fictitious type"); } } @@ -2384,6 +2390,7 @@ fn is_instantiable(cx: ctxt, r_ty: t) -> bool { ty_estr(_) | ty_fn(_) | ty_infer(_) | + ty_err | ty_param(_) | ty_self | ty_type | @@ -2589,7 +2596,7 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool { result = false; } - ty_infer(*) | ty_self(*) => { + ty_infer(*) | ty_self(*) | ty_err => { cx.sess.bug(~"non concrete type in type_is_pod"); } } @@ -2862,6 +2869,8 @@ impl sty : to_bytes::IterBytes { ty_rptr(ref r, ref mt) => to_bytes::iter_bytes_3(&24u8, r, mt, lsb0, f), + + ty_err => 25u8.iter_bytes(lsb0, f) } } } @@ -3357,7 +3366,8 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str { ty_infer(IntVar(_)) => ~"integral variable", ty_infer(FloatVar(_)) => ~"floating-point variable", ty_param(_) => ~"type parameter", - ty_self => ~"self" + ty_self => ~"self", + ty_err => ~"type error" } } @@ -4787,6 +4797,12 @@ impl sty : cmp::Eq { _ => false } } + ty_err => { + match (*other) { + ty_err => true, + _ => false + } + } ty_param(e0a) => { match (*other) { ty_param(e0b) => e0a == e0b, @@ -4944,6 +4960,12 @@ impl sty : cmp::Eq { _ => false } } + ty_err => { + match (*other) { + ty_err => true, + _ => false + } + } ty_param(e0a) => { match (*other) { ty_param(e0b) => e0a == e0b, diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index a733d8e6de958..5a45e13a16f73 100644 --- a/src/librustc/middle/typeck/check.rs +++ b/src/librustc/middle/typeck/check.rs @@ -702,16 +702,6 @@ impl @fn_ctxt { self.inh.node_type_substs.find(id) } - fn report_mismatched_types(sp: span, e: ty::t, a: ty::t, - err: &ty::type_err) { - self.ccx.tcx.sess.span_err( - sp, - fmt!("mismatched types: expected `%s` but found `%s` (%s)", - self.infcx().ty_to_str(e), - self.infcx().ty_to_str(a), - ty::type_err_to_str(self.ccx.tcx, err))); - ty::note_and_explain_type_err(self.ccx.tcx, err); - } fn mk_subty(a_is_expected: bool, span: span, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { @@ -775,6 +765,17 @@ impl @fn_ctxt { rp.map( |_rp| self.infcx().next_region_var_with_lb(span, lower_bound)) } + + fn type_error_message(sp: span, mk_msg: fn(~str) -> ~str, + actual_ty: ty::t, err: Option<&ty::type_err>) { + self.infcx().type_error_message(sp, mk_msg, actual_ty, err); + } + + fn report_mismatched_types(sp: span, e: ty::t, a: ty::t, + err: &ty::type_err) { + self.infcx().report_mismatched_types(sp, e, a, err); + } + } fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> (ty::t, uint) { @@ -979,6 +980,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, args: ~[@ast::expr], deref_args: DerefArgs) -> {fty: ty::t, bot: bool} { + let tcx = fcx.ccx.tcx; let mut bot = false; // Replace all region parameters in the arguments and return @@ -987,58 +989,60 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, debug!("check_call_inner: before universal quant., in_fty=%s", fcx.infcx().ty_to_str(in_fty)); + let mut formal_tys; + // This is subtle: we expect `fty` to be a function type, which // normally introduce a level of binding. In this case, we want to // process the types bound by the function but not by any nested // functions. Therefore, we match one level of structure. - let fn_ty = + let fty = match structure_of(fcx, sp, in_fty) { ty::ty_fn(ref fn_ty) => { - replace_bound_regions_in_fn_ty( - fcx.ccx.tcx, @Nil, None, fn_ty, - |_br| fcx.infcx().next_region_var(sp, - call_expr_id)).fn_ty + let fn_ty = replace_bound_regions_in_fn_ty(tcx, @Nil, + None, fn_ty, |_br| fcx.infcx().next_region_var(sp, + call_expr_id)).fn_ty; + + let supplied_arg_count = args.len(); + + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let expected_arg_count = fn_ty.sig.inputs.len(); + formal_tys = if expected_arg_count == supplied_arg_count { + fn_ty.sig.inputs.map(|a| a.ty) + } else { + tcx.sess.span_err( + sp, fmt!("this function takes %u parameter%s but \ + %u parameter%s supplied", + expected_arg_count, + if expected_arg_count == 1 { + ~"" + } else { + ~"s" + }, + supplied_arg_count, + if supplied_arg_count == 1 { + ~" was" + } else { + ~"s were" + })); + fcx.infcx().next_ty_vars(supplied_arg_count) + }; + ty::mk_fn(tcx, fn_ty) } _ => { - // I would like to make this span_err, but it's - // really hard due to the way that expr_bind() is - // written. - fcx.ccx.tcx.sess.span_fatal(sp, ~"mismatched types: \ - expected function or foreign \ - function but found " - + fcx.infcx().ty_to_str(in_fty)); + fcx.type_error_message(sp, |actual| { + fmt!("expected function or foreign function but \ + found `%s`", actual) }, in_fty, None); + // check each arg against "error", in order to set up + // all the node type bindings + formal_tys = args.map(|_x| ty::mk_err(tcx)); + ty::mk_err(tcx) } }; - let fty = ty::mk_fn(fcx.tcx(), fn_ty); debug!("check_call_inner: after universal quant., fty=%s", fcx.infcx().ty_to_str(fty)); - let supplied_arg_count = args.len(); - - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let expected_arg_count = fn_ty.sig.inputs.len(); - let formal_tys = if expected_arg_count == supplied_arg_count { - fn_ty.sig.inputs.map(|a| a.ty) - } else { - fcx.ccx.tcx.sess.span_err( - sp, fmt!("this function takes %u parameter%s but %u \ - parameter%s supplied", expected_arg_count, - if expected_arg_count == 1u { - ~"" - } else { - ~"s" - }, - supplied_arg_count, - if supplied_arg_count == 1u { - ~" was" - } else { - ~"s were" - })); - fcx.infcx().next_ty_vars(supplied_arg_count) - }; - // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments // that are not anonymous functions, then we typecheck the anonymous @@ -1129,11 +1133,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, // Pull the return type out of the type of the function. match structure_of(fcx, sp, fty) { ty::ty_fn(ref f) => { - bot |= (f.meta.ret_style == ast::noreturn); - fcx.write_ty(call_expr_id, f.sig.output); - return bot; + bot |= (f.meta.ret_style == ast::noreturn); + fcx.write_ty(call_expr_id, f.sig.output); + return bot; + } + _ => { + fcx.write_ty(call_expr_id, ty::mk_err(fcx.ccx.tcx)); + fcx.type_error_message(sp, |_actual| { + ~"expected function"}, fty, None); + return bot; } - _ => fcx.ccx.tcx.sess.span_fatal(sp, ~"calling non-function") } } @@ -1239,8 +1248,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, }; } + // A hack, but this prevents multiple errors for the same code + // (since check_user_binop calls structurally_resolve_type) let (result, rhs_bot) = - check_user_binop(fcx, expr, lhs, lhs_t, op, rhs); + match ty::deref(fcx.tcx(), lhs_t, false).map( + |tt| structurally_resolved_type(fcx, + expr.span, tt.ty)) { + Some(t) if ty::get(t).sty == ty::ty_err => (t, false), + _ => check_user_binop(fcx, expr, lhs, lhs_t, op, rhs) + }; fcx.write_ty(expr.id, result); return lhs_bot | rhs_bot; } @@ -1262,12 +1278,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, _ => () } check_expr(fcx, rhs, None); - - tcx.sess.span_err( - ex.span, ~"binary operation " + ast_util::binop_to_str(op) + - ~" cannot be applied to type `" + - fcx.infcx().ty_to_str(lhs_resolved_t) + - ~"`"); + fcx.type_error_message(ex.span, + |actual| { + fmt!("binary operation %s cannot be applied to type `%s`", + ast_util::binop_to_str(op), actual) + }, + lhs_resolved_t, None); // If the or operator is used it might be that the user forgot to // supply the do keyword. Let's be more helpful in that situation. @@ -1292,10 +1308,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, DontDerefArgs) { Some((ret_ty, _)) => ret_ty, _ => { - fcx.ccx.tcx.sess.span_err( - ex.span, fmt!("cannot apply unary operator `%s` to type `%s`", - op_str, fcx.infcx().ty_to_str(rhs_t))); - rhs_t + fcx.type_error_message(ex.span, |actual| { + fmt!("cannot apply unary operator `%s` to type `%s`", + op_str, actual) + }, rhs_t, None); + rhs_t } } } @@ -1454,17 +1471,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, } } None => { - let t_err = - fcx.infcx().resolve_type_vars_if_possible(expr_t); - let msg = - fmt!( - "attempted access of field `%s` on type `%s`, \ - but no field or method with that name was found", - tcx.sess.str_of(field), - fcx.infcx().ty_to_str(t_err)); - tcx.sess.span_err(expr.span, msg); - // NB: Add bogus type to allow typechecking to continue - fcx.write_ty(expr.id, fcx.infcx().next_ty_var()); + fcx.type_error_message(expr.span, + |actual| { + fmt!("attempted access of field `%s` on type `%s`, but \ + no field or method with that name was found", + tcx.sess.str_of(field), actual) + }, + expr_t, None); + // Add error type for the result + fcx.write_ty(expr.id, ty::mk_err(tcx)); } } @@ -1802,10 +1817,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, field"); } _ => { - tcx.sess.span_err( - expr.span, - fmt!("type %s cannot be dereferenced", - fcx.infcx().ty_to_str(oprnd_t))); + fcx.type_error_message(expr.span, |actual| { + fmt!("type %s cannot be dereferenced", actual) + }, oprnd_t, None); } } } @@ -1958,7 +1972,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, // appear in the context of a call, so we get the expected type of the // parameter. The catch here is that we need to validate two things: // 1. a closure that returns a bool is expected - // 2. the cloure that was given returns unit + // 2. the closure that was given returns unit let expected_sty = unpack_expected(fcx, expected, |x| Some(x)); let inner_ty = match expected_sty { Some(ty::ty_fn(fty)) => { @@ -1966,10 +1980,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, fty.sig.output, ty::mk_bool(tcx)) { result::Ok(_) => (), result::Err(_) => { - tcx.sess.span_fatal( - expr.span, fmt!("a `loop` function's last argument \ - should return `bool`, not `%s`", - fcx.infcx().ty_to_str(fty.sig.output))); + fcx.type_error_message(expr.span, + |actual| { + fmt!("a `loop` function's last argument \ + should return `bool`, not `%s`", actual) + }, + fty.sig.output, None); + fcx.write_ty(id, ty::mk_err(tcx)); + return true; } } ty::mk_fn(tcx, FnTyBase { @@ -1978,11 +1996,22 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, ..fty.sig} }) } - _ => { - tcx.sess.span_fatal(expr.span, ~"a `loop` function's last \ - argument should be of function \ - type"); - } + _ => + match expected { + Some(expected_t) => { + fcx.type_error_message(expr.span, |actual| { + fmt!("a `loop` function's last \ + argument should be of function \ + type, not `%s`", + actual) + }, + expected_t, None); + fcx.write_ty(id, ty::mk_err(tcx)); + return true; + } + None => fcx.tcx().sess.impossible_case(expr.span, + ~"loop body must have an expected type") + } }; match b.node { ast::expr_fn_block(decl, body, cap_clause) => { @@ -2012,13 +2041,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let expected_sty = unpack_expected(fcx, expected, |x| Some(x)); let inner_ty = match expected_sty { Some(ty::ty_fn(fty)) => { - ty::mk_fn(tcx, fty) - } - _ => { - tcx.sess.span_fatal(expr.span, ~"Non-function passed to a `do` \ - function as its last argument, or wrong number of arguments \ - passed to a `do` function"); + ty::mk_fn(tcx, fty) } + _ => match expected { + Some(expected_t) => { + fcx.type_error_message(expr.span, |_actual| { + ~"Non-function passed to a `do` \ + function as its last argument, or wrong number \ + of arguments passed to a `do` function" + }, expected_t, None); + fcx.write_ty(id, ty::mk_err(tcx)); + return true; + } + None => fcx.tcx().sess.impossible_case(expr.span, + ~"do body must have expected type") + } }; match b.node { ast::expr_fn_block(decl, body, cap_clause) => { @@ -2067,13 +2104,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, _ => { if ty::type_is_nil(t_e) { - tcx.sess.span_err(expr.span, ~"cast from nil: " + - fcx.infcx().ty_to_str(t_e) + ~" as " + - fcx.infcx().ty_to_str(t_1)); + fcx.type_error_message(expr.span, |actual| { + fmt!("cast from nil: `%s` as `%s`", actual, + fcx.infcx().ty_to_str(t_1)) + }, t_e, None); } else if ty::type_is_nil(t_1) { - tcx.sess.span_err(expr.span, ~"cast to nil: " + - fcx.infcx().ty_to_str(t_e) + ~" as " + - fcx.infcx().ty_to_str(t_1)); + fcx.type_error_message(expr.span, |actual| { + fmt!("cast to nil: `%s` as `%s`", actual, + fcx.infcx().ty_to_str(t_1)) + }, t_e, None); } let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1); @@ -2085,10 +2124,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, supported here, then file an enhancement issue and record the issue number in this comment. */ - tcx.sess.span_err(expr.span, - ~"non-scalar cast: " + - fcx.infcx().ty_to_str(t_e) + ~" as " + - fcx.infcx().ty_to_str(t_1)); + fcx.type_error_message(expr.span, |actual| { + fmt!("non-scalar cast: `%s` as `%s`", actual, + fcx.infcx().ty_to_str(t_1)) + }, t_e, None); } } } @@ -2157,8 +2196,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let base_fields = match structure_of(fcx, expr.span, bexpr_t) { ty::ty_rec(flds) => flds, _ => { - tcx.sess.span_fatal(expr.span, - ~"record update has non-record base"); + fcx.type_error_message(expr.span, |_actual| { + ~"record update has non-record base" + }, bexpr_t, None); + fcx.write_ty(id, ty::mk_err(tcx)); + return true; } }; fcx.write_ty(id, bexpr_t); @@ -2171,9 +2213,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, } } if !found { - tcx.sess.span_fatal(f.span, + tcx.sess.span_err(f.span, ~"unknown field in record update: " + tcx.sess.str_of(f.node.ident)); + fcx.write_ty(id, ty::mk_err(tcx)); + return true; } } } @@ -2220,9 +2264,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, ~[idx], DontDerefArgs) { Some((ret_ty, _)) => fcx.write_ty(id, ret_ty), _ => { - tcx.sess.span_fatal( - expr.span, ~"cannot index a value of type `" + - fcx.infcx().ty_to_str(base_t) + ~"`"); + fcx.type_error_message(expr.span, |actual| + fmt!("cannot index a value of type `%s`", + actual), base_t, None); + fcx.write_ty(id, ty::mk_err(tcx)); + return true; } } } @@ -2247,9 +2293,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { if !type_is_integral(fcx, sp, t) { - fcx.ccx.tcx.sess.span_err(sp, ~"mismatched types: expected \ - integral type but found `" - + fcx.infcx().ty_to_str(t) + ~"`"); + fcx.type_error_message(sp, |actual| { + fmt!("mismatched types: expected integral type but found `%s`", + actual) + }, t, None); } } @@ -2403,8 +2450,8 @@ fn check_instantiable(tcx: ty::ctxt, let item_ty = ty::node_id_to_type(tcx, item_id); if !ty::is_instantiable(tcx, item_ty) { tcx.sess.span_err(sp, fmt!("this type cannot be instantiated \ - without an instance of itself; \ - consider using `option<%s>`", + without an instance of itself; \ + consider using `option<%s>`", ty_to_str(tcx, item_ty))); } } @@ -2507,8 +2554,8 @@ fn check_enum_variants(ccx: @crate_ctxt, } }) { ccx.tcx.sess.span_err(sp, ~"illegal recursive enum type; \ - wrap the inner value in a box to \ - make it representable"); + wrap the inner value in a box to \ + make it representable"); } // Check that it is possible to instantiate this enum: @@ -2657,8 +2704,10 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { match infer::resolve_type(fcx.infcx(), tp, force_tvar) { Ok(t_s) if !ty::type_is_ty_var(t_s) => return t_s, _ => { - fcx.ccx.tcx.sess.span_fatal - (sp, ~"the type of this value must be known in this context"); + fcx.type_error_message(sp, |_actual| { + ~"the type of this value must be known in this context" + }, tp, None); + return ty::mk_err(fcx.tcx()); } } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index fdcbf8a53e390..78cd677725738 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -697,6 +697,8 @@ impl LookupContext { |m,r| ty::mk_rptr(tcx, r, {ty:self_ty, mutbl:m})) } + ty_err => None, + ty_opaque_closure_ptr(_) | ty_unboxed_vec(_) | ty_opaque_box | ty_type | ty_infer(TyVar(_)) => { self.bug(fmt!("Unexpected type: %s", diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 2c3666419b214..7de2de708cc98 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -476,13 +476,7 @@ fn demand_suptype(vcx: &VtableContext, sp: span, e: ty::t, a: ty::t) { match infer::mk_subty(vcx.infcx, false, sp, a, e) { result::Ok(()) => {} // Ok. result::Err(ref err) => { - vcx.tcx().sess.span_err( - sp, - fmt!("mismatched types: expected `%s` but found `%s` (%s)", - vcx.infcx.ty_to_str(e), - vcx.infcx.ty_to_str(a), - ty::type_err_to_str(vcx.tcx(), err))); - ty::note_and_explain_type_err(vcx.tcx(), err); + vcx.infcx.report_mismatched_types(sp, e, a, err); } } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 9fc7814422f8f..97968e11ffa92 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -13,7 +13,7 @@ use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, get}; use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_class}; use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint}; use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec, ty_uniq}; -use middle::ty::{ty_fn, ty_trait, ty_tup, ty_infer}; +use middle::ty::{ty_err, ty_fn, ty_trait, ty_tup, ty_infer}; use middle::ty::{ty_param, ty_self, ty_type, ty_opaque_box}; use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_ty_var}; use middle::typeck::infer::{infer_ctxt, can_mk_subty}; @@ -76,7 +76,7 @@ fn get_base_type(inference_context: infer_ctxt, span: span, original_type: t) ty_estr(*) | ty_evec(*) | ty_rec(*) | ty_fn(*) | ty_tup(*) | ty_infer(*) | ty_param(*) | ty_self | ty_type | ty_opaque_box | - ty_opaque_closure_ptr(*) | ty_unboxed_vec(*) => { + ty_opaque_closure_ptr(*) | ty_unboxed_vec(*) | ty_err => { debug!("(getting base type) no base type; found %?", get(original_type).sty); None diff --git a/src/librustc/middle/typeck/infer.rs b/src/librustc/middle/typeck/infer.rs index edb6452ab50e4..56befd9734215 100644 --- a/src/librustc/middle/typeck/infer.rs +++ b/src/librustc/middle/typeck/infer.rs @@ -684,5 +684,43 @@ impl infer_ctxt { result::Err(_) => typ } } + + fn type_error_message(sp: span, mk_msg: fn(~str) -> ~str, + actual_ty: ty::t, err: Option<&ty::type_err>) { + let actual_ty = self.resolve_type_vars_if_possible(actual_ty); + + // Don't report an error if actual type is ty_err. + match ty::get(actual_ty).sty { + ty::ty_err => return, + _ => () + } + let error_str = err.map_default(~"", |t_err| + fmt!(" (%s)", + ty::type_err_to_str(self.tcx, *t_err))); + self.tcx.sess.span_err(sp, + fmt!("%s%s", mk_msg(self.ty_to_str(actual_ty)), + error_str)); + err.iter(|err| + ty::note_and_explain_type_err(self.tcx, *err)); + } + + fn report_mismatched_types(sp: span, e: ty::t, a: ty::t, + err: &ty::type_err) { + // Don't report an error if expected is ty_err + let resolved_expected = + self.resolve_type_vars_if_possible(e); + let mk_msg = match ty::get(resolved_expected).sty { + ty::ty_err => return, + _ => { + // if I leave out : ~str, it infers &str and complains + |actual: ~str| { + fmt!("mismatched types: expected `%s` but found `%s`", + self.ty_to_str(resolved_expected), actual) + } + } + }; + self.type_error_message(sp, mk_msg, a, Some(err)); + } + } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 198b26c4ecc69..57c8f79b78a2e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -9,7 +9,7 @@ use middle::ty::{mt, t, param_bound}; use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_enum}; -use middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int}; +use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int}; use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; use middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_self, ty_tup}; use middle::ty::{ty_type, ty_uniq, ty_uint, ty_infer}; @@ -390,6 +390,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str { f.meta.ret_style) } ty_infer(infer_ty) => infer_ty.to_str(), + ty_err => ~"[type error]", ty_param({idx: id, _}) => { ~"'" + str::from_bytes(~[('a' as u8) + (id as u8)]) } diff --git a/src/test/compile-fail/cast-from-nil.rs b/src/test/compile-fail/cast-from-nil.rs index a76df00d0d537..b7cf35e6f1b37 100644 --- a/src/test/compile-fail/cast-from-nil.rs +++ b/src/test/compile-fail/cast-from-nil.rs @@ -1,2 +1,2 @@ -// error-pattern: cast from nil: () as u32 +// error-pattern: cast from nil: `()` as `u32` fn main() { let u = (assert true) as u32; } \ No newline at end of file diff --git a/src/test/compile-fail/cast-to-nil.rs b/src/test/compile-fail/cast-to-nil.rs index 44c0f5a1da2a6..5c5d456484ab8 100644 --- a/src/test/compile-fail/cast-to-nil.rs +++ b/src/test/compile-fail/cast-to-nil.rs @@ -1,2 +1,2 @@ -// error-pattern: cast to nil: u32 as () +// error-pattern: cast to nil: `u32` as `()` fn main() { let u = 0u32 as (); } \ No newline at end of file diff --git a/src/test/compile-fail/extern-no-call.rs b/src/test/compile-fail/extern-no-call.rs index e53f4ee694042..4ed32e16d3304 100644 --- a/src/test/compile-fail/extern-no-call.rs +++ b/src/test/compile-fail/extern-no-call.rs @@ -1,4 +1,4 @@ -// error-pattern:expected function or foreign function but found *u8 +// error-pattern:expected function or foreign function but found `*u8` extern fn f() { } diff --git a/src/test/compile-fail/issue-1871.rs b/src/test/compile-fail/issue-1871.rs index 6937dbdce0728..99458b835f01e 100644 --- a/src/test/compile-fail/issue-1871.rs +++ b/src/test/compile-fail/issue-1871.rs @@ -1,11 +1,12 @@ -// xfail-test +// Tests that we don't generate a spurious error about f.honk's type +// being undeterminable fn main() { let f = 42; let _g = if f < 5 { - f.honk(); + f.honk() //~ ERROR attempted access of field `honk` } else { - 12 + () }; } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index eb8da1519e822..b9ccfc667039d 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -11,5 +11,5 @@ impl ~[A]: vec_monad { } } fn main() { - ["hi"].bind({|x| [x] }); + ["hi"].bind({|x| [x] }); //~ ERROR attempted access of field `bind` }