Implement autoderef in rustc. Un-XFAIL autoderef-full-lval.rs.

This commit is contained in:
Graydon Hoare 2011-01-24 18:03:31 -08:00
parent 0e1e3a9e1e
commit a32d206d27
3 changed files with 130 additions and 24 deletions

View File

@ -422,6 +422,7 @@ TEST_XFAILS_RUSTC := $(filter-out \
arith-0.rs \
arith-1.rs \
arith-2.rs \
autoderef-full-lval.rs \
bind-interior.rs \
bind-thunk.rs \
bind-trivial.rs \

View File

@ -1613,13 +1613,16 @@ fn trans_unary(@block_ctxt cx, ast.unop op,
alt (op) {
case (ast.bitnot) {
sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
ret res(sub.bcx, cx.build.Not(sub.val));
}
case (ast.not) {
sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
ret res(sub.bcx, cx.build.Not(sub.val));
}
case (ast.neg) {
// FIXME: switch by signedness.
sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
ret res(sub.bcx, cx.build.Neg(sub.val));
}
case (ast.box) {
@ -1688,6 +1691,26 @@ fn trans_eager_binop(@block_ctxt cx, ast.binop op,
fail;
}
fn autoderef(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
let ValueRef v1 = v;
let @ty.t t1 = t;
while (true) {
alt (t1.struct) {
case (ty.ty_box(?inner)) {
auto body = cx.build.GEP(v1,
vec(C_int(0),
C_int(abi.box_rc_field_body)));
t1 = inner;
v1 = load_scalar_or_boxed(cx, body, inner);
}
case (_) {
ret res(cx, v1);
}
}
}
}
fn trans_binary(@block_ctxt cx, ast.binop op,
@ast.expr a, @ast.expr b) -> result {
@ -1697,9 +1720,11 @@ fn trans_binary(@block_ctxt cx, ast.binop op,
case (ast.and) {
// Lazy-eval and
auto lhs_res = trans_expr(cx, a);
lhs_res = autoderef(lhs_res.bcx, lhs_res.val, ty.expr_ty(a));
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
auto rhs_res = trans_expr(rhs_cx, b);
rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
auto lhs_false_res = res(lhs_false_cx, C_bool(false));
@ -1715,9 +1740,11 @@ fn trans_binary(@block_ctxt cx, ast.binop op,
case (ast.or) {
// Lazy-eval or
auto lhs_res = trans_expr(cx, a);
lhs_res = autoderef(lhs_res.bcx, lhs_res.val, ty.expr_ty(a));
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
auto rhs_res = trans_expr(rhs_cx, b);
rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
auto lhs_true_res = res(lhs_true_cx, C_bool(true));
@ -1733,9 +1760,11 @@ fn trans_binary(@block_ctxt cx, ast.binop op,
case (_) {
// Remaining cases are eager:
auto lhs = trans_expr(cx, a);
auto sub = trans_expr(lhs.bcx, b);
ret res(sub.bcx, trans_eager_binop(sub.bcx, op,
lhs.val, sub.val));
lhs = autoderef(lhs.bcx, lhs.val, ty.expr_ty(a));
auto rhs = trans_expr(lhs.bcx, b);
rhs = autoderef(rhs.bcx, rhs.val, ty.expr_ty(b));
ret res(rhs.bcx, trans_eager_binop(rhs.bcx, op,
lhs.val, rhs.val));
}
}
fail;
@ -2126,6 +2155,7 @@ fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
&ast.ident field, &ast.ann ann) -> lval_result {
auto lv = trans_lval(cx, base);
auto r = lv.res;
r = autoderef(r.bcx, r.val, ty.expr_ty(base));
check (lv.is_mem);
auto t = ty.expr_ty(base);
alt (t.struct) {
@ -2160,6 +2190,7 @@ fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
@ast.expr idx, &ast.ann ann) -> lval_result {
auto lv = trans_expr(cx, base);
lv = autoderef(lv.bcx, lv.val, ty.expr_ty(base));
auto ix = trans_expr(lv.bcx, idx);
auto v = lv.val;

View File

@ -586,11 +586,68 @@ fn unify(&@fn_ctxt fcx, @ty.t expected, @ty.t actual) -> ty.unify_result {
ret ty.unify(expected, actual, handler);
}
tag autoderef_kind {
AUTODEREF_OK;
NO_AUTODEREF;
}
fn strip_boxes(@ty.t t) -> @ty.t {
auto t1 = t;
while (true) {
alt (t1.struct) {
case (ty.ty_box(?inner)) { t1 = inner; }
case (_) { ret t1; }
}
}
fail;
}
fn add_boxes(uint n, @ty.t t) -> @ty.t {
auto t1 = t;
while (n != 0u) {
t1 = plain_ty(ty.ty_box(t1));
n -= 1u;
}
ret t1;
}
fn count_boxes(@ty.t t) -> uint {
auto n = 0u;
auto t1 = t;
while (true) {
alt (t1.struct) {
case (ty.ty_box(?inner)) { n += 1u; t1 = inner; }
case (_) { ret n; }
}
}
fail;
}
fn demand(&@fn_ctxt fcx, &span sp, @ty.t expected, @ty.t actual) -> @ty.t {
be demand_full(fcx, sp, expected, actual, NO_AUTODEREF);
}
// Requires that the two types unify, and prints an error message if they
// don't. Returns the unified type.
fn demand(&@fn_ctxt fcx, &span sp, @ty.t expected, @ty.t actual) -> @ty.t {
alt (unify(fcx, expected, actual)) {
case (ty.ures_ok(?t)) { ret t; }
fn demand_full(&@fn_ctxt fcx, &span sp,
@ty.t expected, @ty.t actual, autoderef_kind adk) -> @ty.t {
auto expected_1 = expected;
auto actual_1 = actual;
auto implicit_boxes = 0u;
if (adk == AUTODEREF_OK) {
expected_1 = strip_boxes(expected);
actual_1 = strip_boxes(actual);
implicit_boxes = count_boxes(actual);
}
alt (unify(fcx, expected_1, actual_1)) {
case (ty.ures_ok(?t)) { ret add_boxes(implicit_boxes, t); }
case (ty.ures_err(?err, ?expected, ?actual)) {
fcx.ccx.sess.span_err(sp, "mismatched types: expected "
@ -680,6 +737,11 @@ fn demand_pat(&@fn_ctxt fcx, @ty.t expected, @ast.pat pat) -> @ast.pat {
// but we can mitigate that if expected == actual == unified.
fn demand_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
be demand_expr_full(fcx, expected, e, NO_AUTODEREF);
}
fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
autoderef_kind adk) -> @ast.expr {
// FIXME: botch to work around typestate bug in rustboot
let vec[@ast.expr] v = vec();
auto e_1 = ast.expr_vec(v, ast.ann_none);
@ -748,7 +810,11 @@ fn demand_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
e_1 = ast.expr_bind(sube, es, ast.ann_type(t));
}
case (ast.expr_call(?sube, ?es, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
// NB: we call 'demand_full' and pass in adk only in cases where
// e is an expression that could *possibly* produce a box; things
// like expr_binary or expr_bind can't, so there's no need.
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
e_1 = ast.expr_call(sube, es, ast.ann_type(t));
}
case (ast.expr_binary(?bop, ?lhs, ?rhs, ?ann)) {
@ -756,7 +822,9 @@ fn demand_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
e_1 = ast.expr_binary(bop, lhs, rhs, ast.ann_type(t));
}
case (ast.expr_unary(?uop, ?sube, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
// See note in expr_unary for why we're calling demand_full.
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
e_1 = ast.expr_unary(uop, sube, ast.ann_type(t));
}
case (ast.expr_lit(?lit, ?ann)) {
@ -768,7 +836,8 @@ fn demand_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
e_1 = ast.expr_cast(sube, ast_ty, ast.ann_type(t));
}
case (ast.expr_if(?cond, ?then_0, ?else_0, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
auto then_1 = demand_block(fcx, expected, then_0);
auto else_1;
alt (else_0) {
@ -793,36 +862,39 @@ fn demand_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
e_1 = ast.expr_do_while(bloc, cond, ast.ann_type(t));
}
case (ast.expr_block(?bloc, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
e_1 = ast.expr_block(bloc, ast.ann_type(t));
}
case (ast.expr_assign(?lhs_0, ?rhs_0, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
auto lhs_1 = demand_expr(fcx, expected, lhs_0);
auto rhs_1 = demand_expr(fcx, expected, rhs_0);
e_1 = ast.expr_assign(lhs_1, rhs_1, ast.ann_type(t));
}
case (ast.expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
auto lhs_1 = demand_expr(fcx, expected, lhs_0);
auto rhs_1 = demand_expr(fcx, expected, rhs_0);
e_1 = ast.expr_assign_op(op, lhs_1, rhs_1, ast.ann_type(t));
}
case (ast.expr_field(?lhs, ?rhs, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
e_1 = ast.expr_field(lhs, rhs, ast.ann_type(t));
}
case (ast.expr_index(?base, ?index, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
e_1 = ast.expr_index(base, index, ast.ann_type(t));
}
case (ast.expr_path(?pth, ?d, ?ann)) {
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = demand_full(fcx, e.span, expected,
ann_to_type(ann), adk);
e_1 = ast.expr_path(pth, d, ast.ann_type(t));
}
case (_) {
fail;
}
}
ret @fold.respan[ast.expr_](e.span, e_1);
@ -960,10 +1032,12 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
auto rhs_t0 = expr_ty(rhs_0);
// FIXME: Binops have a bit more subtlety than this.
auto lhs_1 = demand_expr(fcx, rhs_t0, lhs_0);
auto rhs_1 = demand_expr(fcx, expr_ty(lhs_1), rhs_0);
auto lhs_1 = demand_expr_full(fcx, rhs_t0, lhs_0,
AUTODEREF_OK);
auto rhs_1 = demand_expr_full(fcx, expr_ty(lhs_1), rhs_0,
AUTODEREF_OK);
auto t = lhs_t0;
auto t = strip_boxes(lhs_t0);
alt (binop) {
case (ast.eq) { t = plain_ty(ty.ty_bool); }
case (ast.lt) { t = plain_ty(ty.ty_bool); }
@ -997,7 +1071,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
}
}
}
case (_) { /* fall through */ }
case (_) { oper_t = strip_boxes(oper_t); }
}
ret @fold.respan[ast.expr_](expr.span,
ast.expr_unary(unop, oper_1,
@ -1378,7 +1452,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
case (ast.expr_field(?base, ?field, _)) {
auto base_1 = check_expr(fcx, base);
auto base_t = expr_ty(base_1);
auto base_t = strip_boxes(expr_ty(base_1));
alt (base_t.struct) {
case (ty.ty_tup(?args)) {
let uint ix = ty.field_num(fcx.ccx.sess,
@ -1434,7 +1508,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
case (ast.expr_index(?base, ?idx, _)) {
auto base_1 = check_expr(fcx, base);
auto base_t = expr_ty(base_1);
auto base_t = strip_boxes(expr_ty(base_1));
auto idx_1 = check_expr(fcx, idx);
auto idx_t = expr_ty(idx_1);