More typeck hacking, check if and call exprs, enable fact and deep tests.
This commit is contained in:
parent
5955e23343
commit
3ba6736383
@ -522,6 +522,8 @@ TEST_XFAILS_SELF := $(filter-out \
|
||||
bool-not.rs \
|
||||
char.rs \
|
||||
dead-code-one-arm-if.rs \
|
||||
deep.rs \
|
||||
fact.rs \
|
||||
hello.rs \
|
||||
int.rs \
|
||||
item-name-overload.rs \
|
||||
|
@ -41,7 +41,7 @@ type glue_fns = rec(ValueRef activate_glue,
|
||||
ValueRef exit_task_glue,
|
||||
vec[ValueRef] upcall_glues);
|
||||
|
||||
state type trans_ctxt = rec(session.session sess,
|
||||
state type crate_ctxt = rec(session.session sess,
|
||||
ModuleRef llmod,
|
||||
hashmap[str, ValueRef] upcalls,
|
||||
hashmap[str, ValueRef] fn_names,
|
||||
@ -55,7 +55,7 @@ state type fn_ctxt = rec(ValueRef llfn,
|
||||
ValueRef lltaskptr,
|
||||
hashmap[ast.def_id, ValueRef] llargs,
|
||||
hashmap[ast.def_id, ValueRef] lllocals,
|
||||
@trans_ctxt tcx);
|
||||
@crate_ctxt ccx);
|
||||
|
||||
tag cleanup {
|
||||
clean(fn(@block_ctxt cx) -> result);
|
||||
@ -238,13 +238,13 @@ fn T_taskptr() -> TypeRef {
|
||||
ret T_ptr(T_task());
|
||||
}
|
||||
|
||||
fn type_of(@trans_ctxt cx, @typeck.ty t) -> TypeRef {
|
||||
fn type_of(@crate_ctxt cx, @typeck.ty t) -> TypeRef {
|
||||
let TypeRef llty = type_of_inner(cx, t);
|
||||
check (llty as int != 0);
|
||||
ret llty;
|
||||
}
|
||||
|
||||
fn type_of_inner(@trans_ctxt cx, @typeck.ty t) -> TypeRef {
|
||||
fn type_of_inner(@crate_ctxt cx, @typeck.ty t) -> TypeRef {
|
||||
alt (t.struct) {
|
||||
case (typeck.ty_nil) { ret T_nil(); }
|
||||
case (typeck.ty_bool) { ret T_bool(); }
|
||||
@ -334,7 +334,7 @@ fn C_int(int i) -> ValueRef {
|
||||
ret C_integral(i, T_int());
|
||||
}
|
||||
|
||||
fn C_str(@trans_ctxt cx, str s) -> ValueRef {
|
||||
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
|
||||
auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
|
||||
auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
|
||||
_str.buf(cx.names.next("str")));
|
||||
@ -395,7 +395,7 @@ fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
|
||||
ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
|
||||
}
|
||||
|
||||
fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
|
||||
fn get_upcall(@crate_ctxt cx, str name, int n_args) -> ValueRef {
|
||||
if (cx.upcalls.contains_key(name)) {
|
||||
ret cx.upcalls.get(name);
|
||||
}
|
||||
@ -409,10 +409,10 @@ fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
|
||||
|
||||
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
|
||||
let int n = _vec.len[ValueRef](args) as int;
|
||||
let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n);
|
||||
let ValueRef llupcall = get_upcall(cx.fcx.ccx, name, n);
|
||||
llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());
|
||||
|
||||
let ValueRef llglue = cx.fcx.tcx.glues.upcall_glues.(n);
|
||||
let ValueRef llglue = cx.fcx.ccx.glues.upcall_glues.(n);
|
||||
let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall);
|
||||
for (ValueRef a in args) {
|
||||
call_args += cx.build.ZExtOrBitCast(a, T_int());
|
||||
@ -510,7 +510,7 @@ fn trans_copy_ty(@block_ctxt cx,
|
||||
ret res(r.bcx, r.bcx.build.Store(src, dst));
|
||||
}
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("ty variant in trans_copy_ty");
|
||||
cx.fcx.ccx.sess.unimpl("ty variant in trans_copy_ty");
|
||||
fail;
|
||||
}
|
||||
|
||||
@ -541,7 +541,7 @@ impure fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
|
||||
case (ast.lit_str(?s)) {
|
||||
auto len = (_str.byte_len(s) as int) + 1;
|
||||
auto sub = trans_upcall(cx, "upcall_new_str",
|
||||
vec(p2i(C_str(cx.fcx.tcx, s)),
|
||||
vec(p2i(C_str(cx.fcx.ccx, s)),
|
||||
C_int(len)));
|
||||
sub.val = sub.bcx.build.IntToPtr(sub.val,
|
||||
T_ptr(T_str(len as uint)));
|
||||
@ -551,7 +551,7 @@ impure fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
|
||||
}
|
||||
}
|
||||
|
||||
fn node_type(@trans_ctxt cx, &ast.ann a) -> TypeRef {
|
||||
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
|
||||
alt (a) {
|
||||
case (ast.ann_none) {
|
||||
log "missing type annotation";
|
||||
@ -583,7 +583,7 @@ impure fn trans_unary(@block_ctxt cx, ast.unop op,
|
||||
ret sub;
|
||||
}
|
||||
case (ast.box) {
|
||||
auto e_ty = node_type(cx.fcx.tcx, a);
|
||||
auto e_ty = node_type(cx.fcx.ccx, a);
|
||||
auto box_ty = T_box(e_ty);
|
||||
sub.val = cx.build.Malloc(box_ty);
|
||||
auto rc = sub.bcx.build.GEP(sub.val,
|
||||
@ -592,7 +592,7 @@ impure fn trans_unary(@block_ctxt cx, ast.unop op,
|
||||
ret res(sub.bcx, cx.build.Store(C_int(1), rc));
|
||||
}
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_unary");
|
||||
cx.fcx.ccx.sess.unimpl("expr variant in trans_unary");
|
||||
fail;
|
||||
}
|
||||
|
||||
@ -737,7 +737,7 @@ impure fn trans_binary(@block_ctxt cx, ast.binop op,
|
||||
ret sub;
|
||||
}
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_binary");
|
||||
cx.fcx.ccx.sess.unimpl("expr variant in trans_binary");
|
||||
fail;
|
||||
}
|
||||
|
||||
@ -864,21 +864,21 @@ fn trans_lval(@block_ctxt cx, &ast.expr e)
|
||||
true, did);
|
||||
}
|
||||
case (ast.def_fn(?did)) {
|
||||
ret tup(res(cx, cx.fcx.tcx.fn_ids.get(did)),
|
||||
ret tup(res(cx, cx.fcx.ccx.fn_ids.get(did)),
|
||||
false, did);
|
||||
}
|
||||
case (_) {
|
||||
cx.fcx.tcx.sess.unimpl("def variant in trans");
|
||||
cx.fcx.ccx.sess.unimpl("def variant in trans");
|
||||
}
|
||||
}
|
||||
}
|
||||
case (none[ast.def]) {
|
||||
cx.fcx.tcx.sess.err("unresolved expr_name in trans");
|
||||
cx.fcx.ccx.sess.err("unresolved expr_name in trans");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_lval");
|
||||
cx.fcx.ccx.sess.unimpl("expr variant in trans_lval");
|
||||
fail;
|
||||
}
|
||||
|
||||
@ -963,7 +963,7 @@ impure fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
|
||||
}
|
||||
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_expr");
|
||||
cx.fcx.ccx.sess.unimpl("expr variant in trans_expr");
|
||||
fail;
|
||||
}
|
||||
|
||||
@ -999,8 +999,8 @@ impure fn trans_check_expr(@block_ctxt cx, &ast.expr e) -> result {
|
||||
auto cond_res = trans_expr(cx, e);
|
||||
|
||||
// FIXME: need pretty-printer.
|
||||
auto V_expr_str = p2i(C_str(cx.fcx.tcx, "<expr>"));
|
||||
auto V_filename = p2i(C_str(cx.fcx.tcx, e.span.filename));
|
||||
auto V_expr_str = p2i(C_str(cx.fcx.ccx, "<expr>"));
|
||||
auto V_filename = p2i(C_str(cx.fcx.ccx, e.span.filename));
|
||||
auto V_line = e.span.lo.line as int;
|
||||
auto args = vec(V_expr_str, V_filename, C_int(V_line));
|
||||
|
||||
@ -1084,7 +1084,7 @@ impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
cx.fcx.tcx.sess.unimpl("stmt variant");
|
||||
cx.fcx.ccx.sess.unimpl("stmt variant");
|
||||
}
|
||||
}
|
||||
ret sub;
|
||||
@ -1103,7 +1103,7 @@ fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
|
||||
str name) -> @block_ctxt {
|
||||
let BasicBlockRef llbb =
|
||||
llvm.LLVMAppendBasicBlock(cx.llfn,
|
||||
_str.buf(cx.tcx.names.next(name)));
|
||||
_str.buf(cx.ccx.names.next(name)));
|
||||
|
||||
ret @rec(llbb=llbb,
|
||||
build=new_builder(llbb, name),
|
||||
@ -1159,7 +1159,7 @@ impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
|
||||
auto bcx = cx;
|
||||
|
||||
for each (@ast.local local in block_locals(b)) {
|
||||
auto ty = node_type(cx.fcx.tcx, local.ann);
|
||||
auto ty = node_type(cx.fcx.ccx, local.ann);
|
||||
auto val = bcx.build.Alloca(ty);
|
||||
cx.fcx.lllocals.insert(local.id, val);
|
||||
}
|
||||
@ -1179,7 +1179,7 @@ impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
|
||||
ret res(bcx, r.val);
|
||||
}
|
||||
|
||||
fn new_fn_ctxt(@trans_ctxt cx,
|
||||
fn new_fn_ctxt(@crate_ctxt cx,
|
||||
str name,
|
||||
&ast._fn f,
|
||||
ast.def_id fid) -> @fn_ctxt {
|
||||
@ -1204,7 +1204,7 @@ fn new_fn_ctxt(@trans_ctxt cx,
|
||||
lltaskptr=lltaskptr,
|
||||
llargs=llargs,
|
||||
lllocals=lllocals,
|
||||
tcx=cx);
|
||||
ccx=cx);
|
||||
}
|
||||
|
||||
fn is_terminated(@block_ctxt cx) -> bool {
|
||||
@ -1212,7 +1212,7 @@ fn is_terminated(@block_ctxt cx) -> bool {
|
||||
ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
|
||||
}
|
||||
|
||||
impure fn trans_fn(@trans_ctxt cx, &ast._fn f, ast.def_id fid) {
|
||||
impure fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid) {
|
||||
|
||||
auto fcx = new_fn_ctxt(cx, cx.path, f, fid);
|
||||
auto bcx = new_top_block_ctxt(fcx);
|
||||
@ -1224,7 +1224,7 @@ impure fn trans_fn(@trans_ctxt cx, &ast._fn f, ast.def_id fid) {
|
||||
}
|
||||
}
|
||||
|
||||
impure fn trans_item(@trans_ctxt cx, &ast.item item) {
|
||||
impure fn trans_item(@crate_ctxt cx, &ast.item item) {
|
||||
alt (item.node) {
|
||||
case (ast.item_fn(?name, ?f, ?fid, _)) {
|
||||
auto sub_cx = @rec(path=cx.path + "." + name with *cx);
|
||||
@ -1237,14 +1237,14 @@ impure fn trans_item(@trans_ctxt cx, &ast.item item) {
|
||||
}
|
||||
}
|
||||
|
||||
impure fn trans_mod(@trans_ctxt cx, &ast._mod m) {
|
||||
impure fn trans_mod(@crate_ctxt cx, &ast._mod m) {
|
||||
for (@ast.item item in m.items) {
|
||||
trans_item(cx, *item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn collect_item(&@trans_ctxt cx, @ast.item i) -> @trans_ctxt {
|
||||
fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
|
||||
alt (i.node) {
|
||||
case (ast.item_fn(?name, ?f, ?fid, ?ann)) {
|
||||
cx.items.insert(fid, i);
|
||||
@ -1262,22 +1262,22 @@ fn collect_item(&@trans_ctxt cx, @ast.item i) -> @trans_ctxt {
|
||||
}
|
||||
|
||||
|
||||
fn collect_items(@trans_ctxt cx, @ast.crate crate) {
|
||||
fn collect_items(@crate_ctxt cx, @ast.crate crate) {
|
||||
|
||||
let fold.ast_fold[@trans_ctxt] fld =
|
||||
fold.new_identity_fold[@trans_ctxt]();
|
||||
let fold.ast_fold[@crate_ctxt] fld =
|
||||
fold.new_identity_fold[@crate_ctxt]();
|
||||
|
||||
fld = @rec( update_env_for_item = bind collect_item(_,_)
|
||||
with *fld );
|
||||
|
||||
fold.fold_crate[@trans_ctxt](cx, fld, crate);
|
||||
fold.fold_crate[@crate_ctxt](cx, fld, crate);
|
||||
}
|
||||
|
||||
fn p2i(ValueRef v) -> ValueRef {
|
||||
ret llvm.LLVMConstPtrToInt(v, T_int());
|
||||
}
|
||||
|
||||
fn trans_exit_task_glue(@trans_ctxt cx) {
|
||||
fn trans_exit_task_glue(@crate_ctxt cx) {
|
||||
let vec[TypeRef] T_args = vec();
|
||||
let vec[ValueRef] V_args = vec();
|
||||
|
||||
@ -1287,14 +1287,14 @@ fn trans_exit_task_glue(@trans_ctxt cx) {
|
||||
lltaskptr=lltaskptr,
|
||||
llargs=new_def_hash[ValueRef](),
|
||||
lllocals=new_def_hash[ValueRef](),
|
||||
tcx=cx);
|
||||
ccx=cx);
|
||||
|
||||
auto bcx = new_top_block_ctxt(fcx);
|
||||
trans_upcall(bcx, "upcall_exit", V_args);
|
||||
bcx.build.RetVoid();
|
||||
}
|
||||
|
||||
fn crate_constant(@trans_ctxt cx) -> ValueRef {
|
||||
fn crate_constant(@crate_ctxt cx) -> ValueRef {
|
||||
|
||||
let ValueRef crate_ptr =
|
||||
llvm.LLVMAddGlobal(cx.llmod, T_crate(),
|
||||
@ -1332,7 +1332,7 @@ fn crate_constant(@trans_ctxt cx) -> ValueRef {
|
||||
ret crate_ptr;
|
||||
}
|
||||
|
||||
fn trans_main_fn(@trans_ctxt cx, ValueRef llcrate) {
|
||||
fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
|
||||
auto T_main_args = vec(T_int(), T_int());
|
||||
auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());
|
||||
|
||||
|
@ -3,6 +3,7 @@ import front.ast.ann;
|
||||
import middle.fold;
|
||||
import driver.session;
|
||||
import util.common;
|
||||
import util.common.append;
|
||||
import util.common.span;
|
||||
|
||||
import std._str;
|
||||
@ -15,11 +16,15 @@ import std.option.none;
|
||||
import std.option.some;
|
||||
|
||||
type ty_table = hashmap[ast.def_id, @ty];
|
||||
type env = rec(session.session sess,
|
||||
type crate_ctxt = rec(session.session sess,
|
||||
@ty_table item_types,
|
||||
hashmap[int,@ty] bindings,
|
||||
mutable int next_var_id);
|
||||
|
||||
type fn_ctxt = rec(@ty ret_ty,
|
||||
@ty_table locals,
|
||||
@crate_ctxt ccx);
|
||||
|
||||
type arg = rec(ast.mode mode, @ty ty);
|
||||
|
||||
// NB: If you change this, you'll probably want to change the corresponding
|
||||
@ -242,14 +247,14 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty {
|
||||
ret @rec(struct=sty, cname=cname);
|
||||
}
|
||||
|
||||
// A convenience function to use an environment to resolve names for
|
||||
// A convenience function to use a crate_ctxt to resolve names for
|
||||
// ast_ty_to_ty.
|
||||
fn ast_ty_to_ty_env(@env e, &@ast.ty ast_ty) -> @ty {
|
||||
fn getter(@env e, ast.def_id id) -> @ty {
|
||||
check (e.item_types.contains_key(id));
|
||||
ret e.item_types.get(id);
|
||||
fn ast_ty_to_ty_crate(@crate_ctxt ccx, &@ast.ty ast_ty) -> @ty {
|
||||
fn getter(@crate_ctxt ccx, ast.def_id id) -> @ty {
|
||||
check (ccx.item_types.contains_key(id));
|
||||
ret ccx.item_types.get(id);
|
||||
}
|
||||
auto f = bind getter(e, _);
|
||||
auto f = bind getter(ccx, _);
|
||||
ret ast_ty_to_ty(f, ast_ty);
|
||||
}
|
||||
|
||||
@ -402,7 +407,28 @@ fn ann_to_type(&ast.ann ann) -> @ty {
|
||||
}
|
||||
}
|
||||
|
||||
fn type_of(@ast.expr expr) -> @ty {
|
||||
fn stmt_ty(@ast.stmt s) -> @ty {
|
||||
alt (s.node) {
|
||||
case (ast.stmt_expr(?e)) {
|
||||
ret expr_ty(e);
|
||||
}
|
||||
case (_) {
|
||||
ret plain_ty(ty_nil);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn block_ty(&ast.block b) -> @ty {
|
||||
auto len = _vec.len[@ast.stmt](b.node.stmts);
|
||||
if (len == 0u) {
|
||||
ret plain_ty(ty_nil);
|
||||
}
|
||||
// FIXME: should rewind to last non-dead stmt? Or perhaps
|
||||
// we prohibit all dead stmts?
|
||||
ret stmt_ty(b.node.stmts.(len - 1u));
|
||||
}
|
||||
|
||||
fn expr_ty(@ast.expr expr) -> @ty {
|
||||
alt (expr.node) {
|
||||
case (ast.expr_vec(_, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_tup(_, ?ann)) { ret ann_to_type(ann); }
|
||||
@ -427,7 +453,7 @@ fn type_of(@ast.expr expr) -> @ty {
|
||||
|
||||
// Type unification
|
||||
|
||||
fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||
// Wraps the given type in an appropriate cname.
|
||||
//
|
||||
// TODO: This doesn't do anything yet. We should carry the cname up from
|
||||
@ -444,7 +470,7 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
|
||||
fn unify_step(&@env e, @ty expected, @ty actual)
|
||||
fn unify_step(&@crate_ctxt ccx, @ty expected, @ty actual)
|
||||
-> unify_result {
|
||||
// TODO: rewrite this using tuple pattern matching when available, to
|
||||
// avoid all this rightward drift and spikiness.
|
||||
@ -460,7 +486,9 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
case (ty_box(?expected_sub)) {
|
||||
alt (actual.struct) {
|
||||
case (ty_box(?actual_sub)) {
|
||||
auto result = unify_step(e, expected_sub, actual_sub);
|
||||
auto result = unify_step(ccx,
|
||||
expected_sub,
|
||||
actual_sub);
|
||||
alt (result) {
|
||||
case (ures_ok(?result_sub)) {
|
||||
ret ures_ok(plain_ty(ty_box(result_sub)));
|
||||
@ -482,7 +510,9 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
case (ty_vec(?expected_sub)) {
|
||||
alt (actual.struct) {
|
||||
case (ty_vec(?actual_sub)) {
|
||||
auto result = unify_step(e, expected_sub, actual_sub);
|
||||
auto result = unify_step(ccx,
|
||||
expected_sub,
|
||||
actual_sub);
|
||||
alt (result) {
|
||||
case (ures_ok(?result_sub)) {
|
||||
ret ures_ok(plain_ty(ty_vec(result_sub)));
|
||||
@ -526,7 +556,8 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
ret ures_err(err, expected, actual);
|
||||
}
|
||||
|
||||
auto result = unify_step(e, expected_elem._1,
|
||||
auto result = unify_step(ccx,
|
||||
expected_elem._1,
|
||||
actual_elem._1);
|
||||
alt (result) {
|
||||
case (ures_ok(?rty)) {
|
||||
@ -577,7 +608,8 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
result_mode = ast.val;
|
||||
}
|
||||
|
||||
auto result = unify_step(e, expected_input.ty,
|
||||
auto result = unify_step(ccx,
|
||||
expected_input.ty,
|
||||
actual_input.ty);
|
||||
|
||||
alt (result) {
|
||||
@ -596,7 +628,8 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
|
||||
// Check the output.
|
||||
auto result_out;
|
||||
auto result = unify_step(e, expected_output,
|
||||
auto result = unify_step(ccx,
|
||||
expected_output,
|
||||
actual_output);
|
||||
alt (result) {
|
||||
case (ures_ok(?rty)) {
|
||||
@ -618,13 +651,13 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
}
|
||||
|
||||
case (ty_var(?expected_id)) {
|
||||
if (e.bindings.contains_key(expected_id)) {
|
||||
check (e.bindings.contains_key(expected_id));
|
||||
auto binding = e.bindings.get(expected_id);
|
||||
ret unify_step(e, binding, actual);
|
||||
if (ccx.bindings.contains_key(expected_id)) {
|
||||
check (ccx.bindings.contains_key(expected_id));
|
||||
auto binding = ccx.bindings.get(expected_id);
|
||||
ret unify_step(ccx, binding, actual);
|
||||
}
|
||||
|
||||
e.bindings.insert(expected_id, actual);
|
||||
ccx.bindings.insert(expected_id, actual);
|
||||
ret ures_ok(actual);
|
||||
}
|
||||
}
|
||||
@ -633,20 +666,21 @@ fn unify(&@env e, @ty expected, @ty actual) -> unify_result {
|
||||
fail;
|
||||
}
|
||||
|
||||
ret unify_step(e, expected, actual);
|
||||
ret unify_step(ccx, expected, actual);
|
||||
}
|
||||
|
||||
// Requires that the two types unify, and prints an error message if they
|
||||
// don't. Returns the unified type.
|
||||
fn demand(&@env e, &span sp, @ty expected, @ty actual) -> @ty {
|
||||
alt (unify(e, expected, actual)) {
|
||||
fn demand(&@crate_ctxt ccx, &span sp, @ty expected, @ty actual) -> @ty {
|
||||
alt (unify(ccx, expected, actual)) {
|
||||
case (ures_ok(?ty)) {
|
||||
ret ty;
|
||||
}
|
||||
|
||||
case (ures_err(?err, ?expected, ?actual)) {
|
||||
e.sess.err("mismatched types: expected " + ty_to_str(expected) +
|
||||
" but found " + ty_to_str(actual) + " (" +
|
||||
ccx.sess.span_err(sp, "mismatched types: expected "
|
||||
+ ty_to_str(expected) + " but found "
|
||||
+ ty_to_str(actual) + " (" +
|
||||
type_err_to_str(err) + ")");
|
||||
|
||||
// TODO: In the future, try returning "expected", reporting the
|
||||
@ -656,20 +690,9 @@ fn demand(&@env e, &span sp, @ty expected, @ty actual) -> @ty {
|
||||
}
|
||||
}
|
||||
|
||||
// Unifies the supplied type with the type of the local `id`, and stores the
|
||||
// unified type in the local table. Emits an error if the type is incompatible
|
||||
// with the previously-stored type for this local.
|
||||
fn demand_local(&@env e, &span sp, &@ty_table locals, ast.def_id local_id,
|
||||
@ty t) {
|
||||
check (locals.contains_key(local_id));
|
||||
auto prev_ty = locals.get(local_id);
|
||||
auto unified_ty = demand(e, sp, prev_ty, t);
|
||||
locals.insert(local_id, unified_ty);
|
||||
}
|
||||
|
||||
// Returns true if the two types unify and false if they don't.
|
||||
fn are_compatible(&@env e, @ty expected, @ty actual) -> bool {
|
||||
alt (unify(e, expected, actual)) {
|
||||
fn are_compatible(&@crate_ctxt ccx, @ty expected, @ty actual) -> bool {
|
||||
alt (unify(ccx, expected, actual)) {
|
||||
case (ures_ok(_)) { ret true; }
|
||||
case (ures_err(_, _, _)) { ret false; }
|
||||
}
|
||||
@ -677,36 +700,37 @@ fn are_compatible(&@env e, @ty expected, @ty actual) -> bool {
|
||||
|
||||
// Writeback: the phase that writes inferred types back into the AST.
|
||||
|
||||
fn resolve_vars(@env e, @ty t) -> @ty {
|
||||
fn resolve_vars(@crate_ctxt ccx, @ty t) -> @ty {
|
||||
alt (t.struct) {
|
||||
case (ty_var(?v)) {
|
||||
check (e.bindings.contains_key(v));
|
||||
ret resolve_vars(e, e.bindings.get(v));
|
||||
check (ccx.bindings.contains_key(v));
|
||||
ret resolve_vars(ccx, ccx.bindings.get(v));
|
||||
}
|
||||
}
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn writeback_local(@env e, &@ty_table locals, &span sp, @ast.local local)
|
||||
fn writeback_local(&fn_ctxt fcx, &span sp, @ast.local local)
|
||||
-> @ast.decl {
|
||||
if (!locals.contains_key(local.id)) {
|
||||
e.sess.err("unable to determine type of local: " + local.ident);
|
||||
if (!fcx.locals.contains_key(local.id)) {
|
||||
fcx.ccx.sess.span_err(sp, "unable to determine type of local: "
|
||||
+ local.ident);
|
||||
}
|
||||
auto local_ty = resolve_vars(e, locals.get(local.id));
|
||||
auto local_ty = resolve_vars(fcx.ccx, fcx.locals.get(local.id));
|
||||
auto local_wb = @rec(ann=ast.ann_type(local_ty) with *local);
|
||||
ret @fold.respan[ast.decl_](sp, ast.decl_local(local_wb));
|
||||
}
|
||||
|
||||
fn writeback(&@env e, &@ty_table locals, &ast.block block) -> ast.block {
|
||||
auto fld = fold.new_identity_fold[@ty_table]();
|
||||
auto f = bind writeback_local(e, _, _, _);
|
||||
fn writeback(&fn_ctxt fcx, &ast.block block) -> ast.block {
|
||||
auto fld = fold.new_identity_fold[fn_ctxt]();
|
||||
auto f = writeback_local;
|
||||
fld = @rec(fold_decl_local = f with *fld);
|
||||
ret fold.fold_block[@ty_table](locals, fld, block);
|
||||
ret fold.fold_block[fn_ctxt](fcx, fld, block);
|
||||
}
|
||||
|
||||
// AST fragment checking
|
||||
|
||||
fn check_lit(&@env e, @ast.lit lit) -> @ty {
|
||||
fn check_lit(@ast.lit lit) -> @ty {
|
||||
auto sty;
|
||||
alt (lit.node) {
|
||||
case (ast.lit_str(_)) { sty = ty_str; }
|
||||
@ -720,22 +744,22 @@ fn check_lit(&@env e, @ast.lit lit) -> @ty {
|
||||
ret plain_ty(sty);
|
||||
}
|
||||
|
||||
fn check_expr(&@env e, &@ty_table locals, @ast.expr expr) -> @ast.expr {
|
||||
fn check_expr(&fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
|
||||
alt (expr.node) {
|
||||
case (ast.expr_lit(?lit, _)) {
|
||||
auto ty = check_lit(e, lit);
|
||||
auto ty = check_lit(lit);
|
||||
ret @fold.respan[ast.expr_](expr.span,
|
||||
ast.expr_lit(lit, ast.ann_type(ty)));
|
||||
}
|
||||
|
||||
|
||||
case (ast.expr_binary(?binop, ?lhs, ?rhs, _)) {
|
||||
auto lhs_1 = check_expr(e, locals, lhs);
|
||||
auto rhs_1 = check_expr(e, locals, rhs);
|
||||
auto lhs_t = type_of(lhs_1);
|
||||
auto rhs_t = type_of(rhs_1);
|
||||
auto lhs_1 = check_expr(fcx, lhs);
|
||||
auto rhs_1 = check_expr(fcx, rhs);
|
||||
auto lhs_t = expr_ty(lhs_1);
|
||||
auto rhs_t = expr_ty(rhs_1);
|
||||
// FIXME: Binops have a bit more subtlety than this.
|
||||
demand(e, expr.span, lhs_t, rhs_t);
|
||||
demand(fcx.ccx, expr.span, lhs_t, rhs_t);
|
||||
auto t = lhs_t;
|
||||
alt (binop) {
|
||||
case (ast.eq) { t = plain_ty(ty_bool); }
|
||||
@ -752,8 +776,8 @@ fn check_expr(&@env e, &@ty_table locals, @ast.expr expr) -> @ast.expr {
|
||||
|
||||
|
||||
case (ast.expr_unary(?unop, ?oper, _)) {
|
||||
auto oper_1 = check_expr(e, locals, oper);
|
||||
auto oper_t = type_of(oper_1);
|
||||
auto oper_1 = check_expr(fcx, oper);
|
||||
auto oper_t = expr_ty(oper_1);
|
||||
// FIXME: Unops have a bit more subtlety than this.
|
||||
ret @fold.respan[ast.expr_](expr.span,
|
||||
ast.expr_unary(unop, oper_1,
|
||||
@ -764,16 +788,24 @@ fn check_expr(&@env e, &@ty_table locals, @ast.expr expr) -> @ast.expr {
|
||||
auto ty = @rec(struct=ty_nil, cname=none[str]);
|
||||
alt (option.get[ast.def](defopt)) {
|
||||
case (ast.def_arg(?id)) {
|
||||
check (locals.contains_key(id));
|
||||
ty = locals.get(id);
|
||||
check (fcx.locals.contains_key(id));
|
||||
ty = fcx.locals.get(id);
|
||||
}
|
||||
case (ast.def_local(?id)) {
|
||||
check (locals.contains_key(id));
|
||||
ty = locals.get(id);
|
||||
check (fcx.locals.contains_key(id));
|
||||
ty = fcx.locals.get(id);
|
||||
}
|
||||
case (ast.def_fn(?id)) {
|
||||
check (fcx.ccx.item_types.contains_key(id));
|
||||
ty = fcx.ccx.item_types.get(id);
|
||||
}
|
||||
case (ast.def_const(?id)) {
|
||||
check (fcx.ccx.item_types.contains_key(id));
|
||||
ty = fcx.ccx.item_types.get(id);
|
||||
}
|
||||
case (_) {
|
||||
// FIXME: handle other names.
|
||||
e.sess.unimpl("definition variant for: "
|
||||
fcx.ccx.sess.unimpl("definition variant for: "
|
||||
+ name.node.ident);
|
||||
fail;
|
||||
}
|
||||
@ -784,16 +816,63 @@ fn check_expr(&@env e, &@ty_table locals, @ast.expr expr) -> @ast.expr {
|
||||
}
|
||||
|
||||
case (ast.expr_assign(?lhs, ?rhs, _)) {
|
||||
auto lhs_1 = check_expr(e, locals, lhs);
|
||||
auto rhs_1 = check_expr(e, locals, rhs);
|
||||
auto lhs_t = type_of(lhs_1);
|
||||
auto rhs_t = type_of(rhs_1);
|
||||
demand(e, expr.span, lhs_t, rhs_t);
|
||||
auto lhs_1 = check_expr(fcx, lhs);
|
||||
auto rhs_1 = check_expr(fcx, rhs);
|
||||
auto lhs_t = expr_ty(lhs_1);
|
||||
auto rhs_t = expr_ty(rhs_1);
|
||||
demand(fcx.ccx, expr.span, lhs_t, rhs_t);
|
||||
ret @fold.respan[ast.expr_](expr.span,
|
||||
ast.expr_assign(lhs_1, rhs_1,
|
||||
ast.ann_type(rhs_t)));
|
||||
}
|
||||
|
||||
case (ast.expr_if(?cond, ?thn, ?elsopt, _)) {
|
||||
auto cond_1 = check_expr(fcx, cond);
|
||||
auto thn_1 = check_block(fcx, thn);
|
||||
demand(fcx.ccx, cond.span, plain_ty(ty_bool), expr_ty(cond_1));
|
||||
auto thn_t = block_ty(thn_1);
|
||||
auto elsopt_1 = none[ast.block];
|
||||
auto elsopt_t = plain_ty(ty_nil);
|
||||
alt (elsopt) {
|
||||
case (some[ast.block](?els)) {
|
||||
auto els_1 = check_block(fcx, els);
|
||||
elsopt_1 = some[ast.block](els_1);
|
||||
elsopt_t = block_ty(els_1);
|
||||
}
|
||||
}
|
||||
demand(fcx.ccx, expr.span, thn_t, elsopt_t);
|
||||
ret @fold.respan[ast.expr_](expr.span,
|
||||
ast.expr_if(cond_1, thn_1, elsopt_1,
|
||||
ast.ann_type(thn_t)));
|
||||
}
|
||||
|
||||
case (ast.expr_call(?f, ?args, _)) {
|
||||
auto f_1 = check_expr(fcx, f);
|
||||
let @ty ret_t = plain_ty(ty_nil);
|
||||
alt (expr_ty(f_1).struct) {
|
||||
case (ty_fn(_, ?r)) {
|
||||
ret_t = r;
|
||||
}
|
||||
case (_) {
|
||||
fcx.ccx.sess.span_err(f_1.span,
|
||||
"callee has non-function type: "
|
||||
+ ty_to_str(expr_ty(f_1)));
|
||||
}
|
||||
}
|
||||
let vec[@ast.expr] args_1 = vec();
|
||||
let vec[arg] args_t = vec();
|
||||
for (@ast.expr a in args) {
|
||||
auto a_1 = check_expr(fcx, a);
|
||||
append[@ast.expr](args_1, a_1);
|
||||
append[arg](args_t, rec(mode=ast.val, ty=expr_ty(a_1)));
|
||||
}
|
||||
demand(fcx.ccx, expr.span, expr_ty(f_1),
|
||||
plain_ty(ty_fn(args_t, ret_t)));
|
||||
ret @fold.respan[ast.expr_](expr.span,
|
||||
ast.expr_call(f_1, args_1,
|
||||
ast.ann_type(ret_t)));
|
||||
}
|
||||
|
||||
case (_) {
|
||||
// TODO
|
||||
ret expr;
|
||||
@ -801,7 +880,13 @@ fn check_expr(&@env e, &@ty_table locals, @ast.expr expr) -> @ast.expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stmt(@env e, @ty_table locals, @ty ret_ty, &@ast.stmt stmt)
|
||||
fn next_ty_var(&fn_ctxt fcx) -> @ty {
|
||||
auto t = plain_ty(ty_var(fcx.ccx.next_var_id));
|
||||
fcx.ccx.next_var_id += 1;
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn check_stmt(&fn_ctxt fcx, &@ast.stmt stmt)
|
||||
-> @ast.stmt {
|
||||
alt (stmt.node) {
|
||||
case (ast.stmt_decl(?decl)) {
|
||||
@ -812,26 +897,25 @@ fn check_stmt(@env e, @ty_table locals, @ty ret_ty, &@ast.stmt stmt)
|
||||
alt (local.ty) {
|
||||
case (none[@ast.ty]) {
|
||||
// Auto slot. Assign a ty_var.
|
||||
local_ty = plain_ty(ty_var(e.next_var_id));
|
||||
e.next_var_id += 1;
|
||||
local_ty = next_ty_var(fcx);
|
||||
}
|
||||
|
||||
case (some[@ast.ty](?ast_ty)) {
|
||||
local_ty = ast_ty_to_ty_env(e, ast_ty);
|
||||
local_ty = ast_ty_to_ty_crate(fcx.ccx, ast_ty);
|
||||
}
|
||||
}
|
||||
locals.insert(local.id, local_ty);
|
||||
fcx.locals.insert(local.id, local_ty);
|
||||
|
||||
auto rhs_ty = local_ty;
|
||||
auto init = local.init;
|
||||
alt (local.init) {
|
||||
case (some[@ast.expr](?expr)) {
|
||||
auto expr_t = check_expr(e, locals, expr);
|
||||
rhs_ty = type_of(expr_t);
|
||||
auto expr_t = check_expr(fcx, expr);
|
||||
rhs_ty = expr_ty(expr_t);
|
||||
init = some[@ast.expr](expr_t);
|
||||
}
|
||||
}
|
||||
demand(e, decl.span, local_ty, rhs_ty);
|
||||
demand(fcx.ccx, decl.span, local_ty, rhs_ty);
|
||||
auto local_1 = @rec(init = init with *local);
|
||||
auto decl_1 = @rec(node=ast.decl_local(local_1)
|
||||
with *decl);
|
||||
@ -850,16 +934,18 @@ fn check_stmt(@env e, @ty_table locals, @ty ret_ty, &@ast.stmt stmt)
|
||||
case (ast.stmt_ret(?expr_opt)) {
|
||||
alt (expr_opt) {
|
||||
case (none[@ast.expr]) {
|
||||
if (!are_compatible(e, ret_ty, plain_ty(ty_nil))) {
|
||||
e.sess.err("ret; in function returning non-void");
|
||||
if (!are_compatible(fcx.ccx, fcx.ret_ty,
|
||||
plain_ty(ty_nil))) {
|
||||
fcx.ccx.sess.err("ret; in function "
|
||||
+ "returning non-nil");
|
||||
}
|
||||
|
||||
ret stmt;
|
||||
}
|
||||
|
||||
case (some[@ast.expr](?expr)) {
|
||||
auto expr_t = check_expr(e, locals, expr);
|
||||
demand(e, expr.span, ret_ty, type_of(expr_t));
|
||||
auto expr_t = check_expr(fcx, expr);
|
||||
demand(fcx.ccx, expr.span, fcx.ret_ty, expr_ty(expr_t));
|
||||
ret @fold.respan[ast.stmt_](stmt.span,
|
||||
ast.stmt_ret(some(expr_t)));
|
||||
}
|
||||
@ -867,20 +953,21 @@ fn check_stmt(@env e, @ty_table locals, @ty ret_ty, &@ast.stmt stmt)
|
||||
}
|
||||
|
||||
case (ast.stmt_log(?expr)) {
|
||||
auto expr_t = check_expr(e, locals, expr);
|
||||
auto expr_t = check_expr(fcx, expr);
|
||||
ret @fold.respan[ast.stmt_](stmt.span, ast.stmt_log(expr_t));
|
||||
}
|
||||
|
||||
case (ast.stmt_check_expr(?expr)) {
|
||||
auto expr_t = check_expr(e, locals, expr);
|
||||
demand(e, expr.span, plain_ty(ty_bool), type_of(expr_t));
|
||||
auto expr_t = check_expr(fcx, expr);
|
||||
demand(fcx.ccx, expr.span, plain_ty(ty_bool), expr_ty(expr_t));
|
||||
ret @fold.respan[ast.stmt_](stmt.span,
|
||||
ast.stmt_check_expr(expr_t));
|
||||
}
|
||||
|
||||
case (ast.stmt_expr(?expr)) {
|
||||
auto expr_t = check_expr(e, locals, expr);
|
||||
if (!are_compatible(e, type_of(expr_t), plain_ty(ty_nil))) {
|
||||
auto expr_t = check_expr(fcx, expr);
|
||||
if (!are_compatible(fcx.ccx, expr_ty(expr_t),
|
||||
plain_ty(ty_nil))) {
|
||||
// TODO: real warning function
|
||||
log "warning: expression used as statement should have " +
|
||||
"void type";
|
||||
@ -893,32 +980,37 @@ fn check_stmt(@env e, @ty_table locals, @ty ret_ty, &@ast.stmt stmt)
|
||||
fail;
|
||||
}
|
||||
|
||||
fn check_block(&@env e, &@ty_table locals, @ty ret_ty, &ast.block block)
|
||||
-> ast.block {
|
||||
auto f = bind check_stmt(e, locals, ret_ty, _);
|
||||
auto stmts_t = _vec.map[@ast.stmt,@ast.stmt](f, block.node.stmts);
|
||||
fn check_block(&fn_ctxt fcx, &ast.block block) -> ast.block {
|
||||
let vec[@ast.stmt] stmts = vec();
|
||||
for (@ast.stmt s in block.node.stmts) {
|
||||
append[@ast.stmt](stmts, check_stmt(fcx, s));
|
||||
}
|
||||
ret fold.respan[ast.block_](block.span,
|
||||
rec(stmts=stmts_t, index=block.node.index));
|
||||
rec(stmts=stmts, index=block.node.index));
|
||||
}
|
||||
|
||||
fn check_fn(&@env e, &span sp, ast.ident ident, &ast._fn f, ast.def_id id,
|
||||
ast.ann ann) -> @ast.item {
|
||||
fn check_fn(&@crate_ctxt ccx, &span sp, ast.ident ident, &ast._fn f,
|
||||
ast.def_id id, ast.ann ann) -> @ast.item {
|
||||
auto local_ty_table = @common.new_def_hash[@ty]();
|
||||
|
||||
// Store the type of each argument in the table.
|
||||
let vec[arg] inputs = vec();
|
||||
for (ast.arg arg in f.inputs) {
|
||||
auto input_ty = ast_ty_to_ty_env(e, arg.ty);
|
||||
auto input_ty = ast_ty_to_ty_crate(ccx, arg.ty);
|
||||
inputs += vec(rec(mode=arg.mode, ty=input_ty));
|
||||
local_ty_table.insert(arg.id, input_ty);
|
||||
}
|
||||
|
||||
auto output_ty = ast_ty_to_ty_env(e, f.output);
|
||||
auto output_ty = ast_ty_to_ty_crate(ccx, f.output);
|
||||
auto fn_sty = ty_fn(inputs, output_ty);
|
||||
auto fn_ann = ast.ann_type(plain_ty(fn_sty));
|
||||
|
||||
auto block_t = check_block(e, local_ty_table, output_ty, f.body);
|
||||
auto block_wb = writeback(e, local_ty_table, block_t);
|
||||
let fn_ctxt fcx = rec(ret_ty = output_ty,
|
||||
locals = local_ty_table,
|
||||
ccx = ccx);
|
||||
|
||||
auto block_t = check_block(fcx, f.body);
|
||||
auto block_wb = writeback(fcx, block_t);
|
||||
auto fn_t = rec(inputs=f.inputs, output=f.output, body=block_wb);
|
||||
ret @fold.respan[ast.item_](sp, ast.item_fn(ident, fn_t, id, fn_ann));
|
||||
}
|
||||
@ -931,15 +1023,15 @@ fn check_crate(session.session sess, @ast.crate crate) -> @ast.crate {
|
||||
auto hasher = hash_int;
|
||||
auto eqer = eq_int;
|
||||
|
||||
auto e = @rec(sess=sess,
|
||||
auto ccx = @rec(sess=sess,
|
||||
item_types=result._1,
|
||||
bindings = map.mk_hashmap[int,@ty](hasher, eqer),
|
||||
mutable next_var_id=0);
|
||||
|
||||
auto fld = fold.new_identity_fold[@env]();
|
||||
auto fld = fold.new_identity_fold[@crate_ctxt]();
|
||||
auto f = check_fn; // FIXME: trans_const_lval bug
|
||||
fld = @rec(fold_item_fn = f with *fld);
|
||||
ret fold.fold_crate[@env](e, fld, result._0);
|
||||
ret fold.fold_crate[@crate_ctxt](ccx, fld, result._0);
|
||||
}
|
||||
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user