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));
|
check (type_has_static_size(ccx, t_out));
|
||||||
let ll_t_out = type_of(ccx, e.span, 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 {
|
fn t_kind(tcx: ty::ctxt, t: ty::t) -> kind {
|
||||||
ret if ty::type_is_fp(tcx, t) {
|
ret if ty::type_is_fp(tcx, t) {
|
||||||
float
|
float
|
||||||
|
@ -3026,6 +3026,8 @@ fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
|
||||||
pointer
|
pointer
|
||||||
} else if ty::type_is_integral(tcx, t) {
|
} else if ty::type_is_integral(tcx, t) {
|
||||||
integral
|
integral
|
||||||
|
} else if ty::type_is_tag(tcx, t) {
|
||||||
|
tag_
|
||||||
} else { other };
|
} else { other };
|
||||||
}
|
}
|
||||||
let k_in = t_kind(ccx.tcx, t_in);
|
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.} {
|
{in: pointer., out: pointer.} {
|
||||||
PointerCast(e_res.bcx, e_res.val, ll_t_out)
|
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.") }
|
_ { ccx.sess.bug("Translating unsupported cast.") }
|
||||||
};
|
};
|
||||||
ret store_in_dest(e_res.bcx, newval, dest);
|
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_tup_like;
|
||||||
export type_is_str;
|
export type_is_str;
|
||||||
export type_is_unique;
|
export type_is_unique;
|
||||||
|
export type_is_tag;
|
||||||
|
export type_is_enum_like;
|
||||||
export type_structurally_contains_uniques;
|
export type_structurally_contains_uniques;
|
||||||
export type_autoderef;
|
export type_autoderef;
|
||||||
export type_param;
|
export type_param;
|
||||||
|
@ -1263,6 +1265,26 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
|
||||||
ret result;
|
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> {
|
fn type_param(cx: ctxt, ty: t) -> option::t<uint> {
|
||||||
alt struct(cx, ty) {
|
alt struct(cx, ty) {
|
||||||
ty_param(id, _) { ret some(id); }
|
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);
|
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
|
// Parses the programmer's textual representation of a type into our internal
|
||||||
// notion of a type. `getter` is a function that returns the type
|
// 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
|
// This will be looked up later on
|
||||||
ty::ty_iface(_, _) {}
|
ty::ty_iface(_, _) {}
|
||||||
_ {
|
_ {
|
||||||
// FIXME there are more forms of cast to support, eventually.
|
let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
|
||||||
if !( type_is_scalar(fcx, expr.span, t_e)
|
if type_is_enum_like(fcx,expr.span,t_e) && t_1_is_scalar {
|
||||||
&& type_is_scalar(fcx, expr.span, t_1)) {
|
/* this case is allowed */
|
||||||
tcx.sess.span_err(expr.span, "non-scalar cast: " +
|
} 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_e) + " as " +
|
||||||
ty_to_str(tcx, t_1));
|
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 {
|
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_alt(color) == name;
|
||||||
assert get_color_if(color) == name;
|
assert get_color_if(color) == name;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue