static bool is_nominal_sub_interface(ast_t* sub, ast_t* super) { ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); ast_t* sub_typeargs = ast_childidx(sub, 2); ast_t* super_typeargs = ast_childidx(super, 2); ast_t* sub_typeparams = ast_childidx(sub_def, 1); ast_t* super_typeparams = ast_childidx(super_def, 1); ast_t* super_members = ast_childidx(super_def, 4); ast_t* super_member = ast_child(super_members); while(super_member != NULL) { ast_t* super_member_id = ast_childidx(super_member, 1); ast_t* sub_member = ast_get(sub_def, ast_name(super_member_id), NULL); if(sub_member == NULL) return false; ast_t* r_sub_member = reify(sub_typeargs, sub_member, sub_typeparams, sub_typeargs); if(r_sub_member== NULL) return false; ast_t* r_super_member = reify(super_typeargs, super_member, super_typeparams, super_typeargs); if(r_super_member == NULL) { ast_free_unattached(r_sub_member); return false; } bool ok = is_fun_sub_fun(r_sub_member, r_super_member, sub, super); ast_free_unattached(r_sub_member); ast_free_unattached(r_super_member); if(!ok) return false; super_member = ast_sibling(super_member); } return true; }
bool is_subtype(ast_t* sub, ast_t* super) { assert(sub != NULL); assert(super != NULL); if(ast_id(super) == TK_DONTCARE) return true; switch(ast_id(sub)) { case TK_UNIONTYPE: return is_union_subtype(sub, super); case TK_ISECTTYPE: return is_isect_subtype(sub, super); case TK_TUPLETYPE: return is_tuple_subtype(sub, super); case TK_NOMINAL: return is_nominal_subtype(sub, super); case TK_TYPEPARAMREF: return is_typeparam_subtype(sub, super); case TK_ARROW: return is_arrow_subtype(sub, super); case TK_FUNTYPE: case TK_INFERTYPE: case TK_ERRORTYPE: return false; case TK_NEW: case TK_BE: case TK_FUN: return is_fun_sub_fun(sub, super, NULL, NULL); default: {} } assert(0); return false; }
static bool is_nominal_sub_interface(ast_t* sub, ast_t* super, errorframe_t* errors) { // implements(N, I) // k <: k' // --- // N k <: I k ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); // Add an assumption: sub <: super if(push_assume(sub, super)) return true; bool ret = true; // A struct has no descriptor, so can't be a subtype of an interface. if(ast_id(sub_def) == TK_STRUCT) { ret = false; if(errors != NULL) { ast_error_frame(errors, sub, "%s is not a subtype of %s: a struct can't be a subtype of an " "interface", ast_print_type(sub), ast_print_type(super)); } } if(!is_sub_cap_and_eph(sub, super, errors)) ret = false; ast_t* sub_typeargs = ast_childidx(sub, 2); ast_t* sub_typeparams = ast_childidx(sub_def, 1); ast_t* super_typeargs = ast_childidx(super, 2); ast_t* super_typeparams = ast_childidx(super_def, 1); ast_t* super_members = ast_childidx(super_def, 4); ast_t* super_member = ast_child(super_members); while(super_member != NULL) { ast_t* super_member_id = ast_childidx(super_member, 1); ast_t* sub_member = ast_get(sub_def, ast_name(super_member_id), NULL); // If we don't provide a method, we aren't a subtype. if(sub_member == NULL) { if(errors != NULL) { ast_error_frame(errors, sub, "%s is not a subtype of %s: it has no method %s", ast_print_type(sub), ast_print_type(super), ast_name(super_member_id)); } ret = false; super_member = ast_sibling(super_member); continue; } // Reify the method on the subtype. ast_t* r_sub_member = reify(sub_member, sub_typeparams, sub_typeargs); assert(r_sub_member != NULL); // Reify the method on the supertype. ast_t* r_super_member = reify(super_member, super_typeparams, super_typeargs); assert(r_super_member != NULL); // Check the reified methods. bool ok = is_fun_sub_fun(r_sub_member, r_super_member, errors); ast_free_unattached(r_sub_member); ast_free_unattached(r_super_member); if(!ok) { ret = false; if(errors != NULL) { ast_error_frame(errors, sub_member, "%s is not a subtype of %s: method %s has an incompatible signature", ast_print_type(sub), ast_print_type(super), ast_name(super_member_id)); } } super_member = ast_sibling(super_member); } pop_assume(); return ret; }