import std::option;
import std::option::none;
import std::option::some;
+import std::smallintmap;
import driver::session;
import front::ast;
tag mode {
mo_val;
- mo_alias;
- mo_either;
+ mo_alias(bool);
}
type arg = rec(mode mode, t ty);
ast::ident ident,
vec[arg] inputs,
t output,
- controlflow cf);
+ controlflow cf,
+ vec[@ast::constr] constrs);
tag any_item {
any_item_rust(@ast::item);
item_table items,
type_cache tcache,
creader_cache rcache,
- hashmap[t,str] short_names_cache);
+ hashmap[t,str] short_names_cache,
+ hashmap[@ast::ty,option::t[t]] ast_ty_to_ty_cache);
type ty_ctxt = ctxt; // Needed for disambiguation from unify::ctxt.
// Convert from method type to function type. Pretty easy; we just drop
// 'ident'.
fn method_ty_to_fn_ty(&ctxt cx, method m) -> t {
- ret mk_fn(cx, m.proto, m.inputs, m.output, m.cf);
+ ret mk_fn(cx, m.proto, m.inputs, m.output, m.cf, m.constrs);
}
// Never construct these manually. These are interned.
option::t[str] cname,
uint hash,
bool has_params,
- bool has_bound_params,
- bool has_vars,
- bool has_locals);
+ bool has_vars);
type t = uint;
ty_machine(util::common::ty_mach);
ty_char;
ty_str;
+ ty_istr;
ty_tag(ast::def_id, vec[t]);
ty_box(mt);
ty_vec(mt);
+ ty_ivec(mt);
+ ty_ptr(mt);
ty_port(t);
ty_chan(t);
ty_task;
ty_tup(vec[mt]);
ty_rec(vec[field]);
- ty_fn(ast::proto, vec[arg], t, controlflow);
+ ty_fn(ast::proto, vec[arg], t, controlflow, vec[@ast::constr]);
ty_native_fn(ast::native_abi, vec[arg], t);
ty_obj(vec[method]);
- ty_var(int); // ephemeral type var
- ty_local(ast::def_id); // type of a local var
+ ty_var(int); // type variable
ty_param(uint); // fn/tag type param
- ty_bound_param(uint); // bound param, only paths
ty_type;
ty_native;
// TODO: ty_fn_arg(t), for a possibly-aliased function argument
// Data structures used in type unification
-type unify_handler = obj {
- fn resolve_local(ast::def_id id) -> option::t[t];
- fn record_local(ast::def_id id, t ty); // TODO: -> unify::result
- fn record_param(uint index, t binding) -> unify::result;
-};
-
tag type_err {
terr_mismatch;
terr_controlflow_mismatch;
const uint idx_f64 = 14u;
const uint idx_char = 15u;
const uint idx_str = 16u;
-const uint idx_task = 17u;
-const uint idx_native = 18u;
-const uint idx_type = 19u;
-const uint idx_bot = 20u;
-const uint idx_first_others = 21u;
+const uint idx_istr = 17u;
+const uint idx_task = 18u;
+const uint idx_native = 19u;
+const uint idx_type = 20u;
+const uint idx_bot = 21u;
+const uint idx_first_others = 22u;
type type_store = interner::interner[raw_t];
intern(cx, ty_machine(ty_f64), none[str]);
intern(cx, ty_char, none[str]);
intern(cx, ty_str, none[str]);
+ intern(cx, ty_istr, none[str]);
intern(cx, ty_task, none[str]);
intern(cx, ty_native, none[str]);
intern(cx, ty_type, none[str]);
tcache = tcache,
rcache = mk_rcache(),
short_names_cache =
- map::mk_hashmap[ty::t,str](ty::hash_ty, ty::eq_ty));
+ map::mk_hashmap[ty::t,str](ty::hash_ty, ty::eq_ty),
+ ast_ty_to_ty_cache =
+ map::mk_hashmap[@ast::ty,option::t[t]](ast::hash_ty, ast::eq_ty));
populate_type_store(cx);
ret cx;
auto h = hash_type_info(st, cname);
let bool has_params = false;
- let bool has_bound_params = false;
let bool has_vars = false;
- let bool has_locals = false;
fn derive_flags_t(&ctxt cx,
&mutable bool has_params,
- &mutable bool has_bound_params,
&mutable bool has_vars,
- &mutable bool has_locals,
&t tt) {
auto rt = interner::get[raw_t](*cx.ts, tt);
has_params = has_params || rt.has_params;
- has_bound_params = has_bound_params || rt.has_bound_params;
has_vars = has_vars || rt.has_vars;
- has_locals = has_locals || rt.has_locals;
}
fn derive_flags_mt(&ctxt cx,
&mutable bool has_params,
- &mutable bool has_bound_params,
&mutable bool has_vars,
- &mutable bool has_locals,
&mt m) {
- derive_flags_t(cx, has_params, has_bound_params,
- has_vars, has_locals, m.ty);
+ derive_flags_t(cx, has_params, has_vars, m.ty);
}
fn derive_flags_arg(&ctxt cx,
&mutable bool has_params,
- &mutable bool has_bound_params,
&mutable bool has_vars,
- &mutable bool has_locals,
&arg a) {
- derive_flags_t(cx, has_params, has_bound_params,
- has_vars, has_locals, a.ty);
+ derive_flags_t(cx, has_params, has_vars, a.ty);
}
fn derive_flags_sig(&ctxt cx,
&mutable bool has_params,
- &mutable bool has_bound_params,
&mutable bool has_vars,
- &mutable bool has_locals,
&vec[arg] args,
&t tt) {
for (arg a in args) {
- derive_flags_arg(cx, has_params, has_bound_params,
- has_vars, has_locals, a);
+ derive_flags_arg(cx, has_params, has_vars, a);
}
- derive_flags_t(cx, has_params, has_bound_params,
- has_vars, has_locals, tt);
+ derive_flags_t(cx, has_params, has_vars, tt);
}
alt (st) {
case (ty_param(_)) {
has_params = true;
}
- case (ty_bound_param(_)) {
- has_bound_params = true;
- }
case (ty_var(_)) { has_vars = true; }
- case (ty_local(_)) { has_locals = true; }
case (ty_tag(_, ?tys)) {
for (t tt in tys) {
- derive_flags_t(cx, has_params, has_bound_params,
- has_vars, has_locals, tt);
+ derive_flags_t(cx, has_params, has_vars, tt);
}
}
case (ty_box(?m)) {
- derive_flags_mt(cx, has_params, has_bound_params,
- has_vars, has_locals, m);
+ derive_flags_mt(cx, has_params, has_vars, m);
}
case (ty_vec(?m)) {
- derive_flags_mt(cx, has_params, has_bound_params,
- has_vars, has_locals, m);
+ derive_flags_mt(cx, has_params, has_vars, m);
}
case (ty_port(?tt)) {
- derive_flags_t(cx, has_params, has_bound_params,
- has_vars, has_locals, tt);
+ derive_flags_t(cx, has_params, has_vars, tt);
}
case (ty_chan(?tt)) {
- derive_flags_t(cx, has_params, has_bound_params,
- has_vars, has_locals, tt);
+ derive_flags_t(cx, has_params, has_vars, tt);
}
case (ty_tup(?mts)) {
for (mt m in mts) {
- derive_flags_mt(cx, has_params, has_bound_params,
- has_vars, has_locals, m);
+ derive_flags_mt(cx, has_params, has_vars, m);
}
}
case (ty_rec(?flds)) {
for (field f in flds) {
- derive_flags_mt(cx, has_params, has_bound_params,
- has_vars, has_locals, f.mt);
+ derive_flags_mt(cx, has_params, has_vars, f.mt);
}
}
- case (ty_fn(_, ?args, ?tt, _)) {
- derive_flags_sig(cx, has_params, has_bound_params,
- has_vars, has_locals, args, tt);
+ case (ty_fn(_, ?args, ?tt, _, _)) {
+ derive_flags_sig(cx, has_params, has_vars, args, tt);
}
case (ty_native_fn(_, ?args, ?tt)) {
- derive_flags_sig(cx, has_params, has_bound_params,
- has_vars, has_locals, args, tt);
+ derive_flags_sig(cx, has_params, has_vars, args, tt);
}
case (ty_obj(?meths)) {
for (method m in meths) {
- derive_flags_sig(cx, has_params, has_bound_params,
- has_vars, has_locals, m.inputs, m.output);
+ derive_flags_sig(cx, has_params, has_vars, m.inputs,
+ m.output);
}
}
case (_) { }
}
ret rec(struct=st, cname=cname, hash=h,
- has_params = has_params,
- has_bound_params = has_bound_params,
- has_vars = has_vars,
- has_locals = has_locals);
+ has_params=has_params,
+ has_vars=has_vars);
}
fn intern(&ctxt cx, &sty st, &option::t[str] cname) {
case (ty_f32) { ret idx_f32; }
case (ty_f64) { ret idx_f64; }
}
- fail;
}
fn mk_char(&ctxt cx) -> t { ret idx_char; }
fn mk_str(&ctxt cx) -> t { ret idx_str; }
+fn mk_istr(&ctxt cx) -> t { ret idx_istr; }
fn mk_tag(&ctxt cx, &ast::def_id did, &vec[t] tys) -> t {
ret gen_ty(cx, ty_tag(did, tys));
ret gen_ty(cx, ty_box(tm));
}
+fn mk_ptr(&ctxt cx, &mt tm) -> t {
+ ret gen_ty(cx, ty_ptr(tm));
+}
+
fn mk_imm_box(&ctxt cx, &t ty) -> t {
ret mk_box(cx, rec(ty=ty, mut=ast::imm));
}
fn mk_vec(&ctxt cx, &mt tm) -> t { ret gen_ty(cx, ty_vec(tm)); }
+fn mk_ivec(&ctxt cx, &mt tm) -> t { ret gen_ty(cx, ty_ivec(tm)); }
+
fn mk_imm_vec(&ctxt cx, &t typ) -> t {
ret gen_ty(cx, ty_vec(rec(ty=typ, mut=ast::imm)));
}
fn mk_rec(&ctxt cx, &vec[field] fs) -> t { ret gen_ty(cx, ty_rec(fs)); }
fn mk_fn(&ctxt cx, &ast::proto proto, &vec[arg] args, &t ty,
- &controlflow cf) -> t {
- ret gen_ty(cx, ty_fn(proto, args, ty, cf));
+ &controlflow cf, &vec[@ast::constr] constrs) -> t {
+ ret gen_ty(cx, ty_fn(proto, args, ty, cf, constrs));
}
fn mk_native_fn(&ctxt cx, &ast::native_abi abi, &vec[arg] args, &t ty) -> t {
ret gen_ty(cx, ty_var(v));
}
-fn mk_local(&ctxt cx, ast::def_id did) -> t {
- ret gen_ty(cx, ty_local(did));
-}
-
fn mk_param(&ctxt cx, uint n) -> t {
ret gen_ty(cx, ty_param(n));
}
-fn mk_bound_param(&ctxt cx, uint n) -> t {
- ret gen_ty(cx, ty_bound_param(n));
-}
-
fn mk_type(&ctxt cx) -> t { ret idx_type; }
fn mk_native(&ctxt cx) -> t { ret idx_native; }
ret result;
}
-fn ty_to_str(&ctxt cx, &t typ) -> str {
-
- fn fn_input_to_str(&ctxt cx, &rec(mode mode, t ty) input) -> str {
- auto s;
- alt (input.mode) {
- case (mo_val) { s = ""; }
- case (mo_alias) { s = "&"; }
- case (mo_either) { s = "?"; }
- }
-
- ret s + ty_to_str(cx, input.ty);
- }
-
- fn fn_to_str(&ctxt cx,
- ast::proto proto,
- option::t[ast::ident] ident,
- vec[arg] inputs, t output) -> str {
- auto f = bind fn_input_to_str(cx, _);
-
- auto s;
- alt (proto) {
- case (ast::proto_iter) {
- s = "iter";
- }
- case (ast::proto_fn) {
- s = "fn";
- }
- }
-
- alt (ident) {
- case (some(?i)) {
- s += " ";
- s += i;
- }
- case (_) { }
- }
-
- s += "(";
- s += str::connect(vec::map[arg,str](f, inputs), ", ");
- s += ")";
-
- if (struct(cx, output) != ty_nil) {
- s += " -> " + ty_to_str(cx, output);
- }
- ret s;
- }
-
- fn method_to_str(&ctxt cx, &method m) -> str {
- ret fn_to_str(cx, m.proto, some[ast::ident](m.ident),
- m.inputs, m.output) + ";";
- }
-
- fn field_to_str(&ctxt cx, &field f) -> str {
- ret mt_to_str(cx, f.mt) + " " + f.ident;
- }
-
- fn mt_to_str(&ctxt cx, &mt m) -> str {
- auto mstr;
- alt (m.mut) {
- case (ast::mut) { mstr = "mutable "; }
- case (ast::imm) { mstr = ""; }
- case (ast::maybe_mut) { mstr = "mutable? "; }
- }
-
- ret mstr + ty_to_str(cx, m.ty);
- }
-
- alt (cname(cx, typ)) {
- case (some(?cs)) {
- ret cs;
- }
- case (_) { }
- }
-
- auto s = "";
-
- alt (struct(cx, typ)) {
- case (ty_native) { s += "native"; }
- case (ty_nil) { s += "()"; }
- case (ty_bot) { s += "_|_"; }
- case (ty_bool) { s += "bool"; }
- case (ty_int) { s += "int"; }
- case (ty_float) { s += "float"; }
- case (ty_uint) { s += "uint"; }
- case (ty_machine(?tm)) { s += common::ty_mach_to_str(tm); }
- case (ty_char) { s += "char"; }
- case (ty_str) { s += "str"; }
- case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); }
- case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; }
- case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; }
- case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; }
- case (ty_type) { s += "type"; }
- case (ty_task) { s += "task"; }
-
- case (ty_tup(?elems)) {
- auto f = bind mt_to_str(cx, _);
- auto strs = vec::map[mt,str](f, elems);
- s += "tup(" + str::connect(strs, ",") + ")";
- }
-
- case (ty_rec(?elems)) {
- auto f = bind field_to_str(cx, _);
- auto strs = vec::map[field,str](f, elems);
- s += "rec(" + str::connect(strs, ",") + ")";
- }
-
- case (ty_tag(?id, ?tps)) {
- // The user should never see this if the cname is set properly!
- s += "<tag#" + util::common::istr(id._0) + ":" +
- util::common::istr(id._1) + ">";
- if (vec::len[t](tps) > 0u) {
- auto f = bind ty_to_str(cx, _);
- auto strs = vec::map[t,str](f, tps);
- s += "[" + str::connect(strs, ",") + "]";
- }
- }
-
- case (ty_fn(?proto, ?inputs, ?output, _)) {
- s += fn_to_str(cx, proto, none[ast::ident], inputs, output);
- }
-
- case (ty_native_fn(_, ?inputs, ?output)) {
- s += fn_to_str(cx, ast::proto_fn, none[ast::ident],
- inputs, output);
- }
-
- case (ty_obj(?meths)) {
- auto f = bind method_to_str(cx, _);
- auto m = vec::map[method,str](f, meths);
- s += "obj {\n\t" + str::connect(m, "\n\t") + "\n}";
- }
-
- case (ty_var(?v)) {
- s += "<T" + util::common::istr(v) + ">";
- }
-
- case (ty_local(?id)) {
- s += "<L" + util::common::istr(id._0) + ":" +
- util::common::istr(id._1) + ">";
- }
-
- case (ty_param(?id)) {
- s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]);
- }
-
- case (ty_bound_param(?id)) {
- s += "''" + str::unsafe_from_bytes([('a' as u8) +
- (id as u8)]);
- }
-
- case (_) {
- s += ty_to_short_str(cx, typ);
- }
-
- }
-
- ret s;
-}
-
-fn ty_to_short_str(&ctxt cx, t typ) -> str {
- auto f = def_to_str;
- auto ecx = @rec(ds=f, tcx=cx, abbrevs=metadata::ac_no_abbrevs);
- auto s = metadata::Encode::ty_str(ecx, typ);
- if (str::byte_len(s) >= 32u) { s = str::substr(s, 0u, 32u); }
- ret s;
-}
-
// Type folds
type ty_walk = fn(t);
case (ty_machine(_)) { /* no-op */ }
case (ty_char) { /* no-op */ }
case (ty_str) { /* no-op */ }
+ case (ty_istr) { /* no-op */ }
case (ty_type) { /* no-op */ }
case (ty_native) { /* no-op */ }
case (ty_box(?tm)) { walk_ty(cx, walker, tm.ty); }
case (ty_vec(?tm)) { walk_ty(cx, walker, tm.ty); }
+ case (ty_ivec(?tm)) { walk_ty(cx, walker, tm.ty); }
case (ty_port(?subty)) { walk_ty(cx, walker, subty); }
case (ty_chan(?subty)) { walk_ty(cx, walker, subty); }
case (ty_tag(?tid, ?subtys)) {
walk_ty(cx, walker, fl.mt.ty);
}
}
- case (ty_fn(?proto, ?args, ?ret_ty, _)) {
+ case (ty_fn(?proto, ?args, ?ret_ty, _, _)) {
for (arg a in args) {
walk_ty(cx, walker, a.ty);
}
}
}
case (ty_var(_)) { /* no-op */ }
- case (ty_local(_)) { /* no-op */ }
case (ty_param(_)) { /* no-op */ }
- case (ty_bound_param(_)) { /* no-op */ }
}
walker(ty);
}
-type ty_fold = fn(t) -> t;
+tag fold_mode {
+ fm_var(fn(int)->t);
+ fm_param(fn(uint)->t);
+ fm_general(fn(t)->t);
+}
-fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t {
+fn fold_ty(&ctxt cx, fold_mode fld, t ty_0) -> t {
auto ty = ty_0;
+
+ // Fast paths.
+ alt (fld) {
+ case (fm_var(_)) { if (!type_contains_vars(cx, ty)) { ret ty; } }
+ case (fm_param(_)) { if (!type_contains_params(cx, ty)) { ret ty; } }
+ case (fm_general(_)) { /* no fast path */ }
+ }
+
alt (struct(cx, ty)) {
case (ty_nil) { /* no-op */ }
case (ty_bot) { /* no-op */ }
ty = copy_cname(cx, mk_box(cx, rec(ty=fold_ty(cx, fld, tm.ty),
mut=tm.mut)), ty);
}
+ case (ty_ptr(?tm)) {
+ ty = copy_cname(cx, mk_ptr(cx, rec(ty=fold_ty(cx, fld, tm.ty),
+ mut=tm.mut)), ty);
+ }
case (ty_vec(?tm)) {
ty = copy_cname(cx, mk_vec(cx, rec(ty=fold_ty(cx, fld, tm.ty),
mut=tm.mut)), ty);
}
ty = copy_cname(cx, mk_rec(cx, new_fields), ty);
}
- case (ty_fn(?proto, ?args, ?ret_ty, ?cf)) {
+ case (ty_fn(?proto, ?args, ?ret_ty, ?cf, ?constrs)) {
let vec[arg] new_args = [];
for (arg a in args) {
auto new_ty = fold_ty(cx, fld, a.ty);
new_args += [rec(mode=a.mode, ty=new_ty)];
}
ty = copy_cname(cx, mk_fn(cx, proto, new_args,
- fold_ty(cx, fld, ret_ty), cf), ty);
+ fold_ty(cx, fld, ret_ty), cf, constrs), ty);
}
case (ty_native_fn(?abi, ?args, ?ret_ty)) {
let vec[arg] new_args = [];
}
new_methods += [rec(proto=m.proto, ident=m.ident,
inputs=new_args,
- output=fold_ty(cx, fld, m.output), cf=m.cf)];
+ output=fold_ty(cx, fld, m.output),
+ cf=m.cf, constrs=m.constrs)];
}
ty = copy_cname(cx, mk_obj(cx, new_methods), ty);
}
- case (ty_var(_)) { /* no-op */ }
- case (ty_local(_)) { /* no-op */ }
- case (ty_param(_)) { /* no-op */ }
- case (ty_bound_param(_)) { /* no-op */ }
+ case (ty_var(?id)) {
+ alt (fld) {
+ case (fm_var(?folder)) { ty = folder(id); }
+ case (_) { /* no-op */ }
+ }
+ }
+ case (ty_param(?id)) {
+ alt (fld) {
+ case (fm_param(?folder)) { ty = folder(id); }
+ case (_) { /* no-op */ }
+ }
+ }
}
- ret fld(ty);
+ // If this is a general type fold, then we need to run it now.
+ alt (fld) {
+ case (fm_general(?folder)) { ret folder(ty); }
+ case (_) { ret ty; }
+ }
}
// Type utilities
case (ty_tup(_)) { ret true; }
case (ty_rec(_)) { ret true; }
case (ty_tag(_,_)) { ret true; }
- case (ty_fn(_,_,_,_)) { ret true; }
+ case (ty_fn(_,_,_,_,_)) { ret true; }
case (ty_obj(_)) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn type_is_sequence(&ctxt cx, &t ty) -> bool {
case (ty_vec(_)) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn sequence_element_type(&ctxt cx, &t ty) -> t {
alt (struct(cx, ty)) {
case (ty_str) { ret mk_mach(cx, common::ty_u8); }
case (ty_vec(?mt)) { ret mt.ty; }
+ // NB: This is not exhaustive.
}
- fail;
+
+ cx.sess.bug("sequence_element_type called on non-sequence value");
}
fn type_is_tup_like(&ctxt cx, &t ty) -> bool {
case (ty_tag(_,_)) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn get_element_type(&ctxt cx, &t ty, uint i) -> t {
case (ty_rec(?flds)) {
ret flds.(i).mt.ty;
}
+ // NB: This is not exhaustive -- struct(cx, ty) could be a box or a
+ // tag.
}
- fail;
+
+ cx.sess.bug("get_element_type called on a value other than a "
+ + "tuple or record");
}
fn type_is_box(&ctxt cx, &t ty) -> bool {
case (ty_box(_)) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn type_is_boxed(&ctxt cx, &t ty) -> bool {
case (ty_task) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn type_is_scalar(&ctxt cx, &t ty) -> bool {
case (ty_char) { ret true; }
case (ty_type) { ret true; }
case (ty_native) { ret true; }
+ case (ty_ptr(_)) { ret true; }
case (_) { ret false; }
}
- fail;
}
-
fn type_has_pointers(&ctxt cx, &t ty) -> bool {
alt (struct(cx, ty)) {
// scalar types
case (ty_nil) { ret false; }
+ case (ty_bot) { ret false; }
case (ty_bool) { ret false; }
case (ty_int) { ret false; }
case (ty_float) { ret false; }
for (variant_info variant in variants) {
auto tup_ty = mk_imm_tup(cx, variant.args);
// Perform any type parameter substitutions.
- tup_ty = bind_params_in_type(cx, tup_ty);
tup_ty = substitute_type_params(cx, tps, tup_ty);
if (type_has_pointers(cx, tup_ty)) { ret true; }
}
}
case (_) { ret true; }
}
- fail;
}
case (ty_native) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool {
case (ty_char) { ret true; }
case (_) { ret false; }
}
- fail;
}
fn type_is_fp(&ctxt cx, &t ty) -> bool {
}
case (_) { ret false; }
}
- fail;
}
fn type_is_signed(&ctxt cx, &t ty) -> bool {
}
case (_) { ret false; }
}
- fail;
}
fn type_param(&ctxt cx, &t ty) -> option::t[uint] {
}
case (ty_char) { ret 15u; }
case (ty_str) { ret 16u; }
+ case (ty_istr) { ret 17u; }
case (ty_tag(?did, ?tys)) {
- auto h = hash_def(17u, did);
+ auto h = hash_def(18u, did);
for (t typ in tys) {
h += h << 5u + hash_ty(typ);
}
ret h;
}
- case (ty_box(?mt)) { ret hash_subty(18u, mt.ty); }
- case (ty_vec(?mt)) { ret hash_subty(19u, mt.ty); }
- case (ty_port(?typ)) { ret hash_subty(20u, typ); }
- case (ty_chan(?typ)) { ret hash_subty(21u, typ); }
- case (ty_task) { ret 22u; }
+ case (ty_box(?mt)) { ret hash_subty(19u, mt.ty); }
+ case (ty_vec(?mt)) { ret hash_subty(20u, mt.ty); }
+ case (ty_ivec(?mt)) { ret hash_subty(21u, mt.ty); }
+ case (ty_port(?typ)) { ret hash_subty(22u, typ); }
+ case (ty_chan(?typ)) { ret hash_subty(23u, typ); }
+ case (ty_task) { ret 24u; }
case (ty_tup(?mts)) {
- auto h = 23u;
+ auto h = 25u;
for (mt tm in mts) {
h += h << 5u + hash_ty(tm.ty);
}
ret h;
}
case (ty_rec(?fields)) {
- auto h = 24u;
+ auto h = 26u;
for (field f in fields) {
h += h << 5u + hash_ty(f.mt.ty);
}
ret h;
}
- case (ty_fn(_, ?args, ?rty, _)) { ret hash_fn(25u, args, rty); }
- case (ty_native_fn(_, ?args, ?rty)) { ret hash_fn(26u, args, rty); }
+ // ???
+ case (ty_fn(_, ?args, ?rty, _, _)) { ret hash_fn(27u, args, rty); }
+ case (ty_native_fn(_, ?args, ?rty)) { ret hash_fn(28u, args, rty); }
case (ty_obj(?methods)) {
- auto h = 27u;
+ auto h = 29u;
for (method m in methods) {
h += h << 5u + str::hash(m.ident);
}
ret h;
}
- case (ty_var(?v)) { ret hash_uint(28u, v as uint); }
- case (ty_local(?did)) { ret hash_def(29u, did); }
- case (ty_param(?pid)) { ret hash_uint(30u, pid); }
- case (ty_bound_param(?pid)) { ret hash_uint(31u, pid); }
+ case (ty_var(?v)) { ret hash_uint(30u, v as uint); }
+ case (ty_param(?pid)) { ret hash_uint(31u, pid); }
case (ty_type) { ret 32u; }
case (ty_native) { ret 33u; }
case (ty_bot) { ret 34u; }
+ case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); }
}
}
// Type equality. This function is private to this module (and slow); external
// users should use `eq_ty()` instead.
+
+fn arg_eq(@ast::constr_arg a, @ast::constr_arg b) -> bool {
+ alt (a.node) {
+ case (ast::carg_base) {
+ alt (b.node) {
+ case (ast::carg_base) {
+ ret true;
+ }
+ case (_) {
+ ret false;
+ }
+ }
+ }
+ case (ast::carg_ident(?s)) {
+ alt (b.node) {
+ case (ast::carg_ident(?t)) {
+ ret (s == t);
+ }
+ case (_) {
+ ret false;
+ }
+ }
+ }
+ case (ast::carg_lit(?l)) {
+ alt (b.node) {
+ case (ast::carg_lit(?m)) {
+ ret util::common::lit_eq(l, m);
+ }
+ case (_) {
+ ret false;
+ }
+ }
+ }
+ }
+}
+fn args_eq(vec[@ast::constr_arg] a, vec[@ast::constr_arg] b) -> bool {
+ let uint i = 0u;
+ for (@ast::constr_arg arg in a) {
+ if (!arg_eq(arg, b.(i))) {
+ ret false;
+ }
+ i += 1u;
+ }
+ ret true;
+}
+
+
+fn constr_eq(&@ast::constr c, &@ast::constr d) -> bool {
+ ret path_to_str(c.node.path) == path_to_str(d.node.path) // FIXME: hack
+ && args_eq(c.node.args, d.node.args);
+}
+
+fn constrs_eq(&vec[@ast::constr] cs, &vec[@ast::constr] ds) -> bool {
+ if (vec::len(cs) != vec::len(ds)) {
+ ret false;
+ }
+ auto i = 0;
+ for (@ast::constr c in cs) {
+ if (!constr_eq(c, ds.(i))) {
+ ret false;
+ }
+ i += 1;
+ }
+ ret true;
+}
+
fn equal_type_structures(&sty a, &sty b) -> bool {
fn equal_mt(&mt a, &mt b) -> bool {
ret a.mut == b.mut && eq_ty(a.ty, b.ty);
case (_) { ret false; }
}
}
+ case (ty_ptr(?mt_a)) {
+ alt (b) {
+ case (ty_ptr(?mt_b)) { ret equal_mt(mt_a, mt_b); }
+ case (_) { ret false; }
+ }
+ }
case (ty_port(?t_a)) {
alt (b) {
case (ty_port(?t_b)) { ret eq_ty(t_a, t_b); }
case (_) { ret false; }
}
}
- case (ty_fn(?p_a, ?args_a, ?rty_a, ?cf_a)) {
+ case (ty_fn(?p_a, ?args_a, ?rty_a, ?cf_a, ?constrs_a)) {
alt (b) {
- case (ty_fn(?p_b, ?args_b, ?rty_b, ?cf_b)) {
+ case (ty_fn(?p_b, ?args_b, ?rty_b, ?cf_b, ?constrs_b)) {
ret p_a == p_b &&
cf_a == cf_b &&
+ constrs_eq(constrs_a, constrs_b) &&
equal_fn(args_a, rty_a, args_b, rty_b);
}
case (_) { ret false; }
case (_) { ret false; }
}
}
- case (ty_local(?did_a)) {
- alt (b) {
- case (ty_local(?did_b)) { ret equal_def(did_a, did_b); }
- case (_) { ret false; }
- }
- }
case (ty_param(?pid_a)) {
alt (b) {
case (ty_param(?pid_b)) { ret pid_a == pid_b; }
case (_) { ret false; }
}
}
- case (ty_bound_param(?pid_a)) {
- alt (b) {
- case (ty_bound_param(?pid_b)) { ret pid_a == pid_b; }
- case (_) { ret false; }
- }
- }
case (ty_type) {
alt (b) {
case (ty_type) { ret true; }
// Type lookups
-fn ann_to_ty_param_substs_opt_and_ty(&node_type_table ntt, &ast::ann ann)
- -> ty_param_substs_opt_and_ty {
- alt (ntt.(ann.id)) {
+fn ann_to_ty_param_substs_opt_and_ty(&ctxt cx, &ast::ann ann)
+ -> ty_param_substs_opt_and_ty {
+
+ // Pull out the node type table.
+ alt ({cx.node_types.(ann.id)}) {
case (none) {
- log_err "ann_to_ty_param_substs_opt_and_ty() called on an " +
- "untyped node";
- fail;
+ cx.sess.bug("ann_to_ty_param_substs_opt_and_ty() called on an " +
+ "untyped node");
}
case (some(?tpot)) { ret tpot; }
}
}
-fn ann_to_type(&node_type_table ntt, &ast::ann ann) -> t {
- ret ann_to_ty_param_substs_opt_and_ty(ntt, ann)._1;
+fn ann_to_type(&ctxt cx, &ast::ann ann) -> t {
+ ret ann_to_ty_param_substs_opt_and_ty(cx, ann)._1;
}
-fn ann_to_type_params(&node_type_table ntt, &ast::ann ann) -> vec[t] {
- alt (ann_to_ty_param_substs_opt_and_ty(ntt, ann)._0) {
+fn ann_to_type_params(&ctxt cx, &ast::ann ann) -> vec[t] {
+ alt (ann_to_ty_param_substs_opt_and_ty(cx, ann)._0) {
case (none) {
let vec[t] result = [];
ret result;
}
}
-fn ann_has_type_params(&node_type_table ntt, &ast::ann ann) -> bool {
- auto tpt = ann_to_ty_param_substs_opt_and_ty(ntt, ann);
+fn ann_has_type_params(&ctxt cx, &ast::ann ann) -> bool {
+ auto tpt = ann_to_ty_param_substs_opt_and_ty(cx, ann);
ret !option::is_none[vec[t]](tpt._0);
}
-// Returns the type of an annotation, with type parameter substitutions
-// performed if applicable.
-fn ann_to_monotype(&ctxt cx, ast::ann a) -> t {
- auto tpot = ann_to_ty_param_substs_opt_and_ty(cx.node_types, a);
+// Returns a type with type parameter substitutions performed if applicable.
+fn ty_param_substs_opt_and_ty_to_monotype(&ctxt cx,
+ &ty_param_substs_opt_and_ty tpot)
+ -> t {
alt (tpot._0) {
case (none) { ret tpot._1; }
- case (some(?tps)) {
- ret substitute_type_params(cx, tps, tpot._1);
- }
+ case (some(?tps)) { ret substitute_type_params(cx, tps, tpot._1); }
}
}
+// Returns the type of an annotation, with type parameter substitutions
+// performed if applicable.
+fn ann_to_monotype(&ctxt cx, ast::ann a) -> t {
+ auto tpot = ann_to_ty_param_substs_opt_and_ty(cx, a);
+ ret ty_param_substs_opt_and_ty_to_monotype(cx, tpot);
+}
+
// Returns the number of distinct type parameters in the given type.
fn count_ty_params(&ctxt cx, t ty) -> uint {
ret interner::get[raw_t](*cx.ts, typ).has_vars;
}
-fn type_contains_locals(&ctxt cx, &t typ) -> bool {
- ret interner::get[raw_t](*cx.ts, typ).has_locals;
-}
-
fn type_contains_params(&ctxt cx, &t typ) -> bool {
ret interner::get[raw_t](*cx.ts, typ).has_params;
}
-fn type_contains_bound_params(&ctxt cx, &t typ) -> bool {
- ret interner::get[raw_t](*cx.ts, typ).has_bound_params;
-}
-
// Type accessors for substructures of types
fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] {
alt (struct(cx, fty)) {
- case (ty::ty_fn(_, ?a, _, _)) { ret a; }
+ case (ty::ty_fn(_, ?a, _, _, _)) { ret a; }
case (ty::ty_native_fn(_, ?a, _)) { ret a; }
}
- fail;
+ cx.sess.bug("ty_fn_args() called on non-fn type");
}
fn ty_fn_proto(&ctxt cx, &t fty) -> ast::proto {
alt (struct(cx, fty)) {
- case (ty::ty_fn(?p, _, _, _)) { ret p; }
+ case (ty::ty_fn(?p, _, _, _, _)) { ret p; }
}
- fail;
+ cx.sess.bug("ty_fn_proto() called on non-fn type");
}
fn ty_fn_abi(&ctxt cx, &t fty) -> ast::native_abi {
alt (struct(cx, fty)) {
case (ty::ty_native_fn(?a, _, _)) { ret a; }
}
- fail;
+ cx.sess.bug("ty_fn_abi() called on non-native-fn type");
}
fn ty_fn_ret(&ctxt cx, &t fty) -> t {
alt (struct(cx, fty)) {
- case (ty::ty_fn(_, _, ?r, _)) { ret r; }
+ case (ty::ty_fn(_, _, ?r, _, _)) { ret r; }
case (ty::ty_native_fn(_, _, ?r)) { ret r; }
}
- fail;
+ cx.sess.bug("ty_fn_ret() called on non-fn type");
}
fn is_fn_ty(&ctxt cx, &t fty) -> bool {
alt (struct(cx, fty)) {
- case (ty::ty_fn(_, _, _, _)) { ret true; }
+ case (ty::ty_fn(_, _, _, _, _)) { ret true; }
case (ty::ty_native_fn(_, _, _)) { ret true; }
case (_) { ret false; }
}
- ret false;
}
-
-// Type accessors for AST nodes
-
-// Given an item, returns the associated type as well as the number of type
-// parameters it has.
-fn native_item_ty(&node_type_table ntt, &@ast::native_item it)
- -> ty_param_count_and_ty {
- auto ty_param_count;
- auto result_ty;
- alt (it.node) {
- case (ast::native_item_fn(_, _, _, ?tps, _, ?ann)) {
- ty_param_count = vec::len[ast::ty_param](tps);
- result_ty = ann_to_type(ntt, ann);
- }
+fn ty_var_id(&ctxt cx, t typ) -> int {
+ alt (struct(cx, typ)) {
+ case (ty::ty_var(?vid)) { ret vid; }
+ case (_) { log_err "ty_var_id called on non-var ty"; fail; }
}
- ret tup(ty_param_count, result_ty);
}
-fn item_ty(&node_type_table ntt, &@ast::item it) -> ty_param_count_and_ty {
- auto ty_param_count;
- auto result_ty;
- alt (it.node) {
- case (ast::item_const(_, _, _, _, ?ann)) {
- ty_param_count = 0u;
- result_ty = ann_to_type(ntt, ann);
- }
- case (ast::item_fn(_, _, ?tps, _, ?ann)) {
- ty_param_count = vec::len[ast::ty_param](tps);
- result_ty = ann_to_type(ntt, ann);
- }
- case (ast::item_mod(_, _, _)) {
- fail; // modules are typeless
- }
- case (ast::item_ty(_, _, ?tps, _, ?ann)) {
- ty_param_count = vec::len[ast::ty_param](tps);
- result_ty = ann_to_type(ntt, ann);
- }
- case (ast::item_tag(_, _, ?tps, ?did, ?ann)) {
- ty_param_count = vec::len[ast::ty_param](tps);
- result_ty = ann_to_type(ntt, ann);
- }
- case (ast::item_obj(_, _, ?tps, _, ?ann)) {
- ty_param_count = vec::len[ast::ty_param](tps);
- result_ty = ann_to_type(ntt, ann);
- }
- }
-
- ret tup(ty_param_count, result_ty);
-}
-fn stmt_ty(&ctxt cx, &@ast::stmt s) -> t {
- alt (s.node) {
- case (ast::stmt_expr(?e,_)) {
- ret expr_ty(cx, e);
- }
- case (_) {
- ret mk_nil(cx);
- }
- }
-}
+// Type accessors for AST nodes
fn block_ty(&ctxt cx, &ast::block b) -> t {
- ret ann_to_type(cx.node_types, b.node.a);
+ ret ann_to_type(cx, b.node.a);
}
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
fn expr_ann(&@ast::expr e) -> ast::ann {
alt (e.node) {
- case (ast::expr_vec(_,_,?a)) { ret a; }
+ case (ast::expr_vec(_,_,_,?a)) { ret a; }
case (ast::expr_tup(_,?a)) { ret a; }
case (ast::expr_rec(_,_,?a)) { ret a; }
case (ast::expr_call(_,_,?a)) { ret a; }
case (ast::expr_index(_,_,?a)) { ret a; }
case (ast::expr_path(_,?a)) { ret a; }
case (ast::expr_ext(_,_,_,_,?a)) { ret a; }
- case (ast::expr_fail(?a)) { ret a; }
+ case (ast::expr_fail(?a,_)) { ret a; }
case (ast::expr_ret(_,?a)) { ret a; }
case (ast::expr_put(_,?a)) { ret a; }
case (ast::expr_be(_,?a)) { ret a; }
-> tup(vec[t], t) {
auto a = expr_ann(expr);
- ret tup(ann_to_type_params(cx.node_types, a),
- ann_to_type(cx.node_types, a));
+ ret tup(ann_to_type_params(cx, a),
+ ann_to_type(cx, a));
}
-fn expr_has_ty_params(&node_type_table ntt, &@ast::expr expr) -> bool {
- ret ann_has_type_params(ntt, expr_ann(expr));
+fn expr_has_ty_params(&ctxt cx, &@ast::expr expr) -> bool {
+ ret ann_has_type_params(cx, expr_ann(expr));
}
fn decl_local_ty(&ctxt cx, &@ast::decl d) -> t {
alt (d.node) {
case (ast::decl_local(?l)) {
- ret ann_to_type(cx.node_types, l.ann);
+ ret ann_to_type(cx, l.ann);
}
case (_) {
cx.sess.bug("decl_local_ty called on an item decl");
i += 1u;
}
sess.span_err(sp, "unknown field '" + id + "' of record");
- fail;
}
fn method_idx(&session::session sess, &span sp,
i += 1u;
}
sess.span_err(sp, "unknown method '" + id + "' of obj");
- fail;
}
fn sort_methods(&vec[method] meths) -> vec[method] {
mod unify {
tag result {
ures_ok(t);
- ures_err(type_err, t, t);
+ ures_err(type_err);
}
- tag set_result {
- usr_ok(vec[t]);
- usr_err(type_err, t, t);
+ tag union_result {
+ unres_ok;
+ unres_err(type_err);
}
- type bindings[T] = rec(ufind::ufind sets,
- hashmap[T,uint] ids,
- mutable vec[mutable option::t[t]] types);
+ tag fixup_result {
+ fix_ok(t); // fixup succeeded
+ fix_err(int); // fixup failed because a type variable was unresolved
+ }
- fn mk_bindings[T](map::hashfn[T] hasher, map::eqfn[T] eqer)
- -> @bindings[T] {
- let vec[mutable option::t[t]] types = [mutable];
- ret @rec(sets=ufind::make(),
- ids=map::mk_hashmap[T,uint](hasher, eqer),
- mutable types=types);
+ type var_bindings = rec(ufind::ufind sets,
+ smallintmap::smallintmap[t] types);
+
+ type ctxt = rec(@var_bindings vb, ty_ctxt tcx);
+
+ fn mk_var_bindings() -> @var_bindings {
+ ret @rec(sets=ufind::make(), types=smallintmap::mk[t]());
}
- fn record_binding[T](&@ctxt cx, &@bindings[T] bindings, &T key, t typ)
- -> result {
- auto n = get_or_create_set[T](bindings, key);
+ // Unifies two sets.
+ fn union(&@ctxt cx, uint set_a, uint set_b) -> union_result {
+ ufind::grow(cx.vb.sets, uint::max(set_a, set_b) + 1u);
- auto result_type = typ;
- if (n < vec::len[option::t[t]](bindings.types)) {
- alt (bindings.types.(n)) {
- case (some(?old_type)) {
- alt (unify_step(cx, old_type, typ)) {
- case (ures_ok(?unified_type)) {
- result_type = unified_type;
+ auto root_a = ufind::find(cx.vb.sets, set_a);
+ auto root_b = ufind::find(cx.vb.sets, set_b);
+ ufind::union(cx.vb.sets, set_a, set_b);
+ auto root_c = ufind::find(cx.vb.sets, set_a);
+
+ alt (smallintmap::find[t](cx.vb.types, root_a)) {
+ case (none[t]) {
+ alt (smallintmap::find[t](cx.vb.types, root_b)) {
+ case (none[t]) { ret unres_ok; }
+ case (some[t](?t_b)) {
+ smallintmap::insert[t](cx.vb.types, root_c, t_b);
+ ret unres_ok;
+ }
+ }
+ }
+ case (some[t](?t_a)) {
+ alt (smallintmap::find[t](cx.vb.types, root_b)) {
+ case (none[t]) {
+ smallintmap::insert[t](cx.vb.types, root_c, t_a);
+ ret unres_ok;
+ }
+ case (some[t](?t_b)) {
+ alt (unify_step(cx, t_a, t_b)) {
+ case (ures_ok(?t_c)) {
+ smallintmap::insert[t](cx.vb.types, root_c,
+ t_c);
+ ret unres_ok;
+ }
+ case (ures_err(?terr)) { ret unres_err(terr); }
}
- case (?res) { ret res; }
}
}
- case (none) { /* fall through */ }
}
}
+ }
- vec::grow_set[option::t[t]](bindings.types, n, none[t],
- some[t](result_type));
+ fn record_var_binding(&@ctxt cx, int key, t typ) -> result {
+ ufind::grow(cx.vb.sets, (key as uint) + 1u);
+ auto root = ufind::find(cx.vb.sets, key as uint);
+ auto result_type = typ;
+ alt (smallintmap::find[t](cx.vb.types, root)) {
+ case (some(?old_type)) {
+ alt (unify_step(cx, old_type, typ)) {
+ case (ures_ok(?unified_type)) {
+ result_type = unified_type;
+ }
+ case (?res) { ret res; }
+ }
+ }
+ case (none) { /* fall through */ }
+ }
+
+ smallintmap::insert[t](cx.vb.types, root, result_type);
ret ures_ok(typ);
}
- type ctxt = rec(@bindings[int] bindings,
- unify_handler handler,
- ty_ctxt tcx);
-
// Wraps the given type in an appropriate cname.
//
// TODO: This doesn't do anything yet. We should carry the cname up from
ret ures_ok(expected);
}
- ret ures_err(terr_mismatch, expected, actual);
+ ret ures_err(terr_mismatch);
}
// Unifies two mutability flags.
auto expected_len = vec::len[arg](expected_inputs);
auto actual_len = vec::len[arg](actual_inputs);
if (expected_len != actual_len) {
- ret fn_common_res_err(ures_err(terr_arg_count,
- expected, actual));
+ ret fn_common_res_err(ures_err(terr_arg_count));
}
// TODO: as above, we should have an iter2 iterator.
auto expected_input = expected_inputs.(i);
auto actual_input = actual_inputs.(i);
- // Unify the result modes. "mo_either" unifies with both modes.
+ // Unify the result modes.
auto result_mode;
- if (expected_input.mode == mo_either) {
- result_mode = actual_input.mode;
- } else if (actual_input.mode == mo_either) {
- result_mode = expected_input.mode;
- } else if (expected_input.mode != actual_input.mode) {
+ if (expected_input.mode != actual_input.mode) {
// FIXME this is the wrong error
- ret fn_common_res_err(ures_err(terr_arg_count,
- expected, actual));
+ ret fn_common_res_err(ures_err(terr_arg_count));
} else {
result_mode = expected_input.mode;
}
- auto result = unify_step(cx, actual_input.ty, expected_input.ty);
+ auto result = unify_step(cx, expected_input.ty, actual_input.ty);
alt (result) {
case (ures_ok(?rty)) {
&t actual,
&vec[arg] expected_inputs, &t expected_output,
&vec[arg] actual_inputs, &t actual_output,
- &controlflow expected_cf, &controlflow actual_cf)
+ &controlflow expected_cf, &controlflow actual_cf,
+ &vec[@ast::constr] expected_constrs,
+ &vec[@ast::constr] actual_constrs)
-> result {
if (e_proto != a_proto) {
- ret ures_err(terr_mismatch, expected, actual);
+ ret ures_err(terr_mismatch);
}
alt (expected_cf) {
case (ast::return) { } // ok
this check is necessary to ensure that the
annotation in an object method matches the
declared object type */
- ret ures_err(terr_controlflow_mismatch,
- expected, actual);
+ ret ures_err(terr_controlflow_mismatch);
}
}
}
}
case (fn_common_res_ok(?result_ins, ?result_out)) {
auto t2 = mk_fn(cx.tcx, e_proto, result_ins, result_out,
- actual_cf);
+ actual_cf, actual_constrs);
ret ures_ok(t2);
}
}
&vec[arg] expected_inputs, &t expected_output,
&vec[arg] actual_inputs, &t actual_output)
-> result {
- if (e_abi != a_abi) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ if (e_abi != a_abi) { ret ures_err(terr_mismatch); }
auto t = unify_fn_common(cx, expected, actual,
expected_inputs, expected_output,
let uint expected_len = vec::len[method](expected_meths);
let uint actual_len = vec::len[method](actual_meths);
- if (expected_len != actual_len) {
- ret ures_err(terr_meth_count, expected, actual);
- }
+ if (expected_len != actual_len) { ret ures_err(terr_meth_count); }
while (i < expected_len) {
auto e_meth = expected_meths.(i);
auto a_meth = actual_meths.(i);
if (! str::eq(e_meth.ident, a_meth.ident)) {
- ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident),
- expected, actual);
+ ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident));
}
auto r = unify_fn(cx,
e_meth.proto, a_meth.proto,
expected, actual,
e_meth.inputs, e_meth.output,
a_meth.inputs, a_meth.output,
- e_meth.cf, a_meth.cf);
+ e_meth.cf, a_meth.cf,
+ e_meth.constrs, a_meth.constrs);
alt (r) {
case (ures_ok(?tfn)) {
alt (struct(cx.tcx, tfn)) {
- case (ty_fn(?proto, ?ins, ?out, ?cf)) {
+ case (ty_fn(?proto, ?ins, ?out, ?cf, ?constrs)) {
result_meths += [rec(inputs = ins,
output = out,
- cf = cf
+ cf = cf,
+ constrs = constrs
with e_meth)];
}
}
ret ures_ok(t);
}
- fn get_or_create_set[T](&@bindings[T] bindings, &T key) -> uint {
- auto set_num;
- alt (bindings.ids.find(key)) {
- case (none) {
- set_num = ufind::make_set(bindings.sets);
- bindings.ids.insert(key, set_num);
+ // If the given type is a variable, returns the structure of that type.
+ fn resolve_type_structure(&ty_ctxt tcx, &@var_bindings vb, t typ)
+ -> fixup_result {
+ alt (struct(tcx, typ)) {
+ case (ty_var(?vid)) {
+ if ((vid as uint) >= ufind::set_count(vb.sets)) {
+ ret fix_err(vid);
+ }
+
+ auto root_id = ufind::find(vb.sets, vid as uint);
+ alt (smallintmap::find[t](vb.types, root_id)) {
+ case (none[t]) { ret fix_err(vid); }
+ case (some[t](?rt)) { ret fix_ok(rt); }
+ }
}
- case (some(?n)) { set_num = n; }
+ case (_) { ret fix_ok(typ); }
}
- ret set_num;
}
fn unify_step(&@ctxt cx, &t expected, &t actual) -> result {
// Fast path.
if (eq_ty(expected, actual)) { ret ures_ok(expected); }
- alt (struct(cx.tcx, actual)) {
+ // Stage 1: Handle the cases in which one side or another is a type
+ // variable.
- // a _|_ type can be used anywhere
- case (ty::ty_bot) {
- ret ures_ok(expected);
- }
-
+ alt (struct(cx.tcx, actual)) {
// If the RHS is a variable type, then just do the appropriate
// binding.
case (ty::ty_var(?actual_id)) {
- auto actual_n = get_or_create_set[int](cx.bindings,
- actual_id);
+ auto actual_n = actual_id as uint;
alt (struct(cx.tcx, expected)) {
case (ty::ty_var(?expected_id)) {
- auto expected_n = get_or_create_set[int](cx.bindings,
- expected_id);
- ufind::union(cx.bindings.sets, expected_n, actual_n);
+ auto expected_n = expected_id as uint;
+ union(cx, expected_n, actual_n);
}
-
case (_) {
// Just bind the type variable to the expected type.
- alt (record_binding[int](cx, cx.bindings, actual_id,
- expected)) {
+ alt (record_var_binding(cx, actual_id, expected)) {
case (ures_ok(_)) { /* fall through */ }
case (?res) { ret res; }
}
}
}
- ret ures_ok(actual);
- }
- case (ty::ty_local(?actual_id)) {
- auto result_ty;
- alt (cx.handler.resolve_local(actual_id)) {
- case (none) { result_ty = expected; }
- case (some(?actual_ty)) {
- auto result = unify_step(cx, expected, actual_ty);
- alt (result) {
- case (ures_ok(?rty)) { result_ty = rty; }
- case (_) { ret result; }
- }
- }
- }
-
- cx.handler.record_local(actual_id, result_ty);
- ret ures_ok(result_ty);
+ ret ures_ok(mk_var(cx.tcx, actual_id));
}
- case (ty::ty_bound_param(?actual_id)) {
- alt (struct(cx.tcx, expected)) {
- case (ty::ty_local(_)) {
- log_err "TODO: bound param unifying with local";
- fail;
- }
- case (_) {
- ret cx.handler.record_param(actual_id, expected);
- }
+ case (_) { /* empty */ }
+ }
+
+ alt (struct(cx.tcx, expected)) {
+ case (ty::ty_var(?expected_id)) {
+ // Add a binding. (`actual` can't actually be a var here.)
+ alt (record_var_binding(cx, expected_id, actual)) {
+ case (ures_ok(_)) { /* fall through */ }
+ case (?res) { ret res; }
}
+ ret ures_ok(mk_var(cx.tcx, expected_id));
}
- case (_) { /* empty */ }
+
+ case (_) { /* fall through */ }
+ }
+
+ // Stage 2: Handle all other cases.
+
+ alt (struct(cx.tcx, actual)) {
+ case (ty::ty_bot) { ret ures_ok(expected); }
+ case (_) { /* fall through */ }
}
alt (struct(cx.tcx, expected)) {
case (ty::ty_nil) { ret struct_cmp(cx, expected, actual); }
// _|_ unifies with anything
- case (ty::ty_bot) { ret ures_ok(expected); }
+ case (ty::ty_bot) { ret ures_ok(actual); }
case (ty::ty_bool) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_int) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_uint) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_float) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_char) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_str) { ret struct_cmp(cx, expected, actual); }
+ case (ty::ty_istr) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_type) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_native) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_param(_)) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_tag(?actual_id, ?actual_tps)) {
if (expected_id._0 != actual_id._0 ||
expected_id._1 != actual_id._1) {
- ret ures_err(terr_mismatch, expected, actual);
+ ret ures_err(terr_mismatch);
}
// TODO: factor this cruft out, see the TODO in the
case (_) { /* fall through */ }
}
- ret ures_err(terr_mismatch, expected, actual);
+ ret ures_err(terr_mismatch);
}
case (ty::ty_box(?expected_mt)) {
case (ty::ty_box(?actual_mt)) {
auto mut;
alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
- case (none) {
- ret ures_err(terr_box_mutability, expected,
- actual);
- }
+ case (none) { ret ures_err(terr_box_mutability); }
case (some(?m)) { mut = m; }
}
}
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
case (ty::ty_vec(?actual_mt)) {
auto mut;
alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
- case (none) {
- ret ures_err(terr_vec_mutability, expected,
- actual);
- }
+ case (none) { ret ures_err(terr_vec_mutability); }
case (some(?m)) { mut = m; }
}
}
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
+ }
+ }
+
+ case (ty::ty_ivec(?expected_mt)) {
+ alt (struct(cx.tcx, actual)) {
+ case (ty::ty_ivec(?actual_mt)) {
+ auto mut;
+ alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
+ case (none) { ret ures_err(terr_vec_mutability); }
+ case (some(?m)) { mut = m; }
+ }
+
+ auto result = unify_step(cx,
+ expected_mt.ty,
+ actual_mt.ty);
+ alt (result) {
+ case (ures_ok(?result_sub)) {
+ auto mt = rec(ty=result_sub, mut=mut);
+ ret ures_ok(mk_ivec(cx.tcx, mt));
+ }
+ case (_) {
+ ret result;
+ }
+ }
+ }
+
+ case (_) { ret ures_err(terr_mismatch); }
}
}
}
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
}
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
if (expected_len != actual_len) {
auto err = terr_tuple_size(expected_len,
actual_len);
- ret ures_err(err, expected, actual);
+ ret ures_err(err);
}
// TODO: implement an iterator that can iterate over
actual_elem.mut)) {
case (none) {
auto err = terr_tuple_mutability;
- ret ures_err(err, expected, actual);
+ ret ures_err(err);
}
case (some(?m)) { mut = m; }
}
ret ures_ok(mk_tup(cx.tcx, result_elems));
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
if (expected_len != actual_len) {
auto err = terr_record_size(expected_len,
actual_len);
- ret ures_err(err, expected, actual);
+ ret ures_err(err);
}
// TODO: implement an iterator that can iterate over
alt (unify_mut(expected_field.mt.mut,
actual_field.mt.mut)) {
case (none) {
- ret ures_err(terr_record_mutability,
- expected, actual);
+ ret ures_err(terr_record_mutability);
}
case (some(?m)) { mut = m; }
}
auto err =
terr_record_fields(expected_field.ident,
actual_field.ident);
- ret ures_err(err, expected, actual);
+ ret ures_err(err);
}
auto result = unify_step(cx,
ret ures_ok(mk_rec(cx.tcx, result_fields));
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
case (ty::ty_fn(?ep, ?expected_inputs,
- ?expected_output, ?expected_cf)) {
+ ?expected_output, ?expected_cf,
+ ?expected_constrs)) {
alt (struct(cx.tcx, actual)) {
case (ty::ty_fn(?ap, ?actual_inputs,
- ?actual_output, ?actual_cf)) {
+ ?actual_output, ?actual_cf,
+ ?actual_constrs)) {
ret unify_fn(cx, ep, ap,
expected, actual,
expected_inputs, expected_output,
actual_inputs, actual_output,
- expected_cf, actual_cf);
+ expected_cf, actual_cf,
+ expected_constrs, actual_constrs);
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
expected_inputs, expected_output,
actual_inputs, actual_output);
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
+ case (_) { ret ures_err(terr_mismatch); }
}
}
ret unify_obj(cx, expected, actual,
expected_meths, actual_meths);
}
- case (_) {
- ret ures_err(terr_mismatch, expected, actual);
- }
- }
- }
-
- case (ty::ty_var(?expected_id)) {
- // Add a binding. (`actual` can't actually be a var here.)
- alt (record_binding[int](cx, cx.bindings, expected_id,
- actual)) {
- case (ures_ok(_)) { /* fall through */ }
- case (?res) { ret res; }
+ case (_) { ret ures_err(terr_mismatch); }
}
- ret ures_ok(expected);
- }
-
- case (ty::ty_local(?expected_id)) {
- auto result_ty;
- alt (cx.handler.resolve_local(expected_id)) {
- case (none) { result_ty = actual; }
- case (some(?expected_ty)) {
- auto result = unify_step(cx, expected_ty, actual);
- alt (result) {
- case (ures_ok(?rty)) { result_ty = rty; }
- case (_) { ret result; }
- }
- }
- }
-
- cx.handler.record_local(expected_id, result_ty);
- ret ures_ok(result_ty);
- }
-
- case (ty::ty_bound_param(?expected_id)) {
- ret cx.handler.record_param(expected_id, actual);
}
}
-
- // TODO: remove me once match-exhaustiveness checking works
- fail;
}
- // Performs type binding substitution.
- fn substitute(&ty_ctxt tcx,
- &@bindings[int] bindings,
- &vec[t] set_types,
- &t typ) -> t {
- if (!type_contains_vars(tcx, typ)) {
- ret typ;
- }
+ fn unify(&t expected,
+ &t actual,
+ &@var_bindings vb,
+ &ty_ctxt tcx) -> result {
+ auto cx = @rec(vb=vb, tcx=tcx);
+ ret unify_step(cx, expected, actual);
+ }
- fn substituter(ty_ctxt tcx,
- @bindings[int] bindings,
- vec[t] types,
- t typ) -> t {
- alt (struct(tcx, typ)) {
- case (ty_var(?id)) {
- alt (bindings.ids.find(id)) {
- case (some(?n)) {
- auto root = ufind::find(bindings.sets, n);
- ret types.(root);
- }
- case (none) { ret typ; }
- }
+ fn dump_var_bindings(ty_ctxt tcx, @var_bindings vb) {
+ auto i = 0u;
+ while (i < vec::len[ufind::node](vb.sets.nodes)) {
+ auto sets = "";
+ auto j = 0u;
+ while (j < vec::len[option::t[uint]](vb.sets.nodes)) {
+ if (ufind::find(vb.sets, j) == i) { sets += #fmt(" %u", j); }
+ j += 1u;
+ }
+
+ auto typespec;
+ alt (smallintmap::find[t](vb.types, i)) {
+ case (none[t]) { typespec = ""; }
+ case (some[t](?typ)) {
+ typespec = " =" + pretty::ppaux::ty_to_str(tcx, typ);
}
- case (_) { ret typ; }
}
- }
- auto f = bind substituter(tcx, bindings, set_types, _);
- ret fold_ty(tcx, f, typ);
- }
-
- fn unify_sets[T](&ty_ctxt tcx, &@bindings[T] bindings) -> set_result {
- obj handler() {
- fn resolve_local(ast::def_id id) -> option::t[t] {
- log_err "resolve_local in unify_sets";
- fail;
- }
- fn record_local(ast::def_id id, t ty) {
- log_err "record_local in unify_sets";
- fail;
- }
- fn record_param(uint index, t binding) -> unify::result {
- log_err "record_param in unify_sets";
- fail;
- }
+ log_err #fmt("set %u:%s%s", i, typespec, sets);
+ i += 1u;
}
+ }
- auto node_count = vec::len[option::t[t]](bindings.types);
+ // Fixups and substitutions
- let vec[option::t[t]] results =
- vec::init_elt[option::t[t]](none[t], node_count);
+ fn fixup_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> fixup_result {
+ fn subst_vars(ty_ctxt tcx, @var_bindings vb,
+ @mutable option::t[int] unresolved, int vid) -> t {
+ if ((vid as uint) >= ufind::set_count(vb.sets)) {
+ *unresolved = some[int](vid);
+ ret ty::mk_var(tcx, vid);
+ }
- auto i = 0u;
- while (i < node_count) {
- auto root = ufind::find(bindings.sets, i);
- alt (bindings.types.(i)) {
- case (none) { /* nothing to do */ }
- case (some(?actual)) {
- alt (results.(root)) {
- case (none) { results.(root) = some[t](actual); }
- case (some(?expected)) {
- // FIXME: Is this right?
- auto bindings = mk_bindings[int](int::hash,
- int::eq_alias);
- alt (unify(expected, actual, handler(), bindings,
- tcx)) {
- case (ures_ok(?result_ty)) {
- results.(i) = some[t](result_ty);
- }
- case (ures_err(?e, ?t_a, ?t_b)) {
- ret usr_err(e, t_a, t_b);
- }
- }
- }
- }
+ auto root_id = ufind::find(vb.sets, vid as uint);
+ alt (smallintmap::find[t](vb.types, root_id)) {
+ case (none[t]) {
+ *unresolved = some[int](vid);
+ ret ty::mk_var(tcx, vid);
+ }
+ case (some[t](?rt)) {
+ ret fold_ty(tcx,
+ fm_var(bind subst_vars(tcx, vb, unresolved, _)), rt);
}
}
- i += 1u;
}
- // FIXME: This is equivalent to map(option::get, results) but it
- // causes an assertion in typeck at the moment.
- let vec[t] real_results = [];
- for (option::t[t] typ in results) {
- real_results += [option::get[t](typ)];
- }
+ auto unresolved = @mutable none[int];
+ auto rty = fold_ty(tcx,
+ fm_var(bind subst_vars(tcx, vb, unresolved, _)),
+ typ);
- ret usr_ok(real_results);
+ auto ur = *unresolved;
+ alt (ur) {
+ case (none[int]) { ret fix_ok(rty); }
+ case (some[int](?var_id)) { ret fix_err(var_id); }
+ }
}
- fn unify(&t expected,
- &t actual,
- &unify_handler handler,
- &@bindings[int] bindings,
- &ty_ctxt tcx) -> result {
- auto cx = @rec(bindings=bindings, handler=handler, tcx=tcx);
- ret unify_step(cx, expected, actual);
- }
+ fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid)
+ -> fixup_result {
+ if ((vid as uint) >= ufind::set_count(vb.sets)) { ret fix_err(vid); }
- fn fixup(&ty_ctxt tcx, &@bindings[int] bindings, t typ) -> result {
- alt (unify_sets[int](tcx, bindings)) {
- case (usr_ok(?set_types)) {
- ret ures_ok(substitute(tcx, bindings, set_types, typ));
- }
- case (usr_err(?terr, ?t0, ?t1)) { ret ures_err(terr, t0, t1); }
+ auto root_id = ufind::find(vb.sets, vid as uint);
+ alt (smallintmap::find[t](vb.types, root_id)) {
+ case (none[t]) { ret fix_err(vid); }
+ case (some[t](?rt)) { ret fixup_vars(tcx, vb, rt); }
}
}
}
}
}
-// Performs bound type parameter replacement using the supplied mapping from
-// parameter IDs to types.
-fn substitute_type_params(&ctxt cx, &vec[t] bindings, &t typ) -> t {
- if (!type_contains_bound_params(cx, typ)) {
- ret typ;
+// Converts type parameters in a type to type variables and returns the
+// resulting type along with a list of type variable IDs.
+fn bind_params_in_type(&ctxt cx, fn()->int next_ty_var, t typ,
+ uint ty_param_count) -> tup(vec[int], t) {
+ let vec[int] param_var_ids = [];
+ auto i = 0u;
+ while (i < ty_param_count) {
+ param_var_ids += [next_ty_var()];
+ i += 1u;
}
- fn replacer(&ctxt cx, vec[t] bindings, t typ) -> t {
- alt (struct(cx, typ)) {
- case (ty_bound_param(?param_index)) {
- ret bindings.(param_index);
- }
- case (_) { ret typ; }
- }
+
+ fn binder(ctxt cx, vec[int] param_var_ids, fn()->int next_ty_var,
+ uint index) -> t {
+ ret mk_var(cx, param_var_ids.(index));
}
- auto f = bind replacer(cx, bindings, _);
- ret fold_ty(cx, f, typ);
+ auto new_typ = fold_ty(cx,
+ fm_param(bind binder(cx, param_var_ids, next_ty_var, _)), typ);
+ ret tup(param_var_ids, new_typ);
}
-// Converts type parameters in a type to bound type parameters.
-fn bind_params_in_type(&ctxt cx, &t typ) -> t {
- if (!type_contains_params(cx, typ)) {
- ret typ;
- }
- fn binder(&ctxt cx, t typ) -> t {
- alt (struct(cx, typ)) {
- case (ty_bound_param(?index)) {
- log_err "bind_params_in_type() called on type that already " +
- "has bound params in it";
- fail;
- }
- case (ty_param(?index)) { ret mk_bound_param(cx, index); }
- case (_) { ret typ; }
- }
+// Replaces type parameters in the given type using the given list of
+// substitions.
+fn substitute_type_params(&ctxt cx, vec[ty::t] substs, t typ) -> t {
+ if (!type_contains_params(cx, typ)) { ret typ; }
+
+ fn substituter(ctxt cx, vec[ty::t] substs, uint idx) -> t {
+ ret substs.(idx);
}
- auto f = bind binder(cx, _);
- ret fold_ty(cx, f, typ);
+ ret fold_ty(cx, fm_param(bind substituter(cx, substs, _)), typ);
}
-
fn def_has_ty_params(&ast::def def) -> bool {
alt (def) {
case (ast::def_fn(_)) { ret true; }
}
}
}
- fail; // not reached
}
// Returns information about the tag variant with the given ID:
}
i += 1u;
}
+
+ cx.sess.bug("tag_variant_with_id(): no variant exists with that ID");
- log_err "tag_variant_with_id(): no variant exists with that ID";
- fail;
}
// If the given item is in an external crate, looks up its type and adds it to
}
}
-fn ret_ty_of_fn_ty(ty_ctxt tcx, t a_ty) -> t {
- alt (ty::struct(tcx, a_ty)) {
- case (ty::ty_fn(_, _, ?ret_ty, _)) {
+fn ret_ty_of_fn_ty(ctxt cx, t a_ty) -> t {
+ alt (ty::struct(cx, a_ty)) {
+ case (ty::ty_fn(_, _, ?ret_ty, _, _)) {
ret ret_ty;
}
case (_) {
- fail;
+ cx.sess.bug("ret_ty_of_fn_ty() called on non-function type");
}
}
}
-fn ret_ty_of_fn(ty_ctxt tcx, ast::ann ann) -> t {
- ret ret_ty_of_fn_ty(tcx, ann_to_type(tcx.node_types, ann));
+fn ret_ty_of_fn(ctxt cx, ast::ann ann) -> t {
+ ret ret_ty_of_fn_ty(cx, ann_to_type(cx, ann));
+}
+
+fn lookup_fn_decl(ty_ctxt tcx, ast::ann ann)
+ -> option::t[tup(ast::fn_decl, ast::def_id)] {
+ auto nada = none[tup(ast::fn_decl, ast::def_id)];
+ alt (tcx.def_map.find(ann.id)) {
+ case (some(ast::def_fn(?d))) {
+ alt (tcx.items.find(d)) {
+ case (some(any_item_rust(?it))) {
+ alt (it.node) {
+ case (ast::item_fn(_,?f,_,_,_)) {
+ ret some(tup(f.decl, d));
+ }
+ case (_) { ret nada; }
+ }
+ }
+ case (_) { ret nada; }
+ }
+ }
+ case (_) { ret nada; }
+ }
}
// Local Variables:
import middle::ty::method;
import middle::ty::mo_val;
import middle::ty::mo_alias;
-import middle::ty::mo_either;
import middle::ty::node_type_table;
import middle::ty::pat_ty;
import middle::ty::path_to_str;
-import middle::ty::struct;
import middle::ty::ty_param_substs_opt_and_ty;
-import middle::ty::ty_to_str;
-import middle::ty::type_is_integral;
-import middle::ty::type_is_scalar;
+import pretty::ppaux::ty_to_str;
import middle::ty::ty_param_count_and_ty;
import middle::ty::ty_nil;
import middle::ty::unify::ures_ok;
import middle::ty::unify::ures_err;
+import middle::ty::unify::fixup_result;
+import middle::ty::unify::fix_ok;
+import middle::ty::unify::fix_err;
import std::int;
import std::str;
+import std::ufind;
import std::uint;
import std::vec;
import std::map;
type ty_table = hashmap[ast::def_id, ty::t];
type fn_purity_table = hashmap[ast::def_id, ast::purity];
-type unify_cache_entry = tup(ty::t,ty::t,vec[mutable ty::t]);
-type unify_cache = hashmap[unify_cache_entry,ty::unify::result];
-
type obj_info = rec(vec[ast::obj_field] obj_fields, ast::def_id this_obj);
type crate_ctxt = rec(mutable vec[obj_info] obj_infos,
@fn_purity_table fn_purity_table,
- unify_cache unify_cache,
- mutable uint cache_hits,
- mutable uint cache_misses,
ty::ctxt tcx);
type fn_ctxt = rec(ty::t ret_ty,
ast::purity purity,
- @ty_table locals,
+ @ty::unify::var_bindings var_bindings,
+ hashmap[ast::def_id,int] locals,
+ hashmap[ast::def_id,ast::ident] local_names,
+ mutable int next_var_id,
+ mutable vec[uint] fixups,
@crate_ctxt ccx);
-type stmt_ctxt = rec(@fn_ctxt fcx,
- mutable int next_var_id,
- mutable vec[uint] fixups);
-
// Used for ast_ty_to_ty() below.
type ty_getter = fn(&ast::def_id) -> ty::ty_param_count_and_ty;
-// Creates a statement context and passes it to the given thunk, then runs
-// fixups. This function has the signature it does so that the caller can
-// never forget to run fixups!
-fn with_stmt_ctxt(&@fn_ctxt fcx, fn(&@stmt_ctxt) f) {
- let vec[uint] fixups = [];
- auto scx = @rec(fcx=fcx, mutable next_var_id=0, mutable fixups=fixups);
- f(scx);
- // TODO: run fixups
-}
-
-// Substitutes the user's explicit types for the parameters in a path
-// expression.
-fn substitute_ty_params(&@crate_ctxt ccx,
- &ty::t typ,
- uint ty_param_count,
- &vec[ty::t] supplied,
- &span sp) -> ty::t {
- fn substituter(@crate_ctxt ccx, vec[ty::t] supplied, ty::t typ) -> ty::t {
- alt (struct(ccx.tcx, typ)) {
- case (ty::ty_bound_param(?pid)) { ret supplied.(pid); }
- case (_) { ret typ; }
- }
- }
-
- auto supplied_len = vec::len[ty::t](supplied);
- if (ty_param_count != supplied_len) {
- ccx.tcx.sess.span_err(sp, "expected " +
- uint::to_str(ty_param_count, 10u) +
- " type parameter(s) but found " +
- uint::to_str(supplied_len, 10u) + " parameter(s)");
- fail;
- }
-
- if (!ty::type_contains_bound_params(ccx.tcx, typ)) {
- ret typ;
- }
-
- auto f = bind substituter(ccx, supplied, _);
- ret ty::fold_ty(ccx.tcx, f, typ);
-}
-
// Returns the type parameter count and the type for the given definition.
fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn)
-> ty_param_count_and_ty {
alt (defn) {
case (ast::def_arg(?id)) {
- // assert (fcx.locals.contains_key(id));
- ret tup(0u, fcx.locals.get(id));
+ assert (fcx.locals.contains_key(id));
+ auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id));
+ ret tup(0u, typ);
}
case (ast::def_local(?id)) {
- auto t;
- alt (fcx.locals.find(id)) {
- case (some(?t1)) { t = t1; }
- case (none) { t = ty::mk_local(fcx.ccx.tcx, id); }
- }
- ret tup(0u, t);
+ assert (fcx.locals.contains_key(id));
+ auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id));
+ ret tup(0u, typ);
}
case (ast::def_obj_field(?id)) {
- // assert (fcx.locals.contains_key(id));
- ret tup(0u, fcx.locals.get(id));
+ assert (fcx.locals.contains_key(id));
+ auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id));
+ ret tup(0u, typ);
}
case (ast::def_fn(?id)) {
ret ty::lookup_item_type(fcx.ccx.tcx, id);
ret ty::lookup_item_type(fcx.ccx.tcx, vid);
}
case (ast::def_binding(?id)) {
- // assert (fcx.locals.contains_key(id));
- ret tup(0u, fcx.locals.get(id));
+ assert (fcx.locals.contains_key(id));
+ auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id));
+ ret tup(0u, typ);
}
case (ast::def_obj(?id)) {
ret ty::lookup_item_type(fcx.ccx.tcx, id);
case (ast::def_ty(_)) {
fcx.ccx.tcx.sess.span_err(sp, "expected value but found type");
- fail;
}
case (_) {
// FIXME: handle other names.
fcx.ccx.tcx.sess.unimpl("definition variant");
- fail;
}
}
}
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
-fn instantiate_path(&@stmt_ctxt scx,
+fn instantiate_path(&@fn_ctxt fcx,
&ast::path pth,
&ty_param_count_and_ty tpt,
&span sp) -> ty_param_substs_opt_and_ty {
auto ty_param_count = tpt._0;
- auto t = bind_params_in_type(scx.fcx.ccx.tcx, tpt._1);
+
+ auto bind_result = bind_params_in_type(fcx.ccx.tcx,
+ bind next_ty_var_id(fcx),
+ tpt._1,
+ ty_param_count);
+ auto ty_param_vars = bind_result._0;
+ auto t = bind_result._1;
auto ty_substs_opt;
auto ty_substs_len = vec::len[@ast::ty](pth.node.types);
let vec[ty::t] ty_substs = [];
auto i = 0u;
while (i < ty_substs_len) {
- ty_substs += [ast_ty_to_ty_crate(scx.fcx.ccx,
- pth.node.types.(i))];
+ // TODO: Report an error if the number of type params in the item
+ // and the supplied number of type params don't match.
+ auto ty_var = ty::mk_var(fcx.ccx.tcx, ty_param_vars.(i));
+ auto ty_subst = ast_ty_to_ty_crate(fcx.ccx,
+ pth.node.types.(i));
+ auto res_ty = demand::simple(fcx, pth.span, ty_var, ty_subst);
+ ty_substs += [res_ty];
i += 1u;
}
ty_substs_opt = some[vec[ty::t]](ty_substs);
if (ty_param_count == 0u) {
- scx.fcx.ccx.tcx.sess.span_err(sp,
- "this item does not take type " +
- "parameters");
+ fcx.ccx.tcx.sess.span_err(sp, "this item does not take type " +
+ "parameters");
fail;
}
} else {
let vec[ty::t] ty_substs = [];
auto i = 0u;
while (i < ty_param_count) {
- ty_substs += [next_ty_var(scx)];
+ ty_substs += [ty::mk_var(fcx.ccx.tcx, ty_param_vars.(i))];
i += 1u;
}
ty_substs_opt = some[vec[ty::t]](ty_substs);
}
- ret tup(ty_substs_opt, t);
+ ret tup(ty_substs_opt, tpt._1);
}
fn ast_mode_to_mode(ast::mode mode) -> ty::mode {
auto ty_mode;
alt (mode) {
case (ast::val) { ty_mode = mo_val; }
- case (ast::alias) { ty_mode = mo_alias; }
+ case (ast::alias(?mut)) { ty_mode = mo_alias(mut); }
}
ret ty_mode;
}
+
+// Type tests
+
+fn structurally_resolved_type(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::t {
+ auto r = ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings,
+ typ);
+ alt (r) {
+ case (fix_ok(?typ_s)) { ret typ_s; }
+ case (fix_err(_)) {
+ fcx.ccx.tcx.sess.span_err(sp, "the type of this value must be " +
+ "known in this context");
+ }
+ }
+}
+
+// Returns the one-level-deep structure of the given type.
+fn structure_of(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::sty {
+ ret ty::struct(fcx.ccx.tcx, structurally_resolved_type(fcx, sp, typ));
+}
+
+fn type_is_integral(&@fn_ctxt fcx, &span sp, ty::t typ) -> bool {
+ auto typ_s = structurally_resolved_type(fcx, sp, typ);
+ ret ty::type_is_integral(fcx.ccx.tcx, typ_s);
+}
+
+fn type_is_scalar(&@fn_ctxt fcx, &span sp, ty::t typ) -> bool {
+ auto typ_s = structurally_resolved_type(fcx, sp, typ);
+ ret ty::type_is_scalar(fcx.ccx.tcx, typ_s);
+}
+
+
// Parses the programmer's textual representation of a type into our internal
// notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
+ alt (tcx.ast_ty_to_ty_cache.find(ast_ty)) {
+ case (some[option::t[ty::t]](some[ty::t](?ty))) { ret ty; }
+ case (some[option::t[ty::t]](none)) {
+ tcx.sess.span_err(ast_ty.span, "illegal recursive type "
+ + "(insert a tag in the cycle, if this is desired)");
+ }
+ case (none[option::t[ty::t]]) { } /* go on */
+ }
+ tcx.ast_ty_to_ty_cache.insert(ast_ty, none[ty::t]);
+
fn ast_arg_to_arg(&ty::ctxt tcx,
&ty_getter getter,
- &rec(ast::mode mode, @ast::ty ty) arg)
+ &ast::ty_arg arg)
-> rec(ty::mode mode, ty::t ty) {
- auto ty_mode = ast_mode_to_mode(arg.mode);
- ret rec(mode=ty_mode, ty=ast_ty_to_ty(tcx, getter, arg.ty));
+ auto ty_mode = ast_mode_to_mode(arg.node.mode);
+ ret rec(mode=ty_mode, ty=ast_ty_to_ty(tcx, getter, arg.node.ty));
}
fn ast_mt_to_mt(&ty::ctxt tcx,
}
fn instantiate(&ty::ctxt tcx,
+ &span sp,
&ty_getter getter,
&ast::def_id id,
&vec[@ast::ty] args) -> ty::t {
// TODO: maybe record cname chains so we can do
// "foo = int" like OCaml?
auto params_opt_and_ty = getter(id);
-
if (params_opt_and_ty._0 == 0u) {
ret params_opt_and_ty._1;
}
// The typedef is type-parametric. Do the type substitution.
//
- // TODO: Make sure the number of supplied bindings matches the number
- // of type parameters in the typedef. Emit a friendly error otherwise.
- auto bound_ty = bind_params_in_type(tcx, params_opt_and_ty._1);
let vec[ty::t] param_bindings = [];
for (@ast::ty ast_ty in args) {
param_bindings += [ast_ty_to_ty(tcx, getter, ast_ty)];
}
- ret ty::substitute_type_params(tcx, param_bindings, bound_ty);
+
+ if (vec::len(param_bindings) !=
+ ty::count_ty_params(tcx, params_opt_and_ty._1)) {
+ tcx.sess.span_err(sp, "Wrong number of type arguments for a"
+ + " polymorphic tag");
+ }
+
+
+ auto typ = ty::substitute_type_params(tcx, param_bindings,
+ params_opt_and_ty._1);
+ ret typ;
}
auto mut = ast::imm;
case (ast::ty_machine(?tm)) { typ = ty::mk_mach(tcx, tm); }
case (ast::ty_char) { typ = ty::mk_char(tcx); }
case (ast::ty_str) { typ = ty::mk_str(tcx); }
+ case (ast::ty_istr) { typ = ty::mk_istr(tcx); }
case (ast::ty_box(?mt)) {
typ = ty::mk_box(tcx, ast_mt_to_mt(tcx, getter, mt));
}
case (ast::ty_vec(?mt)) {
typ = ty::mk_vec(tcx, ast_mt_to_mt(tcx, getter, mt));
}
+ case (ast::ty_ivec(?mt)) {
+ typ = ty::mk_ivec(tcx, ast_mt_to_mt(tcx, getter, mt));
+ }
+ case (ast::ty_ptr(?mt)) {
+ typ = ty::mk_ptr(tcx, ast_mt_to_mt(tcx, getter, mt));
+ }
case (ast::ty_task) { typ = ty::mk_task(tcx); }
case (ast::ty_port(?t)) {
typ = ty::mk_port(tcx, ast_ty_to_ty(tcx, getter, t));
case (ast::ty_rec(?fields)) {
let vec[field] flds = [];
for (ast::ty_field f in fields) {
- auto tm = ast_mt_to_mt(tcx, getter, f.mt);
- vec::push[field](flds, rec(ident=f.ident, mt=tm));
+ auto tm = ast_mt_to_mt(tcx, getter, f.node.mt);
+ vec::push[field](flds, rec(ident=f.node.ident, mt=tm));
}
typ = ty::mk_rec(tcx, flds);
}
- case (ast::ty_fn(?proto, ?inputs, ?output, ?cf)) {
+ case (ast::ty_fn(?proto, ?inputs, ?output, ?cf, ?constrs)) {
auto f = bind ast_arg_to_arg(tcx, getter, _);
auto i = vec::map[ast::ty_arg, arg](f, inputs);
auto out_ty = ast_ty_to_ty(tcx, getter, output);
- typ = ty::mk_fn(tcx, proto, i, out_ty, cf);
+ typ = ty::mk_fn(tcx, proto, i, out_ty, cf, constrs);
}
case (ast::ty_path(?path, ?ann)) {
alt (tcx.def_map.get(ann.id)) {
case (ast::def_ty(?id)) {
- typ = instantiate(tcx, getter, id, path.node.types);
+ typ = instantiate(tcx, ast_ty.span, getter, id,
+ path.node.types);
}
case (ast::def_native_ty(?id)) { typ = getter(id)._1; }
case (ast::def_obj(?id)) {
- typ = instantiate(tcx, getter, id, path.node.types);
+ typ = instantiate(tcx, ast_ty.span, getter, id,
+ path.node.types);
}
case (ast::def_ty_arg(?id)) { typ = ty::mk_param(tcx, id); }
case (_) {
let vec[ty::method] tmeths = [];
auto f = bind ast_arg_to_arg(tcx, getter, _);
for (ast::ty_method m in meths) {
- auto ins = vec::map[ast::ty_arg, arg](f, m.inputs);
- auto out = ast_ty_to_ty(tcx, getter, m.output);
+ auto ins = vec::map[ast::ty_arg, arg](f, m.node.inputs);
+ auto out = ast_ty_to_ty(tcx, getter, m.node.output);
let ty::method new_m =
- rec(proto=m.proto,
- ident=m.ident,
+ rec(proto=m.node.proto,
+ ident=m.node.ident,
inputs=ins,
output=out,
- cf=m.cf);
+ cf=m.node.cf,
+ constrs=m.node.constrs);
vec::push[ty::method](tmeths, new_m);
}
typ = ty::rename(tcx, typ, cname_str);
}
}
+
+ tcx.ast_ty_to_ty_cache.insert(ast_ty, some(typ));
ret typ;
}
mod write {
fn inner(&node_type_table ntt, uint node_id,
&ty_param_substs_opt_and_ty tpot) {
+ auto ntt_ = *ntt;
vec::grow_set[option::t[ty::ty_param_substs_opt_and_ty]]
- (*ntt,
+ (ntt_,
node_id,
none[ty_param_substs_opt_and_ty],
some[ty_param_substs_opt_and_ty](tpot));
+ *ntt = ntt_;
}
// Writes a type parameter count and type pair into the node type table.
// Writes a type parameter count and type pair into the node type table.
// This function allows for the possibility of type variables, which will
// be rewritten later during the fixup phase.
- fn ty_fixup(&@stmt_ctxt scx, uint node_id,
+ fn ty_fixup(@fn_ctxt fcx, uint node_id,
&ty_param_substs_opt_and_ty tpot) {
- inner(scx.fcx.ccx.tcx.node_types, node_id, tpot);
- if (ty::type_contains_vars(scx.fcx.ccx.tcx, tpot._1)) {
- scx.fixups += [node_id];
+ inner(fcx.ccx.tcx.node_types, node_id, tpot);
+ if (ty::type_contains_vars(fcx.ccx.tcx, tpot._1)) {
+ fcx.fixups += [node_id];
}
}
// Writes a type with no type parameters into the node type table. This
// function allows for the possibility of type variables.
- fn ty_only_fixup(&@stmt_ctxt scx, uint node_id, ty::t typ) {
- be ty_fixup(scx, node_id, tup(none[vec[ty::t]], typ));
+ fn ty_only_fixup(@fn_ctxt fcx, uint node_id, ty::t typ) {
+ be ty_fixup(fcx, node_id, tup(none[vec[ty::t]], typ));
}
// Writes a nil type into the node type table.
&ast::def_id def_id) -> ty::ty_param_count_and_ty {
auto input_tys = vec::map[ast::arg,arg](ty_of_arg, decl.inputs);
auto output_ty = convert(decl.output);
- auto t_fn = ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf);
+ auto t_fn = ty::mk_fn(cx.tcx, proto, input_tys, output_ty,
+ decl.cf, decl.constraints);
auto ty_param_count = vec::len[ast::ty_param](ty_params);
auto tpt = tup(ty_param_count, t_fn);
cx.tcx.tcache.insert(def_id, tpt);
auto inputs = vec::map[ast::arg,arg](f, m.node.meth.decl.inputs);
auto output = convert(m.node.meth.decl.output);
ret rec(proto=m.node.meth.proto, ident=m.node.ident,
- inputs=inputs, output=output, cf=m.node.meth.decl.cf);
+ inputs=inputs, output=output, cf=m.node.meth.decl.cf,
+ constrs=m.node.meth.decl.constraints);
}
fn ty_of_obj(@ctxt cx,
for (ast::obj_field f in obj_info.fields) {
auto g = bind getter(cx, _);
auto t_field = ast_ty_to_ty(cx.tcx, g, f.ty);
- vec::push[arg](t_inputs, rec(mode=ty::mo_alias, ty=t_field));
+ vec::push(t_inputs, rec(mode=ty::mo_alias(false), ty=t_field));
}
+ let vec[@ast::constr] constrs = [];
auto t_fn = ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj._1,
- ast::return);
+ ast::return, constrs);
auto tpt = tup(t_obj._0, t_fn);
cx.tcx.tcache.insert(ctor_id, tpt);
let vec[arg] args = [];
for (ast::variant_arg va in variant.node.args) {
auto arg_ty = ast_ty_to_ty(cx.tcx, f, va.ty);
- args += [rec(mode=ty::mo_alias, ty=arg_ty)];
+ args += [rec(mode=ty::mo_alias(false), ty=arg_ty)];
}
auto tag_t = ty::mk_tag(cx.tcx, tag_id, ty_param_tys);
+ // FIXME: this will be different for constrained types
+ let vec[@ast::constr] res_constrs = [];
result_ty = ty::mk_fn(cx.tcx, ast::proto_fn, args, tag_t,
- ast::return);
+ ast::return, res_constrs);
}
auto tpt = tup(ty_param_count, result_ty);
alt (object.dtor) {
case (none) { /* nothing to do */ }
case (some(?m)) {
- // TODO: typechecker botch
- let vec[arg] no_args = [];
- auto t = ty::mk_fn(cx.tcx, ast::proto_fn, no_args,
- ty::mk_nil(cx.tcx), ast::return);
+ let vec[@ast::constr] constrs = [];
+ let vec[arg] res_inputs = [];
+ auto t = ty::mk_fn(cx.tcx, ast::proto_fn, res_inputs,
+ ty::mk_nil(cx.tcx), ast::return, constrs);
write::ty_only(cx.tcx, m.node.ann.id, t);
}
}
// type of the native item. We simply write it into the node type
// table.
auto tpt = ty_of_native_item(cx, i,
- option::get[ast::native_abi](*abi));
+ option::get[ast::native_abi]({*abi}));
alt (i.node) {
case (ast::native_item_ty(_,_)) {
// Type unification
+// TODO: rename to just "unify"
mod unify {
- fn simple(&@stmt_ctxt scx, &ty::t expected, &ty::t actual)
+ fn simple(&@fn_ctxt fcx, &ty::t expected, &ty::t actual)
-> ty::unify::result {
- // FIXME: horrid botch
- let vec[mutable ty::t] param_substs =
- [mutable ty::mk_nil(scx.fcx.ccx.tcx)];
- vec::pop(param_substs);
- ret with_params(scx, expected, actual, param_substs);
- }
-
- fn with_params(&@stmt_ctxt scx,
- &ty::t expected,
- &ty::t actual,
- &vec[mutable ty::t] param_substs) -> ty::unify::result {
- auto cache_key = tup(expected, actual, param_substs);
- alt (scx.fcx.ccx.unify_cache.find(cache_key)) {
- case (some(?r)) {
- scx.fcx.ccx.cache_hits += 1u;
- ret r;
- }
- case (none) {
- scx.fcx.ccx.cache_misses += 1u;
- }
- }
-
- obj unify_handler(@stmt_ctxt scx, vec[mutable ty::t] param_substs) {
- fn resolve_local(ast::def_id id) -> option::t[ty::t] {
- alt (scx.fcx.locals.find(id)) {
- case (none) { ret none[ty::t]; }
- case (some(?existing_type)) {
- if (ty::type_contains_vars(scx.fcx.ccx.tcx,
- existing_type)) {
- // Not fully resolved yet. The writeback phase
- // will mop up.
- ret none[ty::t];
- }
- ret some[ty::t](existing_type);
- }
- }
- }
- fn record_local(ast::def_id id, ty::t new_type) {
- auto unified_type;
- alt (scx.fcx.locals.find(id)) {
- case (none) { unified_type = new_type; }
- case (some(?old_type)) {
- alt (with_params(scx, old_type, new_type,
- param_substs)) {
- case (ures_ok(?ut)) { unified_type = ut; }
- case (_) { fail; /* FIXME */ }
- }
- }
- }
-
- // TODO: "freeze"
- let vec[ty::t] param_substs_1 = [];
- for (ty::t subst in param_substs) {
- param_substs_1 += [subst];
- }
-
- unified_type = ty::substitute_type_params(scx.fcx.ccx.tcx,
- param_substs_1,
- unified_type);
- scx.fcx.locals.insert(id, unified_type);
- }
- fn record_param(uint index, ty::t binding) -> ty::unify::result {
- // Unify with the appropriate type in the parameter
- // substitution list:
- auto old_subst = param_substs.(index);
-
- auto result = with_params(scx, old_subst, binding,
- param_substs);
- alt (result) {
- case (ures_ok(?new_subst)) {
- param_substs.(index) = new_subst;
- ret ures_ok(ty::mk_bound_param(scx.fcx.ccx.tcx,
- index));
- }
- case (_) { ret result; }
- }
- }
- }
-
-
- auto handler = unify_handler(scx, param_substs);
-
- auto bindings = ty::unify::mk_bindings[int](int::hash, int::eq_alias);
- auto result = ty::unify::unify(expected, actual, handler, bindings,
- scx.fcx.ccx.tcx);
-
- alt (result) {
- case (ures_ok(?rty)) {
- if (ty::type_contains_vars(scx.fcx.ccx.tcx, rty)) {
- result = ty::unify::fixup(scx.fcx.ccx.tcx, bindings, rty);
- }
- }
- case (_) { /* nothing */ }
- }
-
- scx.fcx.ccx.unify_cache.insert(cache_key, result);
- ret result;
+ ret ty::unify::unify(expected, actual, fcx.var_bindings, fcx.ccx.tcx);
}
}
NO_AUTODEREF;
}
-fn strip_boxes(&ty::ctxt tcx, &ty::t t) -> ty::t {
+fn strip_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> ty::t {
auto t1 = t;
while (true) {
- alt (struct(tcx, t1)) {
+ alt (structure_of(fcx, sp, t1)) {
case (ty::ty_box(?inner)) { t1 = inner.ty; }
case (_) { ret t1; }
}
}
-fn count_boxes(&ty::ctxt tcx, &ty::t t) -> uint {
+fn count_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> uint {
auto n = 0u;
auto t1 = t;
while (true) {
- alt (struct(tcx, t1)) {
+ alt (structure_of(fcx, sp, t1)) {
case (ty::ty_box(?inner)) { n += 1u; t1 = inner.ty; }
case (_) { ret n; }
}
}
+fn resolve_type_vars_if_possible(&@fn_ctxt fcx, ty::t typ) -> ty::t {
+ alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) {
+ case (fix_ok(?new_type)) { ret new_type; }
+ case (fix_err(_)) { ret typ; }
+ }
+}
+
+
// Demands - procedures that require that two types unify and emit an error
// message if they don't.
type ty_param_substs_and_ty = tup(vec[ty::t], ty::t);
mod demand {
- fn simple(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual)
+ fn simple(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual)
-> ty::t {
let vec[ty::t] tps = [];
- ret full(scx, sp, expected, actual, tps, NO_AUTODEREF)._1;
+ ret full(fcx, sp, expected, actual, tps, NO_AUTODEREF)._1;
}
- fn autoderef(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual,
+ fn autoderef(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual,
autoderef_kind adk) -> ty::t {
let vec[ty::t] tps = [];
- ret full(scx, sp, expected, actual, tps, adk)._1;
+ ret full(fcx, sp, expected, actual, tps, adk)._1;
}
// Requires that the two types unify, and prints an error message if they
// don't. Returns the unified type and the type parameter substitutions.
- fn full(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual,
+ fn full(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual,
&vec[ty::t] ty_param_substs_0, autoderef_kind adk)
-> ty_param_substs_and_ty {
auto implicit_boxes = 0u;
if (adk == AUTODEREF_OK) {
- expected_1 = strip_boxes(scx.fcx.ccx.tcx, expected_1);
- actual_1 = strip_boxes(scx.fcx.ccx.tcx, actual_1);
- implicit_boxes = count_boxes(scx.fcx.ccx.tcx, actual);
+ expected_1 = strip_boxes(fcx, sp, expected_1);
+ actual_1 = strip_boxes(fcx, sp, actual_1);
+ implicit_boxes = count_boxes(fcx, sp, actual);
}
- let vec[mutable ty::t] ty_param_substs =
- [mutable ty::mk_nil(scx.fcx.ccx.tcx)];
- vec::pop(ty_param_substs); // FIXME: horrid botch
+ let vec[mutable ty::t] ty_param_substs = [mutable];
+ let vec[int] ty_param_subst_var_ids = [];
for (ty::t ty_param_subst in ty_param_substs_0) {
- ty_param_substs += [mutable ty_param_subst];
+ // Generate a type variable and unify it with the type parameter
+ // substitution. We will then pull out these type variables.
+ auto t_0 = next_ty_var(fcx);
+ ty_param_substs += [mutable t_0];
+ ty_param_subst_var_ids += [ty::ty_var_id(fcx.ccx.tcx, t_0)];
+
+ simple(fcx, sp, ty_param_subst, t_0);
}
- alt (unify::with_params(scx, expected_1, actual_1, ty_param_substs)) {
+ alt (unify::simple(fcx, expected_1, actual_1)) {
case (ures_ok(?t)) {
- // TODO: Use "freeze", when we have it.
let vec[ty::t] result_ty_param_substs = [];
- for (ty::t ty_param_subst in ty_param_substs) {
- result_ty_param_substs += [ty_param_subst];
+ for (int var_id in ty_param_subst_var_ids) {
+ auto tp_subst = ty::mk_var(fcx.ccx.tcx, var_id);
+ result_ty_param_substs += [tp_subst];
}
ret tup(result_ty_param_substs,
- add_boxes(scx.fcx.ccx, implicit_boxes, t));
+ add_boxes(fcx.ccx, implicit_boxes, t));
}
- case (ures_err(?err, ?expected, ?actual)) {
- scx.fcx.ccx.tcx.sess.span_err
+ case (ures_err(?err)) {
+ auto e_err = resolve_type_vars_if_possible(fcx, expected_1);
+ auto a_err = resolve_type_vars_if_possible(fcx, actual_1);
+
+ fcx.ccx.tcx.sess.span_err
(sp, "mismatched types: expected "
- + ty_to_str(scx.fcx.ccx.tcx, expected) + " but found "
- + ty_to_str(scx.fcx.ccx.tcx, actual) + " ("
+ + ty_to_str(fcx.ccx.tcx, e_err) + " but found "
+ + ty_to_str(fcx.ccx.tcx, a_err) + " ("
+ ty::type_err_to_str(err) + ")");
// TODO: In the future, try returning "expected", reporting
// the error, and continue.
- fail;
}
}
}
// Returns true if the two types unify and false if they don't.
-fn are_compatible(&@stmt_ctxt scx, &ty::t expected, &ty::t actual) -> bool {
- alt (unify::simple(scx, expected, actual)) {
- case (ures_ok(_)) { ret true; }
- case (ures_err(_, _, _)) { ret false; }
+fn are_compatible(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> bool {
+ alt (unify::simple(fcx, expected, actual)) {
+ case (ures_ok(_)) { ret true; }
+ case (ures_err(_)) { ret false; }
}
}
let vec[ty::t] result = [];
auto tpt = ty::lookup_item_type(ccx.tcx, vid);
- alt (struct(ccx.tcx, tpt._1)) {
- case (ty::ty_fn(_, ?ins, _, _)) {
+ alt (ty::struct(ccx.tcx, tpt._1)) {
+ case (ty::ty_fn(_, ?ins, _, _, _)) {
// N-ary variant.
for (ty::arg arg in ins) {
- auto arg_ty = bind_params_in_type(ccx.tcx, arg.ty);
- arg_ty = substitute_ty_params(ccx, arg_ty, ty_param_count,
- tag_ty_params, sp);
+ auto arg_ty = ty::substitute_type_params(ccx.tcx,
+ tag_ty_params, arg.ty);
result += [arg_ty];
}
}
}
-// The "push-down" phase, which takes a typed grammar production and pushes
-// its type down into its constituent parts.
-//
-// For example, consider "auto x; x = 352;". check_expr() doesn't know the
-// type of "x" at the time it sees it, so that function will simply store a
-// type variable for the type of "x". However, after checking the entire
-// assignment expression, check_expr() will assign the type of int to the
-// expression "x = 352" as a whole. In this case, then, the job of these
-// functions is to clean up by assigning the type of int to both sides of the
-// assignment expression.
+// Type resolution: the phase that finds all the types in the AST with
+// unresolved type variables and replaces "ty_var" types with their
+// substitutions.
//
-// TODO: We only need to do this once per statement: check_expr() bubbles the
-// types up, and pushdown_expr() pushes the types down. However, in many cases
-// we're more eager than we need to be, calling pushdown_expr() and friends
-// directly inside check_expr(). This results in a quadratic algorithm.
-
-mod pushdown {
- // Push-down over typed patterns. Note that the pattern that you pass to
- // this function must have been passed to check_pat() first.
- //
- // TODO: enforce this via a predicate.
-
- fn pushdown_pat(&@stmt_ctxt scx, &ty::t expected, &@ast::pat pat) {
- alt (pat.node) {
- case (ast::pat_wild(?ann)) {
- auto t = demand::simple(scx, pat.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::pat_lit(?lit, ?ann)) {
- auto t = demand::simple(scx, pat.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::pat_bind(?id, ?did, ?ann)) {
- auto t = demand::simple(scx, pat.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- scx.fcx.locals.insert(did, t);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::pat_tag(?id, ?subpats, ?ann)) {
- // Take the variant's type parameters out of the expected
- // type.
- auto tag_tps;
- alt (struct(scx.fcx.ccx.tcx, expected)) {
- case (ty::ty_tag(_, ?tps)) { tag_tps = tps; }
- case (_) {
- log_err "tag pattern type not actually a tag?!";
- fail;
- }
- }
-
- // Get the types of the arguments of the variant.
-
- let vec[ty::t] tparams = [];
- auto j = 0u;
- auto actual_ty_params =
- ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann);
-
- for (ty::t some_ty in tag_tps) {
- let ty::t t1 = some_ty;
- let ty::t t2 = actual_ty_params.(j);
-
- let ty::t res = demand::simple(scx, pat.span, t1, t2);
-
- vec::push(tparams, res);
- j += 1u;
- }
-
- auto arg_tys;
- alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) {
- case (ast::def_variant(_, ?vdefid)) {
- arg_tys = variant_arg_types(scx.fcx.ccx, pat.span,
- vdefid, tparams);
- }
- }
-
- auto i = 0u;
- for (@ast::pat subpat in subpats) {
- pushdown_pat(scx, arg_tys.(i), subpat);
- i += 1u;
- }
-
- auto tps =
- ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann);
- auto tt = ann_to_type(scx.fcx.ccx.tcx.node_types, ann);
-
- let ty_param_substs_and_ty res_t = demand::full(scx, pat.span,
- expected, tt, tps, NO_AUTODEREF);
+// TODO: inefficient since not all types have vars in them. It would be better
+// to maintain a list of fixups.
- auto ty_params_subst = ty::ann_to_ty_param_substs_opt_and_ty
- (scx.fcx.ccx.tcx.node_types, ann);
-
- auto ty_params_opt;
- alt (ty_params_subst._0) {
- case (none) {
- ty_params_opt = none[vec[ty::t]];
- }
- case (some(?tps)) {
- ty_params_opt = some[vec[ty::t]](tag_tps);
- }
- }
+mod writeback {
+ fn resolve_type_vars_in_type(&@fn_ctxt fcx, &span sp, ty::t typ)
+ -> ty::t {
+ if (!ty::type_contains_vars(fcx.ccx.tcx, typ)) { ret typ; }
- write::ty_fixup(scx, ann.id, tup(ty_params_opt, tt));
+ alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) {
+ case (fix_ok(?new_type)) { ret new_type; }
+ case (fix_err(?vid)) {
+ fcx.ccx.tcx.sess.span_err(sp,
+ "cannot determine a type for this expression");
}
}
}
- // Push-down 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: This function is incomplete.
-
- fn pushdown_expr(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e) {
- be pushdown_expr_full(scx, expected, e, NO_AUTODEREF);
- }
-
- fn pushdown_expr_full(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e,
- autoderef_kind adk) {
- alt (e.node) {
- case (ast::expr_vec(?es_0, ?mut, ?ann)) {
- // TODO: enforce mutability
-
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- alt (struct(scx.fcx.ccx.tcx, t)) {
- case (ty::ty_vec(?mt)) {
- for (@ast::expr e_0 in es_0) {
- pushdown_expr(scx, mt.ty, e_0);
- }
- }
- case (_) {
- log_err "vec expr doesn't have a vec type!";
- fail;
- }
- }
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_tup(?es_0, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- alt (struct(scx.fcx.ccx.tcx, t)) {
- case (ty::ty_tup(?mts)) {
- auto i = 0u;
- for (ast::elt elt_0 in es_0) {
- pushdown_expr(scx, mts.(i).ty, elt_0.expr);
- i += 1u;
- }
- }
- case (_) {
- log_err "tup expr doesn't have a tup type!";
- fail;
- }
- }
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_rec(?fields_0, ?base_0, ?ann)) {
-
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- alt (struct(scx.fcx.ccx.tcx, t)) {
- case (ty::ty_rec(?field_mts)) {
- alt (base_0) {
- case (none) {
- auto i = 0u;
- for (ast::field field_0 in fields_0) {
- assert (str::eq(field_0.node.ident,
- field_mts.(i).ident));
- pushdown_expr(scx,
- field_mts.(i).mt.ty,
- field_0.node.expr);
- i += 1u;
- }
- }
- case (some(?bx)) {
-
- let vec[field] base_fields = [];
-
- for (ast::field field_0 in fields_0) {
-
- for (ty::field ft in field_mts) {
- if (str::eq(field_0.node.ident,
- ft.ident)) {
- pushdown_expr(scx, ft.mt.ty,
- field_0.node.expr);
- }
- }
- }
- }
- }
- }
- case (_) {
- log_err "rec expr doesn't have a rec type!";
- fail;
- }
- }
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_bind(?sube, ?es, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_call(?sube, ?es, ?ann)) {
- // NB: we call 'demand::autoderef' and pass in adk only in
- // cases where e is an expression that could *possibly*
- // produce a box; things like expr_binary or expr_bind can't,
- // so there's no need.
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_self_method(?id, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_binary(?bop, ?lhs, ?rhs, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_unary(?uop, ?sube, ?ann)) {
- // See note in expr_unary for why we're calling
- // demand::autoderef.
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
-
- /* The following is a bit special-cased, but takes care of
- the case where we say let @vec[whatever] v = @[]; */
- auto inner_ty = t;
- alt (uop) {
- case (ast::box(?mut)) {
- alt (struct(scx.fcx.ccx.tcx, t)) {
- case (ty::ty_box(?inner)) { inner_ty = inner.ty; }
- case (_) {
- scx.fcx.ccx.tcx.sess.span_err(e.span,
- "Expecting an application of box"
- + " to have a box type");
- }
- }
- }
- case (ast::deref) {
- inner_ty = ty::mk_box(scx.fcx.ccx.tcx,
- // maybe_mut should work because it'll unify with
- // the existing type?
- rec(ty=t, mut=ast::maybe_mut));
- }
- case (_) { inner_ty = strip_boxes(scx.fcx.ccx.tcx, t); }
- }
-
- pushdown_expr(scx, inner_ty, sube);
- }
- case (ast::expr_lit(?lit, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_cast(?sube, ?ast_ty, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_if(?cond, ?then_0, ?else_0, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
-
- auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0);
- pushdown_block(scx, expected, then_0);
+ fn resolve_type_vars_for_node(&@fn_ctxt fcx, &span sp, &ast::ann ann) {
+ auto tpot = ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, ann);
+ auto new_ty = resolve_type_vars_in_type(fcx, sp, tpot._1);
- alt (else_0) {
- case (none) { /* no-op */ }
- case (some(?e_0)) {
- auto else_t = ty::expr_ty(scx.fcx.ccx.tcx, e_0);
- pushdown_expr(scx, expected, e_0);
- }
+ auto new_substs_opt;
+ alt (tpot._0) {
+ case (none[vec[ty::t]]) { new_substs_opt = none[vec[ty::t]]; }
+ case (some[vec[ty::t]](?substs)) {
+ let vec[ty::t] new_substs = [];
+ for (ty::t subst in substs) {
+ new_substs += [resolve_type_vars_in_type(fcx, sp, subst)];
}
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_for(?decl, ?seq, ?bloc, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_for_each(?decl, ?seq, ?bloc, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_while(?cond, ?bloc, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_do_while(?bloc, ?cond, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_block(?bloc, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- pushdown_block(scx, t, bloc);
- }
- case (ast::expr_move(?lhs_0, ?rhs_0, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- pushdown_expr(scx, expected, lhs_0);
- pushdown_expr(scx, expected, rhs_0);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_assign(?lhs_0, ?rhs_0, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- pushdown_expr(scx, expected, lhs_0);
- pushdown_expr(scx, expected, rhs_0);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- pushdown_expr(scx, expected, lhs_0);
- pushdown_expr(scx, expected, rhs_0);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_field(?lhs, ?rhs, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_index(?base, ?index, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- }
- case (ast::expr_path(?pth, ?ann)) {
- auto tp_substs_0 =
- ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann);
- auto t_0 = ann_to_type(scx.fcx.ccx.tcx.node_types, ann);
-
- auto result_0 = demand::full(scx, e.span, expected, t_0,
- tp_substs_0, adk);
- auto t = result_0._1;
-
- // Fill in the type parameter substitutions if they weren't
- // provided by the programmer.
- auto ty_params_opt;
- alt (ty::ann_to_ty_param_substs_opt_and_ty
- (scx.fcx.ccx.tcx.node_types, ann)._0) {
- case (none) {
- ty_params_opt = none[vec[ty::t]];
- }
- case (some(?tps)) {
- ty_params_opt = some[vec[ty::t]](tps);
- }
- }
-
- write::ty_fixup(scx, ann.id, tup(ty_params_opt, t));
- }
- case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?ann)) {
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- }
- /* FIXME: should this check the type annotations? */
- case (ast::expr_fail(_)) { /* no-op */ }
- case (ast::expr_log(_,_,_)) { /* no-op */ }
- case (ast::expr_break(_)) { /* no-op */ }
- case (ast::expr_cont(_)) { /* no-op */ }
- case (ast::expr_ret(_,_)) { /* no-op */ }
- case (ast::expr_put(_,_)) { /* no-op */ }
- case (ast::expr_be(_,_)) { /* no-op */ }
- case (ast::expr_check(_,_)) { /* no-op */ }
- case (ast::expr_assert(_,_)) { /* no-op */ }
-
- case (ast::expr_port(?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- write::ty_only_fixup(scx, ann.id, t);
- }
-
- case (ast::expr_chan(?es, ?ann)) {
- auto t = demand::simple(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
- alt (struct(scx.fcx.ccx.tcx, t)) {
- case (ty::ty_chan(?subty)) {
- auto pt = ty::mk_port(scx.fcx.ccx.tcx, subty);
- pushdown_expr(scx, pt, es);
- }
- case (_) {
- log "chan expr doesn't have a chan type!";
- fail;
- }
- }
- write::ty_only_fixup(scx, ann.id, t);
- }
-
- case (ast::expr_alt(?discrim, ?arms_0, ?ann)) {
- auto t = expected;
- for (ast::arm arm_0 in arms_0) {
- pushdown_block(scx, expected, arm_0.block);
- auto bty = block_ty(scx.fcx.ccx.tcx, arm_0.block);
- t = demand::simple(scx, e.span, t, bty);
- }
- write::ty_only_fixup(scx, ann.id, t);
- }
-
- case (ast::expr_recv(?lval, ?expr, ?ann)) {
- pushdown_expr(scx, next_ty_var(scx), lval);
- auto t = expr_ty(scx.fcx.ccx.tcx, lval);
- write::ty_only_fixup(scx, ann.id, t);
- }
-
- case (ast::expr_send(?lval, ?expr, ?ann)) {
- pushdown_expr(scx, next_ty_var(scx), expr);
- auto t = expr_ty(scx.fcx.ccx.tcx, expr);
- pushdown_expr(scx, ty::mk_chan(scx.fcx.ccx.tcx, t), lval);
- }
-
- case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) {
- // NB: we call 'demand::autoderef' and pass in adk only in
- // cases where e is an expression that could *possibly*
- // produce a box; things like expr_binary or expr_bind can't,
- // so there's no need.
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- }
-
- case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
- // NB: Not sure if this is correct, but not worrying too much
- // about it since pushdown is going away anyway.
- auto t = demand::autoderef(scx, e.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
- write::ty_only_fixup(scx, ann.id, t);
- }
-
- case (_) {
- scx.fcx.ccx.tcx.sess.span_unimpl(e.span,
- #fmt("type unification for expression variant: %s",
- pretty::pprust::expr_to_str(e)));
- fail;
+ new_substs_opt = some[vec[ty::t]](new_substs);
}
}
- }
- // Push-down over typed blocks.
- fn pushdown_block(&@stmt_ctxt scx, &ty::t expected, &ast::block bloc) {
- alt (bloc.node.expr) {
- case (some(?e_0)) {
- pushdown_expr(scx, expected, e_0);
- }
- case (none) {
- /* empty */
- }
- }
- demand::simple(scx, bloc.span, expected,
- ann_to_type(scx.fcx.ccx.tcx.node_types, bloc.node.a));
- }
-}
-
-
-// Local variable resolution: the phase that finds all the types in the AST
-// and replaces opaque "ty_local" types with the resolved local types.
-
-mod writeback {
- fn wb_local(&@fn_ctxt fcx, &span sp, &@ast::local local) {
- auto local_ty;
- alt (fcx.locals.find(local.id)) {
- case (none) {
- fcx.ccx.tcx.sess.span_err(sp,
- "unable to determine type of local: " + local.ident);
- fail;
- }
- case (some(?lt)) {
- local_ty = lt;
- }
- }
-
- if (ty::type_contains_vars(fcx.ccx.tcx, local_ty)) {
- fcx.ccx.tcx.sess.span_err(sp,
- "Ambiguous type " + ty_to_str(fcx.ccx.tcx, local_ty)
- + "\n(Try adding more type annotations.)");
- }
- write::ty_only(fcx.ccx.tcx, local.ann.id, local_ty);
- }
-
- fn resolve_local_types(&@fn_ctxt fcx, &ast::ann ann) {
- fn resolver(@fn_ctxt fcx, ty::t typ) -> ty::t {
- alt (struct(fcx.ccx.tcx, typ)) {
- case (ty::ty_local(?lid)) { ret fcx.locals.get(lid); }
- case (_) { ret typ; }
- }
- }
-
- auto tpot =
- ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx.node_types,
- ann);
- auto tt = tpot._1;
- if (!ty::type_contains_locals(fcx.ccx.tcx, tt)) { ret; }
-
- auto f = bind resolver(fcx, _);
- auto new_type = ty::fold_ty(fcx.ccx.tcx, f, tt);
- write::ty(fcx.ccx.tcx, ann.id, tup(tpot._0, new_type));
+ write::ty(fcx.ccx.tcx, ann.id, tup(new_substs_opt, new_ty));
}
fn visit_stmt_pre(@fn_ctxt fcx, &@ast::stmt s) {
- resolve_local_types(fcx, ty::stmt_ann(s));
+ resolve_type_vars_for_node(fcx, s.span, ty::stmt_ann(s));
}
fn visit_expr_pre(@fn_ctxt fcx, &@ast::expr e) {
- resolve_local_types(fcx, ty::expr_ann(e));
+ resolve_type_vars_for_node(fcx, e.span, ty::expr_ann(e));
}
fn visit_block_pre(@fn_ctxt fcx, &ast::block b) {
- resolve_local_types(fcx, b.node.a);
+ resolve_type_vars_for_node(fcx, b.span, b.node.a);
}
- fn visit_arm_pre(@fn_ctxt fcx, &ast::arm a) {
- // FIXME: Need a visit_pat_pre
- resolve_local_types(fcx, ty::pat_ann(a.pat));
+ fn visit_pat_pre(@fn_ctxt fcx, &@ast::pat p) {
+ resolve_type_vars_for_node(fcx, p.span, ty::pat_ann(p));
}
fn visit_decl_pre(@fn_ctxt fcx, &@ast::decl d) {
alt (d.node) {
- case (ast::decl_local(?l)) { wb_local(fcx, d.span, l); }
- case (ast::decl_item(_)) { /* no annotation */ }
+ case (ast::decl_local(?l)) {
+ auto var_id = fcx.locals.get(l.id);
+ auto fix_rslt = ty::unify::resolve_type_var(fcx.ccx.tcx,
+ fcx.var_bindings, var_id);
+ alt (fix_rslt) {
+ case (fix_ok(?lty)) {
+ write::ty_only(fcx.ccx.tcx, l.ann.id, lty);
+ }
+ case (fix_err(_)) {
+ fcx.ccx.tcx.sess.span_err(d.span,
+ "cannot determine a type for this local " +
+ "variable");
+ }
+ }
+ }
+ case (_) { /* no-op */ }
}
}
- fn resolve_local_types_in_block(&@fn_ctxt fcx, &ast::block block) {
+ fn resolve_type_vars_in_block(&@fn_ctxt fcx, &ast::block block) {
// A trick to ignore any contained items.
auto ignore = @mutable false;
fn visit_item_pre(@mutable bool ignore, &@ast::item item) {
visit_stmt_pre=bind visit_stmt_pre(fcx, _),
visit_expr_pre=bind visit_expr_pre(fcx, _),
visit_block_pre=bind visit_block_pre(fcx, _),
- visit_arm_pre=bind visit_arm_pre(fcx, _),
+ visit_pat_pre=bind visit_pat_pre(fcx, _),
visit_decl_pre=bind visit_decl_pre(fcx, _)
with walk::default_visitor());
walk::walk_block(visit, block);
}
+// Local variable gathering. We gather up all locals and create variable IDs
+// for them before typechecking the function.
+
+type gather_result = rec(
+ @ty::unify::var_bindings var_bindings,
+ hashmap[ast::def_id,int] locals,
+ hashmap[ast::def_id,ast::ident] local_names,
+ int next_var_id
+);
+
+fn gather_locals(&@crate_ctxt ccx, &ast::fn_decl decl, &ast::block body,
+ &ast::ann ann) -> gather_result {
+ fn next_var_id(@mutable int nvi) -> int {
+ auto rv = *nvi;
+ *nvi += 1;
+ ret rv;
+ }
+
+ fn assign(&ty::ctxt tcx,
+ &@ty::unify::var_bindings var_bindings,
+ &hashmap[ast::def_id,int] locals,
+ &hashmap[ast::def_id,ast::ident] local_names,
+ @mutable int nvi,
+ ast::def_id lid,
+ &ast::ident ident,
+ option::t[ty::t] ty_opt) {
+ auto var_id = next_var_id(nvi);
+ locals.insert(lid, var_id);
+ local_names.insert(lid, ident);
+
+ alt (ty_opt) {
+ case (none[ty::t]) { /* nothing to do */ }
+ case (some[ty::t](?typ)) {
+ ty::unify::unify(ty::mk_var(tcx, var_id), typ, var_bindings,
+ tcx);
+ }
+ }
+ }
+
+ auto vb = ty::unify::mk_var_bindings();
+ auto locals = new_def_hash[int]();
+ auto local_names = new_def_hash[ast::ident]();
+ auto nvi = @mutable 0;
+
+ // Add object fields, if any.
+ alt (get_obj_info(ccx)) {
+ case (option::some(?oinfo)) {
+ for (ast::obj_field f in oinfo.obj_fields) {
+ auto field_ty = ty::ann_to_type(ccx.tcx, f.ann);
+ assign(ccx.tcx, vb, locals, local_names, nvi, f.id, f.ident,
+ some[ty::t](field_ty));
+ }
+ }
+ case (option::none) { /* no fields */ }
+ }
+
+ // Add formal parameters.
+ auto args = ty::ty_fn_args(ccx.tcx, ty::ann_to_type(ccx.tcx, ann));
+ auto i = 0u;
+ for (ty::arg arg in args) {
+ assign(ccx.tcx, vb, locals, local_names, nvi, decl.inputs.(i).id,
+ decl.inputs.(i).ident, some[ty::t](arg.ty));
+ i += 1u;
+ }
+
+ // Add explicitly-declared locals.
+ fn visit_decl_pre(@crate_ctxt ccx,
+ @ty::unify::var_bindings vb,
+ hashmap[ast::def_id,int] locals,
+ hashmap[ast::def_id,ast::ident] local_names,
+ @mutable int nvi,
+ &@ast::decl d) {
+ alt (d.node) {
+ case (ast::decl_local(?local)) {
+ alt (local.ty) {
+ case (none) {
+ // Auto slot.
+ assign(ccx.tcx, vb, locals, local_names, nvi,
+ local.id, local.ident, none[ty::t]);
+ }
+ case (some(?ast_ty)) {
+ // Explicitly typed slot.
+ auto local_ty = ast_ty_to_ty_crate(ccx, ast_ty);
+ assign(ccx.tcx, vb, locals, local_names, nvi,
+ local.id, local.ident, some[ty::t](local_ty));
+ }
+ }
+ }
+ case (_) { /* no-op */ }
+ }
+ }
+
+ // Add pattern bindings.
+ fn visit_pat_pre(@crate_ctxt ccx,
+ @ty::unify::var_bindings vb,
+ hashmap[ast::def_id,int] locals,
+ hashmap[ast::def_id,ast::ident] local_names,
+ @mutable int nvi,
+ &@ast::pat p) {
+ alt (p.node) {
+ case (ast::pat_bind(?ident, ?did, _)) {
+ assign(ccx.tcx, vb, locals, local_names, nvi, did, ident,
+ none[ty::t]);
+ }
+ case (_) { /* no-op */ }
+ }
+ }
+
+ auto visit =
+ rec(visit_decl_pre=bind visit_decl_pre(ccx, vb, locals, local_names,
+ nvi, _),
+ visit_pat_pre=bind visit_pat_pre(ccx, vb, locals, local_names,
+ nvi, _)
+ with walk::default_visitor());
+ walk::walk_block(visit, body);
+
+ ret rec(
+ var_bindings=vb,
+ locals=locals,
+ local_names=local_names,
+ next_var_id=*nvi
+ );
+}
+
+
// AST fragment utilities
-fn replace_expr_type(&@stmt_ctxt scx,
+fn replace_expr_type(&@fn_ctxt fcx,
&@ast::expr expr,
&tup(vec[ty::t], ty::t) new_tyt) {
auto new_tps;
- if (ty::expr_has_ty_params(scx.fcx.ccx.tcx.node_types, expr)) {
+ if (ty::expr_has_ty_params(fcx.ccx.tcx, expr)) {
new_tps = some[vec[ty::t]](new_tyt._0);
} else {
new_tps = none[vec[ty::t]];
}
- write::ty_fixup(scx, ty::expr_ann(expr).id, tup(new_tps, new_tyt._1));
+ write::ty_fixup(fcx, ty::expr_ann(expr).id, tup(new_tps, new_tyt._1));
+}
+
+fn replace_node_type_only(&ty::ctxt tcx, uint fixup, ty::t new_t) {
+ auto fixup_opt = tcx.node_types.(fixup);
+ auto tps = option::get[ty::ty_param_substs_opt_and_ty](fixup_opt)._0;
+ tcx.node_types.(fixup) =
+ some[ty::ty_param_substs_opt_and_ty](tup(tps, new_t));
}
fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t {
alt (lit.node) {
- case (ast::lit_str(_)) { ret ty::mk_str(ccx.tcx); }
+ case (ast::lit_str(_, ast::sk_rc)) { ret ty::mk_str(ccx.tcx); }
+ case (ast::lit_str(_, ast::sk_unique)) { ret ty::mk_istr(ccx.tcx); }
case (ast::lit_char(_)) { ret ty::mk_char(ccx.tcx); }
case (ast::lit_int(_)) { ret ty::mk_int(ccx.tcx); }
case (ast::lit_float(_)) { ret ty::mk_float(ccx.tcx); }
case (ast::lit_nil) { ret ty::mk_nil(ccx.tcx); }
case (ast::lit_bool(_)) { ret ty::mk_bool(ccx.tcx); }
}
-
- fail; // not reached
}
-fn check_pat(&@stmt_ctxt scx, &@ast::pat pat) {
+// Pattern checking is top-down rather than bottom-up so that bindings get
+// their types immediately.
+fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) {
alt (pat.node) {
case (ast::pat_wild(?ann)) {
- auto typ = next_ty_var(scx);
- write::ty_only_fixup(scx, ann.id, typ);
+ write::ty_only_fixup(fcx, ann.id, expected);
}
case (ast::pat_lit(?lt, ?ann)) {
- auto typ = check_lit(scx.fcx.ccx, lt);
- write::ty_only_fixup(scx, ann.id, typ);
- }
- case (ast::pat_bind(?id, ?def_id, ?a)) {
- auto typ = next_ty_var(scx);
- write::ty_only_fixup(scx, a.id, typ);
- }
- case (ast::pat_tag(?p, ?subpats, ?old_ann)) {
- auto vdef = ast::variant_def_ids
- (scx.fcx.ccx.tcx.def_map.get(old_ann.id));
- auto t = ty::lookup_item_type(scx.fcx.ccx.tcx,
- vdef._1)._1;
- auto len = vec::len[ast::ident](p.node.idents);
- auto last_id = p.node.idents.(len - 1u);
-
- auto tpt = ty::lookup_item_type(scx.fcx.ccx.tcx,
- vdef._0);
-
- auto path_tpot = instantiate_path(scx, p, tpt, pat.span);
-
- alt (struct(scx.fcx.ccx.tcx, t)) {
- // N-ary variants have function types.
- case (ty::ty_fn(_, ?args, ?tag_ty, _)) {
- auto arg_len = vec::len[arg](args);
- auto subpats_len = vec::len[@ast::pat](subpats);
- if (arg_len != subpats_len) {
- // TODO: pluralize properly
- auto err_msg = "tag type " + last_id + " has " +
- uint::to_str(arg_len, 10u) +
- " field(s), but this pattern has " +
- uint::to_str(subpats_len, 10u) +
- " field(s)";
-
- scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg);
- fail; // TODO: recover
- }
-
- for (@ast::pat subpat in subpats) {
- check_pat(scx, subpat);
- }
-
- write::ty_fixup(scx, old_ann.id, path_tpot);
- }
-
- // Nullary variants have tag types.
- case (ty::ty_tag(?tid, _)) {
- auto subpats_len = vec::len[@ast::pat](subpats);
- if (subpats_len > 0u) {
- // TODO: pluralize properly
- auto err_msg = "tag type " + last_id +
- " has no field(s)," +
- " but this pattern has " +
- uint::to_str(subpats_len, 10u) +
- " field(s)";
-
- scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg);
- fail; // TODO: recover
- }
-
- write::ty_fixup(scx, old_ann.id, path_tpot);
+ auto typ = check_lit(fcx.ccx, lt);
+ typ = demand::simple(fcx, pat.span, expected, typ);
+ write::ty_only_fixup(fcx, ann.id, typ);
+ }
+ case (ast::pat_bind(?id, ?def_id, ?ann)) {
+ auto vid = fcx.locals.get(def_id);
+ auto typ = ty::mk_var(fcx.ccx.tcx, vid);
+ typ = demand::simple(fcx, pat.span, expected, typ);
+ write::ty_only_fixup(fcx, ann.id, typ);
+ }
+ case (ast::pat_tag(?path, ?subpats, ?ann)) {
+ // Typecheck the path.
+ auto v_def = fcx.ccx.tcx.def_map.get(ann.id);
+ auto v_def_ids = ast::variant_def_ids(v_def);
+
+ auto tag_tpt = ty::lookup_item_type(fcx.ccx.tcx,
+ v_def_ids._0);
+ auto path_tpot = instantiate_path(fcx, path, tag_tpt, pat.span);
+
+ // Take the tag type params out of `expected`.
+ auto expected_tps;
+ alt (structure_of(fcx, pat.span, expected)) {
+ case (ty::ty_tag(_, ?tps)) { expected_tps = tps; }
+ case (_) {
+ // FIXME: Switch expected and actual in this message? I
+ // can never tell.
+ fcx.ccx.tcx.sess.span_err(pat.span,
+ #fmt("mismatched types: expected tag but found %s",
+ ty_to_str(fcx.ccx.tcx, expected)));
+ }
+ }
+
+ // Unify with the expected tag type.
+ auto ctor_ty = ty::ty_param_substs_opt_and_ty_to_monotype(
+ fcx.ccx.tcx, path_tpot);
+ auto path_tpt = demand::full(fcx, pat.span, expected, ctor_ty,
+ expected_tps, NO_AUTODEREF);
+ path_tpot = tup(some[vec[ty::t]](path_tpt._0), path_tpt._1);
+
+ // Get the number of arguments in this tag variant.
+ auto arg_types = variant_arg_types(fcx.ccx, pat.span,
+ v_def_ids._1, expected_tps);
+
+ auto subpats_len = vec::len[@ast::pat](subpats);
+
+ if (vec::len[ty::t](arg_types) > 0u) {
+ // N-ary variant.
+ auto arg_len = vec::len[ty::t](arg_types);
+ if (arg_len != subpats_len) {
+ // TODO: note definition of tag variant
+ // TODO (issue #448): Wrap a #fmt string over multiple
+ // lines...
+ fcx.ccx.tcx.sess.span_err(pat.span, #fmt(
+ "this pattern has %u field%s, but the corresponding variant has %u field%s",
+ subpats_len,
+ if (subpats_len == 1u) { "" } else { "s" },
+ arg_len,
+ if (arg_len == 1u) { "" } else { "s" }));
+ }
+
+ // TODO: vec::iter2
+ auto i = 0u;
+ for (@ast::pat subpat in subpats) {
+ check_pat(fcx, subpat, arg_types.(i));
+ i += 1u;
}
+ } else if (subpats_len > 0u) {
+ // TODO: note definition of tag variant
+ // TODO (issue #448): Wrap a #fmt string over multiple
+ // lines...
+ fcx.ccx.tcx.sess.span_err(pat.span, #fmt(
+"this pattern has %u field%s, but the corresponding variant has no fields",
+ subpats_len,
+ if (subpats_len == 1u) { "" } else { "s" }));
}
+
+ write::ty_fixup(fcx, ann.id, path_tpot);
}
}
}
}
}
-fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
- // scx.fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
+fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
+ // fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
// pretty::pprust::expr_to_str(expr));
// A generic function to factor out common logic from call and bind
// expressions.
- fn check_call_or_bind(&@stmt_ctxt scx, &@ast::expr f,
+ fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f,
&vec[option::t[@ast::expr]] args) {
// Check the function.
- check_expr(scx, f);
+ check_expr(fcx, f);
- // Check the arguments and generate the argument signature.
- let vec[option::t[@ast::expr]] args_0 = [];
- let vec[arg] arg_tys_0 = [];
- for (option::t[@ast::expr] a_opt in args) {
- alt (a_opt) {
- case (some(?a)) {
- check_expr(scx, a);
- auto typ = expr_ty(scx.fcx.ccx.tcx, a);
- vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ));
- }
- case (none) {
- auto typ = next_ty_var(scx);
- vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ));
- }
- }
- }
+ // Get the function type.
+ auto fty = expr_ty(fcx.ccx.tcx, f);
- auto rt_0 = next_ty_var(scx);
- auto t_0;
- alt (struct(scx.fcx.ccx.tcx, expr_ty(scx.fcx.ccx.tcx, f))) {
- case (ty::ty_fn(?proto, _, _, ?cf)) {
- t_0 = ty::mk_fn(scx.fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf);
+ // Grab the argument types and the return type.
+ auto arg_tys;
+ alt (structure_of(fcx, sp, fty)) {
+ case (ty::ty_fn(_, ?arg_tys_0, _, _, _)) {
+ arg_tys = arg_tys_0;
}
- case (ty::ty_native_fn(?abi, _, _)) {
- t_0 = ty::mk_native_fn(scx.fcx.ccx.tcx, abi, arg_tys_0, rt_0);
+ case (ty::ty_native_fn(_, ?arg_tys_0, _)) {
+ arg_tys = arg_tys_0;
}
- case (?u) {
- scx.fcx.ccx.tcx.sess.span_err(f.span,
- "check_call_or_bind(): fn expr doesn't have fn type,"
- + " instead having: " +
- ty_to_str(scx.fcx.ccx.tcx,
- expr_ty(scx.fcx.ccx.tcx, f)));
- fail;
+ case (_) {
+ fcx.ccx.tcx.sess.span_err(f.span, "mismatched types: " +
+ "expected function or native function but found " +
+ ty_to_str(fcx.ccx.tcx, fty));
}
}
- // Unify the callee and arguments.
- auto tpt_0 = ty::expr_ty_params_and_ty(scx.fcx.ccx.tcx, f);
- auto tpt_1 = demand::full(scx, f.span, tpt_0._1, t_0, tpt_0._0,
- NO_AUTODEREF);
- replace_expr_type(scx, f, tpt_1);
+ // Check that the correct number of arguments were supplied.
+ auto expected_arg_count = vec::len[ty::arg](arg_tys);
+ auto supplied_arg_count = vec::len[option::t[@ast::expr]](args);
+ if (expected_arg_count != supplied_arg_count) {
+ fcx.ccx.tcx.sess.span_err(sp,
+ #fmt("this function takes %u parameter%s but %u parameter%s \
+ supplied",
+ expected_arg_count,
+ if (expected_arg_count == 1u) { "" } else { "s" },
+ supplied_arg_count,
+ if (supplied_arg_count == 1u) { " was" }
+ else { "s were" }));
+ }
+
+ // Check the arguments.
+ // TODO: iter2
+ auto i = 0u;
+ for (option::t[@ast::expr] a_opt in args) {
+ 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 */ }
+ }
+ i += 1u;
+ }
}
// A generic function for checking assignment expressions
- fn check_assignment(&@stmt_ctxt scx, &@ast::expr lhs, &@ast::expr rhs,
- &ast::ann a) {
- check_expr(scx, lhs);
- check_expr(scx, rhs);
- auto lhs_t0 = expr_ty(scx.fcx.ccx.tcx, lhs);
- auto rhs_t0 = expr_ty(scx.fcx.ccx.tcx, rhs);
-
- pushdown::pushdown_expr(scx, rhs_t0, lhs);
- auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs);
- pushdown::pushdown_expr(scx, lhs_t1, rhs);
- auto rhs_t1 = expr_ty(scx.fcx.ccx.tcx, rhs);
-
- write::ty_only_fixup(scx, a.id, rhs_t1);
+ fn check_assignment(&@fn_ctxt fcx, &span sp, &@ast::expr lhs,
+ &@ast::expr rhs, &ast::ann a) {
+ check_expr(fcx, lhs);
+ check_expr(fcx, rhs);
+ auto typ = demand::simple(fcx, sp,
+ expr_ty(fcx.ccx.tcx, lhs),
+ expr_ty(fcx.ccx.tcx, rhs));
+ write::ty_only_fixup(fcx, a.id, typ);
}
// A generic function for checking call expressions
- fn check_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) {
+ fn check_call(&@fn_ctxt fcx, &span sp, &@ast::expr f,
+ &vec[@ast::expr] args) {
let vec[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(scx, f, args_opt_0);
+ check_call_or_bind(fcx, sp, f, args_opt_0);
}
// A generic function for checking for or for-each loops
- fn check_for_or_for_each(&@stmt_ctxt scx, &@ast::decl decl,
+ fn check_for_or_for_each(&@fn_ctxt fcx, &@ast::decl decl,
&ty::t element_ty, &ast::block body,
uint node_id) {
- check_decl_local(scx.fcx, decl);
- check_block(scx, body);
+ check_decl_local(fcx, decl);
+ check_block(fcx, body);
// Unify type of decl with element type of the seq
- demand::simple(scx, decl.span, ty::decl_local_ty(scx.fcx.ccx.tcx,
+ demand::simple(fcx, decl.span, ty::decl_local_ty(fcx.ccx.tcx,
decl),
element_ty);
- auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
- write::ty_only_fixup(scx, node_id, typ);
+ auto typ = ty::mk_nil(fcx.ccx.tcx);
+ write::ty_only_fixup(fcx, node_id, typ);
}
alt (expr.node) {
case (ast::expr_lit(?lit, ?a)) {
- auto typ = check_lit(scx.fcx.ccx, lit);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = check_lit(fcx.ccx, lit);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (ast::expr_binary(?binop, ?lhs, ?rhs, ?a)) {
- check_expr(scx, lhs);
- check_expr(scx, rhs);
- auto lhs_t0 = expr_ty(scx.fcx.ccx.tcx, lhs);
- auto rhs_t0 = expr_ty(scx.fcx.ccx.tcx, rhs);
+ check_expr(fcx, lhs);
+ check_expr(fcx, rhs);
- // FIXME: Binops have a bit more subtlety than this.
- pushdown::pushdown_expr_full(scx, rhs_t0, lhs, AUTODEREF_OK);
- auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs);
- pushdown::pushdown_expr_full(scx, lhs_t1, rhs, AUTODEREF_OK);
+ auto lhs_t = expr_ty(fcx.ccx.tcx, lhs);
- auto t = strip_boxes(scx.fcx.ccx.tcx, lhs_t0);
+ // FIXME: Binops have a bit more subtlety than this.
+ auto t = strip_boxes(fcx, expr.span, lhs_t);
alt (binop) {
- case (ast::eq) { t = ty::mk_bool(scx.fcx.ccx.tcx); }
- case (ast::lt) { t = ty::mk_bool(scx.fcx.ccx.tcx); }
- case (ast::le) { t = ty::mk_bool(scx.fcx.ccx.tcx); }
- case (ast::ne) { t = ty::mk_bool(scx.fcx.ccx.tcx); }
- case (ast::ge) { t = ty::mk_bool(scx.fcx.ccx.tcx); }
- case (ast::gt) { t = ty::mk_bool(scx.fcx.ccx.tcx); }
+ case (ast::eq) { t = ty::mk_bool(fcx.ccx.tcx); }
+ case (ast::lt) { t = ty::mk_bool(fcx.ccx.tcx); }
+ case (ast::le) { t = ty::mk_bool(fcx.ccx.tcx); }
+ case (ast::ne) { t = ty::mk_bool(fcx.ccx.tcx); }
+ case (ast::ge) { t = ty::mk_bool(fcx.ccx.tcx); }
+ case (ast::gt) { t = ty::mk_bool(fcx.ccx.tcx); }
case (_) { /* fall through */ }
}
- write::ty_only_fixup(scx, a.id, t);
+ write::ty_only_fixup(fcx, a.id, t);
}
case (ast::expr_unary(?unop, ?oper, ?a)) {
- check_expr(scx, oper);
+ check_expr(fcx, oper);
- auto oper_t = expr_ty(scx.fcx.ccx.tcx, oper);
+ auto oper_t = expr_ty(fcx.ccx.tcx, oper);
alt (unop) {
case (ast::box(?mut)) {
- oper_t = ty::mk_box(scx.fcx.ccx.tcx,
+ oper_t = ty::mk_box(fcx.ccx.tcx,
rec(ty=oper_t, mut=mut));
}
case (ast::deref) {
- alt (struct(scx.fcx.ccx.tcx, oper_t)) {
+ alt (structure_of(fcx, expr.span, oper_t)) {
case (ty::ty_box(?inner)) { oper_t = inner.ty; }
case (_) {
- scx.fcx.ccx.tcx.sess.span_err
+ fcx.ccx.tcx.sess.span_err
(expr.span,
"dereferencing non-box type: "
- + ty_to_str(scx.fcx.ccx.tcx, oper_t));
+ + ty_to_str(fcx.ccx.tcx, oper_t));
}
}
}
- case (_) { oper_t = strip_boxes(scx.fcx.ccx.tcx, oper_t); }
+ case (ast::not) {
+ if (!type_is_integral(fcx, oper.span, oper_t) &&
+ structure_of(fcx, oper.span, oper_t)
+ != ty::ty_bool) {
+ fcx.ccx.tcx.sess.span_err(expr.span,
+ #fmt("mismatched types: expected bool or \
+ integer but found %s",
+ ty_to_str(fcx.ccx.tcx, oper_t)));
+ }
+ }
+ case (_) { oper_t = strip_boxes(fcx, expr.span, oper_t); }
}
- write::ty_only_fixup(scx, a.id, oper_t);
+ write::ty_only_fixup(fcx, a.id, oper_t);
}
case (ast::expr_path(?pth, ?old_ann)) {
- auto t = ty::mk_nil(scx.fcx.ccx.tcx);
- auto defn = scx.fcx.ccx.tcx.def_map.get(old_ann.id);
+ auto t = ty::mk_nil(fcx.ccx.tcx);
+ auto defn = fcx.ccx.tcx.def_map.get(old_ann.id);
- auto tpt = ty_param_count_and_ty_for_def(scx.fcx, expr.span,
+ auto tpt = ty_param_count_and_ty_for_def(fcx, expr.span,
defn);
if (ty::def_has_ty_params(defn)) {
- auto path_tpot = instantiate_path(scx, pth, tpt, expr.span);
- write::ty_fixup(scx, old_ann.id, path_tpot);
+ auto path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
+ write::ty_fixup(fcx, old_ann.id, path_tpot);
ret;
}
// The definition doesn't take type parameters. If the programmer
// supplied some, that's an error.
if (vec::len[@ast::ty](pth.node.types) > 0u) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"this kind of value does not take type parameters");
- fail;
}
- write::ty_only_fixup(scx, old_ann.id, tpt._1);
+ write::ty_only_fixup(fcx, old_ann.id, tpt._1);
}
case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?a)) {
- check_expr(scx, expanded);
- auto t = expr_ty(scx.fcx.ccx.tcx, expanded);
- write::ty_only_fixup(scx, a.id, t);
+ check_expr(fcx, expanded);
+ auto t = expr_ty(fcx.ccx.tcx, expanded);
+ write::ty_only_fixup(fcx, a.id, t);
}
- case (ast::expr_fail(?a)) {
- write::bot_ty(scx.fcx.ccx.tcx, a.id);
+ case (ast::expr_fail(?a, _)) {
+ write::bot_ty(fcx.ccx.tcx, a.id);
}
case (ast::expr_break(?a)) {
- write::bot_ty(scx.fcx.ccx.tcx, a.id);
+ write::bot_ty(fcx.ccx.tcx, a.id);
}
case (ast::expr_cont(?a)) {
- write::bot_ty(scx.fcx.ccx.tcx, a.id);
+ write::bot_ty(fcx.ccx.tcx, a.id);
}
case (ast::expr_ret(?expr_opt, ?a)) {
alt (expr_opt) {
case (none) {
- auto nil = ty::mk_nil(scx.fcx.ccx.tcx);
- if (!are_compatible(scx, scx.fcx.ret_ty, nil)) {
- // TODO: span_err
- scx.fcx.ccx.tcx.sess.err("ret; in function " +
- "returning non-nil");
+ auto nil = ty::mk_nil(fcx.ccx.tcx);
+ if (!are_compatible(fcx, fcx.ret_ty, nil)) {
+ fcx.ccx.tcx.sess.span_err(expr.span,
+ "ret; in function returning non-nil");
}
- write::bot_ty(scx.fcx.ccx.tcx, a.id);
+ write::bot_ty(fcx.ccx.tcx, a.id);
}
case (some(?e)) {
- check_expr(scx, e);
- pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e);
-
- write::bot_ty(scx.fcx.ccx.tcx, a.id);
+ check_expr(fcx, e);
+ demand::simple(fcx, expr.span, fcx.ret_ty,
+ expr_ty(fcx.ccx.tcx, e));
+ write::bot_ty(fcx.ccx.tcx, a.id);
}
}
}
case (ast::expr_put(?expr_opt, ?a)) {
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
alt (expr_opt) {
case (none) {
- auto nil = ty::mk_nil(scx.fcx.ccx.tcx);
- if (!are_compatible(scx, scx.fcx.ret_ty, nil)) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ auto nil = ty::mk_nil(fcx.ccx.tcx);
+ if (!are_compatible(fcx, fcx.ret_ty, nil)) {
+ fcx.ccx.tcx.sess.span_err(expr.span,
"put; in iterator yielding non-nil");
}
- write::nil_ty(scx.fcx.ccx.tcx, a.id);
+ write::nil_ty(fcx.ccx.tcx, a.id);
}
case (some(?e)) {
- check_expr(scx, e);
- pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e);
-
- write::nil_ty(scx.fcx.ccx.tcx, a.id);
+ check_expr(fcx, e);
+ write::nil_ty(fcx.ccx.tcx, a.id);
}
}
}
// FIXME: prove instead of assert
assert (ast::is_call_expr(e));
- check_expr(scx, e);
- pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e);
+ check_expr(fcx, e);
+ demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e));
- write::nil_ty(scx.fcx.ccx.tcx, a.id);
+ write::nil_ty(fcx.ccx.tcx, a.id);
}
case (ast::expr_log(?l, ?e, ?a)) {
- auto expr_t = check_expr(scx, e);
- write::nil_ty(scx.fcx.ccx.tcx, a.id);
+ auto expr_t = check_expr(fcx, e);
+ write::nil_ty(fcx.ccx.tcx, a.id);
}
case (ast::expr_check(?e, ?a)) {
- check_expr(scx, e);
- demand::simple(scx, expr.span, ty::mk_bool(scx.fcx.ccx.tcx),
- expr_ty(scx.fcx.ccx.tcx, e));
+ check_expr(fcx, e);
+ demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx),
+ expr_ty(fcx.ccx.tcx, e));
/* e must be a call expr where all arguments are either
literals or slots */
alt (e.node) {
alt (operator.node) {
case (ast::expr_path(?oper_name, ?ann)) {
auto d_id;
- alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) {
+ alt (fcx.ccx.tcx.def_map.get(ann.id)) {
case (ast::def_fn(?_d_id)) { d_id = _d_id; }
}
for (@ast::expr operand in operands) {
if (! ast::is_constraint_arg(operand)) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"Constraint args must be "
+ "slot variables or literals");
}
}
- require_pure_function(scx.fcx.ccx, d_id,
+ require_pure_function(fcx.ccx, d_id,
expr.span);
- write::nil_ty(scx.fcx.ccx.tcx, a.id);
+ write::nil_ty(fcx.ccx.tcx, a.id);
}
case (_) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"In a constraint, expected the constraint name "
+ "to be an explicit name");
}
}
}
case (_) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"check on non-predicate");
}
}
}
case (ast::expr_assert(?e, ?a)) {
- check_expr(scx, e);
- auto ety = expr_ty(scx.fcx.ccx.tcx, e);
- demand::simple(scx, expr.span, ty::mk_bool(scx.fcx.ccx.tcx), ety);
+ check_expr(fcx, e);
+ auto ety = expr_ty(fcx.ccx.tcx, e);
+ demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), ety);
- write::nil_ty(scx.fcx.ccx.tcx, a.id);
+ write::nil_ty(fcx.ccx.tcx, a.id);
}
case (ast::expr_move(?lhs, ?rhs, ?a)) {
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
- check_assignment(scx, lhs, rhs, a);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
+ check_assignment(fcx, expr.span, lhs, rhs, a);
}
case (ast::expr_assign(?lhs, ?rhs, ?a)) {
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
- check_assignment(scx, lhs, rhs, a);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
+ check_assignment(fcx, expr.span, lhs, rhs, a);
}
case (ast::expr_assign_op(?op, ?lhs, ?rhs, ?a)) {
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
- check_assignment(scx, lhs, rhs, a);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
+ check_assignment(fcx, expr.span, lhs, rhs, a);
}
case (ast::expr_send(?lhs, ?rhs, ?a)) {
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
- check_expr(scx, lhs);
- check_expr(scx, rhs);
- auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs);
+ check_expr(fcx, lhs);
+ check_expr(fcx, rhs);
+ auto rhs_t = expr_ty(fcx.ccx.tcx, rhs);
+
+ auto chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t);
- auto chan_t = ty::mk_chan(scx.fcx.ccx.tcx, rhs_t);
- pushdown::pushdown_expr(scx, chan_t, lhs);
auto item_t;
- auto lhs_t = expr_ty(scx.fcx.ccx.tcx, lhs);
- alt (struct(scx.fcx.ccx.tcx, lhs_t)) {
+ auto lhs_t = expr_ty(fcx.ccx.tcx, lhs);
+ alt (structure_of(fcx, expr.span, lhs_t)) {
case (ty::ty_chan(?it)) { item_t = it; }
- case (_) { fail; }
+ case (_) {
+ fcx.ccx.tcx.sess.span_err(expr.span,
+ #fmt("mismatched types: expected chan but found %s",
+ ty_to_str(fcx.ccx.tcx, lhs_t)));
+ }
}
- pushdown::pushdown_expr(scx, item_t, rhs);
- write::ty_only_fixup(scx, a.id, chan_t);
+ write::ty_only_fixup(fcx, a.id, chan_t);
}
case (ast::expr_recv(?lhs, ?rhs, ?a)) {
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
- check_expr(scx, lhs);
- check_expr(scx, rhs);
- auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs);
+ check_expr(fcx, lhs);
+ check_expr(fcx, rhs);
- auto port_t = ty::mk_port(scx.fcx.ccx.tcx, lhs_t1);
- pushdown::pushdown_expr(scx, port_t, rhs);
- auto item_t;
- auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs);
- alt (struct(scx.fcx.ccx.tcx, rhs_t)) {
- case (ty::ty_port(?it)) { item_t = it; }
- case (_) { fail; }
- }
- pushdown::pushdown_expr(scx, item_t, lhs);
+ auto item_t = expr_ty(fcx.ccx.tcx, lhs);
+ auto port_t = ty::mk_port(fcx.ccx.tcx, item_t);
+ demand::simple(fcx, expr.span, port_t, expr_ty(fcx.ccx.tcx, rhs));
- write::ty_only_fixup(scx, a.id, item_t);
+ write::ty_only_fixup(fcx, a.id, item_t);
}
case (ast::expr_if(?cond, ?thn, ?elsopt, ?a)) {
- check_expr(scx, cond);
- pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx),
- cond);
-
- check_block(scx, thn);
+ check_expr(fcx, cond);
+ check_block(fcx, thn);
auto if_t = alt (elsopt) {
case (some(?els)) {
- check_expr(scx, els);
+ check_expr(fcx, els);
- auto thn_t = block_ty(scx.fcx.ccx.tcx, thn);
- auto elsopt_t = expr_ty(scx.fcx.ccx.tcx, els);
- if (!ty::type_is_bot(scx.fcx.ccx.tcx, elsopt_t)) {
+ auto thn_t = block_ty(fcx.ccx.tcx, thn);
+ auto elsopt_t = expr_ty(fcx.ccx.tcx, els);
+
+ demand::simple(fcx, expr.span, thn_t, elsopt_t);
+
+ if (!ty::type_is_bot(fcx.ccx.tcx, elsopt_t)) {
elsopt_t
} else {
thn_t
}
}
case (none) {
- ty::mk_nil(scx.fcx.ccx.tcx)
+ ty::mk_nil(fcx.ccx.tcx)
}
};
- write::ty_only_fixup(scx, a.id, if_t);
+ write::ty_only_fixup(fcx, a.id, if_t);
}
case (ast::expr_for(?decl, ?seq, ?body, ?a)) {
- check_expr(scx, seq);
- alt (struct (scx.fcx.ccx.tcx,
- expr_ty(scx.fcx.ccx.tcx, seq))) {
+ check_expr(fcx, seq);
+ alt (structure_of(fcx, expr.span, expr_ty(fcx.ccx.tcx, seq))) {
// FIXME: I include the check_for_or_each call in
// each case because of a bug in typestate.
// The bug is fixed; once there's a new snapshot,
// the call can be moved out of the alt expression
case (ty::ty_vec(?vec_elt_ty)) {
auto elt_ty = vec_elt_ty.ty;
- check_for_or_for_each(scx, decl, elt_ty, body, a.id);
+ check_for_or_for_each(fcx, decl, elt_ty, body, a.id);
}
case (ty::ty_str) {
- auto elt_ty = ty::mk_mach(scx.fcx.ccx.tcx,
+ auto elt_ty = ty::mk_mach(fcx.ccx.tcx,
util::common::ty_u8);
- check_for_or_for_each(scx, decl, elt_ty, body, a.id);
+ check_for_or_for_each(fcx, decl, elt_ty, body, a.id);
}
case (_) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"type of for loop iterator is not a vector or string");
}
}
}
case (ast::expr_for_each(?decl, ?seq, ?body, ?a)) {
- check_expr(scx, seq);
- check_for_or_for_each(scx, decl, expr_ty(scx.fcx.ccx.tcx, seq),
+ check_expr(fcx, seq);
+ check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq),
body, a.id);
}
case (ast::expr_while(?cond, ?body, ?a)) {
- check_expr(scx, cond);
- pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), cond);
- check_block(scx, body);
+ check_expr(fcx, cond);
+ check_block(fcx, body);
+
+ demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx),
+ expr_ty(fcx.ccx.tcx, cond));
- auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = ty::mk_nil(fcx.ccx.tcx);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (ast::expr_do_while(?body, ?cond, ?a)) {
- check_expr(scx, cond);
- pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), cond);
- check_block(scx, body);
+ check_expr(fcx, cond);
+ check_block(fcx, body);
- auto typ = block_ty(scx.fcx.ccx.tcx, body);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = block_ty(fcx.ccx.tcx, body);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (ast::expr_alt(?expr, ?arms, ?a)) {
- check_expr(scx, expr);
+ check_expr(fcx, expr);
// Typecheck the patterns first, so that we get types for all the
// bindings.
- auto pattern_ty = expr_ty(scx.fcx.ccx.tcx, expr);
+ auto pattern_ty = ty::expr_ty(fcx.ccx.tcx, expr);
let vec[@ast::pat] pats = [];
for (ast::arm arm in arms) {
- check_pat(scx, arm.pat);
- pattern_ty = demand::simple(scx, arm.pat.span, pattern_ty,
- pat_ty(scx.fcx.ccx.tcx, arm.pat));
+ check_pat(fcx, arm.pat, pattern_ty);
pats += [arm.pat];
}
- for (@ast::pat pat in pats) {
- pushdown::pushdown_pat(scx, pattern_ty, pat);
- }
-
// Now typecheck the blocks.
- auto result_ty = next_ty_var(scx);
+ auto result_ty = next_ty_var(fcx);
let vec[ast::block] blocks = [];
for (ast::arm arm in arms) {
- check_block(scx, arm.block);
+ check_block(fcx, arm.block);
- auto bty = block_ty(scx.fcx.ccx.tcx, arm.block);
+ auto bty = block_ty(fcx.ccx.tcx, arm.block);
// Failing alt arms don't need to have a matching type
- if (!ty::type_is_bot(scx.fcx.ccx.tcx, bty)) {
- result_ty = demand::simple(scx, arm.block.span,
+ if (!ty::type_is_bot(fcx.ccx.tcx, bty)) {
+ result_ty = demand::simple(fcx, arm.block.span,
result_ty, bty);
}
}
- auto i = 0u;
- for (ast::block bloc in blocks) {
- pushdown::pushdown_block(scx, result_ty, bloc);
- }
-
- pushdown::pushdown_expr(scx, pattern_ty, expr);
-
- write::ty_only_fixup(scx, a.id, result_ty);
+ write::ty_only_fixup(fcx, a.id, result_ty);
}
case (ast::expr_block(?b, ?a)) {
- check_block(scx, b);
+ check_block(fcx, b);
alt (b.node.expr) {
case (some(?expr)) {
- auto typ = expr_ty(scx.fcx.ccx.tcx, expr);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = expr_ty(fcx.ccx.tcx, expr);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (none) {
- auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = ty::mk_nil(fcx.ccx.tcx);
+ write::ty_only_fixup(fcx, a.id, typ);
}
}
}
case (ast::expr_bind(?f, ?args, ?a)) {
// Call the generic checker.
- check_call_or_bind(scx, f, args);
+ check_call_or_bind(fcx, expr.span, f, args);
// Pull the argument and return types out.
auto proto_1;
let vec[ty::arg] arg_tys_1 = [];
auto rt_1;
- auto fty = expr_ty(scx.fcx.ccx.tcx, f);
+ auto fty = expr_ty(fcx.ccx.tcx, f);
auto t_1;
- alt (struct(scx.fcx.ccx.tcx, fty)) {
- case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) {
+ alt (structure_of(fcx, expr.span, fty)) {
+ case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf, ?constrs)) {
proto_1 = proto;
rt_1 = rt;
+ // FIXME:
+ // probably need to munge the constrs to drop constraints
+ // for any bound args
+
// For each blank argument, add the type of that argument
// to the resulting function type.
auto i = 0u;
}
i += 1u;
}
- t_1 = ty::mk_fn(scx.fcx.ccx.tcx, proto_1, arg_tys_1, rt_1,
- cf);
+ t_1 = ty::mk_fn(fcx.ccx.tcx, proto_1, arg_tys_1, rt_1,
+ cf, constrs);
}
case (_) {
log_err "LHS of bind expr didn't have a function type?!";
fail;
}
}
- write::ty_only_fixup(scx, a.id, t_1);
+ write::ty_only_fixup(fcx, a.id, t_1);
}
case (ast::expr_call(?f, ?args, ?a)) {
need to restrict it to being an explicit expr_path if we're
inside a pure function, and need an environment mapping from
function name onto purity-designation */
- require_pure_call(scx.fcx.ccx, scx.fcx.purity, f, expr.span);
+ require_pure_call(fcx.ccx, fcx.purity, f, expr.span);
- check_call(scx, f, args);
+ check_call(fcx, expr.span, f, args);
// Pull the return type out of the type of the function.
- auto rt_1 = ty::mk_nil(scx.fcx.ccx.tcx); // FIXME: typestate botch
- auto fty = expr_ty(scx.fcx.ccx.tcx, f);
- alt (struct(scx.fcx.ccx.tcx, fty)) {
- case (ty::ty_fn(_,_,?rt,_)) { rt_1 = rt; }
+ auto rt_1;
+ auto fty = ty::expr_ty(fcx.ccx.tcx, f);
+ alt (structure_of(fcx, expr.span, fty)) {
+ case (ty::ty_fn(_,_,?rt,_, _)) { rt_1 = rt; }
case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; }
case (_) {
log_err "LHS of call expr didn't have a function type?!";
}
}
- write::ty_only_fixup(scx, a.id, rt_1);
+ write::ty_only_fixup(fcx, a.id, rt_1);
}
case (ast::expr_self_method(?id, ?a)) {
- auto t = ty::mk_nil(scx.fcx.ccx.tcx);
+ auto t = ty::mk_nil(fcx.ccx.tcx);
let ty::t this_obj_ty;
- let option::t[obj_info] this_obj_info = get_obj_info(scx.fcx.ccx);
+ let option::t[obj_info] this_obj_info = get_obj_info(fcx.ccx);
alt (this_obj_info) {
// If we're inside a current object, grab its type.
// FIXME: In the case of anonymous objects with methods
// containing self-calls, this lookup fails because
// obj_info.this_obj is not in the type cache
- this_obj_ty = ty::lookup_item_type(scx.fcx.ccx.tcx,
+ this_obj_ty = ty::lookup_item_type(fcx.ccx.tcx,
obj_info.this_obj)._1;
}
}
// Grab this method's type out of the current object type.
- alt (struct(scx.fcx.ccx.tcx, this_obj_ty)) {
+ alt (structure_of(fcx, expr.span, this_obj_ty)) {
case (ty::ty_obj(?methods)) {
for (ty::method method in methods) {
if (method.ident == id) {
- t = ty::method_ty_to_fn_ty(scx.fcx.ccx.tcx,
+ t = ty::method_ty_to_fn_ty(fcx.ccx.tcx,
method);
}
}
case (_) { fail; }
}
- write::ty_only_fixup(scx, a.id, t);
+ write::ty_only_fixup(fcx, a.id, t);
- require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span);
+ require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
}
case (ast::expr_spawn(_, _, ?f, ?args, ?a)) {
- check_call(scx, f, args);
+ check_call(fcx, expr.span, f, args);
- auto fty = expr_ty(scx.fcx.ccx.tcx, f);
- auto ret_ty = ty::ret_ty_of_fn_ty(scx.fcx.ccx.tcx, fty);
+ auto fty = expr_ty(fcx.ccx.tcx, f);
+ auto ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty);
- demand::simple(scx, f.span, ty::mk_nil(scx.fcx.ccx.tcx), ret_ty);
+ demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty);
// FIXME: Other typechecks needed
- auto typ = ty::mk_task(scx.fcx.ccx.tcx);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = ty::mk_task(fcx.ccx.tcx);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (ast::expr_cast(?e, ?t, ?a)) {
- check_expr(scx, e);
- auto t_1 = ast_ty_to_ty_crate(scx.fcx.ccx, t);
+ check_expr(fcx, e);
+ auto t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
// FIXME: there are more forms of cast to support, eventually.
- if (! (type_is_scalar(scx.fcx.ccx.tcx,
- expr_ty(scx.fcx.ccx.tcx, e)) &&
- type_is_scalar(scx.fcx.ccx.tcx, t_1))) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ if (! (type_is_scalar(fcx, expr.span, expr_ty(fcx.ccx.tcx, e)) &&
+ type_is_scalar(fcx, expr.span, t_1))) {
+ fcx.ccx.tcx.sess.span_err(expr.span,
"non-scalar cast: " +
- ty_to_str(scx.fcx.ccx.tcx,
- expr_ty(scx.fcx.ccx.tcx, e)) +
- " as " + ty_to_str(scx.fcx.ccx.tcx, t_1));
+ ty_to_str(fcx.ccx.tcx,
+ expr_ty(fcx.ccx.tcx, e)) +
+ " as " + ty_to_str(fcx.ccx.tcx, t_1));
}
- write::ty_only_fixup(scx, a.id, t_1);
+ write::ty_only_fixup(fcx, a.id, t_1);
}
- case (ast::expr_vec(?args, ?mut, ?a)) {
+ case (ast::expr_vec(?args, ?mut, ?kind, ?a)) {
let ty::t t;
if (vec::len[@ast::expr](args) == 0u) {
- t = next_ty_var(scx);
+ t = next_ty_var(fcx);
} else {
- check_expr(scx, args.(0));
- t = expr_ty(scx.fcx.ccx.tcx, args.(0));
+ check_expr(fcx, args.(0));
+ t = expr_ty(fcx.ccx.tcx, args.(0));
}
for (@ast::expr e in args) {
- check_expr(scx, e);
- auto expr_t = expr_ty(scx.fcx.ccx.tcx, e);
- demand::simple(scx, expr.span, t, expr_t);
+ check_expr(fcx, e);
+ auto expr_t = expr_ty(fcx.ccx.tcx, e);
+ demand::simple(fcx, expr.span, t, expr_t);
+ }
+
+ auto typ;
+ alt (kind) {
+ case (ast::sk_rc) {
+ typ = ty::mk_vec(fcx.ccx.tcx, rec(ty=t, mut=mut));
+ }
+ case (ast::sk_unique) {
+ typ = ty::mk_ivec(fcx.ccx.tcx, rec(ty=t, mut=mut));
+ }
}
- auto typ = ty::mk_vec(scx.fcx.ccx.tcx, rec(ty=t, mut=mut));
- write::ty_only_fixup(scx, a.id, typ);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (ast::expr_tup(?elts, ?a)) {
let vec[ty::mt] elts_mt = [];
for (ast::elt e in elts) {
- check_expr(scx, e.expr);
- auto ety = expr_ty(scx.fcx.ccx.tcx, e.expr);
+ check_expr(fcx, e.expr);
+ auto ety = expr_ty(fcx.ccx.tcx, e.expr);
elts_mt += [rec(ty=ety, mut=e.mut)];
}
- auto typ = ty::mk_tup(scx.fcx.ccx.tcx, elts_mt);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = ty::mk_tup(fcx.ccx.tcx, elts_mt);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (ast::expr_rec(?fields, ?base, ?a)) {
alt (base) {
case (none) { /* no-op */}
- case (some(?b_0)) { check_expr(scx, b_0); }
+ case (some(?b_0)) { check_expr(fcx, b_0); }
}
let vec[field] fields_t = [];
for (ast::field f in fields) {
- check_expr(scx, f.node.expr);
- auto expr_t = expr_ty(scx.fcx.ccx.tcx, f.node.expr);
+ check_expr(fcx, f.node.expr);
+ auto expr_t = expr_ty(fcx.ccx.tcx, f.node.expr);
auto expr_mt = rec(ty=expr_t, mut=f.node.mut);
vec::push[field](fields_t, rec(ident=f.node.ident,
alt (base) {
case (none) {
- auto typ = ty::mk_rec(scx.fcx.ccx.tcx, fields_t);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = ty::mk_rec(fcx.ccx.tcx, fields_t);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (some(?bexpr)) {
- check_expr(scx, bexpr);
- auto bexpr_t = expr_ty(scx.fcx.ccx.tcx, bexpr);
+ check_expr(fcx, bexpr);
+ auto bexpr_t = expr_ty(fcx.ccx.tcx, bexpr);
let vec[field] base_fields = [];
- alt (struct(scx.fcx.ccx.tcx, bexpr_t)) {
+ alt (structure_of(fcx, expr.span, bexpr_t)) {
case (ty::ty_rec(?flds)) { base_fields = flds; }
case (_) {
- scx.fcx.ccx.tcx.sess.span_err
+ fcx.ccx.tcx.sess.span_err
(expr.span,
"record update non-record base");
}
}
- write::ty_only_fixup(scx, a.id, bexpr_t);
+ write::ty_only_fixup(fcx, a.id, bexpr_t);
for (ty::field f in fields_t) {
auto found = false;
for (ty::field bf in base_fields) {
if (str::eq(f.ident, bf.ident)) {
- demand::simple(scx, expr.span, f.mt.ty,
+ demand::simple(fcx, expr.span, f.mt.ty,
bf.mt.ty);
found = true;
}
}
if (!found) {
- scx.fcx.ccx.tcx.sess.span_err
+ fcx.ccx.tcx.sess.span_err
(expr.span,
"unknown field in record update: "
+ f.ident);
}
case (ast::expr_field(?base, ?field, ?a)) {
- check_expr(scx, base);
- auto base_t = expr_ty(scx.fcx.ccx.tcx, base);
- base_t = strip_boxes(scx.fcx.ccx.tcx, base_t);
- alt (struct(scx.fcx.ccx.tcx, base_t)) {
+ check_expr(fcx, base);
+ auto base_t = expr_ty(fcx.ccx.tcx, base);
+ base_t = strip_boxes(fcx, expr.span, base_t);
+ alt (structure_of(fcx, expr.span, base_t)) {
case (ty::ty_tup(?args)) {
- let uint ix = ty::field_num(scx.fcx.ccx.tcx.sess,
+ let uint ix = ty::field_num(fcx.ccx.tcx.sess,
expr.span, field);
if (ix >= vec::len[ty::mt](args)) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"bad index on tuple");
}
- write::ty_only_fixup(scx, a.id, args.(ix).ty);
+ write::ty_only_fixup(fcx, a.id, args.(ix).ty);
}
case (ty::ty_rec(?fields)) {
- let uint ix = ty::field_idx(scx.fcx.ccx.tcx.sess,
+ let uint ix = ty::field_idx(fcx.ccx.tcx.sess,
expr.span, field, fields);
if (ix >= vec::len[ty::field](fields)) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"bad index on record");
}
- write::ty_only_fixup(scx, a.id, fields.(ix).mt.ty);
+ write::ty_only_fixup(fcx, a.id, fields.(ix).mt.ty);
}
case (ty::ty_obj(?methods)) {
- let uint ix = ty::method_idx(scx.fcx.ccx.tcx.sess,
+ let uint ix = ty::method_idx(fcx.ccx.tcx.sess,
expr.span, field, methods);
if (ix >= vec::len[ty::method](methods)) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"bad index on obj");
}
auto meth = methods.(ix);
- auto t = ty::mk_fn(scx.fcx.ccx.tcx, meth.proto,
- meth.inputs, meth.output, meth.cf);
- write::ty_only_fixup(scx, a.id, t);
+ auto t = ty::mk_fn(fcx.ccx.tcx, meth.proto,
+ meth.inputs, meth.output, meth.cf,
+ meth.constrs);
+ write::ty_only_fixup(fcx, a.id, t);
}
case (_) {
- scx.fcx.ccx.tcx.sess.span_unimpl(expr.span,
+ fcx.ccx.tcx.sess.span_unimpl(expr.span,
"base type for expr_field in typeck::check_expr: " +
- ty_to_str(scx.fcx.ccx.tcx, base_t));
+ ty_to_str(fcx.ccx.tcx, base_t));
}
}
}
case (ast::expr_index(?base, ?idx, ?a)) {
- check_expr(scx, base);
- auto base_t = expr_ty(scx.fcx.ccx.tcx, base);
- base_t = strip_boxes(scx.fcx.ccx.tcx, base_t);
+ check_expr(fcx, base);
+ auto base_t = expr_ty(fcx.ccx.tcx, base);
+ base_t = strip_boxes(fcx, expr.span, base_t);
- check_expr(scx, idx);
- auto idx_t = expr_ty(scx.fcx.ccx.tcx, idx);
- alt (struct(scx.fcx.ccx.tcx, base_t)) {
+ check_expr(fcx, idx);
+ auto idx_t = expr_ty(fcx.ccx.tcx, idx);
+ alt (structure_of(fcx, expr.span, base_t)) {
case (ty::ty_vec(?mt)) {
- if (! type_is_integral(scx.fcx.ccx.tcx, idx_t)) {
- scx.fcx.ccx.tcx.sess.span_err
+ if (! type_is_integral(fcx, idx.span, idx_t)) {
+ fcx.ccx.tcx.sess.span_err
(idx.span,
"non-integral type of vec index: "
- + ty_to_str(scx.fcx.ccx.tcx, idx_t));
+ + ty_to_str(fcx.ccx.tcx, idx_t));
}
- write::ty_only_fixup(scx, a.id, mt.ty);
+ write::ty_only_fixup(fcx, a.id, mt.ty);
}
case (ty::ty_str) {
- if (! type_is_integral(scx.fcx.ccx.tcx, idx_t)) {
- scx.fcx.ccx.tcx.sess.span_err
+ if (! type_is_integral(fcx, idx.span, idx_t)) {
+ fcx.ccx.tcx.sess.span_err
(idx.span,
"non-integral type of str index: "
- + ty_to_str(scx.fcx.ccx.tcx, idx_t));
+ + ty_to_str(fcx.ccx.tcx, idx_t));
}
- auto typ = ty::mk_mach(scx.fcx.ccx.tcx, common::ty_u8);
- write::ty_only_fixup(scx, a.id, typ);
+ auto typ = ty::mk_mach(fcx.ccx.tcx, common::ty_u8);
+ write::ty_only_fixup(fcx, a.id, typ);
}
case (_) {
- scx.fcx.ccx.tcx.sess.span_err
+ fcx.ccx.tcx.sess.span_err
(expr.span,
"vector-indexing bad type: "
- + ty_to_str(scx.fcx.ccx.tcx, base_t));
+ + ty_to_str(fcx.ccx.tcx, base_t));
}
}
}
case (ast::expr_port(?a)) {
- auto t = next_ty_var(scx);
- auto pt = ty::mk_port(scx.fcx.ccx.tcx, t);
- write::ty_only_fixup(scx, a.id, pt);
+ auto t = next_ty_var(fcx);
+ auto pt = ty::mk_port(fcx.ccx.tcx, t);
+ write::ty_only_fixup(fcx, a.id, pt);
}
case (ast::expr_chan(?x, ?a)) {
- check_expr(scx, x);
- auto port_t = expr_ty(scx.fcx.ccx.tcx, x);
- alt (struct(scx.fcx.ccx.tcx, port_t)) {
+ check_expr(fcx, x);
+ auto port_t = expr_ty(fcx.ccx.tcx, x);
+ alt (structure_of(fcx, expr.span, port_t)) {
case (ty::ty_port(?subtype)) {
- auto ct = ty::mk_chan(scx.fcx.ccx.tcx, subtype);
- write::ty_only_fixup(scx, a.id, ct);
+ auto ct = ty::mk_chan(fcx.ccx.tcx, subtype);
+ write::ty_only_fixup(fcx, a.id, ct);
}
case (_) {
- scx.fcx.ccx.tcx.sess.span_err(expr.span,
+ fcx.ccx.tcx.sess.span_err(expr.span,
"bad port type: " +
- ty_to_str(scx.fcx.ccx.tcx, port_t));
+ ty_to_str(fcx.ccx.tcx, port_t));
}
}
}
}
let ast::def_id di = obj_def_ids.ty;
- vec::push[obj_info](scx.fcx.ccx.obj_infos,
+ vec::push[obj_info](fcx.ccx.obj_infos,
rec(obj_fields=fields, this_obj=di));
// Typecheck 'with_obj', if it exists.
// This had better have object type. TOOD: report an
// error if the user is trying to extend a non-object
// with_obj.
- check_expr(scx, e);
+ check_expr(fcx, e);
}
}
// Typecheck the methods.
for (@ast::method method in anon_obj.methods) {
- check_method(scx.fcx.ccx, method);
+ check_method(fcx.ccx, method);
}
- auto t = next_ty_var(scx);
+ auto t = next_ty_var(fcx);
// FIXME: These next three functions are largely ripped off from
m.node.meth.decl.inputs);
auto output = convert(m.node.meth.decl.output);
ret rec(proto=m.node.meth.proto, ident=m.node.ident,
- inputs=inputs, output=output, cf=m.node.meth.decl.cf);
+ inputs=inputs, output=output, cf=m.node.meth.decl.cf,
+ constrs=m.node.meth.decl.constraints);
}
fn get_anon_obj_method_types(@crate_ctxt ccx,
anon_obj.methods);
}
- auto methods = get_anon_obj_method_types(scx.fcx.ccx, anon_obj);
- auto ot = ty::mk_obj(scx.fcx.ccx.tcx,
+ auto methods = get_anon_obj_method_types(fcx.ccx, anon_obj);
+ auto ot = ty::mk_obj(fcx.ccx.tcx,
ty::sort_methods(methods));
- write::ty_only_fixup(scx, a.id, ot);
+ write::ty_only_fixup(fcx, a.id, ot);
// Now remove the info from the stack.
- vec::pop[obj_info](scx.fcx.ccx.obj_infos);
+ vec::pop[obj_info](fcx.ccx.obj_infos);
}
case (_) {
- scx.fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr");
+ fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr");
}
}
}
-fn next_ty_var(&@stmt_ctxt scx) -> ty::t {
- auto t = ty::mk_var(scx.fcx.ccx.tcx, scx.next_var_id);
- scx.next_var_id += 1;
- ret t;
+fn next_ty_var_id(@fn_ctxt fcx) -> int {
+ auto id = fcx.next_var_id;
+ fcx.next_var_id += 1;
+ ret id;
+}
+
+fn next_ty_var(&@fn_ctxt fcx) -> ty::t {
+ ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx));
}
fn get_obj_info(&@crate_ctxt ccx) -> option::t[obj_info] {
ret vec::last[obj_info](ccx.obj_infos);
}
-fn check_decl_initializer(&@stmt_ctxt scx, &ast::def_id lid,
+fn check_decl_initializer(&@fn_ctxt fcx, &ast::def_id lid,
&ast::initializer init) {
- check_expr(scx, init.expr);
+ check_expr(fcx, init.expr);
- auto lty = ty::mk_local(scx.fcx.ccx.tcx, lid);
+ auto lty = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(lid));
alt (init.op) {
case (ast::init_assign) {
- pushdown::pushdown_expr(scx, lty, init.expr);
+ demand::simple(fcx, init.expr.span, lty,
+ expr_ty(fcx.ccx.tcx, init.expr));
}
case (ast::init_move) {
- pushdown::pushdown_expr(scx, lty, init.expr);
+ demand::simple(fcx, init.expr.span, lty,
+ expr_ty(fcx.ccx.tcx, init.expr));
}
case (ast::init_recv) {
- auto port_ty = ty::mk_port(scx.fcx.ccx.tcx, lty);
- pushdown::pushdown_expr(scx, port_ty, init.expr);
+ auto port_ty = ty::mk_port(fcx.ccx.tcx, lty);
+ demand::simple(fcx, init.expr.span, port_ty,
+ expr_ty(fcx.ccx.tcx, init.expr));
}
}
}
fn check_decl_local(&@fn_ctxt fcx, &@ast::decl decl) -> @ast::decl {
alt (decl.node) {
case (ast::decl_local(?local)) {
- auto t = ty::mk_nil(fcx.ccx.tcx);
-
- alt (local.ty) {
- case (none) {
- // Auto slot. Do nothing for now.
- }
-
- case (some(?ast_ty)) {
- auto local_ty = ast_ty_to_ty_crate(fcx.ccx, ast_ty);
- fcx.locals.insert(local.id, local_ty);
- t = local_ty;
- }
- }
-
auto a_res = local.ann;
- write::ty_only(fcx.ccx.tcx, a_res.id, t);
+ auto t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.id));
+ write::ty_only_fixup(fcx, a_res.id, t);
auto initopt = local.init;
alt (local.init) {
case (some(?init)) {
- with_stmt_ctxt(fcx,
- bind check_decl_initializer(_, local.id, init));
+ check_decl_initializer(fcx, local.id, init);
}
case (_) { /* fall through */ }
}
- auto local_1 = @rec(init = initopt, ann = a_res with *local);
+ auto local_1 = @rec(init=initopt, ann=a_res with *local);
ret @rec(node=ast::decl_local(local_1) with *decl);
}
}
}
-fn check_and_pushdown_expr(&@stmt_ctxt scx, &@ast::expr expr) {
- check_expr(scx, expr);
- auto ety = expr_ty(scx.fcx.ccx.tcx, expr);
- pushdown::pushdown_expr(scx, ety, expr);
-}
-
fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) {
auto node_id;
alt (stmt.node) {
}
case (ast::stmt_expr(?expr,?a)) {
node_id = a.id;
- with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, expr));
+ check_expr(fcx, expr);
}
}
write::nil_ty(fcx.ccx.tcx, node_id);
}
-fn check_block(&@stmt_ctxt scx, &ast::block block) {
- for (@ast::stmt s in block.node.stmts) { check_stmt(scx.fcx, s); }
+fn check_block(&@fn_ctxt fcx, &ast::block block) {
+ for (@ast::stmt s in block.node.stmts) { check_stmt(fcx, s); }
alt (block.node.expr) {
- case (none) {
- write::nil_ty(scx.fcx.ccx.tcx, block.node.a.id);
- }
+ case (none) { write::nil_ty(fcx.ccx.tcx, block.node.a.id); }
case (some(?e)) {
- check_expr(scx, e);
- auto ety = expr_ty(scx.fcx.ccx.tcx, e);
- pushdown::pushdown_expr(scx, ety, e);
- write::ty_only_fixup(scx, block.node.a.id, ety);
+ check_expr(fcx, e);
+ auto ety = expr_ty(fcx.ccx.tcx, e);
+ write::ty_only_fixup(fcx, block.node.a.id, ety);
}
}
fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::ann ann) {
// FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression.
- auto rty = ann_to_type(ccx.tcx.node_types, ann);
- let @fn_ctxt fcx = @rec(ret_ty = rty,
- purity = ast::pure_fn,
- locals = @common::new_def_hash[ty::t](),
- ccx = ccx);
-
- with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, e));
+ auto rty = ann_to_type(ccx.tcx, ann);
+ let vec[uint] fixups = [];
+ let @fn_ctxt fcx = @rec(ret_ty=rty,
+ purity=ast::pure_fn,
+ var_bindings=ty::unify::mk_var_bindings(),
+ locals=new_def_hash[int](),
+ local_names=new_def_hash[ast::ident](),
+ mutable next_var_id=0,
+ mutable fixups=fixups,
+ ccx=ccx);
+
+ check_expr(fcx, e);
}
fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto,
- &ast::block body) {
- auto local_ty_table = @common::new_def_hash[ty::t]();
-
- // FIXME: duplicate work: the item annotation already has the arg types
- // and return type translated to typeck::ty values. We don't need do to it
- // again here, we can extract them.
-
- alt (get_obj_info(ccx)) {
- case (option::some(?oinfo)) {
- for (ast::obj_field f in oinfo.obj_fields) {
- auto field_ty = ty::ann_to_type(ccx.tcx.node_types, f.ann);
- local_ty_table.insert(f.id, field_ty);
- }
- }
- case (option::none) { /* no fields */ }
- }
+ &ast::block body, &ast::ann ann) {
+ auto gather_result = gather_locals(ccx, decl, body, ann);
- // Store the type of each argument in the table.
- for (ast::arg arg in decl.inputs) {
- auto input_ty = ast_ty_to_ty_crate(ccx, arg.ty);
- local_ty_table.insert(arg.id, input_ty);
- }
-
- let @fn_ctxt fcx = @rec(ret_ty = ast_ty_to_ty_crate(ccx, decl.output),
- purity = decl.purity,
- locals = local_ty_table,
- ccx = ccx);
+ let vec[uint] fixups = [];
+ let @fn_ctxt fcx = @rec(ret_ty=ast_ty_to_ty_crate(ccx, decl.output),
+ purity=decl.purity,
+ var_bindings=gather_result.var_bindings,
+ locals=gather_result.locals,
+ local_names=gather_result.local_names,
+ mutable next_var_id=gather_result.next_var_id,
+ mutable fixups=fixups,
+ ccx=ccx);
// TODO: Make sure the type of the block agrees with the function type.
- with_stmt_ctxt(fcx, bind check_block(_, body));
+ check_block(fcx, body);
alt (decl.purity) {
case (ast::pure_fn) {
case (_) {}
}
- writeback::resolve_local_types_in_block(fcx, body);
+ writeback::resolve_type_vars_in_block(fcx, body);
}
fn check_method(&@crate_ctxt ccx, &@ast::method method) {
- check_fn(ccx, method.node.meth.decl, method.node.meth.proto,
- method.node.meth.body);
+ auto m = method.node.meth;
+ check_fn(ccx, m.decl, m.proto, m.body, method.node.ann);
}
fn check_item(@crate_ctxt ccx, &@ast::item it) {
case (ast::item_const(_, _, ?e, _, ?a)) {
check_const(ccx, it.span, e, a);
}
- case (ast::item_fn(_, ?f, _, _, _)) {
- check_fn(ccx, f.decl, f.proto, f.body);
+ case (ast::item_fn(_, ?f, _, _, ?a)) {
+ check_fn(ccx, f.decl, f.proto, f.body, a);
}
case (ast::item_obj(_, ?ob, _, ?obj_def_ids, _)) {
// We're entering an object, so gather up the info we need.
}
}
-// Utilities for the unification cache
-
-fn hash_unify_cache_entry(&unify_cache_entry uce) -> uint {
- auto h = ty::hash_ty(uce._0);
- h += h << 5u + ty::hash_ty(uce._1);
-
- auto i = 0u;
- auto tys_len = vec::len(uce._2);
- while (i < tys_len) {
- h += h << 5u + ty::hash_ty(uce._2.(i));
- i += 1u;
- }
-
- ret h;
-}
-
-fn eq_unify_cache_entry(&unify_cache_entry a, &unify_cache_entry b) -> bool {
- if (!ty::eq_ty(a._0, b._0) || !ty::eq_ty(a._1, b._1)) { ret false; }
-
- auto i = 0u;
- auto tys_len = vec::len(a._2);
- if (vec::len(b._2) != tys_len) { ret false; }
-
- while (i < tys_len) {
- if (!ty::eq_ty(a._2.(i), b._2.(i))) { ret false; }
- i += 1u;
- }
-
- ret true;
-}
-
fn mk_fn_purity_table(&@ast::crate crate) -> @fn_purity_table {
auto res = @new_def_hash[ast::purity]();
let vec[obj_info] obj_infos = [];
- auto hasher = hash_unify_cache_entry;
- auto eqer = eq_unify_cache_entry;
- auto unify_cache =
- map::mk_hashmap[unify_cache_entry,ty::unify::result](hasher, eqer);
auto fpt = mk_fn_purity_table(crate); // use a variation on collect
auto ccx = @rec(mutable obj_infos=obj_infos,
fn_purity_table=fpt,
- unify_cache=unify_cache,
- mutable cache_hits=0u,
- mutable cache_misses=0u,
tcx=tcx);
auto visit = rec(visit_item_pre = bind check_item(ccx, _)
with walk::default_visitor());
walk::walk_crate(visit, *crate);
-
- log #fmt("cache hit rate: %u/%u", ccx.cache_hits,
- ccx.cache_hits + ccx.cache_misses);
}
//