Skip to content

Commit 5508c28

Browse files
committed
Factor out the call typechecking logic so that bind can use it
1 parent 80c6726 commit 5508c28

File tree

1 file changed

+101
-42
lines changed

1 file changed

+101
-42
lines changed

src/comp/middle/typeck.rs

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,87 @@ fn check_pat(&@fn_ctxt fcx, @ast.pat pat) -> @ast.pat {
12441244
}
12451245

12461246
fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
1247+
// A generic function to factor out common logic from call and bind
1248+
// expressions.
1249+
fn check_call_or_bind(&@fn_ctxt fcx, &@ast.expr f,
1250+
&vec[option.t[@ast.expr]] args)
1251+
-> tup(@ast.expr, vec[option.t[@ast.expr]]) {
1252+
1253+
// Check the function.
1254+
auto f_0 = check_expr(fcx, f);
1255+
1256+
// Check the arguments and generate the argument signature.
1257+
let vec[option.t[@ast.expr]] args_0 = vec();
1258+
let vec[arg] arg_tys_0 = vec();
1259+
for (option.t[@ast.expr] a_opt in args) {
1260+
alt (a_opt) {
1261+
case (some[@ast.expr](?a)) {
1262+
auto a_0 = check_expr(fcx, a);
1263+
args_0 += vec(some[@ast.expr](a_0));
1264+
1265+
// FIXME: this breaks aliases. We need a ty_fn_arg.
1266+
auto arg_ty = rec(mode=ast.val, ty=expr_ty(a_0));
1267+
append[arg](arg_tys_0, arg_ty);
1268+
}
1269+
case (none[@ast.expr]) {
1270+
args_0 += vec(none[@ast.expr]);
1271+
1272+
// FIXME: breaks aliases too?
1273+
auto typ = next_ty_var(fcx.ccx);
1274+
append[arg](arg_tys_0, rec(mode=ast.val, ty=typ));
1275+
}
1276+
}
1277+
}
1278+
1279+
auto proto_0 = ast.proto_fn; // FIXME: typestate botch
1280+
alt (expr_ty(f_0).struct) {
1281+
case (ty.ty_fn(?proto, _, _)) { proto_0 = proto; }
1282+
case (_) {
1283+
log "check_call_or_bind(): fn expr doesn't have fn type";
1284+
fail;
1285+
}
1286+
}
1287+
1288+
auto rt_0 = next_ty_var(fcx.ccx);
1289+
auto t_0 = plain_ty(ty.ty_fn(proto_0, arg_tys_0, rt_0));
1290+
1291+
// Unify and write back to the function.
1292+
auto f_1 = demand_expr(fcx, t_0, f_0);
1293+
1294+
// Take the argument types out of the resulting function type.
1295+
auto t_1 = expr_ty(f_1);
1296+
1297+
if (!ty.is_fn_ty(t_1)) {
1298+
fcx.ccx.sess.span_err(f_1.span,
1299+
"mismatched types: callee has " +
1300+
"non-function type: " +
1301+
ty_to_str(t_1));
1302+
}
1303+
1304+
let vec[arg] arg_tys_1 = ty.ty_fn_args(t_1);
1305+
let @ty.t rt_1 = ty.ty_fn_ret(t_1);
1306+
1307+
// Unify and write back to the arguments.
1308+
auto i = 0u;
1309+
let vec[option.t[@ast.expr]] args_1 = vec();
1310+
while (i < _vec.len[option.t[@ast.expr]](args_0)) {
1311+
alt (args_0.(i)) {
1312+
case (some[@ast.expr](?e_0)) {
1313+
auto arg_ty_1 = arg_tys_1.(i);
1314+
auto e_1 = demand_expr(fcx, arg_ty_1.ty, e_0);
1315+
append[option.t[@ast.expr]](args_1, some[@ast.expr](e_1));
1316+
}
1317+
case (none[@ast.expr]) {
1318+
append[option.t[@ast.expr]](args_1, none[@ast.expr]);
1319+
}
1320+
}
1321+
1322+
i += 1u;
1323+
}
1324+
1325+
ret tup(f_1, args_1);
1326+
}
1327+
12471328
alt (expr.node) {
12481329
case (ast.expr_lit(?lit, _)) {
12491330
auto ty = check_lit(lit);
@@ -1658,62 +1739,40 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
16581739
i += 1u;
16591740
}
16601741

1661-
let @ty.t t_1 = plain_ty(ty.ty_fn(proto,
1662-
residual_args, rt_0));
1742+
let @ty.t t_1 = plain_ty(ty.ty_fn(proto, residual_args, rt_0));
1743+
16631744
ret @fold.respan[ast.expr_](expr.span,
16641745
ast.expr_bind(f_0, args_1,
16651746
ast.ann_type(t_1)));
1666-
16671747
}
16681748

