#include "type.hpp" #include #include #include #include "error.hpp" void type_scheme::print(const type_mgr& mgr, std::ostream& to) const { if(forall.size() != 0) { to << "forall "; for(auto& var : forall) { to << var << " "; } to << ". "; } monotype->print(mgr, to); } type_ptr substitute(const type_mgr& mgr, const std::map& subst, const type_ptr& t) { type_var* var; type_ptr resolved = mgr.resolve(t, var); if(var) { auto subst_it = subst.find(var->name); if(subst_it == subst.end()) return resolved; return subst_it->second; } else if(type_arr* arr = dynamic_cast(t.get())) { auto left_result = substitute(mgr, subst, arr->left); auto right_result = substitute(mgr, subst, arr->right); if(left_result == arr->left && right_result == arr->right) return t; return type_ptr(new type_arr(left_result, right_result)); } return t; } type_ptr type_scheme::instantiate(type_mgr& mgr) const { if(forall.size() == 0) return monotype; std::map subst; for(auto& var : forall) { subst[var] = mgr.new_type(); } return substitute(mgr, subst, monotype); } void type_var::print(const type_mgr& mgr, std::ostream& to) const { auto it = mgr.types.find(name); if(it != mgr.types.end()) { it->second->print(mgr, to); } else { to << name; } } void type_base::print(const type_mgr& mgr, std::ostream& to) const { to << name; } void type_arr::print(const type_mgr& mgr, std::ostream& to) const { left->print(mgr, to); to << " -> ("; right->print(mgr, to); to << ")"; } std::string type_mgr::new_type_name() { int temp = last_id++; std::string str = ""; while(temp != -1) { str += (char) ('a' + (temp % 26)); temp = temp / 26 - 1; } std::reverse(str.begin(), str.end()); return str; } type_ptr type_mgr::new_type() { return type_ptr(new type_var(new_type_name())); } type_ptr type_mgr::new_arrow_type() { return type_ptr(new type_arr(new_type(), new_type())); } type_ptr type_mgr::resolve(type_ptr t, type_var*& var) const { type_var* cast; var = nullptr; while((cast = dynamic_cast(t.get()))) { auto it = types.find(cast->name); if(it == types.end()) { var = cast; break; } t = it->second; } return t; } void type_mgr::unify(type_ptr l, type_ptr r) { type_var* lvar; type_var* rvar; type_arr* larr; type_arr* rarr; type_base* lid; type_base* rid; l = resolve(l, lvar); r = resolve(r, rvar); if(lvar) { bind(lvar->name, r); return; } else if(rvar) { bind(rvar->name, l); return; } else if((larr = dynamic_cast(l.get())) && (rarr = dynamic_cast(r.get()))) { unify(larr->left, rarr->left); unify(larr->right, rarr->right); return; } else if((lid = dynamic_cast(l.get())) && (rid = dynamic_cast(r.get()))) { if(lid->name == rid->name) return; } throw unification_error(l, r); } void type_mgr::bind(const std::string& s, type_ptr t) { type_var* other = dynamic_cast(t.get()); if(other && other->name == s) return; types[s] = t; } void type_mgr::find_free(const type_ptr& t, std::set& into) const { type_var* var; type_ptr resolved = resolve(t, var); if(var) { into.insert(var->name); } else if(type_arr* arr = dynamic_cast(resolved.get())) { find_free(arr->left, into); find_free(arr->right, into); } }