rust/src/comp/middle/ty.rs

2532 lines
84 KiB
Rust
Raw Normal View History

import std._str;
import std._uint;
import std._vec;
import std.Box;
import std.UFind;
import std.map;
import std.map.hashmap;
import std.option;
import std.option.none;
import std.option.some;
import driver.session;
import front.ast;
import front.ast.mutability;
import front.creader;
import middle.metadata;
import util.common;
import util.common.new_def_hash;
import util.common.span;
import util.typestate_ann.ts_ann;
// Data types
type arg = rec(ast.mode mode, t ty);
type field = rec(ast.ident ident, mt mt);
type method = rec(ast.proto proto,
ast.ident ident,
vec[arg] inputs,
t output);
type mt = rec(t ty, ast.mutability mut);
// Convert from method type to function type. Pretty easy; we just drop
// 'ident'.
fn method_ty_to_fn_ty(@type_store tystore, method m) -> t {
ret mk_fn(tystore, m.proto, m.inputs, m.output);
}
// Never construct these manually. These are interned. Also don't assume that
// you can access the fields of this type directly; soon these will just be
// uints, and that won't work anymore.
//
// TODO: It'd be really nice to be able to hide this definition from the
// outside world, to enforce the above invariants.
type raw_t = rec(sty struct, option.t[str] cname, uint hash);
type t = @raw_t;
// NB: If you change this, you'll probably want to change the corresponding
// AST structure in front/ast.rs as well.
tag sty {
ty_nil;
ty_bool;
ty_int;
ty_float;
ty_uint;
ty_machine(util.common.ty_mach);
ty_char;
ty_str;
ty_tag(ast.def_id, vec[t]);
ty_box(mt);
ty_vec(mt);
ty_port(t);
ty_chan(t);
ty_task;
ty_tup(vec[mt]);
ty_rec(vec[field]);
ty_fn(ast.proto, vec[arg], t);
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_param(uint); // fn/tag type param
ty_bound_param(uint); // bound param, only paths
2011-02-01 23:56:21 +01:00
ty_type;
2011-02-11 00:39:55 +01:00
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_box_mutability;
terr_vec_mutability;
terr_tuple_size(uint, uint);
terr_tuple_mutability;
terr_record_size(uint, uint);
terr_record_mutability;
terr_record_fields(ast.ident,ast.ident);
2010-12-31 19:26:29 +01:00
terr_meth_count;
terr_obj_meths(ast.ident,ast.ident);
terr_arg_count;
}
type ty_param_count_and_ty = tup(uint, t);
type type_cache = hashmap[ast.def_id,ty_param_count_and_ty];
type type_store = hashmap[t,t];
2011-04-22 04:30:53 +02:00
fn mk_type_store() -> @type_store {
auto hasher = hash_ty;
2011-04-22 04:30:53 +02:00
auto eqer = eq_ty_full;
ret @map.mk_hashmap[t,t](hasher, eqer);
}
// Type constructors
2011-04-22 04:30:53 +02:00
// These are private constructors to this module. External users should always
2011-04-20 21:22:28 +02:00
// use the mk_foo() functions below.
fn gen_ty(@type_store tystore, &sty st) -> t {
2011-04-22 04:30:53 +02:00
ret gen_ty_full(tystore, st, none[str]);
}
fn gen_ty_full(@type_store tystore, &sty st, option.t[str] cname) -> t {
2011-04-22 04:30:53 +02:00
auto h = hash_type_structure(st);
auto new_type = @rec(struct=st, cname=cname, hash=h);
// Is it interned?
alt (tystore.find(new_type)) {
case (some[t](?typ)) {
2011-04-22 04:30:53 +02:00
ret typ;
}
case (none[t]) {
2011-04-22 04:30:53 +02:00
// Nope. Insert it and return.
tystore.insert(new_type, new_type);
ret new_type;
}
}
2011-04-20 21:22:28 +02:00
}
fn mk_nil(@type_store ts) -> t { ret gen_ty(ts, ty_nil); }
fn mk_bool(@type_store ts) -> t { ret gen_ty(ts, ty_bool); }
fn mk_int(@type_store ts) -> t { ret gen_ty(ts, ty_int); }
fn mk_float(@type_store ts) -> t { ret gen_ty(ts, ty_float); }
fn mk_uint(@type_store ts) -> t { ret gen_ty(ts, ty_uint); }
fn mk_mach(@type_store ts, util.common.ty_mach tm) -> t {
ret gen_ty(ts, ty_machine(tm));
}
fn mk_char(@type_store ts) -> t { ret gen_ty(ts, ty_char); }
fn mk_str(@type_store ts) -> t { ret gen_ty(ts, ty_str); }
fn mk_tag(@type_store ts, ast.def_id did, vec[t] tys) -> t {
ret gen_ty(ts, ty_tag(did, tys));
}
fn mk_box(@type_store ts, mt tm) -> t {
ret gen_ty(ts, ty_box(tm));
}
fn mk_imm_box(@type_store ts, t ty) -> t {
ret mk_box(ts, rec(ty=ty, mut=ast.imm));
}
fn mk_vec(@type_store ts, mt tm) -> t { ret gen_ty(ts, ty_vec(tm)); }
fn mk_port(@type_store ts, t ty) -> t { ret gen_ty(ts, ty_port(ty)); }
fn mk_chan(@type_store ts, t ty) -> t { ret gen_ty(ts, ty_chan(ty)); }
fn mk_task(@type_store ts) -> t { ret gen_ty(ts, ty_task); }
fn mk_tup(@type_store ts, vec[mt] tms) -> t {
ret gen_ty(ts, ty_tup(tms));
}
fn mk_imm_tup(@type_store ts, vec[t] tys) -> t {
// TODO: map
let vec[ty.mt] mts = vec();
for (t typ in tys) {
mts += vec(rec(ty=typ, mut=ast.imm));
}
ret mk_tup(ts, mts);
}
fn mk_rec(@type_store ts, vec[field] fs) -> t {
ret gen_ty(ts, ty_rec(fs));
}
fn mk_fn(@type_store ts, ast.proto proto, vec[arg] args, t ty) -> t {
ret gen_ty(ts, ty_fn(proto, args, ty));
}
fn mk_native_fn(@type_store ts, ast.native_abi abi, vec[arg] args, t ty)
-> t {
ret gen_ty(ts, ty_native_fn(abi, args, ty));
}
fn mk_obj(@type_store ts, vec[method] meths) -> t {
ret gen_ty(ts, ty_obj(meths));
}
fn mk_var(@type_store ts, int v) -> t { ret gen_ty(ts, ty_var(v)); }
fn mk_local(@type_store ts, ast.def_id did) -> t {
ret gen_ty(ts, ty_local(did));
}
fn mk_param(@type_store ts, uint n) -> t {
ret gen_ty(ts, ty_param(n));
}
fn mk_bound_param(@type_store ts, uint n) -> t {
ret gen_ty(ts, ty_bound_param(n));
}
fn mk_type(@type_store ts) -> t { ret gen_ty(ts, ty_type); }
fn mk_native(@type_store ts) -> t { ret gen_ty(ts, ty_native); }
// Returns the one-level-deep type structure of the given type.
fn struct(@type_store tystore, t typ) -> sty { ret typ.struct; }
// Returns the canonical name of the given type.
fn cname(@type_store tystore, t typ) -> option.t[str] { ret typ.cname; }
// Stringification
fn path_to_str(&ast.path pth) -> str {
auto result = _str.connect(pth.node.idents, ".");
if (_vec.len[@ast.ty](pth.node.types) > 0u) {
auto f = pretty.pprust.ty_to_str;
result += "[";
result += _str.connect(_vec.map[@ast.ty,str](f, pth.node.types), ",");
result += "]";
}
ret result;
}
fn ty_to_str(@type_store ts, &t typ) -> str {
fn fn_input_to_str(@type_store tystore,
&rec(ast.mode mode, t ty) input) -> str {
auto s;
if (mode_is_alias(input.mode)) {
s = "&";
} else {
s = "";
}
ret s + ty_to_str(tystore, input.ty);
}
fn fn_to_str(@type_store tystore,
ast.proto proto,
option.t[ast.ident] ident,
vec[arg] inputs, t output) -> str {
auto f = bind fn_input_to_str(tystore, _);
auto s;
alt (proto) {
case (ast.proto_iter) {
s = "iter";
}
case (ast.proto_fn) {
s = "fn";
}
}
alt (ident) {
case (some[ast.ident](?i)) {
s += " ";
s += i;
}
case (_) { }
}
s += "(";
s += _str.connect(_vec.map[arg,str](f, inputs), ", ");
s += ")";
if (struct(tystore, output) != ty_nil) {
s += " -> " + ty_to_str(tystore, output);
}
ret s;
}
fn method_to_str(@type_store tystore, &method m) -> str {
ret fn_to_str(tystore, m.proto, some[ast.ident](m.ident),
m.inputs, m.output) + ";";
}
fn field_to_str(@type_store tystore, &field f) -> str {
ret mt_to_str(tystore, f.mt) + " " + f.ident;
}
fn mt_to_str(@type_store tystore, &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(tystore, m.ty);
}
auto s = "";
alt (struct(ts, typ)) {
case (ty_native) { s += "native"; }
case (ty_nil) { 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(ts, tm); }
case (ty_vec(?tm)) { s += "vec[" + mt_to_str(ts, tm) + "]"; }
case (ty_port(?t)) { s += "port[" + ty_to_str(ts, t) + "]"; }
case (ty_chan(?t)) { s += "chan[" + ty_to_str(ts, t) + "]"; }
case (ty_type) { s += "type"; }
case (ty_tup(?elems)) {
auto f = bind mt_to_str(ts, _);
auto strs = _vec.map[mt,str](f, elems);
s += "tup(" + _str.connect(strs, ",") + ")";
}
case (ty_rec(?elems)) {
auto f = bind field_to_str(ts, _);
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(ts, _);
auto strs = _vec.map[t,str](f, tps);
2011-02-18 01:23:31 +01:00
s += "[" + _str.connect(strs, ",") + "]";
}
}
case (ty_fn(?proto, ?inputs, ?output)) {
s += fn_to_str(ts, proto, none[ast.ident], inputs, output);
}
case (ty_native_fn(_, ?inputs, ?output)) {
s += fn_to_str(ts, ast.proto_fn, none[ast.ident], inputs, output);
}
case (ty_obj(?meths)) {
alt (cname(ts, typ)) {
case (some[str](?cs)) {
s += cs;
}
case (_) {
auto f = bind method_to_str(ts, _);
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) + ">";
}
2011-01-18 02:24:47 +01:00
case (ty_local(?id)) {
s += "<L" + util.common.istr(id._0) + ":" +
util.common.istr(id._1) + ">";
2011-01-18 02:24:47 +01:00
}
case (ty_param(?id)) {
s += "'" + _str.unsafe_from_bytes(vec(('a' as u8) + (id as u8)));
}
case (ty_bound_param(?id)) {
s += "''" + _str.unsafe_from_bytes(vec(('a' as u8) + (id as u8)));
}
}
ret s;
}
// Type folds
type ty_walk = fn(t);
fn walk_ty(@type_store tystore, ty_walk walker, t ty) {
alt (struct(tystore, ty)) {
case (ty_nil) { /* no-op */ }
case (ty_bool) { /* no-op */ }
case (ty_int) { /* no-op */ }
case (ty_uint) { /* no-op */ }
case (ty_float) { /* no-op */ }
case (ty_machine(_)) { /* no-op */ }
case (ty_char) { /* no-op */ }
case (ty_str) { /* no-op */ }
case (ty_type) { /* no-op */ }
case (ty_native) { /* no-op */ }
case (ty_box(?tm)) { walk_ty(tystore, walker, tm.ty); }
case (ty_vec(?tm)) { walk_ty(tystore, walker, tm.ty); }
case (ty_port(?subty)) { walk_ty(tystore, walker, subty); }
case (ty_chan(?subty)) { walk_ty(tystore, walker, subty); }
case (ty_tag(?tid, ?subtys)) {
for (t subty in subtys) {
walk_ty(tystore, walker, subty);
}
}
case (ty_tup(?mts)) {
for (mt tm in mts) {
walk_ty(tystore, walker, tm.ty);
}
}
case (ty_rec(?fields)) {
for (field fl in fields) {
walk_ty(tystore, walker, fl.mt.ty);
}
}
case (ty_fn(?proto, ?args, ?ret_ty)) {
for (arg a in args) {
walk_ty(tystore, walker, a.ty);
}
walk_ty(tystore, walker, ret_ty);
}
case (ty_native_fn(?abi, ?args, ?ret_ty)) {
for (arg a in args) {
walk_ty(tystore, walker, a.ty);
}
walk_ty(tystore, walker, ret_ty);
}
case (ty_obj(?methods)) {
let vec[method] new_methods = vec();
for (method m in methods) {
for (arg a in m.inputs) {
walk_ty(tystore, walker, a.ty);
}
walk_ty(tystore, walker, m.output);
}
}
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;
fn fold_ty(@type_store tystore, ty_fold fld, t ty_0) -> t {
auto ty = ty_0;
alt (struct(tystore, ty)) {
case (ty_nil) { /* no-op */ }
case (ty_bool) { /* no-op */ }
case (ty_int) { /* no-op */ }
case (ty_uint) { /* no-op */ }
case (ty_float) { /* no-op */ }
case (ty_machine(_)) { /* no-op */ }
case (ty_char) { /* no-op */ }
case (ty_str) { /* no-op */ }
case (ty_type) { /* no-op */ }
case (ty_native) { /* no-op */ }
case (ty_box(?tm)) {
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore,
mk_box(tystore,
rec(ty=fold_ty(tystore, fld, tm.ty),
mut=tm.mut)), ty);
}
case (ty_vec(?tm)) {
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore,
mk_vec(tystore, rec(ty=fold_ty(tystore, fld, tm.ty),
mut=tm.mut)), ty);
}
case (ty_port(?subty)) {
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore,
mk_port(tystore, fold_ty(tystore, fld, subty)), ty);
}
case (ty_chan(?subty)) {
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore,
mk_chan(tystore, fold_ty(tystore, fld, subty)), ty);
}
2011-02-18 01:23:31 +01:00
case (ty_tag(?tid, ?subtys)) {
let vec[t] new_subtys = vec();
for (t subty in subtys) {
new_subtys += vec(fold_ty(tystore, fld, subty));
2011-02-18 01:23:31 +01:00
}
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore, mk_tag(tystore, tid, new_subtys), ty);
2011-02-18 01:23:31 +01:00
}
case (ty_tup(?mts)) {
let vec[mt] new_mts = vec();
for (mt tm in mts) {
auto new_subty = fold_ty(tystore, fld, tm.ty);
new_mts += vec(rec(ty=new_subty, mut=tm.mut));
}
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore, mk_tup(tystore, new_mts), ty);
}
case (ty_rec(?fields)) {
let vec[field] new_fields = vec();
for (field fl in fields) {
auto new_ty = fold_ty(tystore, fld, fl.mt.ty);
auto new_mt = rec(ty=new_ty, mut=fl.mt.mut);
new_fields += vec(rec(ident=fl.ident, mt=new_mt));
}
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore, mk_rec(tystore, new_fields), ty);
}
case (ty_fn(?proto, ?args, ?ret_ty)) {
let vec[arg] new_args = vec();
for (arg a in args) {
auto new_ty = fold_ty(tystore, fld, a.ty);
new_args += vec(rec(mode=a.mode, ty=new_ty));
}
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore, mk_fn(tystore, proto, new_args,
fold_ty(tystore, fld, ret_ty)),
ty);
}
case (ty_native_fn(?abi, ?args, ?ret_ty)) {
let vec[arg] new_args = vec();
for (arg a in args) {
auto new_ty = fold_ty(tystore, fld, a.ty);
new_args += vec(rec(mode=a.mode, ty=new_ty));
}
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore, mk_native_fn(tystore, abi, new_args,
fold_ty(tystore, fld, ret_ty)),
ty);
}
case (ty_obj(?methods)) {
let vec[method] new_methods = vec();
for (method m in methods) {
let vec[arg] new_args = vec();
for (arg a in m.inputs) {
new_args += vec(rec(mode=a.mode,
ty=fold_ty(tystore, fld, a.ty)));
}
new_methods += vec(rec(proto=m.proto, ident=m.ident,
inputs=new_args,
output=fold_ty(tystore, fld,
m.output)));
}
2011-04-22 04:30:53 +02:00
ty = copy_cname(tystore, mk_obj(tystore, new_methods), ty);
}
case (ty_var(_)) { /* no-op */ }
case (ty_local(_)) { /* no-op */ }
case (ty_param(_)) { /* no-op */ }
case (ty_bound_param(_)) { /* no-op */ }
}
ret fld(ty);
}
// Type utilities
fn rename(@type_store tystore, t typ, str new_cname) -> t {
ret gen_ty_full(tystore, struct(tystore, typ), some[str](new_cname));
}
// Returns a type with the structural part taken from `struct_ty` and the
// canonical name from `cname_ty`.
fn copy_cname(@type_store tystore, t struct_ty, t cname_ty) -> t {
ret gen_ty_full(tystore, struct(tystore, struct_ty), cname_ty.cname);
}
// FIXME: remove me when == works on these tags.
fn mode_is_alias(ast.mode m) -> bool {
alt (m) {
case (ast.val) { ret false; }
case (ast.alias) { ret true; }
}
fail;
}
fn type_is_nil(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_nil) { ret true; }
case (_) { ret false; }
}
fail;
}
fn type_is_bool(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_bool) { ret true; }
case (_) { ret false; }
}
}
fn type_is_structural(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
2011-02-18 01:23:31 +01:00
case (ty_tup(_)) { ret true; }
case (ty_rec(_)) { ret true; }
case (ty_tag(_,_)) { ret true; }
case (ty_fn(_,_,_)) { ret true; }
2011-02-18 01:23:31 +01:00
case (ty_obj(_)) { ret true; }
case (_) { ret false; }
}
fail;
}
fn type_is_sequence(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_str) { ret true; }
case (ty_vec(_)) { ret true; }
case (_) { ret false; }
}
fail;
}
fn sequence_element_type(@type_store tystore, t ty) -> t {
alt (struct(tystore, ty)) {
case (ty_str) { ret mk_mach(tystore, common.ty_u8); }
case (ty_vec(?mt)) { ret mt.ty; }
}
fail;
}
fn type_is_tup_like(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
2011-02-18 01:23:31 +01:00
case (ty_box(_)) { ret true; }
case (ty_tup(_)) { ret true; }
case (ty_rec(_)) { ret true; }
case (ty_tag(_,_)) { ret true; }
case (_) { ret false; }
}
fail;
}
fn get_element_type(@type_store tystore, t ty, uint i) -> t {
check (type_is_tup_like(tystore, ty));
alt (struct(tystore, ty)) {
case (ty_tup(?mts)) {
ret mts.(i).ty;
}
case (ty_rec(?flds)) {
ret flds.(i).mt.ty;
}
}
fail;
}
fn type_is_box(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_box(_)) { ret true; }
case (_) { ret false; }
}
fail;
}
fn type_is_boxed(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_str) { ret true; }
case (ty_vec(_)) { ret true; }
case (ty_box(_)) { ret true; }
2011-03-17 02:49:15 +01:00
case (ty_port(_)) { ret true; }
case (ty_chan(_)) { ret true; }
case (_) { ret false; }
}
fail;
}
fn type_is_scalar(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_nil) { ret true; }
case (ty_bool) { ret true; }
case (ty_int) { ret true; }
case (ty_float) { ret true; }
case (ty_uint) { ret true; }
case (ty_machine(_)) { ret true; }
case (ty_char) { ret true; }
2011-02-01 23:56:21 +01:00
case (ty_type) { ret true; }
case (ty_native) { ret true; }
case (_) { ret false; }
}
fail;
}
2011-03-03 22:43:47 +01:00
// FIXME: should we just return true for native types in
// type_is_scalar?
fn type_is_native(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
2011-03-03 22:43:47 +01:00
case (ty_native) { ret true; }
case (_) { ret false; }
}
fail;
}
fn type_has_dynamic_size(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_tup(?mts)) {
auto i = 0u;
while (i < _vec.len[mt](mts)) {
if (type_has_dynamic_size(tystore, mts.(i).ty)) { ret true; }
i += 1u;
}
}
case (ty_rec(?fields)) {
auto i = 0u;
while (i < _vec.len[field](fields)) {
if (type_has_dynamic_size(tystore, fields.(i).mt.ty)) {
ret true;
}
i += 1u;
}
}
case (ty_tag(_, ?subtys)) {
auto i = 0u;
while (i < _vec.len[t](subtys)) {
if (type_has_dynamic_size(tystore, subtys.(i))) { ret true; }
i += 1u;
}
}
case (ty_param(_)) { ret true; }
case (_) { /* fall through */ }
}
ret false;
}
fn type_is_integral(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_int) { ret true; }
case (ty_uint) { ret true; }
case (ty_machine(?m)) {
alt (m) {
case (common.ty_i8) { ret true; }
case (common.ty_i16) { ret true; }
case (common.ty_i32) { ret true; }
case (common.ty_i64) { ret true; }
case (common.ty_u8) { ret true; }
case (common.ty_u16) { ret true; }
case (common.ty_u32) { ret true; }
case (common.ty_u64) { ret true; }
case (_) { ret false; }
}
}
case (ty_char) { ret true; }
case (_) { ret false; }
}
fail;
}
fn type_is_fp(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_machine(?tm)) {
alt (tm) {
case (common.ty_f32) { ret true; }
case (common.ty_f64) { ret true; }
case (_) { ret false; }
}
}
case (ty_float) {
ret true;
}
case (_) { ret false; }
}
fail;
}
fn type_is_signed(@type_store tystore, t ty) -> bool {
alt (struct(tystore, ty)) {
case (ty_int) { ret true; }
case (ty_machine(?tm)) {
alt (tm) {
case (common.ty_i8) { ret true; }
case (common.ty_i16) { ret true; }
case (common.ty_i32) { ret true; }
case (common.ty_i64) { ret true; }
case (_) { ret false; }
}
}
case (_) { ret false; }
}
fail;
}
fn type_param(@type_store tystore, t ty) -> option.t[uint] {
alt (struct(tystore, ty)) {
case (ty_param(?id)) { ret some[uint](id); }
case (_) { /* fall through */ }
}
ret none[uint];
}
fn def_to_str(ast.def_id did) -> str {
ret #fmt("%d:%d", did._0, did._1);
}
2011-04-20 21:22:28 +02:00
// Type hashing. This function is private to this module (and slow); external
// users should use `hash_ty()` instead.
fn hash_type_structure(&sty st) -> uint {
2011-04-20 23:34:17 +02:00
fn hash_uint(uint id, uint n) -> uint {
auto h = id;
h += h << 5u + n;
ret h;
}
2011-04-20 21:22:28 +02:00
2011-04-20 23:34:17 +02:00
fn hash_def(uint id, ast.def_id did) -> uint {
auto h = id;
h += h << 5u + (did._0 as uint);
h += h << 5u + (did._1 as uint);
ret h;
}
2011-04-20 21:22:28 +02:00
fn hash_subty(uint id, t subty) -> uint {
2011-04-20 23:34:17 +02:00
auto h = id;
h += h << 5u + hash_ty(subty);
ret h;
}
fn hash_fn(uint id, vec[arg] args, t rty) -> uint {
2011-04-20 23:34:17 +02:00
auto h = id;
for (arg a in args) {
h += h << 5u + hash_ty(a.ty);
}
h += h << 5u + hash_ty(rty);
ret h;
}
alt (st) {
case (ty_nil) { ret 0u; }
case (ty_bool) { ret 1u; }
case (ty_int) { ret 2u; }
case (ty_float) { ret 3u; }
case (ty_uint) { ret 4u; }
case (ty_machine(?tm)) {
alt (tm) {
case (common.ty_i8) { ret 5u; }
case (common.ty_i16) { ret 6u; }
case (common.ty_i32) { ret 7u; }
case (common.ty_i64) { ret 8u; }
case (common.ty_u8) { ret 9u; }
case (common.ty_u16) { ret 10u; }
case (common.ty_u32) { ret 11u; }
case (common.ty_u64) { ret 12u; }
case (common.ty_f32) { ret 13u; }
case (common.ty_f64) { ret 14u; }
}
}
case (ty_char) { ret 15u; }
case (ty_str) { ret 16u; }
case (ty_tag(?did, ?tys)) {
auto h = hash_def(17u, did);
for (t typ in tys) {
2011-04-20 23:34:17 +02:00
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_tup(?mts)) {
auto h = 23u;
for (mt tm in mts) {
h += h << 5u + hash_ty(tm.ty);
}
ret h;
}
case (ty_rec(?fields)) {
auto h = 24u;
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_obj(?methods)) {
auto h = 27u;
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_type) { ret 32u; }
case (ty_native) { ret 33u; }
}
}
fn hash_ty(&t typ) -> uint { ret typ.hash; }
2011-04-20 21:22:28 +02:00
// Type equality. This function is private to this module (and slow); external
// users should use `eq_ty()` instead.
fn equal_type_structures(&sty a, &sty b) -> bool {
fn equal_ty(t a, t b) -> bool { ret Box.ptr_eq[raw_t](a, b); }
fn equal_proto(ast.proto a, ast.proto b) -> bool {
alt (a) {
case (ast.proto_iter) {
alt (b) {
case (ast.proto_iter) { ret true; }
case (_) { ret false; }
}
}
case (ast.proto_fn) {
alt (b) {
case (ast.proto_fn) { ret true; }
case (_) { ret false; }
}
}
}
}
fn equal_abi(ast.native_abi a, ast.native_abi b) -> bool {
alt (a) {
case (ast.native_abi_rust) {
alt (b) {
case (ast.native_abi_rust) { ret true; }
case (_) { ret false; }
}
}
case (ast.native_abi_cdecl) {
alt (b) {
case (ast.native_abi_cdecl) { ret true; }
case (_) { ret false; }
}
}
case (ast.native_abi_llvm) {
alt (b) {
case (ast.native_abi_llvm) { ret true; }
case (_) { ret false; }
}
}
}
}
fn equal_mut(ast.mutability a, ast.mutability b) -> bool {
alt (a) {
case (ast.mut) {
alt (b) {
case (ast.mut) { ret true; }
case (_) { ret false; }
}
}
case (ast.imm) {
alt (b) {
case (ast.imm) { ret true; }
case (_) { ret false; }
}
}
case (ast.maybe_mut) {
alt (b) {
case (ast.maybe_mut) { ret true; }
case (_) { ret false; }
}
}
}
}
fn equal_mode(ast.mode a, ast.mode b) -> bool {
alt (a) {
case (ast.val) {
alt (b) {
case (ast.val) { ret true; }
case (_) { ret false; }
}
}
case (ast.alias) {
alt (b) {
case (ast.alias) { ret true; }
case (_) { ret false; }
}
}
}
}
fn equal_mt(&mt a, &mt b) -> bool {
ret equal_mut(a.mut, b.mut) && equal_ty(a.ty, b.ty);
}
fn equal_fn(vec[arg] args_a, t rty_a,
vec[arg] args_b, t rty_b) -> bool {
if (!equal_ty(rty_a, rty_b)) { ret false; }
auto len = _vec.len[arg](args_a);
if (len != _vec.len[arg](args_b)) { ret false; }
auto i = 0u;
while (i < len) {
auto arg_a = args_a.(i); auto arg_b = args_b.(i);
if (!equal_mode(arg_a.mode, arg_b.mode) ||
!equal_ty(arg_a.ty, arg_b.ty)) {
ret false;
}
i += 1u;
}
ret true;
}
fn equal_def(ast.def_id did_a, ast.def_id did_b) -> bool {
ret did_a._0 == did_b._0 && did_a._1 == did_b._1;
}
alt (a) {
case (ty_nil) {
alt (b) {
case (ty_nil) { ret true; }
case (_) { ret false; }
}
}
case (ty_bool) {
alt (b) {
case (ty_bool) { ret true; }
case (_) { ret false; }
}
}
case (ty_int) {
alt (b) {
case (ty_int) { ret true; }
case (_) { ret false; }
}
}
case (ty_float) {
alt (b) {
case (ty_float) { ret true; }
case (_) { ret false; }
}
}
case (ty_uint) {
alt (b) {
case (ty_uint) { ret true; }
case (_) { ret false; }
}
}
case (ty_machine(?tm_a)) {
alt (b) {
case (ty_machine(?tm_b)) {
ret hash_type_structure(a) == hash_type_structure(b);
}
case (_) { ret false; }
}
}
case (ty_char) {
alt (b) {
case (ty_char) { ret true; }
case (_) { ret false; }
}
}
case (ty_str) {
alt (b) {
case (ty_str) { ret true; }
case (_) { ret false; }
}
}
case (ty_tag(?id_a, ?tys_a)) {
alt (b) {
case (ty_tag(?id_b, ?tys_b)) {
2011-04-22 04:30:53 +02:00
if (!equal_def(id_a, id_b)) { ret false; }
auto len = _vec.len[t](tys_a);
if (len != _vec.len[t](tys_b)) { ret false; }
auto i = 0u;
while (i < len) {
if (!equal_ty(tys_a.(i), tys_b.(i))) { ret false; }
i += 1u;
}
ret true;
}
case (_) { ret false; }
}
}
case (ty_box(?mt_a)) {
alt (b) {
case (ty_box(?mt_b)) { ret equal_mt(mt_a, mt_b); }
case (_) { ret false; }
}
}
case (ty_vec(?mt_a)) {
alt (b) {
case (ty_vec(?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 equal_ty(t_a, t_b); }
case (_) { ret false; }
}
}
case (ty_chan(?t_a)) {
alt (b) {
case (ty_chan(?t_b)) { ret equal_ty(t_a, t_b); }
case (_) { ret false; }
}
}
case (ty_task) {
alt (b) {
case (ty_task) { ret true; }
case (_) { ret false; }
}
}
case (ty_tup(?mts_a)) {
alt (b) {
case (ty_tup(?mts_b)) {
auto len = _vec.len[mt](mts_a);
if (len != _vec.len[mt](mts_b)) { ret false; }
auto i = 0u;
while (i < len) {
if (!equal_mt(mts_a.(i), mts_b.(i))) { ret false; }
i += 1u;
}
ret true;
}
case (_) { ret false; }
}
}
case (ty_rec(?flds_a)) {
alt (b) {
case (ty_rec(?flds_b)) {
auto len = _vec.len[field](flds_a);
if (len != _vec.len[field](flds_b)) { ret false; }
auto i = 0u;
while (i < len) {
auto fld_a = flds_a.(i); auto fld_b = flds_b.(i);
if (!_str.eq(fld_a.ident, fld_b.ident) ||
!equal_mt(fld_a.mt, fld_b.mt)) {
ret false;
}
i += 1u;
}
ret true;
}
case (_) { ret false; }
}
}
case (ty_fn(?p_a, ?args_a, ?rty_a)) {
alt (b) {
case (ty_fn(?p_b, ?args_b, ?rty_b)) {
ret equal_proto(p_a, p_b) &&
equal_fn(args_a, rty_a, args_b, rty_b);
}
case (_) { ret false; }
}
}
case (ty_native_fn(?abi_a, ?args_a, ?rty_a)) {
alt (b) {
case (ty_native_fn(?abi_b, ?args_b, ?rty_b)) {
ret equal_abi(abi_a, abi_b) &&
equal_fn(args_a, rty_a, args_b, rty_b);
}
case (_) { ret false; }
}
}
case (ty_obj(?methods_a)) {
alt (b) {
case (ty_obj(?methods_b)) {
auto len = _vec.len[method](methods_a);
if (len != _vec.len[method](methods_b)) { ret false; }
auto i = 0u;
while (i < len) {
auto m_a = methods_a.(i); auto m_b = methods_b.(i);
if (!equal_proto(m_a.proto, m_b.proto) ||
!_str.eq(m_a.ident, m_b.ident) ||
2011-04-22 04:30:53 +02:00
!equal_fn(m_a.inputs, m_a.output,
m_b.inputs, m_b.output)) {
ret false;
}
2011-04-22 04:30:53 +02:00
i += 1u;
}
ret true;
}
case (_) { ret false; }
}
}
case (ty_var(?v_a)) {
alt (b) {
case (ty_var(?v_b)) { ret v_a == v_b; }
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; }
case (_) { ret false; }
}
}
case (ty_native) {
alt (b) {
case (ty_native) { ret true; }
case (_) { ret false; }
}
}
}
}
2011-04-22 04:30:53 +02:00
// An expensive type equality function. This function is private to this
// module.
fn eq_ty_full(&t a, &t b) -> bool {
2011-04-22 04:30:53 +02:00
// Check hashes (fast path).
if (a.hash != b.hash) {
ret false;
}
2011-04-22 04:30:53 +02:00
// Check canonical names.
alt (a.cname) {
2011-04-22 04:30:53 +02:00
case (none[str]) {
alt (b.cname) {
2011-04-22 04:30:53 +02:00
case (none[str]) { /* ok */ }
case (_) { ret false; }
}
}
2011-04-22 04:30:53 +02:00
case (some[str](?s_a)) {
alt (b.cname) {
2011-04-22 04:30:53 +02:00
case (some[str](?s_b)) {
if (!_str.eq(s_a, s_b)) { ret false; }
}
case (_) { ret false; }
}
}
2011-04-22 04:30:53 +02:00
}
2011-04-22 04:30:53 +02:00
// Check structures.
ret equal_type_structures(a.struct, b.struct);
2011-04-22 04:30:53 +02:00
}
2011-04-22 04:30:53 +02:00
// This is the equality function the public should use. It works as long as
// the types are interned.
fn eq_ty(&t a, &t b) -> bool { ret Box.ptr_eq[raw_t](a, b); }
fn ann_to_type(&ast.ann ann) -> t {
alt (ann) {
case (ast.ann_none) {
log_err "ann_to_type() called on node with no type";
fail;
}
case (ast.ann_type(?ty, _, _)) {
ret ty;
}
}
}
fn ann_to_type_params(&ast.ann ann) -> vec[t] {
alt (ann) {
case (ast.ann_none) {
log_err "ann_to_type_params() called on node with no type params";
fail;
}
case (ast.ann_type(_, ?tps, _)) {
alt (tps) {
case (none[vec[t]]) {
let vec[t] result = vec();
ret result;
}
case (some[vec[t]](?tps)) { ret tps; }
}
}
}
}
// Returns the type of an annotation, with type parameter substitutions
// performed if applicable.
fn ann_to_monotype(@type_store tystore, ast.ann a) -> t {
// TODO: Refactor to use recursive pattern matching when we're more
// confident that it works.
alt (a) {
case (ast.ann_none) {
log_err "ann_to_monotype() called on expression with no type!";
fail;
}
case (ast.ann_type(?typ, ?tps_opt, _)) {
alt (tps_opt) {
case (none[vec[t]]) { ret typ; }
case (some[vec[t]](?tps)) {
ret substitute_type_params(tystore, tps, typ);
}
}
}
}
}
// Turns a type into an ann_type, using defaults for other fields.
fn triv_ann(t typ) -> ast.ann {
ret ast.ann_type(typ, none[vec[t]], none[@ts_ann]);
}
// Returns the number of distinct type parameters in the given type.
fn count_ty_params(@type_store tystore, t ty) -> uint {
fn counter(@type_store tystore, @mutable vec[uint] param_indices, t ty) {
alt (struct(tystore, ty)) {
case (ty_param(?param_idx)) {
auto seen = false;
for (uint other_param_idx in *param_indices) {
if (param_idx == other_param_idx) {
seen = true;
}
}
if (!seen) {
*param_indices += vec(param_idx);
}
}
case (_) { /* fall through */ }
}
}
let vec[uint] v = vec(); // FIXME: typechecker botch
let @mutable vec[uint] param_indices = @mutable v;
auto f = bind counter(tystore, param_indices, _);
walk_ty(tystore, f, ty);
ret _vec.len[uint](*param_indices);
}
fn type_contains_vars(@type_store tystore, t typ) -> bool {
fn checker(@type_store tystore, @mutable bool flag, t typ) {
alt (struct(tystore, typ)) {
case (ty_var(_)) { *flag = true; }
case (_) { /* fall through */ }
}
}
let @mutable bool flag = @mutable false;
auto f = bind checker(tystore, flag, _);
walk_ty(tystore, f, typ);
ret *flag;
}
2011-01-04 03:22:39 +01:00
// Type accessors for substructures of types
fn ty_fn_args(@type_store tystore, t fty) -> vec[arg] {
alt (struct(tystore, fty)) {
case (ty.ty_fn(_, ?a, _)) { ret a; }
case (ty.ty_native_fn(_, ?a, _)) { ret a; }
}
fail;
}
fn ty_fn_proto(@type_store tystore, t fty) -> ast.proto {
alt (struct(tystore, fty)) {
case (ty.ty_fn(?p, _, _)) { ret p; }
}
fail;
2011-01-04 03:22:39 +01:00
}
fn ty_fn_abi(@type_store tystore, t fty) -> ast.native_abi {
alt (struct(tystore, fty)) {
case (ty.ty_native_fn(?a, _, _)) { ret a; }
}
fail;
}
fn ty_fn_ret(@type_store tystore, t fty) -> t {
alt (struct(tystore, fty)) {
case (ty.ty_fn(_, _, ?r)) { ret r; }
case (ty.ty_native_fn(_, _, ?r)) { ret r; }
}
fail;
2011-01-04 03:22:39 +01:00
}
fn is_fn_ty(@type_store tystore, t fty) -> bool {
alt (struct(tystore, fty)) {
case (ty.ty_fn(_, _, _)) { ret true; }
case (ty.ty_native_fn(_, _, _)) { ret true; }
case (_) { ret false; }
}
ret false;
2011-01-04 03:22:39 +01:00
}
// 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(@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(ann);
}
}
ret tup(ty_param_count, result_ty);
}
fn item_ty(@ast.item it) -> ty_param_count_and_ty {
auto ty_param_count;
2011-01-04 21:46:11 +01:00
auto result_ty;
alt (it.node) {
case (ast.item_const(_, _, _, _, ?ann)) {
ty_param_count = 0u;
2011-01-04 21:46:11 +01:00
result_ty = ann_to_type(ann);
}
case (ast.item_fn(_, _, ?tps, _, ?ann)) {
ty_param_count = _vec.len[ast.ty_param](tps);
2011-01-04 21:46:11 +01:00
result_ty = ann_to_type(ann);
}
case (ast.item_mod(_, _, _)) {
fail; // modules are typeless
}
case (ast.item_ty(_, _, ?tps, _, ?ann)) {
ty_param_count = _vec.len[ast.ty_param](tps);
2011-01-04 21:46:11 +01:00
result_ty = ann_to_type(ann);
}
case (ast.item_tag(_, _, ?tps, ?did, ?ann)) {
ty_param_count = _vec.len[ast.ty_param](tps);
result_ty = ann_to_type(ann);
2011-01-04 21:46:11 +01:00
}
case (ast.item_obj(_, _, ?tps, _, ?ann)) {
ty_param_count = _vec.len[ast.ty_param](tps);
2011-01-04 21:46:11 +01:00
result_ty = ann_to_type(ann);
}
}
ret tup(ty_param_count, result_ty);
2011-01-04 21:46:11 +01:00
}
fn stmt_ty(@type_store tystore, @ast.stmt s) -> t {
alt (s.node) {
case (ast.stmt_expr(?e,_)) {
ret expr_ty(tystore, e);
}
case (_) {
ret mk_nil(tystore);
}
}
}
fn block_ty(@type_store tystore, &ast.block b) -> t {
alt (b.node.expr) {
case (some[@ast.expr](?e)) { ret expr_ty(tystore, e); }
case (none[@ast.expr]) { ret mk_nil(tystore); }
}
}
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
fn pat_ty(@type_store ts, @ast.pat pat) -> t {
alt (pat.node) {
case (ast.pat_wild(?ann)) { ret ann_to_monotype(ts, ann); }
case (ast.pat_lit(_, ?ann)) { ret ann_to_monotype(ts, ann); }
case (ast.pat_bind(_, _, ?ann)) { ret ann_to_monotype(ts, ann); }
case (ast.pat_tag(_, _, _, ?ann)) { ret ann_to_monotype(ts, ann); }
}
fail; // not reached
}
fn expr_ann(@ast.expr expr) -> option.t[ast.ann] {
alt (expr.node) {
case (ast.expr_vec(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_tup(_, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_rec(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_bind(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_call(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_self_method(_, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_spawn(_, _, _, _, ?ann))
{ ret some[ast.ann](ann); }
case (ast.expr_binary(_, _, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_unary(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_lit(_, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_cast(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_if(_, _, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_for(_, _, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_for_each(_, _, _, ?ann))
{ ret some[ast.ann](ann); }
case (ast.expr_while(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_do_while(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_alt(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_block(_, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_assign(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_assign_op(_, _, _, ?ann))
{ ret some[ast.ann](ann); }
case (ast.expr_field(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_index(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_path(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_ext(_, _, _, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_port(?ann)) { ret some[ast.ann](ann); }
case (ast.expr_chan(_, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_send(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_recv(_, _, ?ann)) { ret some[ast.ann](ann); }
case (ast.expr_fail(_)) { ret none[ast.ann]; }
case (ast.expr_break(_)) { ret none[ast.ann]; }
case (ast.expr_cont(_)) { ret none[ast.ann]; }
2011-04-19 11:21:23 +02:00
case (ast.expr_log(_,_,_)) { ret none[ast.ann]; }
case (ast.expr_check_expr(_,_)) { ret none[ast.ann]; }
case (ast.expr_ret(_,_)) { ret none[ast.ann]; }
case (ast.expr_put(_,_)) { ret none[ast.ann]; }
case (ast.expr_be(_,_)) { ret none[ast.ann]; }
}
fail;
}
// Returns the type of an expression as a monotype.
//
// NB: This type doesn't provide type parameter substitutions; e.g. if you
// ask for the type of "id" in "id(3)", it will return "fn(&int) -> int"
// instead of "fn(&T) -> T with T = int". If this isn't what you want, see
// expr_ty_params_and_ty() below.
fn expr_ty(@type_store tystore, @ast.expr expr) -> t {
alt (expr_ann(expr)) {
case (none[ast.ann]) { ret mk_nil(tystore); }
case (some[ast.ann](?a)) { ret ann_to_monotype(tystore, a); }
}
}
fn expr_ty_params_and_ty(@type_store tystore, @ast.expr expr)
-> tup(vec[t], t) {
alt (expr_ann(expr)) {
case (none[ast.ann]) {
let vec[t] tps = vec();
ret tup(tps, mk_nil(tystore));
}
case (some[ast.ann](?a)) {
ret tup(ann_to_type_params(a), ann_to_type(a));
}
}
}
fn expr_has_ty_params(@ast.expr expr) -> bool {
// FIXME: Rewrite using complex patterns when they're trustworthy.
alt (expr_ann(expr)) {
case (none[ast.ann]) { fail; }
case (some[ast.ann](?a)) {
alt (a) {
case (ast.ann_none) { fail; }
case (ast.ann_type(_, ?tps_opt, _)) {
ret !option.is_none[vec[t]](tps_opt);
}
}
}
}
}
// FIXME: At the moment this works only for call, bind, and path expressions.
fn replace_expr_type(@ast.expr expr, tup(vec[t], t) new_tyt) -> @ast.expr {
auto new_tps;
if (expr_has_ty_params(expr)) {
new_tps = some[vec[t]](new_tyt._0);
} else {
new_tps = none[vec[t]];
}
auto ann = ast.ann_type(new_tyt._1, new_tps, none[@ts_ann]);
alt (expr.node) {
case (ast.expr_call(?callee, ?args, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_call(callee, args, ann));
}
case (ast.expr_self_method(?ident, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_self_method(ident, ann));
}
case (ast.expr_bind(?callee, ?args, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_bind(callee, args, ann));
}
case (ast.expr_field(?e, ?i, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_field(e, i, ann));
}
case (ast.expr_path(?p, ?dopt, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_path(p, dopt, ann));
}
case (_) {
log_err "unhandled expr type in replace_expr_type(): " +
pretty.pprust.expr_to_str(expr);
fail;
}
}
}
// Expression utilities
fn field_num(session.session sess, &span sp, &ast.ident id) -> uint {
let uint accum = 0u;
let uint i = 0u;
for (u8 c in id) {
if (i == 0u) {
if (c != ('_' as u8)) {
sess.span_err(sp,
"bad numeric field on tuple: "
+ "missing leading underscore");
}
} else {
if (('0' as u8) <= c && c <= ('9' as u8)) {
accum *= 10u;
accum += (c as uint) - ('0' as uint);
} else {
auto s = "";
s += _str.unsafe_from_byte(c);
sess.span_err(sp,
"bad numeric field on tuple: "
+ " non-digit character: "
+ s);
}
}
i += 1u;
}
ret accum;
}
fn field_idx(session.session sess, &span sp,
&ast.ident id, vec[field] fields) -> uint {
let uint i = 0u;
for (field f in fields) {
if (_str.eq(f.ident, id)) {
ret i;
}
i += 1u;
}
sess.span_err(sp, "unknown field '" + id + "' of record");
fail;
}
fn method_idx(session.session sess, &span sp,
&ast.ident id, vec[method] meths) -> uint {
let uint i = 0u;
for (method m in meths) {
if (_str.eq(m.ident, id)) {
ret i;
}
i += 1u;
}
sess.span_err(sp, "unknown method '" + id + "' of obj");
fail;
}
fn sort_methods(vec[method] meths) -> vec[method] {
fn method_lteq(&method a, &method b) -> bool {
ret _str.lteq(a.ident, b.ident);
}
ret std.sort.merge_sort[method](bind method_lteq(_,_), meths);
}
fn is_lval(@ast.expr expr) -> bool {
alt (expr.node) {
case (ast.expr_field(_,_,_)) { ret true; }
case (ast.expr_index(_,_,_)) { ret true; }
case (ast.expr_path(_,_,_)) { ret true; }
case (_) { ret false; }
}
}
// Type unification via Robinson's algorithm (Robinson 1965). Implemented as
// described in Hoder and Voronkov:
//
// http://www.cs.man.ac.uk/~hoderk/ubench/unification_full.pdf
mod Unify {
tag result {
ures_ok(t);
ures_err(type_err, t, t);
}
2011-04-21 21:10:53 +02:00
type ctxt = rec(UFind.ufind sets,
hashmap[int,uint] var_ids,
mutable vec[mutable vec[t]] types,
unify_handler handler,
@type_store tystore);
// Wraps the given type in an appropriate cname.
//
// TODO: This doesn't do anything yet. We should carry the cname up from
// the expected and/or actual types when unification results in a type
// identical to one or both of the two. The precise algorithm for this is
// something we'll probably need to develop over time.
// Simple structural type comparison.
fn struct_cmp(@ctxt cx, t expected, t actual) -> result {
if (struct(cx.tystore, expected) == struct(cx.tystore, actual)) {
ret ures_ok(expected);
}
ret ures_err(terr_mismatch, expected, actual);
}
// Unifies two mutability flags.
fn unify_mut(ast.mutability expected, ast.mutability actual)
-> option.t[ast.mutability] {
if (expected == actual) {
ret some[ast.mutability](expected);
}
if (expected == ast.maybe_mut) {
ret some[ast.mutability](actual);
}
if (actual == ast.maybe_mut) {
ret some[ast.mutability](expected);
}
ret none[ast.mutability];
}
tag fn_common_res {
fn_common_res_err(result);
fn_common_res_ok(vec[arg], t);
}
2010-12-31 18:48:54 +01:00
2011-04-21 21:10:53 +02:00
fn unify_fn_common(@ctxt cx,
t expected,
t actual,
vec[arg] expected_inputs, t expected_output,
vec[arg] actual_inputs, t actual_output)
-> fn_common_res {
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));
}
2010-12-31 18:48:54 +01:00
// TODO: as above, we should have an iter2 iterator.
let vec[arg] result_ins = vec();
auto i = 0u;
while (i < expected_len) {
auto expected_input = expected_inputs.(i);
auto actual_input = actual_inputs.(i);
// This should be safe, I think?
auto result_mode;
if (mode_is_alias(expected_input.mode) ||
mode_is_alias(actual_input.mode)) {
result_mode = ast.alias;
} else {
result_mode = ast.val;
}
2010-12-31 18:48:54 +01:00
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx, actual_input.ty, expected_input.ty);
2010-12-31 18:48:54 +01:00
alt (result) {
case (ures_ok(?rty)) {
2011-04-21 21:10:53 +02:00
result_ins += vec(rec(mode=result_mode, ty=rty));
}
case (_) {
ret fn_common_res_err(result);
}
}
2010-12-31 18:48:54 +01:00
i += 1u;
2010-12-31 18:48:54 +01:00
}
// Check the output.
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx, expected_output, actual_output);
alt (result) {
case (ures_ok(?rty)) {
ret fn_common_res_ok(result_ins, rty);
}
case (_) {
ret fn_common_res_err(result);
}
2010-12-31 18:48:54 +01:00
}
}
2010-12-31 18:48:54 +01:00
2011-04-21 21:10:53 +02:00
fn unify_fn(@ctxt cx,
ast.proto e_proto,
ast.proto a_proto,
t expected,
t actual,
vec[arg] expected_inputs, t expected_output,
vec[arg] actual_inputs, t actual_output)
-> result {
2010-12-31 18:48:54 +01:00
if (e_proto != a_proto) {
ret ures_err(terr_mismatch, expected, actual);
}
2011-04-21 21:10:53 +02:00
auto t = unify_fn_common(cx, expected, actual,
expected_inputs, expected_output,
actual_inputs, actual_output);
alt (t) {
case (fn_common_res_err(?r)) {
ret r;
}
case (fn_common_res_ok(?result_ins, ?result_out)) {
auto t2 = mk_fn(cx.tystore, e_proto, result_ins, result_out);
ret ures_ok(t2);
}
}
}
2011-04-21 21:10:53 +02:00
fn unify_native_fn(@ctxt cx,
ast.native_abi e_abi,
ast.native_abi a_abi,
t expected,
t actual,
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);
}
2011-04-21 21:10:53 +02:00
auto t = unify_fn_common(cx, expected, actual,
expected_inputs, expected_output,
actual_inputs, actual_output);
alt (t) {
case (fn_common_res_err(?r)) {
ret r;
}
case (fn_common_res_ok(?result_ins, ?result_out)) {
auto t2 = mk_native_fn(cx.tystore, e_abi, result_ins,
result_out);
ret ures_ok(t2);
}
}
2010-12-31 18:48:54 +01:00
}
2011-04-21 21:10:53 +02:00
fn unify_obj(@ctxt cx,
t expected,
t actual,
vec[method] expected_meths,
vec[method] actual_meths) -> result {
2010-12-31 19:26:29 +01:00
let vec[method] result_meths = vec();
let uint i = 0u;
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);
}
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);
}
2011-04-21 21:10:53 +02:00
auto r = unify_fn(cx,
e_meth.proto, a_meth.proto,
2011-04-21 21:10:53 +02:00
expected, actual,
2010-12-31 19:26:29 +01:00
e_meth.inputs, e_meth.output,
a_meth.inputs, a_meth.output);
2011-03-06 19:56:38 +01:00
alt (r) {
case (ures_ok(?tfn)) {
alt (struct(cx.tystore, tfn)) {
2011-03-06 19:56:38 +01:00
case (ty_fn(?proto, ?ins, ?out)) {
result_meths += vec(rec(inputs = ins,
output = out
with e_meth));
}
}
}
case (_) {
ret r;
}
2010-12-31 19:26:29 +01:00
}
i += 1u;
}
auto t = mk_obj(cx.tystore, result_meths);
2010-12-31 19:26:29 +01:00
ret ures_ok(t);
}
2011-04-21 21:10:53 +02:00
fn get_or_create_set(@ctxt cx, int id) -> uint {
auto set_num;
2011-04-21 21:10:53 +02:00
alt (cx.var_ids.find(id)) {
case (none[uint]) {
2011-04-21 21:10:53 +02:00
set_num = UFind.make_set(cx.sets);
cx.var_ids.insert(id, set_num);
}
case (some[uint](?n)) { set_num = n; }
}
ret set_num;
}
fn unify_step(@ctxt cx, t expected, t actual) -> result {
// TODO: rewrite this using tuple pattern matching when available, to
// avoid all this rightward drift and spikiness.
// TODO: occurs check, to make sure we don't loop forever when
// unifying e.g. 'a and option['a]
// Fast path.
if (eq_ty(expected, actual)) { ret ures_ok(expected); }
alt (struct(cx.tystore, actual)) {
// If the RHS is a variable type, then just do the appropriate
// binding.
case (ty.ty_var(?actual_id)) {
2011-04-21 21:10:53 +02:00
auto actual_n = get_or_create_set(cx, actual_id);
alt (struct(cx.tystore, expected)) {
case (ty.ty_var(?expected_id)) {
2011-04-21 21:10:53 +02:00
auto expected_n = get_or_create_set(cx, expected_id);
UFind.union(cx.sets, expected_n, actual_n);
}
case (_) {
// Just bind the type variable to the expected type.
auto vlen = _vec.len[mutable vec[t]](cx.types);
if (actual_n < vlen) {
2011-04-21 21:10:53 +02:00
cx.types.(actual_n) += vec(expected);
} else {
check (actual_n == vlen);
2011-04-21 21:10:53 +02:00
cx.types += vec(mutable vec(expected));
}
}
}
ret ures_ok(actual);
}
case (ty.ty_local(?actual_id)) {
auto result_ty;
2011-04-21 21:10:53 +02:00
alt (cx.handler.resolve_local(actual_id)) {
case (none[t]) { result_ty = expected; }
case (some[t](?actual_ty)) {
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx, expected, actual_ty);
alt (result) {
case (ures_ok(?rty)) { result_ty = rty; }
case (_) { ret result; }
}
}
}
2011-04-21 21:10:53 +02:00
cx.handler.record_local(actual_id, result_ty);
ret ures_ok(result_ty);
}
case (ty.ty_bound_param(?actual_id)) {
alt (struct(cx.tystore, expected)) {
case (ty.ty_local(_)) {
log_err "TODO: bound param unifying with local";
fail;
}
case (_) {
2011-04-21 21:10:53 +02:00
ret cx.handler.record_param(actual_id, expected);
}
}
}
case (_) { /* empty */ }
}
alt (struct(cx.tystore, expected)) {
case (ty.ty_nil) { ret struct_cmp(cx, expected, 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_machine(_)) { 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_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); }
2011-02-18 01:23:31 +01:00
case (ty.ty_tag(?expected_id, ?expected_tps)) {
alt (struct(cx.tystore, actual)) {
2011-02-18 01:23:31 +01:00
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);
}
2011-02-18 01:23:31 +01:00
// TODO: factor this cruft out, see the TODO in the
// ty.ty_tup case
let vec[t] result_tps = vec();
2011-02-18 01:23:31 +01:00
auto i = 0u;
auto expected_len = _vec.len[t](expected_tps);
2011-02-18 01:23:31 +01:00
while (i < expected_len) {
auto expected_tp = expected_tps.(i);
auto actual_tp = actual_tps.(i);
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
2011-02-18 01:23:31 +01:00
expected_tp,
2011-04-21 21:10:53 +02:00
actual_tp);
2011-02-18 01:23:31 +01:00
alt (result) {
case (ures_ok(?rty)) {
_vec.push[t](result_tps, rty);
2011-02-18 01:23:31 +01:00
}
case (_) {
ret result;
}
}
i += 1u;
}
ret ures_ok(mk_tag(cx.tystore, expected_id,
result_tps));
}
case (_) { /* fall through */ }
}
ret ures_err(terr_mismatch, expected, actual);
}
case (ty.ty_box(?expected_mt)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_box(?actual_mt)) {
auto mut;
alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
case (none[ast.mutability]) {
ret ures_err(terr_box_mutability, expected,
actual);
}
case (some[ast.mutability](?m)) { mut = m; }
}
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
expected_mt.ty,
2011-04-21 21:10:53 +02:00
actual_mt.ty);
alt (result) {
case (ures_ok(?result_sub)) {
auto mt = rec(ty=result_sub, mut=mut);
ret ures_ok(mk_box(cx.tystore, mt));
}
case (_) {
ret result;
}
}
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_vec(?expected_mt)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_vec(?actual_mt)) {
auto mut;
alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
case (none[ast.mutability]) {
ret ures_err(terr_vec_mutability, expected,
actual);
}
case (some[ast.mutability](?m)) { mut = m; }
}
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
expected_mt.ty,
2011-04-21 21:10:53 +02:00
actual_mt.ty);
alt (result) {
case (ures_ok(?result_sub)) {
auto mt = rec(ty=result_sub, mut=mut);
ret ures_ok(mk_vec(cx.tystore, mt));
}
case (_) {
ret result;
}
}
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_port(?expected_sub)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_port(?actual_sub)) {
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
expected_sub,
2011-04-21 21:10:53 +02:00
actual_sub);
alt (result) {
case (ures_ok(?result_sub)) {
ret ures_ok(mk_port(cx.tystore, result_sub));
}
case (_) {
ret result;
}
}
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_chan(?expected_sub)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_chan(?actual_sub)) {
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
expected_sub,
2011-04-21 21:10:53 +02:00
actual_sub);
alt (result) {
case (ures_ok(?result_sub)) {
ret ures_ok(mk_chan(cx.tystore, result_sub));
}
case (_) {
ret result;
}
}
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_tup(?expected_elems)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_tup(?actual_elems)) {
auto expected_len = _vec.len[ty.mt](expected_elems);
auto actual_len = _vec.len[ty.mt](actual_elems);
if (expected_len != actual_len) {
auto err = terr_tuple_size(expected_len,
actual_len);
ret ures_err(err, expected, actual);
}
// TODO: implement an iterator that can iterate over
// two arrays simultaneously.
let vec[ty.mt] result_elems = vec();
auto i = 0u;
while (i < expected_len) {
auto expected_elem = expected_elems.(i);
auto actual_elem = actual_elems.(i);
auto mut;
alt (unify_mut(expected_elem.mut,
actual_elem.mut)) {
case (none[ast.mutability]) {
auto err = terr_tuple_mutability;
ret ures_err(err, expected, actual);
}
case (some[ast.mutability](?m)) { mut = m; }
}
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
expected_elem.ty,
2011-04-21 21:10:53 +02:00
actual_elem.ty);
alt (result) {
case (ures_ok(?rty)) {
auto mt = rec(ty=rty, mut=mut);
result_elems += vec(mt);
}
case (_) {
ret result;
}
}
i += 1u;
}
ret ures_ok(mk_tup(cx.tystore, result_elems));
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_rec(?expected_fields)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_rec(?actual_fields)) {
auto expected_len = _vec.len[field](expected_fields);
auto actual_len = _vec.len[field](actual_fields);
if (expected_len != actual_len) {
auto err = terr_record_size(expected_len,
actual_len);
ret ures_err(err, expected, actual);
}
// TODO: implement an iterator that can iterate over
// two arrays simultaneously.
let vec[field] result_fields = vec();
auto i = 0u;
while (i < expected_len) {
auto expected_field = expected_fields.(i);
auto actual_field = actual_fields.(i);
auto mut;
alt (unify_mut(expected_field.mt.mut,
actual_field.mt.mut)) {
case (none[ast.mutability]) {
ret ures_err(terr_record_mutability,
expected, actual);
}
case (some[ast.mutability](?m)) { mut = m; }
}
if (!_str.eq(expected_field.ident,
actual_field.ident)) {
auto err =
terr_record_fields(expected_field.ident,
actual_field.ident);
ret ures_err(err, expected, actual);
}
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx,
expected_field.mt.ty,
2011-04-21 21:10:53 +02:00
actual_field.mt.ty);
alt (result) {
case (ures_ok(?rty)) {
auto mt = rec(ty=rty, mut=mut);
_vec.push[field]
(result_fields,
rec(mt=mt with expected_field));
}
case (_) {
ret result;
}
}
i += 1u;
}
ret ures_ok(mk_rec(cx.tystore, result_fields));
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_fn(?ep, ?expected_inputs, ?expected_output)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_fn(?ap, ?actual_inputs, ?actual_output)) {
2011-04-21 21:10:53 +02:00
ret unify_fn(cx, ep, ap,
expected, actual,
expected_inputs, expected_output,
actual_inputs, actual_output);
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
case (ty.ty_native_fn(?e_abi, ?expected_inputs,
?expected_output)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_native_fn(?a_abi, ?actual_inputs,
?actual_output)) {
2011-04-21 21:10:53 +02:00
ret unify_native_fn(cx, e_abi, a_abi,
expected, actual,
expected_inputs, expected_output,
actual_inputs, actual_output);
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
}
}
2010-12-31 19:26:29 +01:00
case (ty.ty_obj(?expected_meths)) {
alt (struct(cx.tystore, actual)) {
case (ty.ty_obj(?actual_meths)) {
2011-04-21 21:10:53 +02:00
ret unify_obj(cx, expected, actual,
expected_meths, actual_meths);
}
case (_) {
ret ures_err(terr_mismatch, expected, actual);
}
2010-12-31 19:26:29 +01:00
}
}
case (ty.ty_var(?expected_id)) {
// Add a binding.
2011-04-21 21:10:53 +02:00
auto expected_n = get_or_create_set(cx, expected_id);
auto vlen = _vec.len[mutable vec[t]](cx.types);
if (expected_n < vlen) {
2011-04-21 21:10:53 +02:00
cx.types.(expected_n) += vec(actual);
} else {
check (expected_n == vlen);
2011-04-21 21:10:53 +02:00
cx.types += vec(mutable vec(actual));
}
ret ures_ok(expected);
}
case (ty.ty_local(?expected_id)) {
auto result_ty;
2011-04-21 21:10:53 +02:00
alt (cx.handler.resolve_local(expected_id)) {
case (none[t]) { result_ty = actual; }
case (some[t](?expected_ty)) {
2011-04-21 21:10:53 +02:00
auto result = unify_step(cx, expected_ty, actual);
alt (result) {
case (ures_ok(?rty)) { result_ty = rty; }
case (_) { ret result; }
}
}
}
2011-04-21 21:10:53 +02:00
cx.handler.record_local(expected_id, result_ty);
ret ures_ok(result_ty);
}
case (ty.ty_bound_param(?expected_id)) {
2011-04-21 21:10:53 +02:00
ret cx.handler.record_param(expected_id, actual);
}
}
// TODO: remove me once match-exhaustiveness checking works
fail;
}
// Performs type binding substitution.
fn substitute(@ctxt cx, vec[t] set_types, t typ) -> t {
fn substituter(@ctxt cx, vec[t] types, t typ) -> t {
alt (struct(cx.tystore, typ)) {
case (ty_var(?id)) {
2011-04-21 21:10:53 +02:00
alt (cx.var_ids.find(id)) {
case (some[uint](?n)) {
2011-04-21 21:10:53 +02:00
auto root = UFind.find(cx.sets, n);
ret types.(root);
}
case (none[uint]) { ret typ; }
}
}
case (_) { ret typ; }
}
}
2011-04-21 21:10:53 +02:00
auto f = bind substituter(cx, set_types, _);
ret fold_ty(cx.tystore, f, typ);
}
fn unify_sets(@ctxt cx) -> vec[t] {
let vec[t] throwaway = vec();
let vec[mutable vec[t]] set_types = vec(mutable throwaway);
_vec.pop[mutable vec[t]](set_types); // FIXME: botch
2011-04-21 21:10:53 +02:00
for (UFind.node node in cx.sets.nodes) {
let vec[t] v = vec();
set_types += vec(mutable v);
}
auto i = 0u;
while (i < _vec.len[mutable vec[t]](set_types)) {
2011-04-21 21:10:53 +02:00
auto root = UFind.find(cx.sets, i);
set_types.(root) += cx.types.(i);
i += 1u;
}
let vec[t] result = vec();
for (vec[t] types in set_types) {
if (_vec.len[t](types) > 1u) {
log_err "unification of > 1 types in a type set is " +
"unimplemented";
fail;
}
result += vec(types.(0));
}
ret result;
}
fn unify(t expected,
t actual,
&unify_handler handler,
@type_store tystore) -> result {
let vec[t] throwaway = vec();
let vec[mutable vec[t]] types = vec(mutable throwaway);
_vec.pop[mutable vec[t]](types); // FIXME: botch
2011-04-21 21:10:53 +02:00
auto cx = @rec(sets=UFind.make(),
var_ids=common.new_int_hash[uint](),
mutable types=types,
handler=handler,
tystore=tystore);
2011-02-07 23:16:40 +01:00
2011-04-21 21:10:53 +02:00
auto ures = unify_step(cx, expected, actual);
alt (ures) {
case (ures_ok(?typ)) {
// Fast path: if there are no local variables, don't perform
// substitutions.
if (_vec.len[mutable UFind.node](cx.sets.nodes) == 0u) {
ret ures_ok(typ);
}
2011-04-21 21:10:53 +02:00
auto set_types = unify_sets(cx);
auto t2 = substitute(cx, set_types, typ);
ret ures_ok(t2);
}
case (_) { ret ures; }
}
fail; // not reached
}
}
fn type_err_to_str(&ty.type_err err) -> str {
alt (err) {
case (terr_mismatch) {
ret "types differ";
}
case (terr_box_mutability) {
ret "boxed values differ in mutability";
}
case (terr_vec_mutability) {
ret "vectors differ in mutability";
}
case (terr_tuple_size(?e_sz, ?a_sz)) {
ret "expected a tuple with " + _uint.to_str(e_sz, 10u) +
" elements but found one with " + _uint.to_str(a_sz, 10u) +
" elements";
}
case (terr_tuple_mutability) {
ret "tuple elements differ in mutability";
}
case (terr_record_size(?e_sz, ?a_sz)) {
ret "expected a record with " + _uint.to_str(e_sz, 10u) +
" fields but found one with " + _uint.to_str(a_sz, 10u) +
" fields";
}
case (terr_record_mutability) {
ret "record elements differ in mutability";
}
case (terr_record_fields(?e_fld, ?a_fld)) {
ret "expected a record with field '" + e_fld +
"' but found one with field '" + a_fld +
"'";
}
case (terr_arg_count) {
ret "incorrect number of function parameters";
}
2010-12-31 19:26:29 +01:00
case (terr_meth_count) {
ret "incorrect number of object methods";
}
case (terr_obj_meths(?e_meth, ?a_meth)) {
ret "expected an obj with method '" + e_meth +
"' but found one with method '" + a_meth +
"'";
}
}
}
// Performs bound type parameter replacement using the supplied mapping from
// parameter IDs to types.
fn substitute_type_params(@type_store tystore,
vec[t] bindings,
t typ) -> t {
fn replacer(@type_store tystore, vec[t] bindings, t typ) -> t {
alt (struct(tystore, typ)) {
case (ty_bound_param(?param_index)) {
ret bindings.(param_index);
}
case (_) { ret typ; }
}
}
auto f = bind replacer(tystore, bindings, _);
ret fold_ty(tystore, f, typ);
}
// Converts type parameters in a type to bound type parameters.
fn bind_params_in_type(@type_store tystore, t typ) -> t {
fn binder(@type_store tystore, t typ) -> t {
alt (struct(tystore, 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(tystore, index); }
case (_) { ret typ; }
}
}
auto f = bind binder(tystore, _);
ret fold_ty(tystore, f, typ);
}
fn def_has_ty_params(&ast.def def) -> bool {
alt (def) {
case (ast.def_fn(_)) { ret true; }
case (ast.def_obj(_)) { ret true; }
case (ast.def_obj_field(_)) { ret false; }
case (ast.def_mod(_)) { ret false; }
case (ast.def_const(_)) { ret false; }
case (ast.def_arg(_)) { ret false; }
case (ast.def_local(_)) { ret false; }
case (ast.def_variant(_, _)) { ret true; }
case (ast.def_ty(_)) { ret false; }
case (ast.def_ty_arg(_)) { ret false; }
case (ast.def_binding(_)) { ret false; }
case (ast.def_use(_)) { ret false; }
case (ast.def_native_ty(_)) { ret false; }
case (ast.def_native_fn(_)) { ret true; }
}
}
// If the given item is in an external crate, looks up its type and adds it to
// the type cache. Returns the type parameters and type.
fn lookup_item_type(session.session sess,
@type_store tystore,
&type_cache cache,
ast.def_id did) -> ty_param_count_and_ty {
if (did._0 == sess.get_targ_crate_num()) {
// The item is in this crate. The caller should have added it to the
// type cache already; we simply return it.
ret cache.get(did);
}
alt (cache.find(did)) {
case (some[ty_param_count_and_ty](?tpt)) { ret tpt; }
case (none[ty_param_count_and_ty]) {
auto tyt = creader.get_type(sess, tystore, did);
cache.insert(did, tyt);
ret tyt;
}
}
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End: