about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Sullivan <sully@msully.net>2011-07-27 18:39:57 -0700
committerMichael Sullivan <sully@msully.net>2011-07-27 18:46:46 -0700
commitd1298f768c1a1cefa119fccffc7029c6110098d0 (patch)
tree2b38793ee1f68fee900a0eac4d42c57495921279
parent4de0b3d9474eb4b1284a8abf4bd03a5135a19a83 (diff)
downloadrust-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.rs23
-rw-r--r--src/comp/middle/ty.rs3
-rw-r--r--src/comp/middle/typeck.rs42
-rw-r--r--src/test/compile-fail/chan-parameterized-args.rs5
-rw-r--r--src/test/run-pass/bind-parameterized-args-2.rs8
-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
+}