aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <[email protected]>2010-12-02 19:30:06 -0800
committerPatrick Walton <[email protected]>2010-12-03 10:24:55 -0800
commit7bdb93266d3a88e407f7996d374a8364b84b8e01 (patch)
treeba3e129ca4a29f813dc31bce8f99f2b45dcf7e78 /src
parentDrop slots on the way out of scopes. Un-XFAIL box.rs. (diff)
downloadrust-7bdb93266d3a88e407f7996d374a8364b84b8e01.tar.xz
rust-7bdb93266d3a88e407f7996d374a8364b84b8e01.zip
rustc: Translate nullary tag constructors
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/trans.rs246
1 files changed, 174 insertions, 72 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index ccacffca..27dfa443 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -1,4 +1,5 @@
import std._str;
+import std._uint;
import std._vec;
import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;
@@ -387,6 +388,10 @@ fn C_tydesc(TypeRef t) -> ValueRef {
C_null(T_ptr(T_opaque())))); // is_stateful
}
+fn C_union(TypeRef ty, ValueRef val) -> ValueRef {
+ ret llvm.LLVMConstUnion(ty, val);
+}
+
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
let ValueRef llfn =
llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
@@ -560,10 +565,69 @@ fn iter_structural_ty(@block_ctxt cx,
i += 1;
}
}
+ case (typeck.ty_tag(?tid)) {
+ check (cx.fcx.ccx.tags.contains_key(tid));
+ auto info = cx.fcx.ccx.tags.get(tid);
+ auto n_variants = _vec.len[tup(ast.def_id,arity)](info.variants);
+
+ // Look up the tag in the typechecked AST.
+ check (cx.fcx.ccx.items.contains_key(tid));
+ auto tag_item = cx.fcx.ccx.items.get(tid);
+ let vec[ast.variant] variants = vec(); // FIXME: typestate bug
+ alt (tag_item.node) {
+ case (ast.item_tag(_, ?vs, _, _)) {
+ variants = vs;
+ }
+ case (_) {
+ log "trans: ty_tag doesn't actually refer to a tag";
+ fail;
+ }
+ }
+
+ auto lldiscrim_ptr = cx.build.GEP(v, vec(C_int(0), C_int(0)));
+ auto llunion_ptr = cx.build.GEP(v, vec(C_int(0), C_int(1)));
+ auto lldiscrim = cx.build.Load(lldiscrim_ptr);
+
+ auto unr_cx = new_sub_block_ctxt(cx, "tag-iter-unr");
+ unr_cx.build.Unreachable();
+
+ auto llswitch = cx.build.Switch(lldiscrim, unr_cx.llbb,
+ n_variants);
+
+ auto next_cx = new_sub_block_ctxt(cx, "tag-iter-next");
+
+ auto i = 0u;
+ for (tup(ast.def_id,arity) variant in info.variants) {
+ auto variant_cx = new_sub_block_ctxt(cx, "tag-iter-variant-" +
+ _uint.to_str(i, 10u));
+ llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
+
+ alt (variant._1) {
+ case (n_ary) {
+ // FIXME: broken at the moment, causes type_is_binding
+ // errors; need to unpack the fn type returned by
+ // ann_to_type.
+ let vec[ValueRef] vals = vec(C_int(0), C_int(1),
+ C_int(i as int));
+ auto llfld = r.bcx.build.GEP(v, vals);
+ auto ty = typeck.ann_to_type(variants.(i).ann);
+ r = f(variant_cx, llfld, ty);
+ r.bcx.build.Br(next_cx.llbb);
+ }
+ case (nullary) {
+ // Nothing to do.
+ variant_cx.build.Br(next_cx.llbb);
+ }
+ }
+
+ i += 1u;
+ }
+
+ ret res(next_cx, C_nil());
+ }
case (_) {
cx.fcx.ccx.sess.unimpl("type in iter_structural_ty");
}
- // FIXME: handle records and tags when we support them.
}
ret r;
}
@@ -1191,24 +1255,9 @@ fn trans_name(@block_ctxt cx, &ast.name n, &option.t[ast.def] dopt)
}
case (ast.def_variant(?tid, ?vid)) {
check (cx.fcx.ccx.tags.contains_key(tid));
- auto info = cx.fcx.ccx.tags.get(tid);
- auto i = 0;
- for (tup(ast.def_id,arity) v in info.variants) {
- if (vid == v._0) {
- alt (v._1) {
- case (nullary) {
- auto elems = vec(C_int(i));
- ret tup(res(cx, C_struct(elems)), false);
- }
- case (n_ary) {
- cx.fcx.ccx.sess.unimpl("n-ary tag " +
- "constructor in " +
- "trans");
- }
- }
- }
- i += 1;
- }
+ check (cx.fcx.ccx.item_ids.contains_key(vid));
+ ret tup(res(cx, cx.fcx.ccx.item_ids.get(vid)),
+ false);
}
case (_) {
cx.fcx.ccx.sess.unimpl("def variant in trans");
@@ -1791,59 +1840,6 @@ impure fn trans_mod(@crate_ctxt cx, &ast._mod m) {
}
-fn resolve_tag_types_for_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
- alt (i.node) {
- case (ast.item_tag(_, ?variants, _, ?tag_id)) {
- let vec[TypeRef] variant_tys = vec();
-
- auto info = cx.tags.get(tag_id);
- let vec[tup(ast.def_id,arity)] variant_info = vec();
-
- auto tag_ty;
- if (_vec.len[ast.variant](variants) == 0u) {
- tag_ty = T_struct(vec(T_int()));
- } else {
- auto n_ary_idx = 0u;
- for (ast.variant variant in variants) {
- auto arity_info;
- if (_vec.len[@ast.ty](variant.args) > 0u) {
- let vec[TypeRef] lltys = vec();
-
- alt (typeck.ann_to_type(variant.ann).struct) {
- case (typeck.ty_fn(?args, _)) {
- for (typeck.arg arg in args) {
- lltys += vec(type_of(cx, arg.ty));
- }
- }
- case (_) { fail; }
- }
-
- variant_tys += vec(T_struct(lltys));
- arity_info = n_ary;
- } else {
- variant_tys += vec(T_nil());
- arity_info = nullary;
- }
-
- variant_info += vec(tup(variant.id, arity_info));
- }
-
- tag_ty = T_struct(vec(T_int(), T_union(variant_tys)));
- }
-
- info.variants = variant_info;
-
- auto th = cx.tags.get(tag_id).th.llth;
- llvm.LLVMRefineType(llvm.LLVMResolveTypeHandle(th), tag_ty);
- }
- case (_) {
- // fall through
- }
- }
-
- ret cx;
-}
-
fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
alt (i.node) {
case (ast.item_fn(?name, ?f, _, ?fid, ?ann)) {
@@ -1865,6 +1861,7 @@ fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
let vec[tup(ast.def_id,arity)] variant_info = vec();
cx.tags.insert(tag_id, @rec(th=mk_type_handle(),
mutable variants=variant_info));
+ cx.items.insert(tag_id, i);
}
case (_) { /* fall through */ }
@@ -1884,6 +1881,55 @@ fn collect_items(@crate_ctxt cx, @ast.crate crate) {
fold.fold_crate[@crate_ctxt](cx, fld, crate);
}
+// The tag type resolution pass, which determines all the LLVM types that
+// correspond to each tag type in the crate.
+
+fn resolve_tag_types_for_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
+ alt (i.node) {
+ case (ast.item_tag(_, ?variants, _, ?tag_id)) {
+ let vec[TypeRef] variant_tys = vec();
+
+ auto info = cx.tags.get(tag_id);
+ let vec[tup(ast.def_id,arity)] variant_info = vec();
+
+ for (ast.variant variant in variants) {
+ auto arity_info;
+ if (_vec.len[@ast.ty](variant.args) > 0u) {
+ let vec[TypeRef] lltys = vec();
+
+ alt (typeck.ann_to_type(variant.ann).struct) {
+ case (typeck.ty_fn(?args, _)) {
+ for (typeck.arg arg in args) {
+ lltys += vec(type_of(cx, arg.ty));
+ }
+ }
+ case (_) { fail; }
+ }
+
+ variant_tys += vec(T_struct(lltys));
+ arity_info = n_ary;
+ } else {
+ variant_tys += vec(T_nil());
+ arity_info = nullary;
+ }
+
+ variant_info += vec(tup(variant.id, arity_info));
+ }
+
+ info.variants = variant_info;
+
+ auto tag_ty = T_struct(vec(T_int(), T_union(variant_tys)));
+ auto th = cx.tags.get(tag_id).th.llth;
+ llvm.LLVMRefineType(llvm.LLVMResolveTypeHandle(th), tag_ty);
+ }
+ case (_) {
+ // fall through
+ }
+ }
+
+ ret cx;
+}
+
fn resolve_tag_types(@crate_ctxt cx, @ast.crate crate) {
let fold.ast_fold[@crate_ctxt] fld =
fold.new_identity_fold[@crate_ctxt]();
@@ -1894,6 +1940,61 @@ fn resolve_tag_types(@crate_ctxt cx, @ast.crate crate) {
fold.fold_crate[@crate_ctxt](cx, fld, crate);
}
+// The constant translation pass.
+
+fn trans_constant(&@crate_ctxt cx, @ast.item it) -> @crate_ctxt {
+ alt (it.node) {
+ case (ast.item_tag(_, ?variants, _, ?tag_id)) {
+ auto info = cx.tags.get(tag_id);
+
+ auto tag_ty = llvm.LLVMResolveTypeHandle(info.th.llth);
+ check (llvm.LLVMCountStructElementTypes(tag_ty) == 2u);
+ auto elts = vec(0 as TypeRef, 0 as TypeRef);
+ llvm.LLVMGetStructElementTypes(tag_ty, _vec.buf[TypeRef](elts));
+ auto union_ty = elts.(1);
+
+ auto i = 0u;
+ while (i < _vec.len[tup(ast.def_id,arity)](info.variants)) {
+ auto variant_info = info.variants.(i);
+ alt (variant_info._1) {
+ case (nullary) {
+ // Nullary tags become constants.
+ auto union_val = C_union(union_ty, C_nil());
+ auto val = C_struct(vec(C_int(i as int), union_val));
+
+ // FIXME: better name
+ auto gvar = llvm.LLVMAddGlobal(cx.llmod, val_ty(val),
+ _str.buf("tag"));
+ llvm.LLVMSetInitializer(gvar, val);
+ llvm.LLVMSetGlobalConstant(gvar, True);
+ cx.item_ids.insert(variant_info._0, gvar);
+ }
+ case (n_ary) {
+ // N-ary tags are treated as functions and generated
+ // later.
+ }
+ }
+
+ i += 1u;
+ }
+ }
+ case (_) {
+ // empty
+ }
+ }
+
+ ret cx;
+}
+
+fn trans_constants(@crate_ctxt cx, @ast.crate crate) {
+ let fold.ast_fold[@crate_ctxt] fld =
+ fold.new_identity_fold[@crate_ctxt]();
+
+ fld = @rec(update_env_for_item = bind trans_constant(_,_) with *fld);
+
+ fold.fold_crate[@crate_ctxt](cx, fld, crate);
+}
+
fn p2i(ValueRef v) -> ValueRef {
ret llvm.LLVMConstPtrToInt(v, T_int());
}
@@ -2060,6 +2161,7 @@ fn trans_crate(session.session sess, @ast.crate crate, str output) {
collect_items(cx, crate);
resolve_tag_types(cx, crate);
+ trans_constants(cx, crate);
trans_mod(cx, crate.node.module);
trans_exit_task_glue(cx);