16691749
case (ast.expr_call(?f, ?args, _)) {
1670-
1671-
// Check the function.
1672-
auto f_0 = check_expr(fcx, f);
1673-
1674-
// Check the arguments and generate the argument signature.
1675-
let vec[@ast.expr] args_0 = vec();
1676-
let vec[arg] arg_tys_0 = vec();
1677-
for (@ast.expr a in args) {
1678-
auto a_0 = check_expr(fcx, a);
1679-
append[@ast.expr](args_0, a_0);
1680-
1681-
// FIXME: this breaks aliases. We need a ty_fn_arg.
1682-
append[arg](arg_tys_0, rec(mode=ast.val, ty=expr_ty(a_0)));
1750+
let vec[option.t[@ast.expr]] args_opt_0 = vec();
1751+
for (@ast.expr arg in args) {
1752+
args_opt_0 += vec(some[@ast.expr](arg));
16831753
}
1684-
auto rt_0 = next_ty_var(fcx.ccx);
1685-
auto t_0 = plain_ty(ty.ty_fn(ty.ty_fn_proto(expr_ty(f_0)),
1686-
arg_tys_0, rt_0));
1687-
1688-
// Unify and write back to the function.
1689-
auto f_1 = demand_expr(fcx, t_0, f_0);
16901754

1691-
// Take the argument types out of the resulting function type.
1692-
auto t_1 = expr_ty(f_1);
1755+
// Call the generic checker.
1756+
auto result = check_call_or_bind(fcx, f, args_opt_0);
16931757

1694-
if (!ty.is_fn_ty(t_1)) {
1695-
fcx.ccx.sess.span_err(f_1.span,
1696-
"mismatched types: callee has " +
1697-
"non-function type: " +
1698-
ty_to_str(t_1));
1699-
}
1700-
1701-
let vec[arg] arg_tys_1 = ty.ty_fn_args(t_1);
1702-
let @ty.t rt_1 = ty.ty_fn_ret(t_1);
1703-
1704-
// Unify and write back to the arguments.
1705-
auto i = 0u;
1758+
// Pull out the arguments.
17061759
let vec[@ast.expr] args_1 = vec();
1707-
while (i < _vec.len[@ast.expr](args_0)) {
1708-
auto arg_ty_1 = arg_tys_1.(i);
1709-
auto e = demand_expr(fcx, arg_ty_1.ty, args_0.(i));
1710-
append[@ast.expr](args_1, e);
1760+
for (option.t[@ast.expr] arg in result._1) {
1761+
args_1 += vec(option.get[@ast.expr](arg));
1762+
}
17111763

1712-
i += 1u;
1764+
// Pull the return type out of the type of the function.
1765+
auto rt_1 = plain_ty(ty.ty_nil); // FIXME: typestate botch
1766+
alt (expr_ty(result._0).struct) {
1767+
case (ty.ty_fn(_,_,?rt)) { rt_1 = rt; }
1768+
case (_) {
1769+
log "LHS of call expr didn't have a function type?!";
1770+
fail;
1771+
}
17131772
}
17141773

17151774
ret @fold.respan[ast.expr_](expr.span,
1716-
ast.expr_call(f_1, args_1,
1775+
ast.expr_call(result._0, args_1,
17171776
ast.ann_type(rt_1)));
17181777
}
17191778

0 commit comments

Comments
 (0)