import mem:* import str:* import vec:* import util:* import tree:* import ast:* import binding:* adt type { _unknown, _void, _template_placeholder, _ptr: *binding, _ref: *binding, _obj: *tree, // triple, is_variadic, is raw> _fun: triple>, *binding>, bool, bool>, _bool, _char, _uchar, _short, _ushort, _int, _uint, _long, _ulong, _float, _double } fun unify(t1: *binding, t2: *binding) { println("attempting to unify " + to_string(t1->bound_to) + " and " + to_string(t2->bound_to)) if (is_unknown(t1->bound_to)) { t1->set(t2->bound_to) } else if (is_unknown(t2->bound_to)) { t2->set(t1->bound_to) } else { if (shallow_equality(t1->bound_to, t2->bound_to)) { if (is_fun(t1->bound_to)) { unify(t1->bound_to->_fun.first.second, t2->bound_to->_fun.first.second) for (var i = 0; i < t1->bound_to->_fun.first.first.size; i++;) unify(t1->bound_to->_fun.first.first[i], t2->bound_to->_fun.first.first[i]) } else if (is_ptr(t1->bound_to)) { unify(t1->bound_to->_ptr, t2->bound_to->_ptr) } else if (is_obj(t1->bound_to)) { for (var i = 0; i < t1->bound_to->_obj->data._binding.second.size; i++;) { unify(t1->bound_to->_obj->data._binding.second[i], t2->bound_to->_obj->data._binding.second[i]) } } } else { error("Doesn't typecheck! Attempted to unify " + to_string(t1->bound_to) + " and " + to_string(t2->bound_to)) } } } fun shallow_equality(a: *type, b: *type):bool { if (is_ptr(a) != is_ptr(b)) return false if (is_ptr(a) && is_ptr(b)) return true match(*a) { type::_fun(x) { return is_fun(b) && a->_fun.third == b->_fun.third } type::_obj(x) { return is_obj(b) && (get_ast_binding(x) == get_ast_binding(b->_obj) || ((!ast_bound(x) || !ast_bound(b->_obj)) && x->data._binding.second.size == b->_obj->data._binding.second.size && x->data._binding.first == b->_obj->data._binding.first)) } } return *a == *b } fun inst_temp_type(t: *binding, replacements: ref map<*binding, *binding>): *binding { match (*t->bound_to) { type::_unknown() error("Unknown in temp type") type::_obj(o) { var binding_types = o->data._binding.second.map(fun(b: *binding): *binding return inst_temp_type(b, replacements);) for (var i = 0; i < o->data._binding.second.size; i++;) { if (o->data._binding.second[i] != binding_types[i]) return binding_p(type::_obj(_binding(o->data._binding.first, binding_types, o->data._binding.third))) } } type::_ptr(p) { var cp = inst_temp_type(p, replacements) if (cp == p) return t else return binding_p(type::_ptr(cp)) } type::_ref(r) { var cr = inst_temp_type(r, replacements) if (cr == r) return t else return binding_p(type::_ref(cr)) } type::_fun(b) { // triple, is_variadic, is raw> var rt = inst_temp_type(b.first.second, replacements) var pts = b.first.first.map(fun(pt: *binding): *binding return inst_temp_type(pt, replacements);) if (rt != b.first.second) return binding_p(type::_fun(make_triple(make_pair(pts, rt), b.second, b.third))) for (var i = 0; i < pts.size; i++;) if (pts[i] != b.first.first[i]) return binding_p(type::_fun(make_triple(make_pair(pts, rt), b.second, b.third))) return t } type::_template_placeholder() return replacements[t] } return t } fun equality(a: *type, b: *type, count_unknown_as_equal: bool): bool { /*println("equality of " + to_string(a) + " and " + to_string(b))*/ if (count_unknown_as_equal && (is_unknown(a) || is_unknown(b))) return true match(*a) { type::_obj(x) { if (!is_obj(b)) return false if (get_ast_binding(x) == get_ast_binding(b->_obj)) return true if (!count_unknown_as_equal || (ast_bound(x) && ast_bound(b->_obj)) || x->data._binding.first != b->_obj->data._binding.first || x->data._binding.second.size != b->_obj->data._binding.second.size) return false for (var i = 0; i < x->data._binding.second.size; i++;) { if (!equality(x->data._binding.second[i]->bound_to, b->_obj->data._binding.second[i]->bound_to, count_unknown_as_equal)) return false } return true } type::_ptr(p) { if (!is_ptr(b)) return false return equality(p->bound_to, b->_ptr->bound_to, count_unknown_as_equal) } type::_ref(r) { if (!is_ref(b)) return false return equality(r->bound_to, b->_ref->bound_to, count_unknown_as_equal) } type::_fun(i) { if ( !(is_fun(b) && a->_fun.second == b->_fun.second && a->_fun.third == b->_fun.third) ) return false if ( !equality(a->_fun.first.second->bound_to, b->_fun.first.second->bound_to, count_unknown_as_equal) ) return false if ( !(a->_fun.first.first.size == b->_fun.first.first.size) ) return false for (var i = 0; i < a->_fun.first.first.size; i++;) if ( !equality(a->_fun.first.first[i]->bound_to, b->_fun.first.first[i]->bound_to, count_unknown_as_equal) ) return false return true } } return *a == *b } fun to_string(it: *type): str { match (*it) { type::_unknown() return str("_unknown") type::_void() return str("_void") type::_ptr(p) return "*" + to_string(p->bound_to) type::_ref(r) return "ref" + to_string(r->bound_to) type::_obj(b) { return "_obj(" + to_string(b->data) + ")" } type::_fun(b) { // triple, is_variadic, is raw> var to_ret = str() if (b.second) to_ret += "_run(" else to_ret += "_fun(" to_ret += str(", ").join(b.first.first.map(fun(pt: *binding): str return to_string(pt->bound_to);)) if (b.third) to_ret += " ..." return to_ret + "): " + to_string(b.first.second->bound_to) } type::_template_placeholder() return str("_template_placeholder") type::_bool() return str("_bool") type::_char() return str("_char") type::_uchar() return str("_uchar") type::_short() return str("_short") type::_ushort() return str("_ushort") type::_int() return str("_int") type::_uint() return str("_uint") type::_long() return str("_long") type::_ulong() return str("_ulong") type::_float() return str("_float") type::_double() return str("_double") } return str("impossible type") } fun is_unknown(x: *type): bool { match (*x) { type::_unknown() return true } return false } fun is_void(x: *type): bool { match (*x) { type::_void() return true } return false } fun is_ptr(x: *type): bool { match (*x) { type::_ptr(p) return true } return false } fun is_ref(x: *type): bool { match (*x) { type::_ref(r) return true } return false } fun is_obj(x: *type): bool { match (*x) { type::_obj() return true } return false } fun is_fun(x: *type): bool { match (*x) { type::_fun(b) return true } return false } fun is_template_placeholder(x: *type): bool { match (*x) { type::_template_placeholder() return true } return false } fun is_bool(x: *type): bool { match (*x) { type::_bool() return true } return false } fun is_char(x: *type): bool { match (*x) { type::_char() return true } return false } fun is_uchar(x: *type): bool { match (*x) { type::_uchar() return true } return false } fun is_short(x: *type): bool { match (*x) { type::_short() return true } return false } fun is_ushort(x: *type): bool { match (*x) { type::_ushort() return true } return false } fun is_int(x: *type): bool { match (*x) { type::_int() return true } return false } fun is_uint(x: *type): bool { match (*x) { type::_uint() return true } return false } fun is_long(x: *type): bool { match (*x) { type::_long() return true } return false } fun is_ulong(x: *type): bool { match (*x) { type::_ulong() return true } return false } fun is_float(x: *type): bool { match (*x) { type::_float() return true } return false } fun is_double(x: *type): bool { match (*x) { type::_double() return true } return false } fun is_signed(x: *type): bool { match (*x) { type::_char() return true type::_int() return true type::_long() return true type::_short() return true type::_float() return true type::_double() return true type::_uchar() return false type::_ushort() return false type::_uint() return false type::_ulong() return false } return false }