Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First attemt at supporting explicit discriminant numbers on tag variants #1397

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/comp/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const tag_item_method: uint = 0x31u;
const tag_impl_iface: uint = 0x32u;
const tag_impl_iface_did: uint = 0x33u;

// discriminator value for variants
const tag_disr_val: uint = 0x34u;

// djb's cdb hashes.
fn hash_node_id(&&node_id: int) -> uint { ret 177573u ^ (node_id as uint); }

Expand Down
20 changes: 19 additions & 1 deletion src/comp/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ fn variant_tag_id(d: ebml::doc) -> ast::def_id {
ret parse_def_id(ebml::doc_data(tagdoc));
}

fn variant_disr_val(d: ebml::doc) -> option::t<int> {
alt ebml::maybe_get_doc(d, tag_disr_val) {
some(val_doc) {
let val_buf = ebml::doc_data(val_doc);
let val = int::parse_buf(val_buf, 10u);
ret some(val);
}
_ { ret none;}
}
}

fn doc_type(doc: ebml::doc, tcx: ty::ctxt, cdata: cmd) -> ty::t {
let tp = ebml::get_doc(doc, tag_items_data_item_type);
parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, {|did|
Expand Down Expand Up @@ -240,6 +251,7 @@ fn get_tag_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
let item = find_item(id, items);
let infos: [ty::variant_info] = [];
let variant_ids = tag_variant_ids(item, cdata);
let disr_val = 0;
for did: ast::def_id in variant_ids {
let item = find_item(did.node, items);
let ctor_ty = item_type(item, tcx, cdata);
Expand All @@ -250,7 +262,13 @@ fn get_tag_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
}
_ { /* Nullary tag variant. */ }
}
infos += [@{args: arg_tys, ctor_ty: ctor_ty, id: did}];
alt variant_disr_val(item) {
some(val) { disr_val = val; }
_ { /* empty */ }
}
infos += [@{args: arg_tys, ctor_ty: ctor_ty, id: did,
disr_val: disr_val}];
disr_val += 1;
}
ret infos;
}
Expand Down
12 changes: 12 additions & 0 deletions src/comp/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ fn encode_discriminant(ecx: @encode_ctxt, ebml_w: ebml::writer, id: node_id) {
ebml::end_tag(ebml_w);
}

fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: ebml::writer, disr_val: int) {
ebml::start_tag(ebml_w, tag_disr_val);
ebml_w.writer.write(str::bytes(int::to_str(disr_val,10u)));
ebml::end_tag(ebml_w);
}

fn encode_tag_id(ebml_w: ebml::writer, id: def_id) {
ebml::start_tag(ebml_w, tag_items_data_item_tag_id);
ebml_w.writer.write(str::bytes(def_to_str(id)));
Expand All @@ -237,6 +243,7 @@ fn encode_tag_id(ebml_w: ebml::writer, id: def_id) {
fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
id: node_id, variants: [variant],
&index: [entry<int>], ty_params: [ty_param]) {
let disr_val = 0;
for variant: variant in variants {
index += [{val: variant.node.id, pos: ebml_w.writer.tell()}];
ebml::start_tag(ebml_w, tag_items_data_item);
Expand All @@ -249,8 +256,13 @@ fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
encode_symbol(ecx, ebml_w, variant.node.id);
}
encode_discriminant(ecx, ebml_w, variant.node.id);
if variant.node.disr_val != disr_val {
encode_disr_val(ecx, ebml_w, variant.node.disr_val);
disr_val = variant.node.disr_val;
}
encode_type_param_bounds(ebml_w, ecx, ty_params);
ebml::end_tag(ebml_w);
disr_val += 1;
}
}

Expand Down
44 changes: 25 additions & 19 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1726,17 +1726,15 @@ fn iter_structural_ty(cx: @block_ctxt, av: ValueRef, t: ty::t,
Unreachable(unr_cx);
let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants);
let next_cx = new_sub_block_ctxt(cx, "tag-iter-next");
let i = 0u;
for variant: ty::variant_info in *variants {
let variant_cx =
new_sub_block_ctxt(cx,
"tag-iter-variant-" +
uint::to_str(i, 10u));
AddCase(llswitch, C_int(ccx, i as int), variant_cx.llbb);
int::to_str(variant.disr_val, 10u));
AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb);
variant_cx =
iter_variant(variant_cx, llunion_a_ptr, variant, tps, tid, f);
Br(variant_cx, next_cx.llbb);
i += 1u;
}
ret next_cx;
}
Expand Down Expand Up @@ -2745,12 +2743,9 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
let bcx = alloc_result.bcx;
let lltagptr = PointerCast(bcx, lltagblob, T_ptr(lltagty));
let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
let d = if vec::len(*ty::tag_variants(ccx.tcx, tid)) != 1u {
let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
let lldiscrim = Load(bcx, lldiscrim_gv);
lldiscrim
} else { C_int(ccx, 0) };
Store(bcx, d, lldiscrimptr);
let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
let lldiscrim = Load(bcx, lldiscrim_gv);
Store(bcx, lldiscrim, lldiscrimptr);
ret lval_no_env(bcx, lltagptr, temporary);
}
}
Expand Down Expand Up @@ -3022,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
Expand All @@ -3031,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);
Expand Down Expand Up @@ -3064,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);
Expand Down Expand Up @@ -4685,7 +4694,7 @@ fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::fn_decl,


fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
variant: ast::variant, index: int, is_degen: bool,
variant: ast::variant, is_degen: bool,
ty_params: [ast::ty_param]) {
let ccx = cx.ccx;

Expand Down Expand Up @@ -4735,7 +4744,7 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
let lltagptr =
PointerCast(bcx, fcx.llretptr, T_opaque_tag_ptr(ccx));
let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
Store(bcx, C_int(ccx, index), lldiscrimptr);
Store(bcx, C_int(ccx, variant.node.disr_val), lldiscrimptr);
GEPi(bcx, lltagptr, [0, 1])
};
i = 0u;
Expand Down Expand Up @@ -5086,10 +5095,8 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
ast::item_tag(variants, tps) {
let sub_cx = extend_path(cx, item.ident);
let degen = vec::len(variants) == 1u;
let i = 0;
for variant: ast::variant in variants {
trans_tag_variant(sub_cx, item.id, variant, i, degen, tps);
i += 1;
trans_tag_variant(sub_cx, item.id, variant, degen, tps);
}
}
ast::item_const(_, expr) { trans_const(cx.ccx, expr, item.id); }
Expand Down Expand Up @@ -5421,19 +5428,18 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
visit::visit_item(it, new_pt, v);
alt it.node {
ast::item_tag(variants, _) {
let i = 0u;
for variant in variants {
let p = new_pt + [variant.node.name, "discrim"];
let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
let disr_val = variant.node.disr_val;
let discrim_gvar = str::as_buf(s, {|buf|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
});
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, i as int));
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val));
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
ccx.discrims.insert(
ast_util::local_def(variant.node.id), discrim_gvar);
ccx.discrim_symbols.insert(variant.node.id, s);
i += 1u;
}
}
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
Expand Down
8 changes: 3 additions & 5 deletions src/comp/middle/trans_alt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import trans_common::*;
// An option identifying a branch (either a literal, a tag variant or a range)
tag opt {
lit(@ast::expr);
var(/* variant id */uint, /* variant dids */{tg: def_id, var: def_id});
var(/* disr val */int, /* variant dids */{tg: def_id, var: def_id});
range(@ast::expr, @ast::expr);
}
fn opt_eq(a: opt, b: opt) -> bool {
Expand Down Expand Up @@ -53,7 +53,7 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
}
}
}
var(id, _) { ret single_result(rslt(bcx, C_int(ccx, id as int))); }
var(disr_val, _) { ret single_result(rslt(bcx, C_int(ccx, disr_val))); }
range(l1, l2) {
ret range_result(rslt(bcx, trans::trans_const_expr(ccx, l1)),
rslt(bcx, trans::trans_const_expr(ccx, l2)));
Expand All @@ -64,10 +64,8 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
fn variant_opt(ccx: @crate_ctxt, pat_id: ast::node_id) -> opt {
let vdef = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat_id));
let variants = ty::tag_variants(ccx.tcx, vdef.tg);
let i = 0u;
for v: ty::variant_info in *variants {
if vdef.var == v.id { ret var(i, vdef); }
i += 1u;
if vdef.var == v.id { ret var(v.disr_val, vdef); }
}
fail;
}
Expand Down
29 changes: 27 additions & 2 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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); }
Expand Down Expand Up @@ -2686,7 +2708,8 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option::t<t> {
}

// Tag information
type variant_info = @{args: [ty::t], ctor_ty: ty::t, id: ast::def_id};
type variant_info = @{args: [ty::t], ctor_ty: ty::t, id: ast::def_id,
disr_val: int};

fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
alt cx.tag_var_cache.find(id) {
Expand All @@ -2705,7 +2728,9 @@ fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
} else { [] };
@{args: arg_tys,
ctor_ty: ctor_ty,
id: ast_util::local_def(variant.node.id)}
id: ast_util::local_def(variant.node.id),
disr_val: variant.node.disr_val
}
})
}
}
Expand Down
15 changes: 11 additions & 4 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -2215,10 +2219,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));
}
Expand Down
3 changes: 2 additions & 1 deletion src/comp/syntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,8 @@ type native_mod =

type variant_arg = {ty: @ty, id: node_id};

type variant_ = {name: ident, args: [variant_arg], id: node_id};
type variant_ = {name: ident, args: [variant_arg], id: node_id,
disr_val: int, disr_expr: option::t<@expr>};

type variant = spanned<variant_>;

Expand Down
4 changes: 3 additions & 1 deletion src/comp/syntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,9 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
ret {ty: fld.fold_ty(va.ty), id: va.id};
}
let fold_variant_arg = bind fold_variant_arg_(_, fld);
ret {name: v.name, args: vec::map(v.args, fold_variant_arg), id: v.id};
ret {name: v.name, args: vec::map(v.args, fold_variant_arg), id: v.id,
disr_val: v.disr_val, disr_expr: v.disr_expr
/* FIXME: is this right (copying disr_val and disr_expr) */};
}

fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident { ret i; }
Expand Down
Loading