1
Fork 0

Add support for casting enum-like tags to scalar values.

This commit is contained in:
Kevin Atkinson 2012-01-10 14:55:54 -07:00 committed by Graydon Hoare
parent 08abf8d37f
commit 1dc3debdaf
5 changed files with 63 additions and 6 deletions

View file

@ -3017,7 +3017,7 @@ fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
check (type_has_static_size(ccx, t_out));
let ll_t_out = type_of(ccx, e.span, t_out);
tag kind { pointer; integral; float; other; }
tag kind { pointer; integral; float; tag_; other; }
fn t_kind(tcx: ty::ctxt, t: ty::t) -> kind {
ret if ty::type_is_fp(tcx, t) {
float
@ -3026,6 +3026,8 @@ fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
pointer
} else if ty::type_is_integral(tcx, t) {
integral
} else if ty::type_is_tag(tcx, t) {
tag_
} else { other };
}
let k_in = t_kind(ccx.tcx, t_in);
@ -3059,6 +3061,18 @@ fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
{in: pointer., out: pointer.} {
PointerCast(e_res.bcx, e_res.val, ll_t_out)
}
{in: tag_., out: integral.} | {in: tag_., out: float.} {
let cx = e_res.bcx;
let lltagty = T_opaque_tag_ptr(ccx);
let av_tag = PointerCast(cx, e_res.val, lltagty);
let lldiscrim_a_ptr = GEPi(cx, av_tag, [0, 0]);
let lldiscrim_a = Load(cx, lldiscrim_a_ptr);
alt k_out {
integral. {int_cast(e_res.bcx, ll_t_out,
val_ty(lldiscrim_a), lldiscrim_a, true)}
float. {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)}
}
}
_ { ccx.sess.bug("Translating unsupported cast.") }
};
ret store_in_dest(e_res.bcx, newval, dest);

View file

@ -173,6 +173,8 @@ export type_is_copyable;
export type_is_tup_like;
export type_is_str;
export type_is_unique;
export type_is_tag;
export type_is_enum_like;
export type_structurally_contains_uniques;
export type_autoderef;
export type_param;
@ -1263,6 +1265,26 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
ret result;
}
fn type_is_tag(cx: ctxt, ty: t) -> bool {
alt struct(cx, ty) {
ty_tag(_, _) { ret true; }
_ { ret false;}
}
}
// Whether a type is enum like, that is a tag type with only nullary
// constructors
fn type_is_enum_like(cx: ctxt, ty: t) -> bool {
alt struct(cx, ty) {
ty_tag(did, tps) {
let variants = tag_variants(cx, did);
let some_n_ary = vec::any(*variants, {|v| vec::len(v.args) > 0u});
ret !some_n_ary;
}
_ { ret false;}
}
}
fn type_param(cx: ctxt, ty: t) -> option::t<uint> {
alt struct(cx, ty) {
ty_param(id, _) { ret some(id); }

View file

@ -211,6 +211,10 @@ fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
ret ty::type_is_scalar(fcx.ccx.tcx, typ_s);
}
fn type_is_enum_like(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
let typ_s = structurally_resolved_type(fcx, sp, typ);
ret ty::type_is_enum_like(fcx.ccx.tcx, typ_s);
}
// Parses the programmer's textual representation of a type into our internal
// notion of a type. `getter` is a function that returns the type
@ -2211,10 +2215,13 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// This will be looked up later on
ty::ty_iface(_, _) {}
_ {
let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
if type_is_enum_like(fcx,expr.span,t_e) && t_1_is_scalar {
/* this case is allowed */
} else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) {
// FIXME there are more forms of cast to support, eventually.
if !( type_is_scalar(fcx, expr.span, t_e)
&& type_is_scalar(fcx, expr.span, t_1)) {
tcx.sess.span_err(expr.span, "non-scalar cast: " +
tcx.sess.span_err(expr.span,
"non-scalar cast: " +
ty_to_str(tcx, t_e) + " as " +
ty_to_str(tcx, t_1));
}

View file

@ -0,0 +1,12 @@
//error-pattern: non-scalar cast
// black and white have the same discriminator value ...
tag non_nullary {
nullary;
other(int);
}
fn main() {
let v = nullary;
let val = v as int;
}

View file

@ -17,7 +17,9 @@ fn main() {
}
fn test_color(color: color, val: int, name: str) unsafe {
assert unsafe::reinterpret_cast(color) == val;
//assert unsafe::reinterpret_cast(color) == val;
assert color as int == val;
assert color as float == val as float;
assert get_color_alt(color) == name;
assert get_color_if(color) == name;
}