From 1dc3debdafbf29c6ac4ff3cf336da62e13e1871e Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Tue, 10 Jan 2012 14:55:54 -0700 Subject: [PATCH] Add support for casting enum-like tags to scalar values. --- src/comp/middle/trans.rs | 16 +++++++++++++- src/comp/middle/ty.rs | 22 +++++++++++++++++++ src/comp/middle/typeck.rs | 15 +++++++++---- .../tag-variant-cast-non-nullary.rs | 12 ++++++++++ src/test/run-pass/tag-variant-disr-val.rs | 4 +++- 5 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/tag-variant-cast-non-nullary.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 998c944b6e0..2c5c45ed570 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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); diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index dbd688de402..a79e4401569 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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 { alt struct(cx, ty) { ty_param(id, _) { ret some(id); } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index be926322f64..1d701f9b9ab 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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)); } diff --git a/src/test/compile-fail/tag-variant-cast-non-nullary.rs b/src/test/compile-fail/tag-variant-cast-non-nullary.rs new file mode 100644 index 00000000000..ecc518e75a1 --- /dev/null +++ b/src/test/compile-fail/tag-variant-cast-non-nullary.rs @@ -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; +} diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index a09de4794c4..1efe40d547d 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -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; }