Skip to content

Commit d1298f7

Browse files
committed
Have bind support non-alias parametric non-bound arguments.
This was previously disallowed by the typechecker and not properly handled in trans. I removed the typechecker check (replacing it with a simpler check that spawned functions don't have type params) and fixed trans. Closes #756.
1 parent 4de0b3d commit d1298f7

File tree

6 files changed

+37
-47
lines changed

6 files changed

+37
-47
lines changed

src/comp/middle/trans.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4499,12 +4499,20 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t,
44994499

45004500
// Arg will be provided when the thunk is invoked.
45014501
none. {
4502-
let passed_arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
4502+
let arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
45034503
if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
4504-
assert (!is_val);
4505-
passed_arg = bcx.build.PointerCast(passed_arg, llout_arg_ty);
4504+
// If the argument was passed by value and isn't a
4505+
// pointer type, we need to spill it to an alloca in
4506+
// order to do a pointer cast. Argh.
4507+
if is_val && !ty::type_is_boxed(cx.ccx.tcx, out_arg.ty) {
4508+
let argp = do_spill(bcx, arg);
4509+
argp = bcx.build.PointerCast(argp, T_ptr(llout_arg_ty));
4510+
arg = bcx.build.Load(argp);
4511+
} else {
4512+
arg = bcx.build.PointerCast(arg, llout_arg_ty);
4513+
}
45064514
}
4507-
llargs += ~[passed_arg];
4515+
llargs += ~[arg];
45084516
a += 1u;
45094517
}
45104518
}
@@ -5348,7 +5356,6 @@ fn type_is_immediate(ccx: &@crate_ctxt, t: &ty::t) -> bool {
53485356

53495357
fn do_spill(cx: &@block_ctxt, v: ValueRef) -> ValueRef {
53505358
// We have a value but we have to spill it to pass by alias.
5351-
53525359
let llptr = alloca(cx, val_ty(v));
53535360
cx.build.Store(v, llptr);
53545361
ret llptr;
@@ -6310,8 +6317,6 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, args: &ast::arg[],
63106317
let arg_n: uint = 0u;
63116318
for aarg: ast::arg in args {
63126319
if aarg.mode == ast::val {
6313-
let arg_t = type_of_arg(bcx.fcx.lcx, fcx.sp, arg_tys.(arg_n));
6314-
let a = alloca(bcx, arg_t);
63156320
let argval;
63166321
alt bcx.fcx.llargs.find(aarg.id) {
63176322
some(x) { argval = x; }
@@ -6320,9 +6325,9 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, args: &ast::arg[],
63206325
(aarg.ty.span, "unbound arg ID in copy_args_to_allocas");
63216326
}
63226327
}
6323-
bcx.build.Store(argval, a);
6324-
// Overwrite the llargs entry for this arg with its alloca.
6328+
let a = do_spill(bcx, argval);
63256329

6330+
// Overwrite the llargs entry for this arg with its alloca.
63266331
bcx.fcx.llargs.insert(aarg.id, a);
63276332
}
63286333
arg_n += 1u;

src/comp/middle/ty.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,8 +1744,7 @@ fn node_id_to_type_params(cx: &ctxt, id: &ast::node_id) -> t[] {
17441744
}
17451745

17461746
fn node_id_has_type_params(cx: &ctxt, id: &ast::node_id) -> bool {
1747-
let tpt = node_id_to_ty_param_substs_opt_and_ty(cx, id);
1748-
ret !option::is_none[t[]](tpt.substs);
1747+
ret ivec::len(node_id_to_type_params(cx, id)) > 0u;
17491748
}
17501749

17511750

src/comp/middle/typeck.rs

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
15321532

15331533
// A generic function to factor out common logic from call and bind
15341534
// expressions.
1535-
15361535
fn check_call_or_bind(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
15371536
args: &(option::t[@ast::expr])[],
15381537
call_kind: call_kind) {
@@ -1585,38 +1584,14 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
15851584
// TODO: iter2
15861585
let i = 0u;
15871586
for a_opt: option::t[@ast::expr] in args {
1588-
let check_ty_vars = call_kind == kind_spawn;
15891587
alt a_opt {
15901588
some(a) {
15911589
check_expr(fcx, a);
15921590
demand::full(fcx, a.span, arg_tys.(i).ty,
15931591
expr_ty(fcx.ccx.tcx, a), ~[],
15941592
AUTODEREF_BLOCK_COERCE);
15951593
}
1596-
none. { check_ty_vars = true; }
1597-
}
1598-
/* If this argument is going to be a thunk argument
1599-
(that is, it's an underscore-bind thing or a spawn
1600-
argument), then it has to be either passed by reference,
1601-
or have a statically known size. */
1602-
alt call_kind {
1603-
kind_call. { }
1604-
_ {
1605-
/* bind or spawn */
1606-
if check_ty_vars &&
1607-
(ty::type_contains_params(fcx.ccx.tcx, arg_tys.(i).ty)
1608-
||
1609-
ty::type_contains_vars(fcx.ccx.tcx,
1610-
arg_tys.(i).ty)) &&
1611-
arg_tys.(i).mode == mo_val {
1612-
// For why the check is necessary, see the
1613-
// none case in trans_bind_thunk
1614-
fcx.ccx.tcx.sess.span_fatal
1615-
(sp, call_kind_str(call_kind) +
1616-
" arguments with types containing parameters \
1617-
must be passed by alias");
1618-
}
1619-
}
1594+
none. { }
16201595
}
16211596
i += 1u;
16221597
}
@@ -1639,8 +1614,8 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
16391614
for arg: @ast::expr in args {
16401615
args_opt_0 += ~[some[@ast::expr](arg)];
16411616
}
1642-
// Call the generic checker.
16431617

1618+
// Call the generic checker.
16441619
check_call_or_bind(fcx, sp, f, args_opt_0, call_kind);
16451620
}
16461621
// A generic function for checking for or for-each loops
@@ -2059,10 +2034,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
20592034
}
20602035
ast::expr_bind(f, args) {
20612036
// Call the generic checker.
2062-
20632037
check_call_or_bind(fcx, expr.span, f, args, kind_bind);
2064-
// Pull the argument and return types out.
20652038

2039+
// Pull the argument and return types out.
20662040
let proto_1;
20672041
let arg_tys_1: ty::arg[] = ~[];
20682042
let rt_1;
@@ -2078,7 +2052,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
20782052

20792053
// For each blank argument, add the type of that argument
20802054
// to the resulting function type.
2081-
20822055
let i = 0u;
20832056
while i < ivec::len[option::t[@ast::expr]](args) {
20842057
alt args.(i) {
@@ -2180,8 +2153,15 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
21802153
let fty = expr_ty(fcx.ccx.tcx, f);
21812154
let ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty);
21822155
demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty);
2183-
// FIXME: Other typechecks needed
21842156

2157+
// make sure they aren't spawning a function with type params
2158+
if ty::expr_has_ty_params(fcx.ccx.tcx, f) {
2159+
fcx.ccx.tcx.sess.span_fatal(
2160+
f.span,
2161+
"spawning functions with type params not allowed (for now)");
2162+
}
2163+
2164+
// FIXME: Other typechecks needed
21852165
let typ = ty::mk_task(fcx.ccx.tcx);
21862166
write::ty_only_fixup(fcx, id, typ);
21872167
}

src/test/compile-fail/chan-parameterized-args.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// xfail-stage0
2-
// error-pattern:Spawn arguments with types containing parameters must be
2+
// error-pattern:spawning functions with type params not allowed
33
fn main() {
4-
// Similar to bind-parameterized-args
54
fn echo[T](c: chan[T], oc: chan[chan[T]]) {
65
let p: port[T] = port();
76
oc <| chan(p);
@@ -15,4 +14,4 @@ fn main() {
1514
let p2 = port[chan[int]]();
1615

1716
spawn echo(chan(p), chan(p2));
18-
}
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// xfail-stage0
2+
fn main() {
3+
fn echo[T](c: int, x: fn(&T)) { log_err "wee"; }
4+
5+
let y = bind echo(42, _);
6+
7+
y(fn(i: &str){});
8+
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// xfail-stage0
2-
// error-pattern:Bind arguments with types containing parameters must be
32
fn main() {
43
fn echo[T](c: int, x: vec[T]) { }
54

65
let y: fn(vec[int]) = bind echo(42, _);
76

87
y([1]);
9-
}
8+
}

0 commit comments

Comments
 (0)