diff options
| author | Graydon Hoare <[email protected]> | 2011-01-24 18:03:31 -0800 |
|---|---|---|
| committer | Graydon Hoare <[email protected]> | 2011-01-24 18:03:31 -0800 |
| commit | a32d206d27779bc479270fcb41f770de7d57cf34 (patch) | |
| tree | 90d0229e6805f3c860876680ebd41d428ab03d0e | |
| parent | Do better at parsing expr_paths with type arguments. (diff) | |
| download | rust-a32d206d27779bc479270fcb41f770de7d57cf34.tar.xz rust-a32d206d27779bc479270fcb41f770de7d57cf34.zip | |
Implement autoderef in rustc. Un-XFAIL autoderef-full-lval.rs.
| -rw-r--r-- | src/Makefile | 1 | ||||
| -rw-r--r-- | src/comp/middle/trans.rs | 37 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 116 |
3 files changed, 130 insertions, 24 deletions
diff --git a/src/Makefile b/src/Makefile index ad0e209a..675a4823 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 \ diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 4f333348..6246bbd1 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 42322c20..98fcc0d4 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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); |