bool safe_to_autorecover(ast_t* receiver_type, ast_t* type) { switch(ast_id(receiver_type)) { case TK_ISECTTYPE: { ast_t* child = ast_child(receiver_type); while(child != NULL) { if(safe_field_write(cap_single(child), type)) return true; child = ast_sibling(child); } return false; } case TK_UNIONTYPE: { ast_t* child = ast_child(receiver_type); while(child != NULL) { if(!safe_field_write(cap_single(child), type)) return false; child = ast_sibling(child); } return true; } case TK_NOMINAL: case TK_TYPEPARAMREF: return safe_field_write(cap_single(receiver_type), type); case TK_ARROW: { ast_t* upper = viewpoint_upper(receiver_type); bool ok = safe_to_autorecover(upper, type); if(upper != receiver_type) ast_free_unattached(upper); return ok; } default: {} } assert(0); return false; }
static trace_t trace_type_nominal(ast_t* type) { switch(ast_id((ast_t*)ast_data(type))) { case TK_INTERFACE: case TK_TRAIT: switch(cap_single(type)) { case TK_VAL: return TRACE_VAL_UNKNOWN; case TK_TAG: return TRACE_TAG_UNKNOWN; default: {} } return TRACE_MUT_UNKNOWN; case TK_PRIMITIVE: { if(is_machine_word(type)) return TRACE_MACHINE_WORD; return TRACE_PRIMITIVE; } case TK_STRUCT: case TK_CLASS: if(is_maybe(type)) return TRACE_MAYBE; switch(cap_single(type)) { case TK_VAL: return TRACE_VAL_KNOWN; case TK_TAG: return TRACE_TAG_KNOWN; default: {} } return TRACE_MUT_KNOWN; case TK_ACTOR: return TRACE_TAG_KNOWN; default: {} } pony_assert(0); return TRACE_NONE; }
static trace_t trace_type_nominal(ast_t* type) { switch(ast_id((ast_t*)ast_data(type))) { case TK_INTERFACE: case TK_TRAIT: switch(cap_single(type)) { case TK_VAL: return TRACE_UNKNOWN_VAL; case TK_TAG: return TRACE_TAG_OR_ACTOR; default: {} } return TRACE_UNKNOWN; case TK_PRIMITIVE: return TRACE_PRIMITIVE; case TK_STRUCT: case TK_CLASS: if(is_maybe(type)) return TRACE_MAYBE; switch(cap_single(type)) { case TK_VAL: return TRACE_KNOWN_VAL; case TK_TAG: return TRACE_TAG; default: {} } return TRACE_KNOWN; case TK_ACTOR: return TRACE_ACTOR; default: {} } assert(0); return TRACE_NONE; }
static bool trace_as_tag(compile_t* c, LLVMValueRef value, ast_t* type) { switch(ast_id(type)) { case TK_UNIONTYPE: case TK_ISECTTYPE: { ast_t* child = ast_child(type); while(child != NULL) { if(!trace_as_tag(c, value, child)) return false; child = ast_sibling(child); } return true; } case TK_TUPLETYPE: return false; case TK_NOMINAL: return cap_single(type) == TK_TAG; default: {} } assert(0); return false; }
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; }
static ast_t* make_arrow_type(ast_t* left, ast_t* right) { switch(ast_id(right)) { case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_TUPLETYPE: { ast_t* type = ast_from(right, ast_id(right)); ast_t* child = ast_child(right); while(child != NULL) { ast_append(type, make_arrow_type(left, child)); child = ast_sibling(child); } return type; } case TK_NOMINAL: case TK_TYPEPARAMREF: { switch(cap_single(right)) { case TK_VAL: case TK_TAG: return right; default: {} } return make_single_arrow(left, right); } case TK_ARROW: return make_single_arrow(left, right); default: {} } assert(0); return NULL; }
static bool safe_field_write(token_id cap, ast_t* type) { switch(ast_id(type)) { case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_TUPLETYPE: { // Safe to write if every component is safe to write. ast_t* child = ast_child(type); while(child != NULL) { if(!safe_field_write(cap, child)) return false; child = ast_sibling(child); } return true; } case TK_ARROW: { ast_t* upper = viewpoint_upper(type); bool ok = safe_field_write(cap, upper); if(upper != type) ast_free_unattached(upper); return ok; } case TK_NOMINAL: case TK_TYPEPARAMREF: return cap_safetowrite(cap, cap_single(type)); default: {} } assert(0); return false; }
bool safe_to_write(ast_t* ast, ast_t* type) { switch(ast_id(ast)) { case TK_VAR: case TK_LET: case TK_VARREF: case TK_DONTCARE: return true; case TK_FVARREF: case TK_FLETREF: case TK_EMBEDREF: { // If the ast is x.f, we need the type of x, which will be a nominal // type or an arrow type, since we were able to lookup a field on it. AST_GET_CHILDREN(ast, left, right); ast_t* l_type = ast_type(left); // Any viewpoint adapted type will not be safe to write to. if(ast_id(l_type) != TK_NOMINAL) return false; token_id l_cap = cap_single(l_type); // If the RHS is safe to write, we're done. if(safe_field_write(l_cap, type)) return true; // If the field type (without adaptation) is safe, then it's ok as // well. So iso.tag = ref should be allowed. ast_t* r_type = ast_type(right); return safe_field_write(l_cap, r_type); } case TK_TUPLE: { // At this point, we know these will be the same length. assert(ast_id(type) == TK_TUPLETYPE); ast_t* child = ast_child(ast); ast_t* type_child = ast_child(type); while(child != NULL) { if(!safe_to_write(child, type_child)) return false; child = ast_sibling(child); type_child = ast_sibling(type_child); } assert(type_child == NULL); return true; } case TK_SEQ: { // Occurs when there is a tuple on the left. Each child of the tuple will // be a sequence, but only sequences with a single writeable child are // valid. Other types won't appear here. return safe_to_write(ast_child(ast), type); } default: {} } assert(0); return false; }
ast_result_t pass_flatten(ast_t** astp, pass_opt_t* options) { ast_t* ast = *astp; switch(ast_id(ast)) { case TK_UNIONTYPE: return flatten_union(options, ast); case TK_ISECTTYPE: return flatten_isect(options, ast); case TK_NEW: { switch(ast_id(options->check.frame->type)) { case TK_CLASS: return flatten_constructor(options, ast); case TK_ACTOR: return flatten_async(options, ast); default: {} } break; } case TK_BE: return flatten_async(options, ast); case TK_ARROW: return flatten_arrow(options, astp); case TK_TYPEPARAMREF: return flatten_typeparamref(options, ast); case TK_EMBED: { // An embedded field must have a known, class type. AST_GET_CHILDREN(ast, id, type, init); bool ok = true; if(ast_id(type) != TK_NOMINAL) ok = false; ast_t* def = (ast_t*)ast_data(type); if(def == NULL) { ok = false; } else { switch(ast_id(def)) { case TK_STRUCT: case TK_CLASS: break; default: ok = false; break; } } if(!ok) { ast_error(options->check.errors, type, "embedded fields must be classes or structs"); return AST_ERROR; } if(cap_single(type) == TK_TAG) { ast_error(options->check.errors, type, "embedded fields cannot be tag"); return AST_ERROR; } return AST_OK; } case TK_ACTOR: case TK_CLASS: case TK_STRUCT: case TK_PRIMITIVE: case TK_TRAIT: case TK_INTERFACE: return flatten_provides_list(options, ast, 3); default: {} } return AST_OK; }