ast_t* viewpoint_type(ast_t* l_type, ast_t* r_type) { switch(ast_id(l_type)) { case TK_TUPLETYPE: case TK_UNIONTYPE: case TK_ISECTTYPE: { // Only occurs in codegen. return r_type; } case TK_NOMINAL: { if(ast_id(r_type) == TK_ARROW) return make_arrow_type(l_type, r_type); AST_GET_CHILDREN(l_type, pkg, id, typeargs, cap, eph); token_id tcap = ast_id(cap); if(tcap == TK_CAP_READ) return make_arrow_type(l_type, r_type); return viewpoint_cap(tcap, ast_id(eph), r_type); } case TK_TYPEPARAMREF: { if(ast_id(r_type) == TK_ARROW) return make_arrow_type(l_type, r_type); AST_GET_CHILDREN(l_type, id, cap, eph); token_id tcap = ast_id(cap); if(tcap == TK_CAP_READ) return make_arrow_type(l_type, r_type); return viewpoint_cap(tcap, ast_id(eph), r_type); } case TK_ARROW: case TK_BOXTYPE: case TK_THISTYPE: return make_arrow_type(l_type, r_type); default: {} } return NULL; }
ast_t* viewpoint_cap(token_id cap, token_id eph, ast_t* type) { if(cap == TK_TAG) return NULL; switch(ast_id(type)) { case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_TUPLETYPE: { // Adapt all elements. ast_t* r_type = ast_from(type, ast_id(type)); ast_t* child = ast_child(type); while(child != NULL) { ast_append(r_type, viewpoint_cap(cap, eph, child)); child = ast_sibling(child); } return r_type; } case TK_NOMINAL: return viewpoint_for_type(cap, eph, type, 3); case TK_TYPEPARAMREF: return viewpoint_for_type(cap, eph, type, 1); case TK_ARROW: { // Adapt the lower bounds. ast_t* lower = viewpoint_lower(type); ast_t* r_type = viewpoint_cap(cap, eph, lower); if(r_type != lower) ast_free_unattached(lower); return r_type; } default: {} } assert(0); return NULL; }
ast_t* viewpoint_type(ast_t* l_type, ast_t* r_type) { switch(ast_id(l_type)) { case TK_TUPLETYPE: case TK_UNIONTYPE: case TK_ISECTTYPE: { // Only occurs in codegen. return r_type; } case TK_NOMINAL: { if(ast_id(r_type) == TK_ARROW) return make_arrow_type(l_type, r_type); AST_GET_CHILDREN(l_type, pkg, id, typeargs, cap, eph); return viewpoint_cap(ast_id(cap), ast_id(eph), r_type); } case TK_TYPEPARAMREF: { if(ast_id(r_type) == TK_ARROW) return make_arrow_type(l_type, r_type); // If the left side is a type parameter, return an arrow type if the // capability is box, otherwise adapt the type. AST_GET_CHILDREN(l_type, id, cap, eph); token_id tcap = ast_id(cap); if(tcap == TK_BOX_GENERIC) return make_arrow_type(l_type, r_type); return viewpoint_cap(tcap, ast_id(eph), r_type); } case TK_ARROW: case TK_BOXTYPE: case TK_THISTYPE: return make_arrow_type(l_type, r_type); default: {} } return NULL; }
static token_id partial_application_cap(ast_t* ftype, ast_t* receiver, ast_t* positional) { // Check if the apply method in the generated object literal can accept a box // receiver. If not, it must be a ref receiver. It can accept a box receiver // if box->receiver <: lhs->receiver and box->arg <: lhs->param. AST_GET_CHILDREN(ftype, cap, typeparams, params, result); ast_t* type = ast_type(receiver); ast_t* view_type = viewpoint_cap(TK_BOX, TK_NONE, type); ast_t* need_type = set_cap_and_ephemeral(type, ast_id(cap), TK_NONE); bool ok = is_subtype(view_type, need_type); ast_free_unattached(view_type); ast_free_unattached(need_type); if(!ok) return TK_REF; ast_t* param = ast_child(params); ast_t* arg = ast_child(positional); while(arg != NULL) { if(ast_id(arg) != TK_NONE) { type = ast_type(arg); view_type = viewpoint_cap(TK_BOX, TK_NONE, type); need_type = ast_childidx(param, 1); ok = is_subtype(view_type, need_type); ast_free_unattached(view_type); ast_free_unattached(need_type); if(!ok) return TK_REF; } arg = ast_sibling(arg); param = ast_sibling(param); } return TK_BOX; }
ast_t* viewpoint_upper(ast_t* type) { if(ast_id(type) == TK_ARROW) { AST_GET_CHILDREN(type, left, right); ast_t* r_right = viewpoint_upper(right); return viewpoint_cap(TK_BOX, TK_NONE, r_right); } return type; }
bool flatten_arrows(ast_t** astp, bool errors) { ast_t* ast = *astp; ast_t* node_type = ast_type(ast); if(node_type != NULL) { if(!flatten_arrows(&node_type, errors)) return false; } if(ast_id(ast) == TK_ARROW) { AST_GET_CHILDREN(ast, left, right); ast_t* flat; if(!flatten_arrows(&right, errors)) return false; if((ast_id(left) == TK_BOXTYPE) && (ast_id(right) != TK_ARROW)) flat = viewpoint_cap(TK_BOX, TK_NONE, right); else flat = viewpoint_type(left, right); if(flat == NULL) { if(errors) ast_error(ast, "can't flatten arrow type"); return false; } ast_replace(astp, flat); return true; } ast_t* child = ast_child(ast); while(child != NULL) { if(!flatten_arrows(&child, errors)) return false; child = ast_sibling(child); } return true; }
ast_t* viewpoint_lower(ast_t* type) { switch(ast_id(type)) { case TK_TUPLETYPE: case TK_UNIONTYPE: case TK_ISECTTYPE: { // Adapt all elements. ast_t* r_type = ast_from(type, ast_id(type)); ast_t* child = ast_child(type); while(child != NULL) { ast_append(r_type, viewpoint_lower(child)); child = ast_sibling(child); } return r_type; } case TK_NOMINAL: return viewpoint_lower_for_type(type, 3); case TK_TYPEPARAMREF: return viewpoint_lower_for_type(type, 1); case TK_ARROW: { AST_GET_CHILDREN(type, left, right); // If left is a boxtype, right's lower bounds is its actual type. if(ast_id(left) == TK_BOXTYPE) return viewpoint_cap(TK_BOX, TK_NONE, right); // If left is a thistype or a typeparamref type, right's lower bounds is // calculated on its own. return viewpoint_lower(right); } default: {} } return NULL; }