diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 00b92cac5a0..5f13134e06d 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -8,11 +8,10 @@ import syntax::walk; import metadata::csearch; import driver::session; import util::common; +import util::common::*; import syntax::codemap::span; import std::map::new_int_hash; import std::map::new_str_hash; -import util::common::new_def_hash; -import util::common::log_expr_err; import middle::ty; import middle::ty::node_id_to_type; import middle::ty::arg; @@ -1485,7 +1484,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { // expressions. fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f, - &(option::t[@ast::expr])[] args, bool is_call) { + &(option::t[@ast::expr])[] args, call_kind call_kind) { // Check the function. check_expr(fcx, f); @@ -1494,8 +1493,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto fty = expr_ty(fcx.ccx.tcx, f); // We want to autoderef calls but not binds - auto fty_stripped = - if (is_call) { do_autoderef(fcx, sp, fty) } else { fty }; + auto fty_stripped = alt (call_kind) { + case (kind_call) { do_autoderef(fcx, sp, fty) } + case (_) { fty } }; // Grab the argument types and the return type. auto arg_tys; @@ -1532,13 +1532,38 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto i = 0u; for (option::t[@ast::expr] a_opt in args) { + auto check_ty_vars = call_kind == kind_spawn; alt (a_opt) { case (some(?a)) { check_expr(fcx, a); demand::simple(fcx, a.span, arg_tys.(i).ty, expr_ty(fcx.ccx.tcx, a)); } - case (none) {/* no-op */ } + case (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) { + case (kind_call) { } + case (_) { /* 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"); + } + } } i += 1u; } @@ -1556,14 +1581,14 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { // A generic function for checking call expressions fn check_call(&@fn_ctxt fcx, &span sp, &@ast::expr f, - &(@ast::expr)[] args) { + &(@ast::expr)[] args, call_kind call_kind) { let (option::t[@ast::expr])[] args_opt_0 = ~[]; for (@ast::expr arg in args) { args_opt_0 += ~[some[@ast::expr](arg)]; } // Call the generic checker. - check_call_or_bind(fcx, sp, f, args_opt_0, true); + check_call_or_bind(fcx, sp, f, args_opt_0, call_kind); } // A generic function for checking for or for-each loops @@ -1990,7 +2015,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_bind(?f, ?args)) { // Call the generic checker. - check_call_or_bind(fcx, expr.span, f, args, false); + check_call_or_bind(fcx, expr.span, f, args, kind_bind); // Pull the argument and return types out. auto proto_1; @@ -2035,7 +2060,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { function name onto purity-designation */ require_pure_call(fcx.ccx, fcx.purity, f, expr.span); - check_call(fcx, expr.span, f, args); + check_call(fcx, expr.span, f, args, kind_call); // Pull the return type out of the type of the function. auto rt_1; @@ -2085,7 +2110,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); } case (ast::expr_spawn(_, _, ?f, ?args)) { - check_call(fcx, expr.span, f, args); + check_call(fcx, expr.span, f, args, kind_spawn); auto fty = expr_ty(fcx.ccx.tcx, f); auto 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); diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs index 04243a204c9..c2281739bf5 100644 --- a/src/comp/util/common.rs +++ b/src/comp/util/common.rs @@ -182,6 +182,19 @@ fn any[T](&fn(&T) -> bool f, &vec[T] v) -> bool { ret false; } +tag call_kind { + kind_call; + kind_spawn; + kind_bind; +} + +fn call_kind_str(call_kind c) -> str { + alt (c) { + case (kind_call) { "Call" } + case (kind_spawn) { "Spawn" } + case (kind_bind) { "Bind" } + } +} // // Local Variables: // mode: rust diff --git a/src/test/compile-fail/bind-parameterized-args.rs b/src/test/compile-fail/bind-parameterized-args.rs new file mode 100644 index 00000000000..5e2dd24fb28 --- /dev/null +++ b/src/test/compile-fail/bind-parameterized-args.rs @@ -0,0 +1,10 @@ +// xfail-stage0 +// error-pattern:Bind arguments with types containing parameters must be +fn main() { + fn echo[T](int c, vec[T] x) { + } + + let fn(vec[int]) -> () y = bind echo(42, _); + + y([1]); +} diff --git a/src/test/compile-fail/chan-parameterized-args.rs b/src/test/compile-fail/chan-parameterized-args.rs new file mode 100644 index 00000000000..78c9a743c75 --- /dev/null +++ b/src/test/compile-fail/chan-parameterized-args.rs @@ -0,0 +1,18 @@ +// xfail-stage0 +// error-pattern:Spawn arguments with types containing parameters must be +fn main() { +// Similar to bind-parameterized-args + fn echo[T](chan[T] c, chan[chan[T]] oc) { + let port[T] p = port(); + oc <| chan(p); + + auto x; + p |> x; + c <| x; + } + + auto p = port[int](); + auto p2 = port[chan[int]](); + + spawn echo(chan(p), chan(p2)); +} \ No newline at end of file