token_id cap_from_constraint(ast_t* type) { switch(ast_id(type)) { case TK_UNIONTYPE: { ast_t* child = ast_child(type); token_id cap = cap_from_constraint(child); child = ast_sibling(child); while(child != NULL) { cap = cap_union_constraint(cap, cap_from_constraint(child)); child = ast_sibling(child); } return cap; } case TK_ISECTTYPE: { ast_t* child = ast_child(type); token_id cap = cap_from_constraint(child); child = ast_sibling(child); while(child != NULL) { cap = cap_isect_constraint(cap, cap_from_constraint(child)); child = ast_sibling(child); } return cap; } case TK_NOMINAL: case TK_TYPEPARAMREF: return cap_typeparam(cap_single(type)); case TK_ARROW: { AST_GET_CHILDREN(type, left, right); return cap_from_constraint(right); } default: {} } assert(0); return TK_NONE; }
ast_result_t flatten_typeparamref(ast_t* ast) { AST_GET_CHILDREN(ast, id, cap, ephemeral); // Get the lowest capability that could fulfill the constraint. ast_t* def = (ast_t*)ast_data(ast); AST_GET_CHILDREN(def, name, constraint, default_type); if(ast_id(cap) != TK_NONE) { ast_error(cap, "can't specify a capability on a type parameter"); return AST_ERROR; } // Set the typeparamref cap. token_id tcap = cap_from_constraint(constraint); ast_setid(cap, tcap); return AST_OK; }
static bool is_fun_sub_fun(ast_t* sub, ast_t* super, ast_t* isub, ast_t* isuper) { token_id tsub = ast_id(sub); token_id tsuper = ast_id(super); switch(tsub) { case TK_NEW: case TK_BE: case TK_FUN: break; default: return false; } switch(tsuper) { case TK_NEW: case TK_BE: case TK_FUN: break; default: return false; } // A constructor can only be a subtype of a constructor. if(((tsub == TK_NEW) || (tsuper == TK_NEW)) && (tsub != tsuper)) return false; AST_GET_CHILDREN(sub, sub_cap, sub_id, sub_typeparams, sub_params); AST_GET_CHILDREN(super, super_cap, super_id, super_typeparams, super_params); // Must have the same name. if(ast_name(sub_id) != ast_name(super_id)) return false; // Must have the same number of type parameters and parameters. if((ast_childcount(sub_typeparams) != ast_childcount(super_typeparams)) || (ast_childcount(sub_params) != ast_childcount(super_params))) return false; ast_t* r_sub = sub; if(ast_id(super_typeparams) != TK_NONE) { // Reify sub with the type parameters of super. BUILD(typeargs, super_typeparams, NODE(TK_TYPEARGS)); ast_t* super_typeparam = ast_child(super_typeparams); while(super_typeparam != NULL) { AST_GET_CHILDREN(super_typeparam, super_id, super_constraint); token_id cap = cap_from_constraint(super_constraint); BUILD(typearg, super_typeparam, NODE(TK_TYPEPARAMREF, TREE(super_id) NODE(cap) NONE)); ast_t* def = ast_get(super_typeparam, ast_name(super_id), NULL); ast_setdata(typearg, def); ast_append(typeargs, typearg); super_typeparam = ast_sibling(super_typeparam); } r_sub = reify(sub, sub, sub_typeparams, typeargs); ast_free_unattached(typeargs); } bool ok = is_reified_fun_sub_fun(r_sub, super, isub, isuper); if(r_sub != sub) ast_free_unattached(r_sub); return ok; }