static bool genfun_new(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); codegen_startfun(c, m->func, m->di_file, m->di_method); name_params(c, t, m, params, m->func); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; // Return 'this'. if(t->primitive == NULL) value = LLVMGetParam(m->func, 0); codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, value); codegen_debugloc(c, NULL); codegen_finishfun(c); return true; }
void fun_defaults(ast_t* ast) { assert(ast != NULL); AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body, docstring); // If the receiver cap is not specified, set it to box. if(ast_id(cap) == TK_NONE) ast_setid(cap, TK_BOX); // If the return value is not specified, set it to None. if(ast_id(result) == TK_NONE) { ast_t* type = type_sugar(ast, NULL, "None"); ast_replace(&result, type); } // If the return type is None, add a None at the end of the body, unless it // already ends with an error or return statement if(is_none(result) && (ast_id(body) != TK_NONE)) { ast_t* last_cmd = ast_childlast(body); if(ast_id(last_cmd) != TK_ERROR && ast_id(last_cmd) != TK_RETURN) { BUILD_NO_DEBUG(ref, body, NODE(TK_REFERENCE, ID("None"))); ast_append(body, ref); } } }
static bool check_embed_construction(pass_opt_t* opt, ast_t* left, ast_t* right) { bool result = true; if(ast_id(left) == TK_EMBEDREF) { if(!is_expr_constructor(right)) { ast_error(opt->check.errors, left, "an embedded field must be assigned using a constructor"); ast_error_continue(opt->check.errors, right, "the assigned expression is here"); return false; } } else if(ast_id(left) == TK_TUPLE) { if(ast_id(right) == TK_TUPLE) { ast_t* l_child = ast_child(left); ast_t* r_child = ast_child(right); while(l_child != NULL) { if(ast_id(l_child) != TK_DONTCARE) { assert((ast_id(l_child) == TK_SEQ) && (ast_id(r_child) == TK_SEQ)); ast_t* l_member = ast_childlast(l_child); ast_t* r_member = ast_childlast(r_child); if(!check_embed_construction(opt, l_member, r_member)) result = false; } l_child = ast_sibling(l_child); r_child = ast_sibling(r_child); } assert(r_child == NULL); } else if(tuple_contains_embed(left)) { ast_error(opt->check.errors, left, "an embedded field must be assigned using a constructor"); ast_error_continue(opt->check.errors, right, "the assigned expression isn't a tuple literal"); } } return result; }
// Process the method provided to the given entity. // Stage 2. static bool provided_methods(ast_t* entity) { assert(entity != NULL); ast_t* provides = ast_childidx(entity, 3); ast_t* entity_members = ast_childidx(entity, 4); ast_t* last_member = ast_childlast(entity_members); bool r = true; // Run through our provides list for(ast_t* p = ast_child(provides); p != NULL; p = ast_sibling(p)) { ast_t* trait_def = (ast_t*)ast_data(p); assert(trait_def != NULL); ast_t* type_args = ast_childidx(p, 2); ast_t* type_params = ast_childidx(trait_def, 1); ast_t* members = ast_childidx(trait_def, 4); // Run through the methods of each provided type for(ast_t* m = ast_child(members); m != NULL; m = ast_sibling(m)) { // Check behaviour compatability if(ast_id(m) == TK_BE) { if(ast_id(entity) == TK_PRIMITIVE || ast_id(entity) == TK_CLASS) { ast_error(entity, "%s can't provide traits that have behaviours", (ast_id(entity) == TK_CLASS) ? "classes" : "primitives"); r = false; continue; } } if(is_method(m)) { // We have a provided method // Reify the method with the type parameters from trait definition and type // arguments from trait reference ast_t* reified = reify(type_args, m, type_params, type_args); if(reified == NULL) // Reification error, already reported return false; if(!provided_method(entity, reified, m, &last_member)) r = false; } } } return r; }
static bool genfun_fun(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); if(m->name == c->str__final) { t->final_fn = m->func; LLVMSetFunctionCallConv(m->func, LLVMCCallConv); } codegen_startfun(c, m->func, m->di_file, m->di_method); name_params(c, t, m, params, m->func); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; if(value != GEN_NOVALUE) { LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(m->func)); LLVMTypeRef r_type = LLVMGetReturnType(f_type); // If the result type is known to be a tuple, do the correct assignment // cast even if the body type is not a tuple. ast_t* body_type = ast_type(body); if(ast_id(result) == TK_TUPLETYPE) body_type = result; LLVMValueRef ret = gen_assign_cast(c, r_type, value, body_type); if(ret == NULL) return false; codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, ret); codegen_debugloc(c, NULL); } codegen_finishfun(c); return true; }
static bool is_expr_constructor(ast_t* ast) { assert(ast != NULL); switch(ast_id(ast)) { case TK_CALL: return ast_id(ast_childidx(ast, 2)) == TK_NEWREF; case TK_SEQ: return is_expr_constructor(ast_childlast(ast)); case TK_IF: case TK_WHILE: case TK_REPEAT: { ast_t* body = ast_childidx(ast, 1); ast_t* else_expr = ast_childidx(ast, 2); return is_expr_constructor(body) && is_expr_constructor(else_expr); } case TK_TRY: { ast_t* body = ast_childidx(ast, 0); ast_t* else_expr = ast_childidx(ast, 1); return is_expr_constructor(body) && is_expr_constructor(else_expr); } case TK_MATCH: { ast_t* cases = ast_childidx(ast, 1); ast_t* else_expr = ast_childidx(ast, 2); ast_t* the_case = ast_child(cases); while(the_case != NULL) { if(!is_expr_constructor(ast_childidx(the_case, 2))) return false; the_case = ast_sibling(the_case); } return is_expr_constructor(else_expr); } case TK_RECOVER: return is_expr_constructor(ast_childidx(ast, 1)); default: return false; } }
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; }
static bool genfun_newbe(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); assert(m->func_handler != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); // Generate the handler. codegen_startfun(c, m->func_handler, m->di_file, m->di_method); name_params(c, t, m, params, m->func_handler); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; LLVMBuildRetVoid(c->builder); codegen_finishfun(c); // Generate the sender. codegen_startfun(c, m->func, NULL, NULL); LLVMValueRef this_ptr = LLVMGetParam(m->func, 0); // Send the arguments in a message to 'this'. LLVMTypeRef msg_type_ptr = send_message(c, params, this_ptr, m->func, m->vtable_index); // Return 'this'. codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, this_ptr); codegen_debugloc(c, NULL); codegen_finishfun(c); // Add the dispatch case. add_dispatch_case(c, t, params, m->vtable_index, m->func_handler, msg_type_ptr); return true; }
static bool tuple_contains_embed(ast_t* ast) { assert(ast_id(ast) == TK_TUPLE); ast_t* child = ast_child(ast); while(child != NULL) { if(ast_id(child) != TK_DONTCARE) { assert(ast_id(child) == TK_SEQ); ast_t* member = ast_childlast(child); if(ast_id(member) == TK_EMBEDREF) { return true; } else if(ast_id(member) == TK_TUPLE) { if(tuple_contains_embed(member)) return true; } } child = ast_sibling(child); } return false; }
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name, reach_type_t* t, ast_t* args, bool intrinsic) { ast_t* last_arg = ast_childlast(args); if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS)) return declare_ffi_vararg(c, f_name, t); int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); count = 0; ast_t* arg = ast_child(args); deferred_reification_t* reify = c->frame->reify; while(arg != NULL) { ast_t* p_type = ast_type(arg); if(p_type == NULL) p_type = ast_childidx(arg, 1); p_type = deferred_reify(reify, p_type, c->opt); reach_type_t* pt = reach_type(c->reach, p_type); pony_assert(pt != NULL); f_params[count++] = ((compile_type_t*)pt->c_type)->use_type; ast_free_unattached(p_type); arg = ast_sibling(arg); } LLVMTypeRef r_type = ffi_return_type(c, t, intrinsic); LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false); LLVMValueRef func = LLVMAddFunction(c->module, f_name, f_type); ponyint_pool_free_size(buf_size, f_params); return func; }
static ast_t* find_embed_constructor_receiver(ast_t* call) { call_tuple_indices_t tuple_indices = {NULL, 0, 4}; tuple_indices_init(&tuple_indices); ast_t* parent = make_tuple_indices(&tuple_indices, call); ast_t* fieldref = NULL; if((parent != NULL) && (ast_id(parent) == TK_ASSIGN)) { // Traverse the LHS of the assignment looking for what our constructor call // is assigned to. ast_t* current = ast_child(parent); while((ast_id(current) == TK_TUPLE) || (ast_id(current) == TK_SEQ)) { parent = current; if(ast_id(current) == TK_TUPLE) { // If there are no indices left, we're destructuring a tuple. // Errors in those cases have already been catched by the expr // pass. if(tuple_indices.count == 0) break; size_t index = tuple_indices_pop(&tuple_indices); current = ast_childidx(parent, index); } else { current = ast_childlast(parent); } } if(ast_id(current) == TK_EMBEDREF) fieldref = current; } tuple_indices_destroy(&tuple_indices); return fieldref; }
static ast_result_t sugar_module(ast_t* ast) { ast_t* docstring = ast_child(ast); ast_t* package = ast_parent(ast); assert(ast_id(package) == TK_PACKAGE); if(strcmp(package_name(package), "$0") != 0) { // Every module not in builtin has an implicit use builtin command. // Since builtin is always the first package processed it is $0. BUILD(builtin, ast, NODE(TK_USE, NONE STRING(stringtab("builtin")) NONE)); ast_add(ast, builtin); } if((docstring == NULL) || (ast_id(docstring) != TK_STRING)) return AST_OK; ast_t* package_docstring = ast_childlast(package); if(ast_id(package_docstring) == TK_STRING) { ast_error(docstring, "the package already has a docstring"); ast_error(package_docstring, "the existing docstring is here"); return AST_ERROR; } ast_append(package, docstring); ast_remove(docstring); return AST_OK; }
// Coerce a literal expression to given tuple or non-tuple types static bool coerce_literal_to_type(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); if(lit_type == NULL || (ast_id(lit_type) != TK_LITERAL && ast_id(lit_type) != TK_OPERATORLITERAL)) { // Not a literal return true; } if(ast_child(lit_type) != NULL) { // Control block literal return coerce_control_block(astp, target_type, chain, options, report_errors); } switch(ast_id(literal_expr)) { case TK_TUPLE: // Tuple literal { size_t cardinality = ast_childcount(literal_expr); if(!coerce_group(astp, target_type, chain, cardinality, options, report_errors)) return false; break; } case TK_INT: return uif_type_from_chain(options, literal_expr, target_type, chain, false, report_errors); case TK_FLOAT: return uif_type_from_chain(options, literal_expr, target_type, chain, true, report_errors); case TK_ARRAY: if(!coerce_group(astp, target_type, chain, CHAIN_CARD_ARRAY, options, report_errors)) return false; break; case TK_SEQ: { // Only coerce the last expression in the sequence ast_t* last = ast_childlast(literal_expr); if(!coerce_literal_to_type(&last, target_type, chain, options, report_errors)) return false; ast_settype(literal_expr, ast_type(last)); return true; } case TK_CALL: { AST_GET_CHILDREN(literal_expr, positional, named, receiver); ast_t* arg = ast_child(positional); if(!coerce_literal_to_type(&receiver, target_type, chain, options, report_errors)) return false; if(arg != NULL && !coerce_literal_to_type(&arg, target_type, chain, options, report_errors)) return false; ast_settype(literal_expr, ast_type(ast_child(receiver))); return true; } case TK_DOT: { ast_t* receiver = ast_child(literal_expr); if(!coerce_literal_to_type(&receiver, target_type, chain, options, report_errors)) return false; break; } default: ast_error(literal_expr, "Internal error, coerce_literal_to_type node %s", ast_get_print(literal_expr)); assert(0); return false; } // Need to reprocess node now all the literals have types ast_settype(literal_expr, NULL); return (pass_expr(astp, options) == AST_OK); }
static void genfun_dwarf_return(compile_t* c, ast_t* body) { ast_t* last = ast_childlast(body); dwarf_location(&c->dwarf, last); }
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name, reach_type_t* t, ast_t* args, bool err, bool intrinsic) { ast_t* last_arg = ast_childlast(args); if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS)) return declare_ffi_vararg(c, f_name, t, err); int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); count = 0; ast_t* arg = ast_child(args); while(arg != NULL) { ast_t* p_type = ast_type(arg); if(p_type == NULL) p_type = ast_childidx(arg, 1); reach_type_t* pt = reach_type(c->reach, p_type); pony_assert(pt != NULL); // An intrinsic that takes a Bool should be i1, not ibool. if(intrinsic && is_bool(pt->ast)) f_params[count++] = c->i1; else f_params[count++] = pt->use_type; arg = ast_sibling(arg); } LLVMTypeRef r_type; if(t->underlying == TK_TUPLETYPE) { // Can't use the named type. Build an unnamed type with the same // elements. unsigned int count = LLVMCountStructElementTypes(t->use_type); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* e_types = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetStructElementTypes(t->use_type, e_types); if(intrinsic) { ast_t* child = ast_child(t->ast); size_t i = 0; while(child != NULL) { // A Bool in an intrinsic tuple return type is an i1, not an ibool. if(is_bool(child)) e_types[i] = c->i1; child = ast_sibling(child); i++; } } r_type = LLVMStructTypeInContext(c->context, e_types, count, false); ponyint_pool_free_size(buf_size, e_types); } else { // An intrinsic that returns a Bool returns an i1, not an ibool. if(intrinsic && is_bool(t->ast)) r_type = c->i1; else r_type = t->use_type; } LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false); LLVMValueRef func = LLVMAddFunction(c->module, f_name, f_type); if(!err) { #if PONY_LLVM >= 309 LLVM_DECLARE_ATTRIBUTEREF(nounwind_attr, nounwind, 0); LLVMAddAttributeAtIndex(func, LLVMAttributeFunctionIndex, nounwind_attr); #else LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute); #endif } ponyint_pool_free_size(buf_size, f_params); return func; }
LLVMValueRef gen_call(compile_t* c, ast_t* ast) { // Special case calls. LLVMValueRef special; if(special_case_call(c, ast, &special)) return special; AST_GET_CHILDREN(ast, positional, named, postfix); AST_GET_CHILDREN(postfix, receiver, method); ast_t* typeargs = NULL; // Dig through function qualification. switch(ast_id(receiver)) { case TK_NEWREF: case TK_NEWBEREF: case TK_BEREF: case TK_FUNREF: case TK_BECHAIN: case TK_FUNCHAIN: typeargs = method; AST_GET_CHILDREN_NO_DECL(receiver, receiver, method); break; default: {} } // Get the receiver type. const char* method_name = ast_name(method); ast_t* type = ast_type(receiver); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); // Generate the arguments. size_t count = ast_childcount(positional) + 1; size_t buf_size = count * sizeof(void*); LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); ast_t* arg = ast_child(positional); int i = 1; while(arg != NULL) { LLVMValueRef value = gen_expr(c, arg); if(value == NULL) { ponyint_pool_free_size(buf_size, args); return NULL; } args[i] = value; arg = ast_sibling(arg); i++; } bool is_new_call = false; // Generate the receiver. Must be done after the arguments because the args // could change things in the receiver expression that must be accounted for. if(call_needs_receiver(postfix, t)) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: { call_tuple_indices_t tuple_indices = {NULL, 0, 4}; tuple_indices.data = (size_t*)ponyint_pool_alloc_size(4 * sizeof(size_t)); ast_t* current = ast; ast_t* parent = ast_parent(current); while((parent != NULL) && (ast_id(parent) != TK_ASSIGN) && (ast_id(parent) != TK_CALL)) { if(ast_id(parent) == TK_TUPLE) { size_t index = 0; ast_t* child = ast_child(parent); while(current != child) { ++index; child = ast_sibling(child); } tuple_indices_push(&tuple_indices, index); } current = parent; parent = ast_parent(current); } // If we're constructing an embed field, pass a pointer to the field // as the receiver. Otherwise, allocate an object. if((parent != NULL) && (ast_id(parent) == TK_ASSIGN)) { size_t index = 1; current = ast_childidx(parent, 1); while((ast_id(current) == TK_TUPLE) || (ast_id(current) == TK_SEQ)) { parent = current; if(ast_id(current) == TK_TUPLE) { // If there are no indices left, we're destructuring a tuple. // Errors in those cases have already been catched by the expr // pass. if(tuple_indices.count == 0) break; index = tuple_indices_pop(&tuple_indices); current = ast_childidx(parent, index); } else { current = ast_childlast(parent); } } if(ast_id(current) == TK_EMBEDREF) { args[0] = gen_fieldptr(c, current); set_descriptor(c, t, args[0]); } else { args[0] = gencall_alloc(c, t); } } else { args[0] = gencall_alloc(c, t); } is_new_call = true; ponyint_pool_free_size(tuple_indices.alloc * sizeof(size_t), tuple_indices.data); break; } case TK_BEREF: case TK_FUNREF: case TK_BECHAIN: case TK_FUNCHAIN: args[0] = gen_expr(c, receiver); break; default: pony_assert(0); return NULL; } } else { // Use a null for the receiver type. args[0] = LLVMConstNull(t->use_type); } // Static or virtual dispatch. token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, method_name, typeargs); LLVMValueRef func = dispatch_function(c, t, m, args[0]); bool is_message = false; if((ast_id(postfix) == TK_NEWBEREF) || (ast_id(postfix) == TK_BEREF) || (ast_id(postfix) == TK_BECHAIN)) { switch(t->underlying) { case TK_ACTOR: is_message = true; break; case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_INTERFACE: case TK_TRAIT: if(m->cap == TK_TAG) is_message = can_inline_message_send(t, m, method_name); break; default: {} } } // Cast the arguments to the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params); arg = ast_child(positional); i = 1; LLVMValueRef r = NULL; if(is_message) { // If we're sending a message, trace and send here instead of calling the // sender to trace the most specific types possible. LLVMValueRef* cast_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); cast_args[0] = args[0]; while(arg != NULL) { cast_args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg)); arg = ast_sibling(arg); i++; } token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, method_name, typeargs); codegen_debugloc(c, ast); gen_send_message(c, m, args, cast_args, positional); codegen_debugloc(c, NULL); switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: r = args[0]; break; default: r = c->none_instance; break; } ponyint_pool_free_size(buf_size, cast_args); } else { while(arg != NULL) { args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg)); arg = ast_sibling(arg); i++; } if(func != NULL) { // If we can error out and we have an invoke target, generate an invoke // instead of a call. codegen_debugloc(c, ast); if(ast_canerror(ast) && (c->frame->invoke_target != NULL)) r = invoke_fun(c, func, args, i, "", true); else r = codegen_call(c, func, args, i); if(is_new_call) { LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(r, "pony.newcall", md); } codegen_debugloc(c, NULL); } } // Class constructors return void, expression result is the receiver. if(((ast_id(postfix) == TK_NEWREF) || (ast_id(postfix) == TK_NEWBEREF)) && (t->underlying == TK_CLASS)) r = args[0]; // Chained methods forward their receiver. if((ast_id(postfix) == TK_BECHAIN) || (ast_id(postfix) == TK_FUNCHAIN)) r = args[0]; ponyint_pool_free_size(buf_size, args); ponyint_pool_free_size(buf_size, params); return r; }
bool expr_return(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; if(t->frame->method_body == NULL) { ast_error(ast, "return must occur in a method body"); return false; } // return is always the last expression in a sequence assert(ast_sibling(ast) == NULL); if(ast_parent(ast) == t->frame->method_body) { ast_error(ast, "use return only to exit early from a method, not at the end"); return false; } ast_t* type = ast_childidx(t->frame->method, 4); ast_t* body = ast_child(ast); if(!coerce_literals(&body, type, opt)) return false; ast_t* body_type = ast_type(body); if(is_typecheck_error(body_type)) return false; if(is_control_type(body_type)) { ast_error(body, "return value cannot be a control statement"); return false; } bool ok = true; switch(ast_id(t->frame->method)) { case TK_NEW: if(!is_none(body_type)) { ast_error(ast, "return in a constructor must return None"); ok = false; } break; case TK_BE: if(!is_none(body_type)) { ast_error(ast, "return in a behaviour must return None"); ok = false; } break; default: { // The body type must be a subtype of the return type, and an alias of // the body type must be a subtype of an alias of the return type. ast_t* a_type = alias(type); ast_t* a_body_type = alias(body_type); if(!is_subtype(body_type, type) || !is_subtype(a_body_type, a_type)) { ast_t* last = ast_childlast(body); ast_error(last, "returned value isn't the return type"); ast_error(type, "function return type: %s", ast_print_type(type)); ast_error(body_type, "returned value type: %s", ast_print_type(body_type)); ok = false; } ast_free_unattached(a_type); ast_free_unattached(a_body_type); } } ast_settype(ast, ast_from(ast, TK_RETURN)); ast_inheritflags(ast); return ok; }
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; }
bool expr_return(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; // return is always the last expression in a sequence assert(ast_sibling(ast) == NULL); if(ast_parent(ast) == t->frame->method_body) { ast_error(ast, "use return only to exit early from a method, not at the end"); return false; } ast_t* type = ast_childidx(t->frame->method, 4); ast_t* body = ast_child(ast); if(!coerce_literals(&body, type, opt)) return false; ast_t* body_type = ast_type(body); if(is_typecheck_error(body_type)) return false; if(is_control_type(body_type)) { ast_error(body, "return value cannot be a control statement"); return false; } bool ok = true; switch(ast_id(t->frame->method)) { case TK_NEW: if(is_this_incomplete(t, ast)) { ast_error(ast, "all fields must be defined before constructor returns"); ok = false; } break; case TK_BE: assert(is_none(body_type)); break; default: { // The body type must be a subtype of the return type, and an alias of // the body type must be a subtype of an alias of the return type. ast_t* a_type = alias(type); ast_t* a_body_type = alias(body_type); 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, "returned value isn't the return type"); ast_error_frame(&frame, type, "function return type: %s", ast_print_type(type)); ast_error_frame(&frame, body_type, "returned value 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); } } ast_settype(ast, ast_from(ast, TK_RETURN)); ast_inheritflags(ast); return ok; }
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name, gentype_t* g, ast_t* args, bool err) { ast_t* last_arg = ast_childlast(args); if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS)) return declare_ffi_vararg(c, f_name, g, err); int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); count = 0; ast_t* arg = ast_child(args); while(arg != NULL) { ast_t* p_type = ast_type(arg); if(p_type == NULL) p_type = ast_childidx(arg, 1); gentype_t param_g; if(!gentype(c, p_type, ¶m_g)) return NULL; f_params[count++] = param_g.use_type; arg = ast_sibling(arg); } // We may have generated the function by generating a parameter type. LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name); if(func == NULL) { LLVMTypeRef r_type; if(g->underlying == TK_TUPLETYPE) { // Can't use the named type. Build an unnamed type with the same // elements. unsigned int count = LLVMCountStructElementTypes(g->use_type); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* e_types = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetStructElementTypes(g->use_type, e_types); r_type = LLVMStructTypeInContext(c->context, e_types, count, false); ponyint_pool_free_size(buf_size, e_types); } else { r_type = g->use_type; } LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false); func = LLVMAddFunction(c->module, f_name, f_type); if(!err) LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute); } ponyint_pool_free_size(buf_size, f_params); return func; }