Const field access (working) and vec indexing (almost). More for #2317.

This commit is contained in:
Graydon Hoare
2012-08-08 19:41:50 -07:00
parent 5c9c9a6a9f
commit a0e3a2ae8e
3 changed files with 110 additions and 2 deletions

View File

@@ -102,6 +102,8 @@ fn check_expr(sess: session, def_map: resolve3::DefMap,
expr_vstore(_, vstore_fixed(_)) |
expr_vec(_, m_imm) |
expr_addr_of(m_imm, _) |
expr_field(*) |
expr_index(*) |
expr_tup(*) |
expr_struct(*) |
expr_rec(*) => { }

View File

@@ -43,6 +43,33 @@ fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
return (v, sz, llunitty);
}
fn const_deref(v: ValueRef) -> ValueRef {
assert llvm::LLVMIsGlobalConstant(v) == True;
llvm::LLVMGetInitializer(v)
}
fn const_get_elt(v: ValueRef, u: uint) -> ValueRef {
let u = u;
llvm::LLVMConstExtractValue(v, ptr::addr_of(u), 1 as c_uint)
}
fn const_autoderef(ty: ty::t, v: ValueRef)
-> (ty::t, ValueRef) {
let mut t1 = ty;
let mut v1 = v;
loop {
// Only rptrs can be autoderef'ed in a const context.
match ty::get(ty).struct {
ty::ty_rptr(_, mt) => {
t1 = mt.ty;
v1 = const_deref(v1);
}
_ => return (t1,v1)
}
}
}
fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
let _icx = cx.insn_ctxt(~"const_expr");
match e.node {
@@ -106,8 +133,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
return match u {
ast::box(_) |
ast::uniq(_) |
ast::deref => cx.sess.span_bug(e.span,
~"bad unop type in const_expr"),
ast::deref => const_deref(te),
ast::not => llvm::LLVMConstNot(te),
ast::neg => {
if is_float { llvm::LLVMConstFNeg(te) }
@@ -115,6 +141,66 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
}
}
}
ast::expr_field(base, field, _) => {
let bt = ty::expr_ty(cx.tcx, base);
let bv = const_expr(cx, base);
let (bt, bv) = const_autoderef(bt, bv);
let fields = match ty::get(bt).struct {
ty::ty_rec(fs) => fs,
ty::ty_class(did, substs) =>
ty::class_items_as_mutable_fields(cx.tcx, did, substs),
_ => cx.sess.span_bug(e.span,
~"field access on unknown type in const"),
};
let ix = field_idx_strict(cx.tcx, e.span, field, fields);
const_get_elt(bv, ix)
}
ast::expr_index(base, index) => {
let bt = ty::expr_ty(cx.tcx, base);
let bv = const_expr(cx, base);
let (bt, bv) = const_autoderef(bt, bv);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,
const_eval::const_uint(u) => u,
_ => cx.sess.span_bug(index.span,
~"index is not an integer-constant \
expression")
};
let (arr,len) = match ty::get(bt).struct {
ty::ty_evec(_, vstore) | ty::ty_estr(vstore) =>
match vstore {
ty::vstore_fixed(u) =>
(bv, C_uint(cx, u)),
ty::vstore_slice(_) => {
let unit_ty = ty::sequence_element_type(cx.tcx, bt);
let llunitty = type_of::type_of(cx, unit_ty);
let unit_sz = shape::llsize_of(cx, llunitty);
(const_deref(const_get_elt(bv, 0)),
llvm::LLVMConstUDiv(const_get_elt(bv, 1),
unit_sz))
},
_ => cx.sess.span_bug(base.span,
~"index-expr base must be \
fixed-size or slice")
},
_ => cx.sess.span_bug(base.span,
~"index-expr base must be \
a vector or string type")
};
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
let len = match ty::get(bt).struct {
ty::ty_estr(*) => {assert len > 0; len - 1},
_ => len
};
if iv >= len {
// Better late than never for reporting this?
cx.sess.span_err(e.span,
~"const index-expr is out of bounds");
}
const_get_elt(arr, iv as uint)
}
ast::expr_cast(base, tp) => {
let ety = ty::expr_ty(cx.tcx, e), llty = type_of::type_of(cx, ety);
let basety = ty::expr_ty(cx.tcx, base);

View File

@@ -0,0 +1,20 @@
// Not quite working on the indexing part yet.
/*
const x : [int]/4 = [1,2,3,4];
const y : &[int] = &[1,2,3,4];
const p : int = x[2];
const q : int = y[2];
*/
const s : {a: int, b: int} = {a: 10, b: 20};
const t : int = s.b;
fn main() {
// io::println(fmt!("%?", p));
// io::println(fmt!("%?", q));
io::println(fmt!("%?", t));
// assert p == 3;
// assert q == 3;
assert t == 20;
}