Remove the global bindings table in the typechecker
This commit is contained in:
parent
d3cb25d5d1
commit
c0741c13ab
1 changed files with 304 additions and 99 deletions
|
@ -18,7 +18,6 @@ import std.option.some;
|
||||||
type ty_table = hashmap[ast.def_id, @ty];
|
type ty_table = hashmap[ast.def_id, @ty];
|
||||||
type crate_ctxt = rec(session.session sess,
|
type crate_ctxt = rec(session.session sess,
|
||||||
@ty_table item_types,
|
@ty_table item_types,
|
||||||
hashmap[int,@ty] bindings,
|
|
||||||
mutable int next_var_id);
|
mutable int next_var_id);
|
||||||
|
|
||||||
type fn_ctxt = rec(@ty ret_ty,
|
type fn_ctxt = rec(@ty ret_ty,
|
||||||
|
@ -42,7 +41,10 @@ tag sty {
|
||||||
ty_vec(@ty);
|
ty_vec(@ty);
|
||||||
ty_tup(vec[tup(bool /* mutability */, @ty)]);
|
ty_tup(vec[tup(bool /* mutability */, @ty)]);
|
||||||
ty_fn(vec[arg], @ty); // TODO: effect
|
ty_fn(vec[arg], @ty); // TODO: effect
|
||||||
ty_var(int);
|
ty_var(int); // ephemeral type var
|
||||||
|
ty_local(ast.def_id); // type of a local var
|
||||||
|
// TODO: ty_param(ast.def_id), for fn type params
|
||||||
|
// TODO: ty_fn_arg(@ty), for a possibly-aliased function argument
|
||||||
}
|
}
|
||||||
|
|
||||||
tag type_err {
|
tag type_err {
|
||||||
|
@ -381,6 +383,20 @@ fn collect_item_types(@ast.crate crate) -> tup(@ast.crate, @ty_table) {
|
||||||
item_to_ty);
|
item_to_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expression utilities
|
||||||
|
|
||||||
|
fn last_expr_of_block(&ast.block bloc) -> option.t[@ast.expr] {
|
||||||
|
auto len = _vec.len[@ast.stmt](bloc.node.stmts);
|
||||||
|
if (len == 0u) {
|
||||||
|
ret none[@ast.expr];
|
||||||
|
}
|
||||||
|
auto last_stmt = bloc.node.stmts.(len - 1u);
|
||||||
|
alt (last_stmt.node) {
|
||||||
|
case (ast.stmt_expr(?e)) { ret some[@ast.expr](e); }
|
||||||
|
case (_) { ret none[@ast.expr]; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Type utilities
|
// Type utilities
|
||||||
|
|
||||||
// FIXME: remove me when == works on these tags.
|
// FIXME: remove me when == works on these tags.
|
||||||
|
@ -457,13 +473,10 @@ fn stmt_ty(@ast.stmt s) -> @ty {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_ty(&ast.block b) -> @ty {
|
fn block_ty(&ast.block b) -> @ty {
|
||||||
auto len = _vec.len[@ast.stmt](b.node.stmts);
|
alt (last_expr_of_block(b)) {
|
||||||
if (len == 0u) {
|
case (some[@ast.expr](?e)) { ret expr_ty(e); }
|
||||||
ret plain_ty(ty_nil);
|
case (none[@ast.expr]) { 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 {
|
fn expr_ty(@ast.expr expr) -> @ty {
|
||||||
|
@ -491,7 +504,7 @@ fn expr_ty(@ast.expr expr) -> @ty {
|
||||||
|
|
||||||
// Type unification
|
// Type unification
|
||||||
|
|
||||||
fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
fn unify(&fn_ctxt fcx, @ty expected, @ty actual) -> unify_result {
|
||||||
// Wraps the given type in an appropriate cname.
|
// Wraps the given type in an appropriate cname.
|
||||||
//
|
//
|
||||||
// TODO: This doesn't do anything yet. We should carry the cname up from
|
// TODO: This doesn't do anything yet. We should carry the cname up from
|
||||||
|
@ -508,10 +521,41 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
ret ures_err(terr_mismatch, expected, actual);
|
ret ures_err(terr_mismatch, expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_step(&@crate_ctxt ccx, @ty expected, @ty actual)
|
fn unify_step(&fn_ctxt fcx, &hashmap[int,@ty] bindings, @ty expected,
|
||||||
-> unify_result {
|
@ty actual) -> unify_result {
|
||||||
// TODO: rewrite this using tuple pattern matching when available, to
|
// TODO: rewrite this using tuple pattern matching when available, to
|
||||||
// avoid all this rightward drift and spikiness.
|
// avoid all this rightward drift and spikiness.
|
||||||
|
|
||||||
|
// If the RHS is a variable type, then just do the appropriate
|
||||||
|
// binding.
|
||||||
|
alt (actual.struct) {
|
||||||
|
case (ty_var(?actual_id)) {
|
||||||
|
alt (bindings.find(actual_id)) {
|
||||||
|
case (some[@ty](?actual_ty)) {
|
||||||
|
// FIXME: change the binding here?
|
||||||
|
// FIXME: "be"
|
||||||
|
ret unify_step(fcx, bindings, expected, actual_ty);
|
||||||
|
}
|
||||||
|
case (none[@ty]) {
|
||||||
|
bindings.insert(actual_id, expected);
|
||||||
|
ret ures_ok(expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (ty_local(?actual_id)) {
|
||||||
|
auto actual_ty = fcx.locals.get(actual_id);
|
||||||
|
auto result = unify_step(fcx, bindings, expected, actual_ty);
|
||||||
|
alt (result) {
|
||||||
|
case (ures_ok(?result_ty)) {
|
||||||
|
fcx.locals.insert(actual_id, result_ty);
|
||||||
|
}
|
||||||
|
case (_) { /* empty */ }
|
||||||
|
}
|
||||||
|
ret result;
|
||||||
|
}
|
||||||
|
case (_) { /* empty */ }
|
||||||
|
}
|
||||||
|
|
||||||
alt (expected.struct) {
|
alt (expected.struct) {
|
||||||
case (ty_nil) { ret struct_cmp(expected, actual); }
|
case (ty_nil) { ret struct_cmp(expected, actual); }
|
||||||
case (ty_bool) { ret struct_cmp(expected, actual); }
|
case (ty_bool) { ret struct_cmp(expected, actual); }
|
||||||
|
@ -524,7 +568,8 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
case (ty_box(?expected_sub)) {
|
case (ty_box(?expected_sub)) {
|
||||||
alt (actual.struct) {
|
alt (actual.struct) {
|
||||||
case (ty_box(?actual_sub)) {
|
case (ty_box(?actual_sub)) {
|
||||||
auto result = unify_step(ccx,
|
auto result = unify_step(fcx,
|
||||||
|
bindings,
|
||||||
expected_sub,
|
expected_sub,
|
||||||
actual_sub);
|
actual_sub);
|
||||||
alt (result) {
|
alt (result) {
|
||||||
|
@ -548,7 +593,8 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
case (ty_vec(?expected_sub)) {
|
case (ty_vec(?expected_sub)) {
|
||||||
alt (actual.struct) {
|
alt (actual.struct) {
|
||||||
case (ty_vec(?actual_sub)) {
|
case (ty_vec(?actual_sub)) {
|
||||||
auto result = unify_step(ccx,
|
auto result = unify_step(fcx,
|
||||||
|
bindings,
|
||||||
expected_sub,
|
expected_sub,
|
||||||
actual_sub);
|
actual_sub);
|
||||||
alt (result) {
|
alt (result) {
|
||||||
|
@ -594,7 +640,8 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
ret ures_err(err, expected, actual);
|
ret ures_err(err, expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = unify_step(ccx,
|
auto result = unify_step(fcx,
|
||||||
|
bindings,
|
||||||
expected_elem._1,
|
expected_elem._1,
|
||||||
actual_elem._1);
|
actual_elem._1);
|
||||||
alt (result) {
|
alt (result) {
|
||||||
|
@ -646,7 +693,8 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
result_mode = ast.val;
|
result_mode = ast.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = unify_step(ccx,
|
auto result = unify_step(fcx,
|
||||||
|
bindings,
|
||||||
expected_input.ty,
|
expected_input.ty,
|
||||||
actual_input.ty);
|
actual_input.ty);
|
||||||
|
|
||||||
|
@ -666,7 +714,8 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
|
|
||||||
// Check the output.
|
// Check the output.
|
||||||
auto result_out;
|
auto result_out;
|
||||||
auto result = unify_step(ccx,
|
auto result = unify_step(fcx,
|
||||||
|
bindings,
|
||||||
expected_output,
|
expected_output,
|
||||||
actual_output);
|
actual_output);
|
||||||
alt (result) {
|
alt (result) {
|
||||||
|
@ -689,14 +738,30 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ty_var(?expected_id)) {
|
case (ty_var(?expected_id)) {
|
||||||
if (ccx.bindings.contains_key(expected_id)) {
|
alt (bindings.find(expected_id)) {
|
||||||
check (ccx.bindings.contains_key(expected_id));
|
case (some[@ty](?expected_ty)) {
|
||||||
auto binding = ccx.bindings.get(expected_id);
|
// FIXME: change the binding here?
|
||||||
ret unify_step(ccx, binding, actual);
|
// FIXME: "be"
|
||||||
|
ret unify_step(fcx, bindings, expected_ty, actual);
|
||||||
|
}
|
||||||
|
case (none[@ty]) {
|
||||||
|
bindings.insert(expected_id, actual);
|
||||||
|
ret ures_ok(actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ccx.bindings.insert(expected_id, actual);
|
case (ty_local(?expected_id)) {
|
||||||
ret ures_ok(actual);
|
auto expected_ty = fcx.locals.get(expected_id);
|
||||||
|
auto result = unify_step(fcx, bindings, expected_ty, actual);
|
||||||
|
alt (result) {
|
||||||
|
case (ures_ok(?result_ty)) {
|
||||||
|
|
||||||
|
fcx.locals.insert(expected_id, result_ty);
|
||||||
|
}
|
||||||
|
case (_) { /* empty */ }
|
||||||
|
}
|
||||||
|
ret result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,19 +769,25 @@ fn unify(&@crate_ctxt ccx, @ty expected, @ty actual) -> unify_result {
|
||||||
fail;
|
fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret unify_step(ccx, expected, actual);
|
fn hash_int(&int x) -> uint { ret x as uint; }
|
||||||
|
fn eq_int(&int a, &int b) -> bool { ret a == b; }
|
||||||
|
auto hasher = hash_int;
|
||||||
|
auto eqer = eq_int;
|
||||||
|
auto bindings = map.mk_hashmap[int,@ty](hasher, eqer);
|
||||||
|
|
||||||
|
ret unify_step(fcx, bindings, expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires that the two types unify, and prints an error message if they
|
// Requires that the two types unify, and prints an error message if they
|
||||||
// don't. Returns the unified type.
|
// don't. Returns the unified type.
|
||||||
fn demand(&@crate_ctxt ccx, &span sp, @ty expected, @ty actual) -> @ty {
|
fn demand(&fn_ctxt fcx, &span sp, @ty expected, @ty actual) -> @ty {
|
||||||
alt (unify(ccx, expected, actual)) {
|
alt (unify(fcx, expected, actual)) {
|
||||||
case (ures_ok(?ty)) {
|
case (ures_ok(?ty)) {
|
||||||
ret ty;
|
ret ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ures_err(?err, ?expected, ?actual)) {
|
case (ures_err(?err, ?expected, ?actual)) {
|
||||||
ccx.sess.span_err(sp, "mismatched types: expected "
|
fcx.ccx.sess.span_err(sp, "mismatched types: expected "
|
||||||
+ ty_to_str(expected) + " but found "
|
+ ty_to_str(expected) + " but found "
|
||||||
+ ty_to_str(actual) + " (" +
|
+ ty_to_str(actual) + " (" +
|
||||||
type_err_to_str(err) + ")");
|
type_err_to_str(err) + ")");
|
||||||
|
@ -729,32 +800,130 @@ fn demand(&@crate_ctxt ccx, &span sp, @ty expected, @ty actual) -> @ty {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the two types unify and false if they don't.
|
// Returns true if the two types unify and false if they don't.
|
||||||
fn are_compatible(&@crate_ctxt ccx, @ty expected, @ty actual) -> bool {
|
fn are_compatible(&fn_ctxt fcx, @ty expected, @ty actual) -> bool {
|
||||||
alt (unify(ccx, expected, actual)) {
|
alt (unify(fcx, expected, actual)) {
|
||||||
case (ures_ok(_)) { ret true; }
|
case (ures_ok(_)) { ret true; }
|
||||||
case (ures_err(_, _, _)) { ret false; }
|
case (ures_err(_, _, _)) { ret false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writeback: the phase that writes inferred types back into the AST.
|
// Type unification over typed expressions. Note that the expression that you
|
||||||
|
// pass to this function must have been passed to check_expr() first.
|
||||||
|
//
|
||||||
|
// TODO: enforce this via a predicate.
|
||||||
|
// TODO: propagate the types downward. This makes the typechecker quadratic,
|
||||||
|
// but we can mitigate that if expected == actual == unified.
|
||||||
|
|
||||||
fn resolve_vars(@crate_ctxt ccx, @ty t) -> @ty {
|
fn demand_expr(&fn_ctxt fcx, @ty expected, @ast.expr e) -> @ast.expr {
|
||||||
alt (t.struct) {
|
// FIXME: botch to work around typestate bug in rustboot
|
||||||
case (ty_var(?v)) {
|
let vec[@ast.expr] v = vec();
|
||||||
check (ccx.bindings.contains_key(v));
|
auto e_1 = ast.expr_vec(v, ast.ann_none);
|
||||||
ret resolve_vars(ccx, ccx.bindings.get(v));
|
|
||||||
|
alt (e.node) {
|
||||||
|
case (ast.expr_vec(?es, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_vec(es, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_tup(?es, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_tup(es, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_rec(?es, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_rec(es, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_call(?sube, ?es, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_call(sube, es, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_binary(?bop, ?lhs, ?rhs, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_binary(bop, lhs, rhs, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_unary(?uop, ?sube, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_unary(uop, sube, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_lit(?lit, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_lit(lit, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_cast(?sube, ?ast_ty, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_cast(sube, ast_ty, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_if(?cond, ?then, ?els, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_if(cond, then, els, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_while(?cond, ?bloc, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_while(cond, bloc, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_do_while(?bloc, ?cond, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_do_while(bloc, cond, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_block(?bloc, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_block(bloc, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_assign(?lhs, ?rhs, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_assign(lhs, rhs, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_field(?lhs, ?rhs, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_field(lhs, rhs, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_index(?base, ?index, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_index(base, index, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (ast.expr_name(?name, ?d, ?ann)) {
|
||||||
|
auto t = demand(fcx, e.span, ann_to_type(ann), expected);
|
||||||
|
e_1 = ast.expr_name(name, d, ast.ann_type(t));
|
||||||
|
}
|
||||||
|
case (_) {
|
||||||
|
fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret t;
|
|
||||||
|
ret @fold.respan[ast.expr_](e.span, e_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type unification over typed blocks.
|
||||||
|
fn demand_block(&fn_ctxt fcx, @ty expected, &ast.block bloc) -> ast.block {
|
||||||
|
alt (last_expr_of_block(bloc)) {
|
||||||
|
case (some[@ast.expr](?e_0)) {
|
||||||
|
auto e_1 = demand_expr(fcx, expected, e_0);
|
||||||
|
|
||||||
|
auto len = _vec.len[@ast.stmt](bloc.node.stmts);
|
||||||
|
auto last_stmt_0 = bloc.node.stmts.(len - 1u);
|
||||||
|
auto prev_stmts = _vec.pop[@ast.stmt](bloc.node.stmts);
|
||||||
|
auto last_stmt_1 = @fold.respan[ast.stmt_](last_stmt_0.span,
|
||||||
|
ast.stmt_expr(e_1));
|
||||||
|
auto stmts_1 = prev_stmts + vec(last_stmt_1);
|
||||||
|
|
||||||
|
auto block_ = rec(stmts=stmts_1, index=bloc.node.index);
|
||||||
|
ret fold.respan[ast.block_](bloc.span, block_);
|
||||||
|
}
|
||||||
|
case (none[@ast.expr]) {
|
||||||
|
demand(fcx, bloc.span, expected, plain_ty(ty_nil));
|
||||||
|
ret bloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writeback: the phase that writes inferred types back into the AST.
|
||||||
|
|
||||||
fn writeback_local(&fn_ctxt fcx, &span sp, @ast.local local)
|
fn writeback_local(&fn_ctxt fcx, &span sp, @ast.local local)
|
||||||
-> @ast.decl {
|
-> @ast.decl {
|
||||||
if (!fcx.locals.contains_key(local.id)) {
|
if (!fcx.locals.contains_key(local.id)) {
|
||||||
fcx.ccx.sess.span_err(sp, "unable to determine type of local: "
|
fcx.ccx.sess.span_err(sp, "unable to determine type of local: "
|
||||||
+ local.ident);
|
+ local.ident);
|
||||||
}
|
}
|
||||||
auto local_ty = resolve_vars(fcx.ccx, fcx.locals.get(local.id));
|
auto local_ty = fcx.locals.get(local.id);
|
||||||
auto local_wb = @rec(ann=ast.ann_type(local_ty) with *local);
|
auto local_wb = @rec(ann=ast.ann_type(local_ty) with *local);
|
||||||
ret @fold.respan[ast.decl_](sp, ast.decl_local(local_wb));
|
ret @fold.respan[ast.decl_](sp, ast.decl_local(local_wb));
|
||||||
}
|
}
|
||||||
|
@ -792,13 +961,16 @@ fn check_expr(&fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
|
||||||
|
|
||||||
|
|
||||||
case (ast.expr_binary(?binop, ?lhs, ?rhs, _)) {
|
case (ast.expr_binary(?binop, ?lhs, ?rhs, _)) {
|
||||||
auto lhs_1 = check_expr(fcx, lhs);
|
auto lhs_0 = check_expr(fcx, lhs);
|
||||||
auto rhs_1 = check_expr(fcx, rhs);
|
auto rhs_0 = check_expr(fcx, rhs);
|
||||||
auto lhs_t = expr_ty(lhs_1);
|
auto lhs_t0 = expr_ty(lhs_0);
|
||||||
auto rhs_t = expr_ty(rhs_1);
|
auto rhs_t0 = expr_ty(rhs_0);
|
||||||
|
|
||||||
// FIXME: Binops have a bit more subtlety than this.
|
// FIXME: Binops have a bit more subtlety than this.
|
||||||
demand(fcx.ccx, expr.span, lhs_t, rhs_t);
|
auto lhs_1 = demand_expr(fcx, rhs_t0, lhs_0);
|
||||||
auto t = lhs_t;
|
auto rhs_1 = demand_expr(fcx, expr_ty(lhs_1), rhs_0);
|
||||||
|
|
||||||
|
auto t = lhs_t0;
|
||||||
alt (binop) {
|
alt (binop) {
|
||||||
case (ast.eq) { t = plain_ty(ty_bool); }
|
case (ast.eq) { t = plain_ty(ty_bool); }
|
||||||
case (ast.lt) { t = plain_ty(ty_bool); }
|
case (ast.lt) { t = plain_ty(ty_bool); }
|
||||||
|
@ -823,23 +995,25 @@ fn check_expr(&fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast.expr_name(?name, ?defopt, _)) {
|
case (ast.expr_name(?name, ?defopt, _)) {
|
||||||
auto ty = @rec(struct=ty_nil, cname=none[str]);
|
auto t = @rec(struct=ty_nil, cname=none[str]);
|
||||||
alt (option.get[ast.def](defopt)) {
|
alt (option.get[ast.def](defopt)) {
|
||||||
case (ast.def_arg(?id)) {
|
case (ast.def_arg(?id)) {
|
||||||
check (fcx.locals.contains_key(id));
|
check (fcx.locals.contains_key(id));
|
||||||
ty = fcx.locals.get(id);
|
t = fcx.locals.get(id);
|
||||||
}
|
}
|
||||||
case (ast.def_local(?id)) {
|
case (ast.def_local(?id)) {
|
||||||
check (fcx.locals.contains_key(id));
|
alt (fcx.locals.find(id)) {
|
||||||
ty = fcx.locals.get(id);
|
case (some[@ty](?t1)) { t = t1; }
|
||||||
|
case (none[@ty]) { t = plain_ty(ty_local(id)); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case (ast.def_fn(?id)) {
|
case (ast.def_fn(?id)) {
|
||||||
check (fcx.ccx.item_types.contains_key(id));
|
check (fcx.ccx.item_types.contains_key(id));
|
||||||
ty = fcx.ccx.item_types.get(id);
|
t = fcx.ccx.item_types.get(id);
|
||||||
}
|
}
|
||||||
case (ast.def_const(?id)) {
|
case (ast.def_const(?id)) {
|
||||||
check (fcx.ccx.item_types.contains_key(id));
|
check (fcx.ccx.item_types.contains_key(id));
|
||||||
ty = fcx.ccx.item_types.get(id);
|
t = fcx.ccx.item_types.get(id);
|
||||||
}
|
}
|
||||||
case (_) {
|
case (_) {
|
||||||
// FIXME: handle other names.
|
// FIXME: handle other names.
|
||||||
|
@ -850,65 +1024,103 @@ fn check_expr(&fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
|
||||||
}
|
}
|
||||||
ret @fold.respan[ast.expr_](expr.span,
|
ret @fold.respan[ast.expr_](expr.span,
|
||||||
ast.expr_name(name, defopt,
|
ast.expr_name(name, defopt,
|
||||||
ast.ann_type(ty)));
|
ast.ann_type(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast.expr_assign(?lhs, ?rhs, _)) {
|
case (ast.expr_assign(?lhs, ?rhs, _)) {
|
||||||
auto lhs_1 = check_expr(fcx, lhs);
|
auto lhs_0 = check_expr(fcx, lhs);
|
||||||
auto rhs_1 = check_expr(fcx, rhs);
|
auto rhs_0 = check_expr(fcx, rhs);
|
||||||
auto lhs_t = expr_ty(lhs_1);
|
auto lhs_t0 = expr_ty(lhs_0);
|
||||||
auto rhs_t = expr_ty(rhs_1);
|
auto rhs_t0 = expr_ty(rhs_0);
|
||||||
demand(fcx.ccx, expr.span, lhs_t, rhs_t);
|
|
||||||
|
auto lhs_1 = demand_expr(fcx, rhs_t0, lhs_0);
|
||||||
|
auto rhs_1 = demand_expr(fcx, expr_ty(lhs_1), rhs_0);
|
||||||
|
|
||||||
|
auto ann = ast.ann_type(rhs_t0);
|
||||||
ret @fold.respan[ast.expr_](expr.span,
|
ret @fold.respan[ast.expr_](expr.span,
|
||||||
ast.expr_assign(lhs_1, rhs_1,
|
ast.expr_assign(lhs_1, rhs_1, ann));
|
||||||
ast.ann_type(rhs_t)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast.expr_if(?cond, ?thn, ?elsopt, _)) {
|
case (ast.expr_if(?cond, ?thn, ?elsopt, _)) {
|
||||||
auto cond_1 = check_expr(fcx, cond);
|
auto cond_0 = check_expr(fcx, cond);
|
||||||
auto thn_1 = check_block(fcx, thn);
|
auto cond_1 = demand_expr(fcx, plain_ty(ty_bool), cond_0);
|
||||||
demand(fcx.ccx, cond.span, plain_ty(ty_bool), expr_ty(cond_1));
|
|
||||||
auto thn_t = block_ty(thn_1);
|
auto thn_0 = check_block(fcx, thn);
|
||||||
auto elsopt_1 = none[ast.block];
|
auto thn_t = block_ty(thn_0);
|
||||||
auto elsopt_t = plain_ty(ty_nil);
|
|
||||||
|
auto elsopt_1;
|
||||||
|
auto elsopt_t;
|
||||||
alt (elsopt) {
|
alt (elsopt) {
|
||||||
case (some[ast.block](?els)) {
|
case (some[ast.block](?els)) {
|
||||||
auto els_1 = check_block(fcx, els);
|
auto els_0 = check_block(fcx, els);
|
||||||
|
auto els_1 = demand_block(fcx, thn_t, els_0);
|
||||||
elsopt_1 = some[ast.block](els_1);
|
elsopt_1 = some[ast.block](els_1);
|
||||||
elsopt_t = block_ty(els_1);
|
elsopt_t = block_ty(els_1);
|
||||||
}
|
}
|
||||||
|
case (none[ast.block]) {
|
||||||
|
elsopt_1 = none[ast.block];
|
||||||
|
elsopt_t = plain_ty(ty_nil);
|
||||||
}
|
}
|
||||||
demand(fcx.ccx, expr.span, thn_t, elsopt_t);
|
}
|
||||||
|
|
||||||
|
auto thn_1 = demand_block(fcx, elsopt_t, thn_0);
|
||||||
|
|
||||||
ret @fold.respan[ast.expr_](expr.span,
|
ret @fold.respan[ast.expr_](expr.span,
|
||||||
ast.expr_if(cond_1, thn_1, elsopt_1,
|
ast.expr_if(cond_1, thn_1, elsopt_1,
|
||||||
ast.ann_type(thn_t)));
|
ast.ann_type(elsopt_t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast.expr_call(?f, ?args, _)) {
|
case (ast.expr_call(?f, ?args, _)) {
|
||||||
auto f_1 = check_expr(fcx, f);
|
// Check the function.
|
||||||
let @ty ret_t = plain_ty(ty_nil);
|
auto f_0 = check_expr(fcx, f);
|
||||||
alt (expr_ty(f_1).struct) {
|
|
||||||
case (ty_fn(_, ?r)) {
|
// Check the arguments and generate the argument signature.
|
||||||
ret_t = r;
|
let vec[@ast.expr] args_0 = vec();
|
||||||
|
let vec[arg] arg_tys_0 = vec();
|
||||||
|
for (@ast.expr a in args) {
|
||||||
|
auto a_0 = check_expr(fcx, a);
|
||||||
|
append[@ast.expr](args_0, a_0);
|
||||||
|
|
||||||
|
// FIXME: this breaks aliases. We need a ty_fn_arg.
|
||||||
|
append[arg](arg_tys_0, rec(mode=ast.val, ty=expr_ty(a_0)));
|
||||||
|
}
|
||||||
|
auto rt_0 = plain_ty(ty_var(-2)); // FIXME: broken!
|
||||||
|
auto t_0 = plain_ty(ty_fn(arg_tys_0, rt_0));
|
||||||
|
|
||||||
|
// Unify and write back to the function.
|
||||||
|
auto f_1 = demand_expr(fcx, t_0, f_0);
|
||||||
|
|
||||||
|
// Take the argument types out of the resulting function type.
|
||||||
|
auto t_1 = expr_ty(f_1);
|
||||||
|
let vec[arg] arg_tys_1 = vec(); // TODO: typestate botch
|
||||||
|
let @ty rt_1 = plain_ty(ty_nil); // TODO: typestate botch
|
||||||
|
alt (t_1.struct) {
|
||||||
|
case (ty_fn(?arg_tys, ?rt)) {
|
||||||
|
arg_tys_1 = arg_tys;
|
||||||
|
rt_1 = rt;
|
||||||
}
|
}
|
||||||
case (_) {
|
case (_) {
|
||||||
fcx.ccx.sess.span_err(f_1.span,
|
fcx.ccx.sess.span_err(f_1.span,
|
||||||
"callee has non-function type: "
|
"mismatched types: callee has " +
|
||||||
+ ty_to_str(expr_ty(f_1)));
|
"non-function type: " +
|
||||||
|
ty_to_str(t_1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unify and write back to the arguments.
|
||||||
|
auto i = 0u;
|
||||||
let vec[@ast.expr] args_1 = vec();
|
let vec[@ast.expr] args_1 = vec();
|
||||||
let vec[arg] args_t = vec();
|
while (i < _vec.len[@ast.expr](args_0)) {
|
||||||
for (@ast.expr a in args) {
|
auto arg_ty_1 = arg_tys_1.(i);
|
||||||
auto a_1 = check_expr(fcx, a);
|
auto e = demand_expr(fcx, arg_ty_1.ty, args_0.(i));
|
||||||
append[@ast.expr](args_1, a_1);
|
append[@ast.expr](args_1, e);
|
||||||
append[arg](args_t, rec(mode=ast.val, ty=expr_ty(a_1)));
|
|
||||||
|
i += 1u;
|
||||||
}
|
}
|
||||||
demand(fcx.ccx, expr.span, expr_ty(f_1),
|
|
||||||
plain_ty(ty_fn(args_t, ret_t)));
|
|
||||||
ret @fold.respan[ast.expr_](expr.span,
|
ret @fold.respan[ast.expr_](expr.span,
|
||||||
ast.expr_call(f_1, args_1,
|
ast.expr_call(f_1, args_1,
|
||||||
ast.ann_type(ret_t)));
|
ast.ann_type(rt_1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast.expr_cast(?e, ?t, _)) {
|
case (ast.expr_cast(?e, ?t, _)) {
|
||||||
|
@ -965,12 +1177,13 @@ fn check_stmt(&fn_ctxt fcx, &@ast.stmt stmt)
|
||||||
auto init = local.init;
|
auto init = local.init;
|
||||||
alt (local.init) {
|
alt (local.init) {
|
||||||
case (some[@ast.expr](?expr)) {
|
case (some[@ast.expr](?expr)) {
|
||||||
auto expr_t = check_expr(fcx, expr);
|
auto expr_0 = check_expr(fcx, expr);
|
||||||
rhs_ty = expr_ty(expr_t);
|
auto lty = plain_ty(ty_local(local.id));
|
||||||
init = some[@ast.expr](expr_t);
|
auto expr_1 = demand_expr(fcx, lty, expr_0);
|
||||||
|
init = some[@ast.expr](expr_1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
demand(fcx.ccx, decl.span, local_ty, rhs_ty);
|
|
||||||
auto local_1 = @rec(init = init with *local);
|
auto local_1 = @rec(init = init with *local);
|
||||||
auto decl_1 = @rec(node=ast.decl_local(local_1)
|
auto decl_1 = @rec(node=ast.decl_local(local_1)
|
||||||
with *decl);
|
with *decl);
|
||||||
|
@ -989,8 +1202,7 @@ fn check_stmt(&fn_ctxt fcx, &@ast.stmt stmt)
|
||||||
case (ast.stmt_ret(?expr_opt)) {
|
case (ast.stmt_ret(?expr_opt)) {
|
||||||
alt (expr_opt) {
|
alt (expr_opt) {
|
||||||
case (none[@ast.expr]) {
|
case (none[@ast.expr]) {
|
||||||
if (!are_compatible(fcx.ccx, fcx.ret_ty,
|
if (!are_compatible(fcx, fcx.ret_ty, plain_ty(ty_nil))) {
|
||||||
plain_ty(ty_nil))) {
|
|
||||||
fcx.ccx.sess.err("ret; in function "
|
fcx.ccx.sess.err("ret; in function "
|
||||||
+ "returning non-nil");
|
+ "returning non-nil");
|
||||||
}
|
}
|
||||||
|
@ -1000,7 +1212,7 @@ fn check_stmt(&fn_ctxt fcx, &@ast.stmt stmt)
|
||||||
|
|
||||||
case (some[@ast.expr](?expr)) {
|
case (some[@ast.expr](?expr)) {
|
||||||
auto expr_t = check_expr(fcx, expr);
|
auto expr_t = check_expr(fcx, expr);
|
||||||
demand(fcx.ccx, expr.span, fcx.ret_ty, expr_ty(expr_t));
|
demand(fcx, expr.span, fcx.ret_ty, expr_ty(expr_t));
|
||||||
ret @fold.respan[ast.stmt_](stmt.span,
|
ret @fold.respan[ast.stmt_](stmt.span,
|
||||||
ast.stmt_ret(some(expr_t)));
|
ast.stmt_ret(some(expr_t)));
|
||||||
}
|
}
|
||||||
|
@ -1014,15 +1226,14 @@ fn check_stmt(&fn_ctxt fcx, &@ast.stmt stmt)
|
||||||
|
|
||||||
case (ast.stmt_check_expr(?expr)) {
|
case (ast.stmt_check_expr(?expr)) {
|
||||||
auto expr_t = check_expr(fcx, expr);
|
auto expr_t = check_expr(fcx, expr);
|
||||||
demand(fcx.ccx, expr.span, plain_ty(ty_bool), expr_ty(expr_t));
|
demand(fcx, expr.span, plain_ty(ty_bool), expr_ty(expr_t));
|
||||||
ret @fold.respan[ast.stmt_](stmt.span,
|
ret @fold.respan[ast.stmt_](stmt.span,
|
||||||
ast.stmt_check_expr(expr_t));
|
ast.stmt_check_expr(expr_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast.stmt_expr(?expr)) {
|
case (ast.stmt_expr(?expr)) {
|
||||||
auto expr_t = check_expr(fcx, expr);
|
auto expr_t = check_expr(fcx, expr);
|
||||||
if (!are_compatible(fcx.ccx, expr_ty(expr_t),
|
if (!are_compatible(fcx, expr_ty(expr_t), plain_ty(ty_nil))) {
|
||||||
plain_ty(ty_nil))) {
|
|
||||||
// TODO: real warning function
|
// TODO: real warning function
|
||||||
log "warning: expression used as statement should have " +
|
log "warning: expression used as statement should have " +
|
||||||
"void type";
|
"void type";
|
||||||
|
@ -1073,14 +1284,8 @@ fn check_fn(&@crate_ctxt ccx, &span sp, ast.ident ident, &ast._fn f,
|
||||||
fn check_crate(session.session sess, @ast.crate crate) -> @ast.crate {
|
fn check_crate(session.session sess, @ast.crate crate) -> @ast.crate {
|
||||||
auto result = collect_item_types(crate);
|
auto result = collect_item_types(crate);
|
||||||
|
|
||||||
fn hash_int(&int x) -> uint { ret x as uint; }
|
|
||||||
fn eq_int(&int a, &int b) -> bool { ret a == b; }
|
|
||||||
auto hasher = hash_int;
|
|
||||||
auto eqer = eq_int;
|
|
||||||
|
|
||||||
auto ccx = @rec(sess=sess,
|
auto ccx = @rec(sess=sess,
|
||||||
item_types=result._1,
|
item_types=result._1,
|
||||||
bindings = map.mk_hashmap[int,@ty](hasher, eqer),
|
|
||||||
mutable next_var_id=0);
|
mutable next_var_id=0);
|
||||||
|
|
||||||
auto fld = fold.new_identity_fold[@crate_ctxt]();
|
auto fld = fold.new_identity_fold[@crate_ctxt]();
|
||||||
|
|
Loading…
Reference in a new issue