bool literal_is(ast_t* ast, pass_opt_t* opt) { pony_assert(ast != NULL); pony_assert(ast_id(ast) == TK_IS || ast_id(ast) == TK_ISNT); AST_GET_CHILDREN(ast, left, right); ast_t* l_type = ast_type(left); ast_t* r_type = ast_type(right); if(is_typecheck_error(l_type) || is_typecheck_error(r_type)) return false; if(!is_type_literal(l_type) && !is_type_literal(r_type)) // No literals here. return true; if(is_type_literal(l_type) && !is_type_literal(r_type)) { // Coerce left to type of right. return coerce_literals(&left, r_type, opt); } if(!is_type_literal(l_type) && is_type_literal(r_type)) { // Coerce right to type of left. return coerce_literals(&right, l_type, opt); } // Both sides are literals, that's a problem. pony_assert(is_type_literal(l_type)); pony_assert(is_type_literal(r_type)); ast_error(opt->check.errors, ast, "Cannot infer type of operands"); return false; }
bool expr_repeat(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, body, cond, else_clause); ast_t* body_type = ast_type(body); ast_t* cond_type = ast_type(cond); ast_t* else_type = ast_type(else_clause); if(is_typecheck_error(cond_type)) return false; if(!is_bool(cond_type)) { ast_error(opt->check.errors, cond, "condition must be a Bool"); return false; } if(is_typecheck_error(body_type) || is_typecheck_error(else_type)) return false; // All consumes have to be in scope when the loop body finishes. errorframe_t errorf = NULL; if(!ast_all_consumes_in_scope(body, body, &errorf)) { errorframe_report(&errorf, opt->check.errors); return false; } // Union with any existing type due to a break expression. ast_t* type = ast_type(ast); // No symbol status is inherited from the loop body or condition. Nothing // from outside can be consumed, and definitions inside may not occur. if(!is_control_type(body_type)) type = control_type_add_branch(opt, type, body); if(!is_control_type(else_type)) { type = control_type_add_branch(opt, type, else_clause); ast_inheritbranch(ast, else_clause); // Use a branch count of two instead of one. This means we will pick up any // consumes, but not any definitions, since definitions may not occur. ast_consolidate_branches(ast, 2); } if(type == NULL) type = ast_from(ast, TK_REPEAT); ast_settype(ast, type); literal_unify_control(ast, opt); // Push our symbol status to our parent scope. ast_inheritstatus(ast_parent(ast), ast); return true; }
bool expr_try(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, body, else_clause, then_clause); ast_t* body_type = ast_type(body); ast_t* else_type = ast_type(else_clause); ast_t* then_type = ast_type(then_clause); if(is_typecheck_error(body_type) || is_typecheck_error(else_type) || is_typecheck_error(then_type)) return false; ast_t* type = NULL; if(!is_control_type(body_type)) type = control_type_add_branch(opt, type, body); if(!is_control_type(else_type)) type = control_type_add_branch(opt, type, else_clause); if(type == NULL) { if(ast_sibling(ast) != NULL) { ast_error(opt->check.errors, ast_sibling(ast), "unreachable code"); return false; } type = ast_from(ast, TK_TRY); } // The then clause does not affect the type of the expression. if(is_control_type(then_type)) { ast_error(opt->check.errors, then_clause, "then clause always terminates the function"); return false; } if(is_type_literal(then_type)) { ast_error(opt->check.errors, then_clause, "Cannot infer type of unused literal"); return false; } ast_settype(ast, type); literal_unify_control(ast, opt); // Push the symbol status from the then clause to our parent scope. ast_inheritstatus(ast_parent(ast), then_clause); return true; }
static bool tuple_access(ast_t* ast) { // Left is a postfix expression, right is a lookup name. ast_t* left = ast_child(ast); ast_t* right = ast_sibling(left); ast_t* type = ast_type(left); if(is_typecheck_error(type)) return false; // Change the lookup name to an integer index. if(!make_tuple_index(&right)) { ast_error(right, "lookup on a tuple must take the form _X, where X is an integer"); return false; } // Make sure our index is in bounds. type = ast_childidx(type, (size_t)ast_int(right)); if(type == NULL) { ast_error(right, "tuple index is out of bounds"); return false; } ast_setid(ast, TK_FLETREF); ast_settype(ast, type); ast_inheritflags(ast); return true; }
bool expr_recover(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, cap, expr); ast_t* type = ast_type(expr); if(is_typecheck_error(type)) return false; if(is_type_literal(type)) { make_literal_type(ast); return true; } ast_t* r_type = recover_type(type, ast_id(cap)); if(r_type == NULL) { ast_error(opt->check.errors, ast, "can't recover to this capability"); ast_error_continue(opt->check.errors, expr, "expression type is %s", ast_print_type(type)); return false; } ast_settype(ast, r_type); // Push our symbol status to our parent scope. ast_inheritstatus(ast_parent(ast), expr); return true; }
static bool expr_addressof_ffi(pass_opt_t* opt, ast_t* ast) { ast_t* expr = ast_child(ast); switch(ast_id(expr)) { case TK_FVARREF: case TK_VARREF: case TK_FLETREF: case TK_LETREF: break; case TK_PARAMREF: ast_error(ast, "can't take the address of a function parameter"); return false; default: ast_error(ast, "can only take the address of a field or local variable"); return false; } // Set the type to Pointer[ast_type(expr)]. ast_t* expr_type = ast_type(expr); if(is_typecheck_error(expr_type)) return false; ast_t* type = type_pointer_to(opt, expr_type); ast_settype(ast, type); return true; }
static bool check_type_params(ast_t** astp) { ast_t* lhs = *astp; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; ast_t* typeparams = ast_childidx(type, 1); assert(ast_id(type) == TK_FUNTYPE); if(ast_id(typeparams) == TK_NONE) return true; BUILD(typeargs, typeparams, NODE(TK_TYPEARGS)); if(!check_constraints(typeparams, typeargs, true)) { ast_free_unattached(typeargs); return false; } type = reify(type, typeparams, typeargs); typeparams = ast_childidx(type, 1); ast_replace(&typeparams, ast_from(typeparams, TK_NONE)); REPLACE(astp, NODE(ast_id(lhs), TREE(lhs) TREE(typeargs))); ast_settype(*astp, type); return true; }
static bool auto_recover_call(ast_t* ast, ast_t* receiver_type, ast_t* positional, ast_t* result) { // We can recover the receiver (ie not alias the receiver type) if all // arguments are safe and the result is either safe or unused. if(is_result_needed(ast) && !safe_to_autorecover(receiver_type, result)) return false; ast_t* arg = ast_child(positional); while(arg != NULL) { if(ast_id(arg) != TK_NONE) { ast_t* arg_type = ast_type(arg); if(is_typecheck_error(arg_type)) return false; ast_t* a_type = alias(arg_type); bool ok = safe_to_autorecover(receiver_type, a_type); ast_free_unattached(a_type); if(!ok) return false; } arg = ast_sibling(arg); } return true; }
bool expr_param(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, id, type, init); ast_settype(ast, type); bool ok = true; if(ast_id(init) != TK_NONE) { // Initialiser type must match declared type. if(!coerce_literals(&init, type, opt)) return false; ast_t* init_type = ast_type(init); if(is_typecheck_error(init_type)) return false; init_type = alias(init_type); errorframe_t err = NULL; if(!is_subtype(init_type, type, &err, opt)) { errorframe_t err2 = NULL; ast_error_frame(&err2, init, "default argument is not a subtype of the parameter type"); errorframe_append(&err2, &err); errorframe_report(&err2, opt->check.errors); ok = false; } ast_free_unattached(init_type); } return ok; }
// Unify all the branches of the given AST to the same type static bool unify(ast_t* ast, pass_opt_t* options, bool report_errors) { assert(ast != NULL); ast_t* type = ast_type(ast); if(is_typecheck_error(type)) return false; if(!is_type_literal(type)) // Not literal, nothing to unify return true; assert(type != NULL); ast_t* non_literal = ast_type(type); if(non_literal != NULL) { // Type has a non-literal element, coerce literals to that lit_chain_t chain; chain_init_head(&chain); return coerce_literal_to_type(&ast, non_literal, &chain, options, report_errors); //return coerce_literals(&ast, non_literal, options); } // Still a pure literal return true; }
bool expr_recover(ast_t* ast) { AST_GET_CHILDREN(ast, cap, expr); ast_t* type = ast_type(expr); if(is_typecheck_error(type)) return false; if(is_type_literal(type)) { make_literal_type(ast); return true; } ast_t* r_type = recover_type(type, ast_id(cap)); if(r_type == NULL) { errorframe_t frame = NULL; ast_error_frame(&frame, ast, "can't recover to this capability"); ast_error_frame(&frame, expr, "expression type is %s", ast_print_type(type)); errorframe_report(&frame); return false; } ast_settype(ast, r_type); ast_inheritflags(ast); // Push our symbol status to our parent scope. ast_inheritstatus(ast_parent(ast), expr); return true; }
bool expr_field(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, id, type, init); if(ast_id(init) != TK_NONE) { // Initialiser type must match declared type. if(!coerce_literals(&init, type, opt)) return false; ast_t* init_type = ast_type(init); if(is_typecheck_error(init_type)) return false; init_type = alias(init_type); if(!is_subtype(init_type, type)) { ast_error(init, "field/param initialiser is not a subtype of the field/param type"); ast_error(type, "field/param type: %s", ast_print_type(type)); ast_error(init, "initialiser type: %s", ast_print_type(init_type)); ast_free_unattached(init_type); return false; } ast_free_unattached(init_type); } ast_settype(ast, type); return true; }
static bool method_call(pass_opt_t* opt, ast_t* ast) { if(!method_application(opt, ast, false)) return false; AST_GET_CHILDREN(ast, positional, namedargs, lhs); ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); ast_settype(ast, result); ast_inheritflags(ast); switch(ast_id(lhs)) { case TK_NEWBEREF: case TK_BEREF: ast_setsend(ast); return true; case TK_NEWREF: case TK_FUNREF: ast_setmightsend(ast); return true; default: {} } assert(0); return false; }
static bool member_access(pass_opt_t* opt, ast_t* ast, bool partial) { // Left is a postfix expression, right is an id. AST_GET_CHILDREN(ast, left, right); assert(ast_id(right) == TK_ID); ast_t* type = ast_type(left); if(is_typecheck_error(type)) return false; ast_t* find = lookup(opt, ast, type, ast_name(right)); if(find == NULL) return false; bool ret = true; switch(ast_id(find)) { case TK_TYPEPARAM: ast_error(opt->check.errors, right, "can't look up a typeparam on an expression"); ret = false; break; case TK_FVAR: if(!expr_fieldref(opt, ast, find, TK_FVARREF)) return false; break; case TK_FLET: if(!expr_fieldref(opt, ast, find, TK_FLETREF)) return false; break; case TK_EMBED: if(!expr_fieldref(opt, ast, find, TK_EMBEDREF)) return false; break; case TK_NEW: case TK_BE: case TK_FUN: ret = method_access(opt, ast, find); break; default: assert(0); ret = false; break; } ast_free_unattached(find); if(!partial) ast_inheritflags(ast); return ret; }
static bool method_application(pass_opt_t* opt, ast_t* ast, bool partial) { AST_GET_CHILDREN(ast, positional, namedargs, question, lhs); if(!method_check_type_params(opt, &lhs)) return false; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); if(!extend_positional_args(opt, params, positional)) return false; if(!apply_named_args(opt, params, positional, namedargs)) return false; if(!check_arg_types(opt, params, positional, partial)) return false; switch(ast_id(lhs)) { case TK_FUNREF: case TK_FUNAPP: if(ast_id(ast_child(type)) != TK_AT) { if(!check_receiver_cap(opt, ast, NULL)) return false; if(!check_nonsendable_recover(opt, ast)) return false; } else { ast_t* receiver = ast_child(lhs); // Dig through function qualification. if((ast_id(receiver) == TK_FUNREF) || (ast_id(receiver) == TK_FUNAPP) || (ast_id(receiver) == TK_FUNCHAIN)) receiver = ast_child(receiver); ast_t* recv_type = ast_type(receiver); if(!is_known(recv_type) && (ast_id(receiver) == TK_TYPEREF)) { ast_error(opt->check.errors, lhs, "a bare method cannot be called on " "an abstract type reference"); return false; } } break; default: {} } return true; }
bool expr_consume(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, cap, term); ast_t* type = ast_type(term); if(is_typecheck_error(type)) return false; const char* name = NULL; switch(ast_id(term)) { case TK_VARREF: case TK_LETREF: case TK_PARAMREF: { ast_t* id = ast_child(term); name = ast_name(id); break; } case TK_THIS: { name = stringtab("this"); break; } default: ast_error(opt->check.errors, ast, "consume must take 'this', a local, or a parameter"); return false; } // Can't consume from an outer scope while in a loop condition. if((opt->check.frame->loop_cond != NULL) && !ast_within_scope(opt->check.frame->loop_cond, ast, name)) { ast_error(opt->check.errors, ast, "can't consume from an outer scope in a loop condition"); return false; } ast_setstatus(ast, name, SYM_CONSUMED); token_id tcap = ast_id(cap); ast_t* c_type = consume_type(type, tcap); if(c_type == NULL) { ast_error(opt->check.errors, ast, "can't consume to this capability"); ast_error_continue(opt->check.errors, term, "expression type is %s", ast_print_type(type)); return false; } ast_settype(ast, c_type); return true; }
bool expr_if(pass_opt_t* opt, ast_t* ast) { ast_t* cond = ast_child(ast); ast_t* left = ast_sibling(cond); ast_t* right = ast_sibling(left); ast_t* cond_type = ast_type(cond); if(is_typecheck_error(cond_type)) return false; if(!is_bool(cond_type)) { ast_error(cond, "condition must be a Bool"); return false; } ast_t* l_type = ast_type(left); ast_t* r_type = ast_type(right); ast_t* type = NULL; size_t branch_count = 0; if(!is_control_type(l_type)) { type = control_type_add_branch(type, left); ast_inheritbranch(ast, left); branch_count++; } if(!is_control_type(r_type)) { type = control_type_add_branch(type, right); ast_inheritbranch(ast, right); branch_count++; } if(type == NULL) { if(ast_sibling(ast) != NULL) { ast_error(ast_sibling(ast), "unreachable code"); return false; } type = ast_from(ast, TK_IF); } ast_settype(ast, type); ast_inheritflags(ast); ast_consolidate_branches(ast, branch_count); literal_unify_control(ast, opt); // Push our symbol status to our parent scope. ast_inheritstatus(ast_parent(ast), ast); return true; }
bool expr_literal(pass_opt_t* opt, ast_t* ast, const char* name) { ast_t* type = type_builtin(opt, ast, name); if(is_typecheck_error(type)) return false; ast_settype(ast, type); return true; }
bool expr_field(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, id, type, init); // An embedded field must have a known, non-actor type. if(ast_id(ast) == TK_EMBED) { if(!is_known(type) || is_actor(type)) { ast_error(ast, "embedded fields must always be primitives or classes"); return false; } } if(ast_id(init) != TK_NONE) { // Initialiser type must match declared type. if(!coerce_literals(&init, type, opt)) return false; ast_t* init_type = ast_type(init); if(is_typecheck_error(init_type)) return false; init_type = alias(init_type); if(!is_subtype(init_type, type)) { ast_error(init, "field/param initialiser is not a subtype of the field/param type"); ast_error(type, "field/param type: %s", ast_print_type(type)); ast_error(init, "initialiser type: %s", ast_print_type(init_type)); ast_free_unattached(init_type); return false; } // If it's an embedded field, check for a constructor result. if(ast_id(ast) == TK_EMBED) { if((ast_id(init) != TK_CALL) || (ast_id(ast_childidx(init, 2)) != TK_NEWREF)) { ast_error(ast, "an embedded field must be initialised using a constructor"); return false; } } ast_free_unattached(init_type); } ast_settype(ast, type); return true; }
ast_t* control_type_add_branch(ast_t* control_type, ast_t* branch) { assert(branch != NULL); ast_t* branch_type = ast_type(branch); if(is_typecheck_error(branch_type)) return branch_type; if(is_type_literal(branch_type)) { // The new branch is a literal if(control_type == NULL) control_type = ast_from(branch, TK_LITERAL); if(ast_id(control_type) != TK_LITERAL) { // The current control type is not a literal, fix that ast_t* old_control = control_type; control_type = ast_from(branch, TK_LITERAL); ast_settype(control_type, old_control); } assert(ast_id(control_type) == TK_LITERAL); // Add a literal branch reference to the new branch ast_t* member = ast_from(branch, TK_LITERALBRANCH); ast_setdata(member, (void*)branch); ast_append(control_type, member); ast_t* branch_non_lit = ast_type(branch_type); if(branch_non_lit != NULL) { // The branch's literal type has a non-literal component ast_t* non_literal_type = ast_type(control_type); ast_settype(control_type, type_union(non_literal_type, branch_non_lit)); } return control_type; } if(control_type != NULL && ast_id(control_type) == TK_LITERAL) { // New branch is not literal, but the control structure is // Add new branch type to the control structure's non-literal aspect ast_t* non_literal_type = ast_type(control_type); non_literal_type = type_union(non_literal_type, branch_type); ast_settype(control_type, non_literal_type); return control_type; } // No literals here, just union the types return type_union(control_type, branch_type); }
// Determine the UIF types that the given type may be static int uifset(pass_opt_t* opt, ast_t* type, lit_chain_t* chain) { assert(chain != NULL); if(is_typecheck_error(type)) return UIF_NO_TYPES; switch(ast_id(type)) { case TK_UNIONTYPE: return uifset_union(opt, type, chain); case TK_ISECTTYPE: return uifset_intersect(opt, type, chain); case TK_ARROW: // Since we don't care about capabilities we can just use the rhs assert(ast_id(ast_childidx(type, 1)) == TK_NOMINAL); return uifset(opt, ast_childidx(type, 1), chain); case TK_TYPEPARAMREF: if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality return UIF_NO_TYPES; return uifset_formal_param(opt, type, chain); case TK_TUPLETYPE: if(chain->cardinality != ast_childcount(type)) // Incorrect cardinality return UIF_NO_TYPES; return uifset(opt, ast_childidx(type, chain->index), chain->next); case TK_NOMINAL: if(strcmp(ast_name(ast_childidx(type, 1)), "Array") == 0) { if(chain->cardinality != CHAIN_CARD_ARRAY) // Incorrect cardinality return UIF_NO_TYPES; ast_t* type_args = ast_childidx(type, 2); assert(ast_childcount(type_args) == 1); return uifset(opt, ast_child(type_args), chain->next); } if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality return UIF_NO_TYPES; return uifset_simple_type(opt, type); default: ast_error(type, "Internal error: uif type, node %d", ast_id(type)); assert(0); return UIF_ERROR; } }
// Coerce a literal group (tuple or array) to be the specified target type static bool coerce_group(ast_t** astp, ast_t* target_type, lit_chain_t* chain, size_t cardinality, pass_opt_t* options, bool report_errors) { pony_assert(astp != NULL); ast_t* literal_expr = *astp; pony_assert(literal_expr != NULL); pony_assert(ast_id(literal_expr) == TK_TUPLE || ast_id(literal_expr) == TK_ARRAY); pony_assert(chain != NULL); pony_assert(cardinality != CHAIN_CARD_BASE); size_t i = 0; lit_chain_t link; chain_add(chain, &link, cardinality); if(ast_id(literal_expr) == TK_ARRAY) { // The first child of an array AST is the forced type, the second child is // the sequence of elements. literal_expr = ast_childidx(literal_expr, 1); } // Process each group element separately for(ast_t* p = ast_child(literal_expr); p != NULL; p = ast_sibling(p)) { ast_t* p_type = ast_type(p); if(is_typecheck_error(p_type)) return false; if(is_type_literal(p_type)) { // This element is a literal if(cardinality != CHAIN_CARD_ARRAY) { chain_clear_cache(&link); link.index = i; } if(!coerce_literal_to_type(&p, target_type, &link, options, report_errors)) return false; } i++; } chain_remove(chain); return true; }
bool expr_fieldref(pass_opt_t* opt, ast_t* ast, ast_t* find, token_id tid) { AST_GET_CHILDREN(ast, left, right); ast_t* l_type = ast_type(left); if(is_typecheck_error(l_type)) return false; AST_GET_CHILDREN(find, id, f_type, init); // Viewpoint adapted type of the field. ast_t* type = viewpoint_type(l_type, f_type); if(ast_id(type) == TK_ARROW) { ast_t* upper = viewpoint_upper(type); if(upper == NULL) { ast_error(ast, "can't read a field through %s", ast_print_type(l_type)); return false; } ast_free_unattached(upper); } // Set the unadapted field type. ast_settype(right, f_type); // Set the type so that it isn't free'd as unattached. ast_setid(ast, tid); ast_settype(ast, type); if(ast_id(left) == TK_THIS) { // Handle symbol status if the left side is 'this'. ast_t* id = ast_child(find); const char* name = ast_name(id); sym_status_t status; ast_get(ast, name, &status); if(!valid_reference(opt, ast, type, status)) return false; } return true; }
static bool method_call(pass_opt_t* opt, ast_t* ast) { if(!method_application(opt, ast, false)) return false; AST_GET_CHILDREN(ast, positional, namedargs, lhs); ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); ast_settype(ast, result); return true; }
static bool auto_recover_call(ast_t* ast, ast_t* receiver_type, ast_t* positional, ast_t* result) { switch(ast_id(ast)) { case TK_FUNREF: case TK_FUNAPP: case TK_FUNCHAIN: break; default: pony_assert(0); break; } // We can recover the receiver (ie not alias the receiver type) if all // arguments are safe and the result is either safe or unused. // The result of a chained method is always unused. ast_t* call = ast_parent(ast); if(is_result_needed(call) && !safe_to_autorecover(receiver_type, result)) return false; ast_t* arg = ast_child(positional); while(arg != NULL) { if(ast_id(arg) != TK_NONE) { ast_t* arg_type = ast_type(arg); if(is_typecheck_error(arg_type)) return false; ast_t* a_type = alias(arg_type); bool ok = safe_to_autorecover(receiver_type, a_type); ast_free_unattached(a_type); if(!ok) return false; } arg = ast_sibling(arg); } return true; }
static bool tuple_access(pass_opt_t* opt, ast_t* ast) { // Left is a postfix expression, right is a lookup name. ast_t* left = ast_child(ast); ast_t* right = ast_sibling(left); ast_t* type = ast_type(left); if(is_typecheck_error(type)) return false; // Change the lookup name to an integer index. if(!make_tuple_index(&right)) { ast_error(opt->check.errors, right, "lookup on a tuple must take the form _X, where X is an integer"); return false; } // Make sure our index is in bounds. make_tuple_index automatically shifts // from one indexed to zero, so we have to use -1 and >= for our comparisons. size_t right_idx = (size_t)ast_int(right)->low; size_t tuple_size = ast_childcount(type); if (right_idx == (size_t)-1) { ast_error(opt->check.errors, right, "tuples are one indexed not zero indexed. Did you mean _1?"); return false; } else if (right_idx >= tuple_size) { ast_error(opt->check.errors, right, "tuple index " __zu " is out of " "valid range. Valid range is [1, " __zu "]", right_idx, tuple_size); return false; } type = ast_childidx(type, right_idx); assert(type != NULL); ast_setid(ast, TK_FLETREF); ast_settype(ast, type); ast_inheritflags(ast); return true; }
bool expr_field(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, id, type, init); if(ast_id(init) != TK_NONE) { // Only parameters have initialisers. Field initialisers are moved into // constructors in the sugar pass. assert(ast_id(ast) == TK_PARAM); // Initialiser type must match declared type. if(!coerce_literals(&init, type, opt)) return false; ast_t* init_type = ast_type(init); if(is_typecheck_error(init_type)) return false; init_type = alias(init_type); errorframe_t info = NULL; if(!is_subtype(init_type, type, &info)) { errorframe_t frame = NULL; ast_error_frame(&frame, init, "default argument is not a subtype of the parameter type"); ast_error_frame(&frame, type, "parameter type: %s", ast_print_type(type)); ast_error_frame(&frame, init, "default argument type: %s", ast_print_type(init_type)); errorframe_append(&frame, &info); errorframe_report(&frame); ast_free_unattached(init_type); return false; } ast_free_unattached(init_type); } ast_settype(ast, type); return true; }
static bool check_return_type(ast_t* ast) { AST_GET_CHILDREN(ast, cap, id, typeparams, params, type, can_error, body); ast_t* body_type = ast_type(body); if(is_typecheck_error(body_type)) return false; // The last statement is an error, and we've already checked any return // expressions in the method. if(is_control_type(body_type)) return true; // If it's a compiler intrinsic, ignore it. if(ast_id(body_type) == TK_COMPILE_INTRINSIC) return true; // The body type must match the return type, without subsumption, or an alias // of the body type must be a subtype of the return type. ast_t* a_type = alias(type); ast_t* a_body_type = alias(body_type); bool ok = true; errorframe_t info = NULL; if(!is_subtype(body_type, type, &info) || !is_subtype(a_body_type, a_type, &info)) { errorframe_t frame = NULL; ast_t* last = ast_childlast(body); ast_error_frame(&frame, last, "function body isn't the result type"); ast_error_frame(&frame, type, "function return type: %s", ast_print_type(type)); ast_error_frame(&frame, body_type, "function body type: %s", ast_print_type(body_type)); errorframe_append(&frame, &info); errorframe_report(&frame); ok = false; } ast_free_unattached(a_type); ast_free_unattached(a_body_type); return ok; }
// Coerce a literal control block to be the specified target type static bool coerce_control_block(ast_t** astp, ast_t* target_type, lit_chain_t* chain, pass_opt_t* options, bool report_errors) { assert(astp != NULL); ast_t* literal_expr = *astp; assert(literal_expr != NULL); ast_t* lit_type = ast_type(literal_expr); assert(lit_type != NULL); assert(ast_id(lit_type) == TK_LITERAL); ast_t* block_type = ast_type(lit_type); for(ast_t* p = ast_child(lit_type); p != NULL; p = ast_sibling(p)) { assert(ast_id(p) == TK_LITERALBRANCH); ast_t* branch = (ast_t*)ast_data(p); assert(branch != NULL); if(!coerce_literal_to_type(&branch, target_type, chain, options, report_errors)) { ast_free_unattached(block_type); return false; } block_type = type_union(block_type, ast_type(branch)); } if(is_typecheck_error(block_type)) return false; // block_type may be a sub-tree of the current type of literal_expr. // This means we must copy it before setting it as the type since ast_settype // will first free the existing type of literal_expr, which may include // block_type. if(ast_parent(block_type) != NULL) block_type = ast_dup(block_type); ast_settype(literal_expr, block_type); return true; }
static bool package_access(pass_opt_t* opt, ast_t** astp) { ast_t* ast = *astp; // Left is a packageref, right is an id. ast_t* left = ast_child(ast); ast_t* right = ast_sibling(left); ast_t* type = ast_type(left); if(is_typecheck_error(type)) return false; assert(ast_id(left) == TK_PACKAGEREF); assert(ast_id(right) == TK_ID); // Must be a type in a package. const char* package_name = ast_name(ast_child(left)); ast_t* package = ast_get(left, package_name, NULL); if(package == NULL) { ast_error(right, "can't access package '%s'", package_name); return false; } assert(ast_id(package) == TK_PACKAGE); const char* type_name = ast_name(right); type = ast_get(package, type_name, NULL); if(type == NULL) { ast_error(right, "can't find type '%s' in package '%s'", type_name, package_name); return false; } ast_settype(ast, type_sugar(ast, package_name, type_name)); ast_setid(ast, TK_TYPEREF); return expr_typeref(opt, astp); }