Skip to content

Commit e1620de

Browse files
committed
In typeck, check for dynamically sized by-value arguments to thunks
A check in trans didn't have a corresponding check in typeck, causing some programs (to wit, compile-fail/chan-parameterized-args.rs - part of this commit) to fail with an assertion failure in trans instead of a type error. Fixed it. In short, arguments that are future thunk arguments (any spawn arguments, and _ arguments in bind) need to either not contain type params or type vars, or be by-reference. Closes #665.
1 parent 9fe03b3 commit e1620de

File tree

4 files changed

+77
-11
lines changed

4 files changed

+77
-11
lines changed

src/comp/middle/typeck.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import syntax::walk;
88
import metadata::csearch;
99
import driver::session;
1010
import util::common;
11+
import util::common::*;
1112
import syntax::codemap::span;
1213
import std::map::new_int_hash;
1314
import std::map::new_str_hash;
14-
import util::common::new_def_hash;
15-
import util::common::log_expr_err;
1615
import middle::ty;
1716
import middle::ty::node_id_to_type;
1817
import middle::ty::arg;
@@ -1485,7 +1484,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
14851484
// expressions.
14861485

14871486
fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f,
1488-
&(option::t[@ast::expr])[] args, bool is_call) {
1487+
&(option::t[@ast::expr])[] args, call_kind call_kind) {
14891488
// Check the function.
14901489

14911490
check_expr(fcx, f);
@@ -1494,8 +1493,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
14941493
auto fty = expr_ty(fcx.ccx.tcx, f);
14951494

14961495
// We want to autoderef calls but not binds
1497-
auto fty_stripped =
1498-
if (is_call) { do_autoderef(fcx, sp, fty) } else { fty };
1496+
auto fty_stripped = alt (call_kind) {
1497+
case (kind_call) { do_autoderef(fcx, sp, fty) }
1498+
case (_) { fty } };
14991499

15001500
// Grab the argument types and the return type.
15011501
auto arg_tys;
@@ -1532,13 +1532,38 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
15321532

15331533
auto i = 0u;
15341534
for (option::t[@ast::expr] a_opt in args) {
1535+
auto check_ty_vars = call_kind == kind_spawn;
15351536
alt (a_opt) {
15361537
case (some(?a)) {
15371538
check_expr(fcx, a);
15381539
demand::simple(fcx, a.span, arg_tys.(i).ty,
15391540
expr_ty(fcx.ccx.tcx, a));
15401541
}
1541-
case (none) {/* no-op */ }
1542+
case (none) {
1543+
check_ty_vars = true;
1544+
}
1545+
}
1546+
/* If this argument is going to be a thunk argument
1547+
(that is, it's an underscore-bind thing or a spawn
1548+
argument), then it has to be either passed by reference,
1549+
or have a statically known size. */
1550+
alt (call_kind) {
1551+
case (kind_call) { }
1552+
case (_) { /* bind or spawn */
1553+
if (check_ty_vars &&
1554+
((ty::type_contains_params(fcx.ccx.tcx,
1555+
arg_tys.(i).ty))
1556+
|| ty::type_contains_vars(fcx.ccx.tcx,
1557+
arg_tys.(i).ty))
1558+
&& arg_tys.(i).mode == mo_val) {
1559+
// For why the check is necessary, see the
1560+
// none case in trans_bind_thunk
1561+
fcx.ccx.tcx.sess.span_fatal(sp,
1562+
call_kind_str(call_kind) +
1563+
" arguments with types containing parameters \
1564+
must be passed by alias");
1565+
}
1566+
}
15421567
}
15431568
i += 1u;
15441569
}
@@ -1556,14 +1581,14 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
15561581
// A generic function for checking call expressions
15571582

15581583
fn check_call(&@fn_ctxt fcx, &span sp, &@ast::expr f,
1559-
&(@ast::expr)[] args) {
1584+
&(@ast::expr)[] args, call_kind call_kind) {
15601585
let (option::t[@ast::expr])[] args_opt_0 = ~[];
15611586
for (@ast::expr arg in args) {
15621587
args_opt_0 += ~[some[@ast::expr](arg)];
15631588
}
15641589
// Call the generic checker.
15651590

1566-
check_call_or_bind(fcx, sp, f, args_opt_0, true);
1591+
check_call_or_bind(fcx, sp, f, args_opt_0, call_kind);
15671592
}
15681593
// A generic function for checking for or for-each loops
15691594

@@ -1990,7 +2015,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
19902015
case (ast::expr_bind(?f, ?args)) {
19912016
// Call the generic checker.
19922017

1993-
check_call_or_bind(fcx, expr.span, f, args, false);
2018+
check_call_or_bind(fcx, expr.span, f, args, kind_bind);
19942019
// Pull the argument and return types out.
19952020

19962021
auto proto_1;
@@ -2035,7 +2060,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
20352060
function name onto purity-designation */
20362061

20372062
require_pure_call(fcx.ccx, fcx.purity, f, expr.span);
2038-
check_call(fcx, expr.span, f, args);
2063+
check_call(fcx, expr.span, f, args, kind_call);
20392064
// Pull the return type out of the type of the function.
20402065

20412066
auto rt_1;
@@ -2085,7 +2110,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
20852110
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
20862111
}
20872112
case (ast::expr_spawn(_, _, ?f, ?args)) {
2088-
check_call(fcx, expr.span, f, args);
2113+
check_call(fcx, expr.span, f, args, kind_spawn);
20892114
auto fty = expr_ty(fcx.ccx.tcx, f);
20902115
auto ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty);
20912116
demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty);

src/comp/util/common.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,19 @@ fn any[T](&fn(&T) -> bool f, &vec[T] v) -> bool {
182182
ret false;
183183
}
184184

185+
tag call_kind {
186+
kind_call;
187+
kind_spawn;
188+
kind_bind;
189+
}
190+
191+
fn call_kind_str(call_kind c) -> str {
192+
alt (c) {
193+
case (kind_call) { "Call" }
194+
case (kind_spawn) { "Spawn" }
195+
case (kind_bind) { "Bind" }
196+
}
197+
}
185198
//
186199
// Local Variables:
187200
// mode: rust
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// xfail-stage0
2+
// error-pattern:Bind arguments with types containing parameters must be
3+
fn main() {
4+
fn echo[T](int c, vec[T] x) {
5+
}
6+
7+
let fn(vec[int]) -> () y = bind echo(42, _);
8+
9+
y([1]);
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// xfail-stage0
2+
// error-pattern:Spawn arguments with types containing parameters must be
3+
fn main() {
4+
// Similar to bind-parameterized-args
5+
fn echo[T](chan[T] c, chan[chan[T]] oc) {
6+
let port[T] p = port();
7+
oc <| chan(p);
8+
9+
auto x;
10+
p |> x;
11+
c <| x;
12+
}
13+
14+
auto p = port[int]();
15+
auto p2 = port[chan[int]]();
16+
17+
spawn echo(chan(p), chan(p2));
18+
}

0 commit comments

Comments
 (0)