// The subtype is a pointer, the supertype could be anything. static bool is_pointer_subtype(ast_t* sub, ast_t* super) { switch(ast_id(super)) { case TK_NOMINAL: { // Must be a Pointer, and the type argument must be the same. return is_pointer(super) && is_eq_typeargs(sub, super) && is_sub_cap_and_ephemeral(sub, super); } case TK_TYPEPARAMREF: { // We must be a subtype of the constraint. ast_t* def = (ast_t*)ast_data(super); ast_t* constraint = ast_childidx(def, 1); return is_pointer_subtype(sub, constraint); } case TK_ARROW: { // We must be a subtype of the lower bounds. ast_t* lower = viewpoint_lower(super); bool ok = is_pointer_subtype(sub, lower); ast_free_unattached(lower); return ok; } default: {} } return false; }
// Both sub and super are nominal types. static bool is_nominal_sub_nominal(ast_t* sub, ast_t* super) { if(!is_sub_cap_and_ephemeral(sub, super)) return false; ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); // If we are the same nominal type, our typeargs must be the same. if(sub_def == super_def) return is_eq_typeargs(sub, super); switch(ast_id(super_def)) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: // If we aren't the same type, we can't be a subtype of a concrete type. return false; case TK_INTERFACE: // Check for an explicit provide or a structural subtype. return is_nominal_sub_trait(sub, super) || is_nominal_sub_interface(sub, super); case TK_TRAIT: // Check for a nominal subtype. return is_nominal_sub_trait(sub, super); default: {} } return false; }
// The subtype is a typeparam, the supertype is a typeparam. static bool is_typeparam_sub_typeparam(ast_t* sub, ast_t* super) { // If the supertype is also a typeparam, we must be the same typeparam by // identity and be a subtype by cap and ephemeral. ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); if(sub_def != super_def) return false; return is_sub_cap_and_ephemeral(sub, super); }
// The subtype is a nominal, the super type is a typeparam. static bool is_nominal_sub_typeparam(ast_t* sub, ast_t* super) { // Must be a subtype of the lower bounds of the constraint. ast_t* def = (ast_t*)ast_data(super); ast_t* constraint = ast_childidx(def, 1); if(ast_id(constraint) == TK_NOMINAL) { ast_t* constraint_def = (ast_t*)ast_data(constraint); switch(ast_id(constraint_def)) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { // Constraint must be modified with super ephemerality. AST_GET_CHILDREN(super, name, cap, eph); ast_t* r_constraint = set_cap_and_ephemeral(constraint, TK_NONE, ast_id(eph)); // Must be a subtype of the constraint. bool ok = is_subtype(sub, constraint); ast_free_unattached(r_constraint); if(!ok) return false; // Capability must be a subtype of the lower bounds of the typeparam. ast_t* lower = viewpoint_lower(super); ok = is_sub_cap_and_ephemeral(sub, lower); ast_free_unattached(lower); return ok; } default: {} } } return false; }
static matchtype_t could_subtype_or_deny(ast_t* sub, ast_t* super) { // At this point, sub must be a subtype of super. if(is_subtype(sub, super)) return MATCHTYPE_ACCEPT; // If sub would be a subtype of super if it had super's capability and // ephemerality, we deny other matches. token_id cap, eph; switch(ast_id(super)) { case TK_NOMINAL: { AST_GET_CHILDREN(super, sup_pkg, sup_id, sup_typeargs, sup_cap, sup_eph); cap = ast_id(sup_cap); eph = ast_id(sup_eph); break; } case TK_TYPEPARAMREF: { AST_GET_CHILDREN(super, sup_id, sup_cap, sup_eph); cap = ast_id(sup_cap); eph = ast_id(sup_eph); break; } default: assert(0); return MATCHTYPE_DENY; } ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); ast_t* r_type = set_cap_and_ephemeral(sub, cap, eph); matchtype_t ok = MATCHTYPE_REJECT; if(is_subtype(r_type, super)) { // Sub would be a subtype of super if their capabilities were the same. // Deny any match, since this would break capabilities. ok = MATCHTYPE_DENY; } else if(sub_def != super_def) { // Sub and super are unrelated types and sub is not a subtype of super. ok = MATCHTYPE_REJECT; } else if((sub_def == super_def) && is_sub_cap_and_ephemeral(sub, super)) { // Sub and super are the same base type, but have different type args. // Only accept if sub's type args are typeparamrefs and they could be a // subtype of super's type args. assert(ast_id(sub) == TK_NOMINAL); assert(ast_id(super) == TK_NOMINAL); AST_GET_CHILDREN(sub, sub_pkg, sub_id, sub_typeargs); AST_GET_CHILDREN(super, sup_pkg, sup_id, sup_typeargs); ast_t* sub_typearg = ast_child(sub_typeargs); ast_t* sup_typearg = ast_child(sup_typeargs); ok = MATCHTYPE_ACCEPT; while(sub_typearg != NULL) { if(!could_subtype_typearg(sub_typearg, sup_typearg)) { ok = MATCHTYPE_REJECT; break; } sub_typearg = ast_sibling(sub_typearg); sup_typearg = ast_sibling(sup_typearg); } } ast_free_unattached(r_type); return ok; }