1
Fork 0

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:
Tim Chevalier 2012-11-16 19:22:48 -08:00
parent 77ef4e7176
commit ef833d4101
15 changed files with 256 additions and 146 deletions

View file

@ -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"
}
}

View file

@ -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"),

View file

@ -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);

View file

@ -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,

View file

@ -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());
}
}
}

View file

@ -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",

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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));
}
}

View file

@ -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)])
}

View file

@ -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; }

View file

@ -1,2 +1,2 @@
// error-pattern: cast to nil: u32 as ()
// error-pattern: cast to nil: `u32` as `()`
fn main() { let u = 0u32 as (); }

View file

@ -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() {
}

View file

@ -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
()
};
}

View file

@ -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`
}