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; }
// 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_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; }
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); }
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; }
// 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; }
// Infer the types of any literals in the pattern of the given case static bool infer_pattern_type(ast_t* pattern, ast_t* match_expr_type, pass_opt_t* opt) { assert(pattern != NULL); assert(match_expr_type != NULL); if(is_type_literal(match_expr_type)) { ast_error(match_expr_type, "cannot infer type for literal match expression"); return false; } return coerce_literals(&pattern, match_expr_type, opt); }
ast_result_t expr_ffi(pass_opt_t* opt, ast_t* ast) { if(!package_allow_ffi(&opt->check)) { ast_error(opt->check.errors, ast, "This package isn't allowed to do C FFI"); return AST_FATAL; } AST_GET_CHILDREN(ast, name, return_typeargs, args, namedargs, question); assert(name != NULL); ast_t* decl; if(!ffi_get_decl(&opt->check, ast, &decl, opt)) return AST_ERROR; if(decl != NULL) // We have a declaration return declared_ffi(opt, ast, decl); // We do not have a declaration for(ast_t* arg = ast_child(args); arg != NULL; arg = ast_sibling(arg)) { ast_t* a_type = ast_type(arg); if((a_type != NULL) && is_type_literal(a_type)) { ast_error(opt->check.errors, arg, "Cannot pass number literals as unchecked FFI arguments"); return AST_ERROR; } } ast_t* return_type = ast_child(return_typeargs); if(return_type == NULL) { ast_error(opt->check.errors, name, "FFIs without declarations must specify return type"); return AST_ERROR; } ast_settype(ast, return_type); ast_inheritflags(ast); if(ast_id(question) == TK_QUESTION) ast_seterror(ast); return AST_OK; }
bool expr_tuple(pass_opt_t* opt, ast_t* ast) { ast_t* child = ast_child(ast); ast_t* type; if(ast_sibling(child) == NULL) { type = ast_type(child); } else { type = ast_from(ast, TK_TUPLETYPE); while(child != NULL) { ast_t* c_type = ast_type(child); if(c_type == NULL) return false; if(is_control_type(c_type)) { ast_error(opt->check.errors, child, "a tuple can't contain a control flow expression"); return false; } if(is_type_literal(c_type)) { // At least one tuple member is literal, so whole tuple is ast_free(type); make_literal_type(ast); ast_inheritflags(ast); return true; } ast_append(type, c_type); child = ast_sibling(child); } } ast_settype(ast, type); ast_inheritflags(ast); return true; }
bool expr_ffi(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, name, return_typeargs, args, namedargs, question); assert(name != NULL); ast_t* decl; if(!ffi_get_decl(&opt->check, ast, &decl, opt)) return false; if(decl != NULL) // We have a declaration return declared_ffi(opt, ast, decl); // We do not have a declaration for(ast_t* arg = ast_child(args); arg != NULL; arg = ast_sibling(arg)) { ast_t* a_type = ast_type(arg); if((a_type != NULL) && is_type_literal(a_type)) { ast_error(opt->check.errors, arg, "Cannot pass number literals as unchecked FFI arguments"); return false; } } ast_t* return_type = ast_child(return_typeargs); if(return_type == NULL) { ast_error(opt->check.errors, name, "FFIs without declarations must specify return type"); return false; } ast_settype(ast, return_type); return true; }
bool expr_try(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, body, else_clause, then_clause); // It has to be possible for the left side to result in an error. if((ast_id(ast) == TK_TRY) && !ast_canerror(body)) { ast_error(body, "try expression never results in an error"); return false; } 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(type, body); if(!is_control_type(else_type)) type = control_type_add_branch(type, else_clause); if(type == NULL) { if(ast_sibling(ast) != NULL) { ast_error(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(then_clause, "then clause always terminates the function"); return false; } if(is_type_literal(then_type)) { ast_error(then_clause, "Cannot infer type of unused literal"); return false; } ast_settype(ast, type); // Doesn't inherit error from the body. if(ast_canerror(else_clause) || ast_canerror(then_clause)) ast_seterror(ast); if(ast_cansend(body) || ast_cansend(else_clause) || ast_cansend(then_clause)) ast_setsend(ast); if(ast_mightsend(body) || ast_mightsend(else_clause) || ast_mightsend(then_clause)) ast_setmightsend(ast); 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; }
bool expr_seq(pass_opt_t* opt, ast_t* ast) { bool ok = true; // Any expression other than the last that is still literal is an error for(ast_t* p = ast_child(ast); ast_sibling(p) != NULL; p = ast_sibling(p)) { ast_t* p_type = ast_type(p); if(is_typecheck_error(p_type)) { ok = false; } else if(is_type_literal(p_type)) { ast_error(p, "Cannot infer type of unused literal"); ok = false; } } // We might already have a type due to a return expression. ast_t* type = ast_type(ast); ast_t* last = ast_childlast(ast); if((type != NULL) && !coerce_literals(&last, type, opt)) return false; // Type is unioned with the type of the last child. type = control_type_add_branch(type, last); ast_settype(ast, type); ast_inheritflags(ast); if(!ast_has_scope(ast)) return ok; ast_t* parent = ast_parent(ast); switch(ast_id(parent)) { case TK_TRY: case TK_TRY_NO_CHECK: { // Propagate consumes forward in a try expression. AST_GET_CHILDREN(parent, body, else_clause, then_clause); if(body == ast) { // Push our consumes, but not defines, to the else clause. ast_inheritbranch(else_clause, body); ast_consolidate_branches(else_clause, 2); } else if(else_clause == ast) { // Push our consumes, but not defines, to the then clause. This // includes the consumes from the body. ast_inheritbranch(then_clause, else_clause); ast_consolidate_branches(then_clause, 2); } } default: {} } return ok; }
static ast_result_t declared_ffi(pass_opt_t* opt, ast_t* call, ast_t* decl) { assert(call != NULL); assert(decl != NULL); assert(ast_id(decl) == TK_FFIDECL); AST_GET_CHILDREN(call, call_name, call_ret_typeargs, args, named_args, call_error); AST_GET_CHILDREN(decl, decl_name, decl_ret_typeargs, params, named_params, decl_error); // Check args vs params ast_t* param = ast_child(params); ast_t* arg = ast_child(args); while((arg != NULL) && (param != NULL) && ast_id(param) != TK_ELLIPSIS) { ast_t* p_type = ast_childidx(param, 1); if(!coerce_literals(&arg, p_type, opt)) return AST_ERROR; ast_t* a_type = ast_type(arg); errorframe_t info = NULL; if((a_type != NULL) && !void_star_param(p_type, a_type) && !is_subtype(a_type, p_type, &info, opt)) { errorframe_t frame = NULL; ast_error_frame(&frame, arg, "argument not a subtype of parameter"); ast_error_frame(&frame, param, "parameter type: %s", ast_print_type(p_type)); ast_error_frame(&frame, arg, "argument type: %s", ast_print_type(a_type)); errorframe_append(&frame, &info); errorframe_report(&frame, opt->check.errors); return AST_ERROR; } arg = ast_sibling(arg); param = ast_sibling(param); } if(arg != NULL && param == NULL) { ast_error(opt->check.errors, arg, "too many arguments"); return AST_ERROR; } if(param != NULL && ast_id(param) != TK_ELLIPSIS) { ast_error(opt->check.errors, named_args, "too few arguments"); return AST_ERROR; } for(; arg != NULL; arg = ast_sibling(arg)) { ast_t* a_type = ast_type(arg); if((a_type != NULL) && is_type_literal(a_type)) { ast_error(opt->check.errors, arg, "Cannot pass number literals as unchecked FFI arguments"); return AST_ERROR; } } // Check return types ast_t* call_ret_type = ast_child(call_ret_typeargs); ast_t* decl_ret_type = ast_child(decl_ret_typeargs); errorframe_t info = NULL; if((call_ret_type != NULL) && !is_eqtype(call_ret_type, decl_ret_type, &info, opt)) { errorframe_t frame = NULL; ast_error_frame(&frame, call_ret_type, "call return type does not match declaration"); errorframe_append(&frame, &info); errorframe_report(&frame, opt->check.errors); return AST_ERROR; } // Check partiality if((ast_id(decl_error) == TK_NONE) && (ast_id(call_error) != TK_NONE)) { ast_error(opt->check.errors, call_error, "call is partial but the declaration is not"); return AST_ERROR; } if((ast_id(decl_error) == TK_QUESTION) || (ast_id(call_error) == TK_QUESTION)) { ast_seterror(call); } // Store the declaration so that codegen can generate a non-variadic // signature for the FFI call. ast_setdata(call, decl); ast_settype(call, decl_ret_type); ast_inheritflags(call); return AST_OK; }
bool expr_match(pass_opt_t* opt, ast_t* ast) { assert(ast_id(ast) == TK_MATCH); AST_GET_CHILDREN(ast, expr, cases, else_clause); // A literal match expression should have been caught by the cases, but check // again to avoid an assert if we've missed a case ast_t* expr_type = ast_type(expr); if(is_typecheck_error(expr_type)) return false; if(is_type_literal(expr_type)) { ast_error(expr, "cannot infer type for literal match expression"); return false; } ast_t* cases_type = ast_type(cases); ast_t* else_type = ast_type(else_clause); if(is_typecheck_error(cases_type) || is_typecheck_error(else_type)) return false; ast_t* type = NULL; size_t branch_count = 0; if(!is_control_type(cases_type)) { type = control_type_add_branch(type, cases); ast_inheritbranch(ast, cases); branch_count++; } if(!is_control_type(else_type)) { type = control_type_add_branch(type, else_clause); ast_inheritbranch(ast, else_clause); branch_count++; } if(type == NULL) { if(ast_sibling(ast) != NULL) { ast_error(ast_sibling(ast), "unreachable code"); return false; } type = ast_from(ast, TK_MATCH); } 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; }