diff options
| author | Michael Sullivan <sully@msully.net> | 2011-07-27 18:39:57 -0700 | 
|---|---|---|
| committer | Michael Sullivan <sully@msully.net> | 2011-07-27 18:46:46 -0700 | 
| commit | d1298f768c1a1cefa119fccffc7029c6110098d0 (patch) | |
| tree | 2b38793ee1f68fee900a0eac4d42c57495921279 | |
| parent | 4de0b3d9474eb4b1284a8abf4bd03a5135a19a83 (diff) | |
| download | rust-d1298f768c1a1cefa119fccffc7029c6110098d0.tar.gz rust-d1298f768c1a1cefa119fccffc7029c6110098d0.zip  | |
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.
| -rw-r--r-- | src/comp/middle/trans.rs | 23 | ||||
| -rw-r--r-- | src/comp/middle/ty.rs | 3 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 42 | ||||
| -rw-r--r-- | src/test/compile-fail/chan-parameterized-args.rs | 5 | ||||
| -rw-r--r-- | src/test/run-pass/bind-parameterized-args-2.rs | 8 | ||||
| -rw-r--r-- | src/test/run-pass/bind-parameterized-args.rs (renamed from src/test/compile-fail/bind-parameterized-args.rs) | 3 | 
6 files changed, 37 insertions, 47 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index b745ab8a6d3..2e3c2a41446 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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; diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 08e6447c2d0..5ff5a018f88 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index d567b9d45bc..2ec020fdb87 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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); } diff --git a/src/test/compile-fail/chan-parameterized-args.rs b/src/test/compile-fail/chan-parameterized-args.rs index 93c0b6aaf2e..4c62dffcab2 100644 --- a/src/test/compile-fail/chan-parameterized-args.rs +++ b/src/test/compile-fail/chan-parameterized-args.rs @@ -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)); -} \ No newline at end of file +} diff --git a/src/test/run-pass/bind-parameterized-args-2.rs b/src/test/run-pass/bind-parameterized-args-2.rs new file mode 100644 index 00000000000..476cef93e2f --- /dev/null +++ b/src/test/run-pass/bind-parameterized-args-2.rs @@ -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){}); +} diff --git a/src/test/compile-fail/bind-parameterized-args.rs b/src/test/run-pass/bind-parameterized-args.rs index 2b22cadb4cd..7274cd48972 100644 --- a/src/test/compile-fail/bind-parameterized-args.rs +++ b/src/test/run-pass/bind-parameterized-args.rs @@ -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]); -} \ No newline at end of file +}  | 
