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.
This commit is contained in:
Michael Sullivan 2011-07-27 18:39:57 -07:00
parent 4de0b3d947
commit d1298f768c
6 changed files with 37 additions and 47 deletions

View File

@ -4499,12 +4499,20 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t,
// Arg will be provided when the thunk is invoked.
none. {
let passed_arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
let arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
assert (!is_val);
passed_arg = bcx.build.PointerCast(passed_arg, llout_arg_ty);
// If the argument was passed by value and isn't a
// pointer type, we need to spill it to an alloca in
// order to do a pointer cast. Argh.
if is_val && !ty::type_is_boxed(cx.ccx.tcx, out_arg.ty) {
let argp = do_spill(bcx, arg);
argp = bcx.build.PointerCast(argp, T_ptr(llout_arg_ty));
arg = bcx.build.Load(argp);
} else {
arg = bcx.build.PointerCast(arg, llout_arg_ty);
}
}
llargs += ~[passed_arg];
llargs += ~[arg];
a += 1u;
}
}
@ -5348,7 +5356,6 @@ fn type_is_immediate(ccx: &@crate_ctxt, t: &ty::t) -> bool {
fn do_spill(cx: &@block_ctxt, v: ValueRef) -> ValueRef {
// We have a value but we have to spill it to pass by alias.
let llptr = alloca(cx, val_ty(v));
cx.build.Store(v, llptr);
ret llptr;
@ -6310,8 +6317,6 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, args: &ast::arg[],
let arg_n: uint = 0u;
for aarg: ast::arg in args {
if aarg.mode == ast::val {
let arg_t = type_of_arg(bcx.fcx.lcx, fcx.sp, arg_tys.(arg_n));
let a = alloca(bcx, arg_t);
let argval;
alt bcx.fcx.llargs.find(aarg.id) {
some(x) { argval = x; }
@ -6320,9 +6325,9 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, args: &ast::arg[],
(aarg.ty.span, "unbound arg ID in copy_args_to_allocas");
}
}
bcx.build.Store(argval, a);
// Overwrite the llargs entry for this arg with its alloca.
let a = do_spill(bcx, argval);
// Overwrite the llargs entry for this arg with its alloca.
bcx.fcx.llargs.insert(aarg.id, a);
}
arg_n += 1u;

View File

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

View File

@ -1532,7 +1532,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
// A generic function to factor out common logic from call and bind
// expressions.
fn check_call_or_bind(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
args: &(option::t[@ast::expr])[],
call_kind: call_kind) {
@ -1585,7 +1584,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
// TODO: iter2
let i = 0u;
for a_opt: option::t[@ast::expr] in args {
let check_ty_vars = call_kind == kind_spawn;
alt a_opt {
some(a) {
check_expr(fcx, a);
@ -1593,30 +1591,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
expr_ty(fcx.ccx.tcx, a), ~[],
AUTODEREF_BLOCK_COERCE);
}
none. { check_ty_vars = true; }
}
/* If this argument is going to be a thunk argument
(that is, it's an underscore-bind thing or a spawn
argument), then it has to be either passed by reference,
or have a statically known size. */
alt call_kind {
kind_call. { }
_ {
/* bind or spawn */
if check_ty_vars &&
(ty::type_contains_params(fcx.ccx.tcx, arg_tys.(i).ty)
||
ty::type_contains_vars(fcx.ccx.tcx,
arg_tys.(i).ty)) &&
arg_tys.(i).mode == mo_val {
// For why the check is necessary, see the
// none case in trans_bind_thunk
fcx.ccx.tcx.sess.span_fatal
(sp, call_kind_str(call_kind) +
" arguments with types containing parameters \
must be passed by alias");
}
}
none. { }
}
i += 1u;
}
@ -1639,8 +1614,8 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
for arg: @ast::expr in args {
args_opt_0 += ~[some[@ast::expr](arg)];
}
// Call the generic checker.
// Call the generic checker.
check_call_or_bind(fcx, sp, f, args_opt_0, call_kind);
}
// A generic function for checking for or for-each loops
@ -2059,10 +2034,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
}
ast::expr_bind(f, args) {
// Call the generic checker.
check_call_or_bind(fcx, expr.span, f, args, kind_bind);
// Pull the argument and return types out.
// Pull the argument and return types out.
let proto_1;
let arg_tys_1: ty::arg[] = ~[];
let rt_1;
@ -2078,7 +2052,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
// For each blank argument, add the type of that argument
// to the resulting function type.
let i = 0u;
while i < ivec::len[option::t[@ast::expr]](args) {
alt args.(i) {
@ -2180,8 +2153,15 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
let fty = expr_ty(fcx.ccx.tcx, f);
let ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty);
demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty);
// FIXME: Other typechecks needed
// make sure they aren't spawning a function with type params
if ty::expr_has_ty_params(fcx.ccx.tcx, f) {
fcx.ccx.tcx.sess.span_fatal(
f.span,
"spawning functions with type params not allowed (for now)");
}
// FIXME: Other typechecks needed
let typ = ty::mk_task(fcx.ccx.tcx);
write::ty_only_fixup(fcx, id, typ);
}

View File

@ -1,7 +1,6 @@
// xfail-stage0
// error-pattern:Spawn arguments with types containing parameters must be
// error-pattern:spawning functions with type params not allowed
fn main() {
// Similar to bind-parameterized-args
fn echo[T](c: chan[T], oc: chan[chan[T]]) {
let p: port[T] = port();
oc <| chan(p);
@ -15,4 +14,4 @@ fn main() {
let p2 = port[chan[int]]();
spawn echo(chan(p), chan(p2));
}
}

View File

@ -0,0 +1,8 @@
// xfail-stage0
fn main() {
fn echo[T](c: int, x: fn(&T)) { log_err "wee"; }
let y = bind echo(42, _);
y(fn(i: &str){});
}

View File

@ -1,9 +1,8 @@
// xfail-stage0
// error-pattern:Bind arguments with types containing parameters must be
fn main() {
fn echo[T](c: int, x: vec[T]) { }
let y: fn(vec[int]) = bind echo(42, _);
y([1]);
}
}