Add support for casting enum-like tags to scalar values.
This commit is contained in:
parent
08abf8d37f
commit
1dc3debdaf
5 changed files with 63 additions and 6 deletions
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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(_, _) {}
|
||||
_ {
|
||||
// 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: " +
|
||||
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.
|
||||
tcx.sess.span_err(expr.span,
|
||||
"non-scalar cast: " +
|
||||
ty_to_str(tcx, t_e) + " as " +
|
||||
ty_to_str(tcx, t_1));
|
||||
}
|
||||
|
|
12
src/test/compile-fail/tag-variant-cast-non-nullary.rs
Normal file
12
src/test/compile-fail/tag-variant-cast-non-nullary.rs
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue