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. So if you see derived type errors appearing from now on, file a bug! r=graydon Closes #1871
This commit is contained in:
parent
77ef4e7176
commit
ef833d4101
15 changed files with 256 additions and 146 deletions
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<ast::def_id>) -> 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<ast::def_id>) -> 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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)])
|
||||
}
|
||||
|
|
|
@ -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; }
|
|
@ -1,2 +1,2 @@
|
|||
// error-pattern: cast to nil: u32 as ()
|
||||
// error-pattern: cast to nil: `u32` as `()`
|
||||
fn main() { let u = 0u32 as (); }
|
|
@ -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() {
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,5 +11,5 @@ impl<A> ~[A]: vec_monad<A> {
|
|||
}
|
||||
}
|
||||
fn main() {
|
||||
["hi"].bind({|x| [x] });
|
||||
["hi"].bind({|x| [x] }); //~ ERROR attempted access of field `bind`
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue