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:
parent
4de0b3d947
commit
d1298f768c
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
8
src/test/run-pass/bind-parameterized-args-2.rs
Normal file
8
src/test/run-pass/bind-parameterized-args-2.rs
Normal 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){});
|
||||
}
|
@ -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]);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user