Skip to content

Autoderef calls #606

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

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
2 changes: 1 addition & 1 deletion src/comp/middle/alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ fn def_is_local(&ast::def d, bool objfields_count) -> bool {
}

fn fty_args(&ctx cx, ty::t fty) -> ty::arg[] {
ret alt (ty::struct(*cx.tcx, fty)) {
ret alt (ty::struct(*cx.tcx, ty::type_autoderef(*cx.tcx, fty))) {
case (ty::ty_fn(_, ?args, _, _, _)) { args }
case (ty::ty_native_fn(_, ?args, _)) { args }
};
Expand Down
68 changes: 40 additions & 28 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3367,7 +3367,7 @@ fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, ValueRef lhs0,
auto rhs_r = autoderef(cx, rhs0, t0);
auto rhs = rhs_r.val;
cx = rhs_r.bcx;
auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
auto t = ty::type_autoderef(cx.fcx.lcx.ccx.tcx, t0);
// Determine the operation we need.
// FIXME: Use or-patterns when we have them.

Expand Down Expand Up @@ -4099,12 +4099,18 @@ fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
}
}

fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
-> result {
let ValueRef v1 = v;
let ty::t t1 = t;
while (true) {
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
case (ty::ty_box(?mt)) {
// If we are working with an lval, we want to
// unconditionally load at the top of the loop
// to get rid of the extra indirection
if (is_lval) { v1 = cx.build.Load(v1); }

auto body =
cx.build.GEP(v1,
[C_int(0), C_int(abi::box_rc_field_body)]);
Expand All @@ -4118,23 +4124,20 @@ fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
v1 = cx.build.PointerCast(body, T_ptr(llty));
} else { v1 = body; }
v1 = load_if_immediate(cx, v1, t1);

// But if we aren't working with an lval, we get rid of
// a layer of indirection at the bottom of the loop so
// that it is gone when we return...
if (!is_lval) { v1 = load_if_immediate(cx, v1, t1); }
}
case (_) { break; }
}
}
ret rslt(cx, v1);
}

fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
let ty::t t1 = t;
while (true) {
alt (ty::struct(ccx.tcx, t1)) {
case (ty::ty_box(?mt)) { t1 = mt.ty; }
case (_) { break; }
}
}
ret t1;
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
ret autoderef_lval(cx, v, t, false);
}

fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
Expand Down Expand Up @@ -4199,7 +4202,7 @@ fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
auto rhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, b);
rhs = autoderef(rhs.bcx, rhs.val, rhty);
ret trans_eager_binop(rhs.bcx, op,
autoderefed_ty(cx.fcx.lcx.ccx, lhty),
ty::type_autoderef(cx.fcx.lcx.ccx.tcx,lhty),
lhs.val, rhs.val);
}
}
Expand Down Expand Up @@ -4910,7 +4913,7 @@ fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result {
fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0,
&ast::ident field, ast::node_id id) -> lval_result {
auto r = autoderef(cx, v, t0);
auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
auto t = ty::type_autoderef(cx.fcx.lcx.ccx.tcx, t0);
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
case (ty::ty_tup(_)) {
let uint ix = ty::field_num(cx.fcx.lcx.ccx.sess, sp, field);
Expand Down Expand Up @@ -5648,17 +5651,33 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
// with trans_call.

auto f_res = trans_lval(cx, f);
let ty::t fn_ty;
alt (f_res.method_ty) {
case (some(?meth)) {
// self-call
fn_ty = meth;
}
case (_) {
fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
}
}

auto bcx = f_res.res.bcx;

auto faddr = f_res.res.val;
auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
alt (f_res.llobj) {
case (some(_)) {
// It's a vtbl entry.
faddr = f_res.res.bcx.build.Load(faddr);
faddr = bcx.build.Load(faddr);
}
case (none) {
// It's a closure.
auto bcx = f_res.res.bcx;
auto pair = faddr;
// It's a closure. We have to autoderef.
auto res = autoderef_lval(bcx, f_res.res.val, fn_ty, true);
bcx = res.bcx;
fn_ty = ty::type_autoderef(bcx.fcx.lcx.ccx.tcx, fn_ty);

auto pair = res.val;
faddr =
bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
faddr = bcx.build.Load(faddr);
Expand All @@ -5667,19 +5686,12 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
llenv = bcx.build.Load(llclosure);
}
}
let ty::t fn_ty;
alt (f_res.method_ty) {
case (some(?meth)) {
// self-call
fn_ty = meth;
}
case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
}

auto ret_ty = ty::node_id_to_type(cx.fcx.lcx.ccx.tcx, id);
auto args_res =
trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
trans_args(bcx, llenv, f_res.llobj, f_res.generic,
lliterbody, args, fn_ty);
auto bcx = args_res._0;
bcx = args_res._0;
auto llargs = args_res._1;
auto llretslot = args_res._2;
/*
Expand Down
12 changes: 12 additions & 0 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export type_is_copyable;
export type_is_tup_like;
export type_is_str;
export type_owns_heap_mem;
export type_autoderef;
export type_param;
export def_to_str;
export unify;
Expand Down Expand Up @@ -1281,6 +1282,17 @@ fn type_param(&ctxt cx, &t ty) -> option::t[uint] {
ret none[uint];
}

fn type_autoderef(&ctxt cx, &ty::t t) -> ty::t {
let ty::t t1 = t;
while (true) {
alt (struct(cx, t1)) {
case (ty::ty_box(?mt)) { t1 = mt.ty; }
case (_) { break; }
}
}
ret t1;
}

fn def_to_str(&ast::def_id did) -> str { ret #fmt("%d:%d", did._0, did._1); }


Expand Down
17 changes: 11 additions & 6 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,17 +1336,21 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
// expressions.

fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f,
&vec[option::t[@ast::expr]] args) {
&vec[option::t[@ast::expr]] args, bool is_call) {
// Check the function.

check_expr(fcx, f);
// Get the function type.

auto fty = expr_ty(fcx.ccx.tcx, f);
// Grab the argument types and the return type.

// We want to autoderef calls but not binds
auto fty_stripped =
if (is_call) { strip_boxes(fcx, sp, fty) } else { fty };

// Grab the argument types and the return type.
auto arg_tys;
alt (structure_of(fcx, sp, fty)) {
alt (structure_of(fcx, sp, fty_stripped)) {
case (ty::ty_fn(_, ?arg_tys_0, _, _, _)) { arg_tys = arg_tys_0; }
case (ty::ty_native_fn(_, ?arg_tys_0, _)) { arg_tys = arg_tys_0; }
case (_) {
Expand Down Expand Up @@ -1410,7 +1414,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
}
// Call the generic checker.

check_call_or_bind(fcx, sp, f, args_opt_0);
check_call_or_bind(fcx, sp, f, args_opt_0, true);
}
// A generic function for checking for or for-each loops

Expand Down Expand Up @@ -1806,7 +1810,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
case (ast::expr_bind(?f, ?args)) {
// Call the generic checker.

check_call_or_bind(fcx, expr.span, f, args);
check_call_or_bind(fcx, expr.span, f, args, false);
// Pull the argument and return types out.

auto proto_1;
Expand Down Expand Up @@ -1855,7 +1859,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
// Pull the return type out of the type of the function.

auto rt_1;
auto fty = ty::expr_ty(fcx.ccx.tcx, f);
auto fty = strip_boxes(fcx, expr.span,
ty::expr_ty(fcx.ccx.tcx, f));
alt (structure_of(fcx, expr.span, fty)) {
case (ty::ty_fn(_, _, ?rt, _, _)) { rt_1 = rt; }
case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; }
Expand Down
7 changes: 7 additions & 0 deletions src/test/compile-fail/auto-deref-bind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// error-pattern: mismatched types

fn add1(int i) -> int { ret i+1; }
fn main() {
auto f = @add1;
auto g = bind f(5);
}
11 changes: 11 additions & 0 deletions src/test/run-pass/auto-deref-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// xfail-stage0

fn add1(int i) -> int { ret i+1; }
fn main() {
auto f = @add1;
auto g = @f;
auto h = @@@add1;
assert(f(5) == 6);
assert(g(8) == 9);
assert(h(0x1badd00d) == 0x1badd00e);
}