| author | |
| committer | |
| log | 581d16154baa3b33ad7c07da07306dd1be346411 |
| tree | e9c1c69e85696a8eb2d73a9c826d6b2cb1a9bb3a |
| parent | ac6bf53069d3dccc3236cee05d5da026642ee4d4 |
| parent | ff2ddcf38d7a2f0fbed40f645278a09ca940a68a |
| signature |
@asyncCall now takes arguments as a tuple instead of varargs10 files changed, 244 insertions(+), 105 deletions(-)
doc/langref.html.in+2-2| ... | ... | @@ -6689,7 +6689,7 @@ comptime { |
| 6689 | 6689 | {#header_close#} |
| 6690 | 6690 | |
| 6691 | 6691 | {#header_open|@asyncCall#} |
| 6692 | <pre>{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre> | |
| 6692 | <pre>{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: var) anyframe->T{#endsyntax#}</pre> | |
| 6693 | 6693 | <p> |
| 6694 | 6694 | {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer, |
| 6695 | 6695 | which may or may not be an {#link|async function|Async Functions#}. |
| ... | ... | @@ -6716,7 +6716,7 @@ test "async fn pointer in a struct field" { |
| 6716 | 6716 | }; |
| 6717 | 6717 | var foo = Foo{ .bar = func }; |
| 6718 | 6718 | var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined; |
| 6719 | const f = @asyncCall(&bytes, {}, foo.bar, &data); | |
| 6719 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | |
| 6720 | 6720 | assert(data == 2); |
| 6721 | 6721 | resume f; |
| 6722 | 6722 | assert(data == 4); |
lib/std/dwarf.zig+1-1| ... | ... | @@ -359,7 +359,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia |
| 359 | 359 | const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64)); |
| 360 | 360 | var frame = try allocator.create(F); |
| 361 | 361 | defer allocator.destroy(frame); |
| 362 | return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, endian, is_64); | |
| 362 | return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 }); | |
| 363 | 363 | }, |
| 364 | 364 | else => error.InvalidDebugInfo, |
| 365 | 365 | }; |
lib/std/special/test_runner.zig+1-1| ... | ... | @@ -35,7 +35,7 @@ pub fn main() anyerror!void { |
| 35 | 35 | async_frame_buffer = try std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size); |
| 36 | 36 | } |
| 37 | 37 | const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func); |
| 38 | break :blk await @asyncCall(async_frame_buffer, {}, casted_fn); | |
| 38 | break :blk await @asyncCall(async_frame_buffer, {}, casted_fn, .{}); | |
| 39 | 39 | }, |
| 40 | 40 | .blocking => { |
| 41 | 41 | skip_count += 1; |
lib/std/start.zig+1-1| ... | ... | @@ -214,7 +214,7 @@ inline fn initEventLoopAndCallMain() u8 { |
| 214 | 214 | |
| 215 | 215 | var result: u8 = undefined; |
| 216 | 216 | var frame: @Frame(callMainAsync) = undefined; |
| 217 | _ = @asyncCall(&frame, &result, callMainAsync, loop); | |
| 217 | _ = @asyncCall(&frame, &result, callMainAsync, .{loop}); | |
| 218 | 218 | loop.run(); |
| 219 | 219 | return result; |
| 220 | 220 | } |
src/all_types.hpp+15| ... | ... | @@ -2641,6 +2641,7 @@ enum IrInstSrcId { |
| 2641 | 2641 | IrInstSrcIdCall, |
| 2642 | 2642 | IrInstSrcIdCallArgs, |
| 2643 | 2643 | IrInstSrcIdCallExtra, |
| 2644 | IrInstSrcIdAsyncCallExtra, | |
| 2644 | 2645 | IrInstSrcIdConst, |
| 2645 | 2646 | IrInstSrcIdReturn, |
| 2646 | 2647 | IrInstSrcIdContainerInitList, |
| ... | ... | @@ -3255,6 +3256,20 @@ struct IrInstSrcCallExtra { |
| 3255 | 3256 | ResultLoc *result_loc; |
| 3256 | 3257 | }; |
| 3257 | 3258 | |
| 3259 | // This is a pass1 instruction, used by @asyncCall, when the args node | |
| 3260 | // is not a literal. | |
| 3261 | // `args` is expected to be either a struct or a tuple. | |
| 3262 | struct IrInstSrcAsyncCallExtra { | |
| 3263 | IrInstSrc base; | |
| 3264 | ||
| 3265 | CallModifier modifier; | |
| 3266 | IrInstSrc *fn_ref; | |
| 3267 | IrInstSrc *ret_ptr; | |
| 3268 | IrInstSrc *new_stack; | |
| 3269 | IrInstSrc *args; | |
| 3270 | ResultLoc *result_loc; | |
| 3271 | }; | |
| 3272 | ||
| 3258 | 3273 | struct IrInstGenCall { |
| 3259 | 3274 | IrInstGen base; |
| 3260 | 3275 |
src/ir.cpp+139-29| ... | ... | @@ -310,6 +310,8 @@ static void destroy_instruction_src(IrInstSrc *inst) { |
| 310 | 310 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCall *>(inst)); |
| 311 | 311 | case IrInstSrcIdCallExtra: |
| 312 | 312 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallExtra *>(inst)); |
| 313 | case IrInstSrcIdAsyncCallExtra: | |
| 314 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAsyncCallExtra *>(inst)); | |
| 313 | 315 | case IrInstSrcIdUnOp: |
| 314 | 316 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnOp *>(inst)); |
| 315 | 317 | case IrInstSrcIdCondBr: |
| ... | ... | @@ -1173,6 +1175,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) { |
| 1173 | 1175 | return IrInstSrcIdCallExtra; |
| 1174 | 1176 | } |
| 1175 | 1177 | |
| 1178 | static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsyncCallExtra *) { | |
| 1179 | return IrInstSrcIdAsyncCallExtra; | |
| 1180 | } | |
| 1181 | ||
| 1176 | 1182 | static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) { |
| 1177 | 1183 | return IrInstSrcIdConst; |
| 1178 | 1184 | } |
| ... | ... | @@ -2442,6 +2448,25 @@ static IrInstSrc *ir_build_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode * |
| 2442 | 2448 | return &call_instruction->base; |
| 2443 | 2449 | } |
| 2444 | 2450 | |
| 2451 | static IrInstSrc *ir_build_async_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, | |
| 2452 | CallModifier modifier, IrInstSrc *fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstSrc *args, ResultLoc *result_loc) | |
| 2453 | { | |
| 2454 | IrInstSrcAsyncCallExtra *call_instruction = ir_build_instruction<IrInstSrcAsyncCallExtra>(irb, scope, source_node); | |
| 2455 | call_instruction->modifier = modifier; | |
| 2456 | call_instruction->fn_ref = fn_ref; | |
| 2457 | call_instruction->ret_ptr = ret_ptr; | |
| 2458 | call_instruction->new_stack = new_stack; | |
| 2459 | call_instruction->args = args; | |
| 2460 | call_instruction->result_loc = result_loc; | |
| 2461 | ||
| 2462 | ir_ref_instruction(fn_ref, irb->current_basic_block); | |
| 2463 | if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); | |
| 2464 | ir_ref_instruction(new_stack, irb->current_basic_block); | |
| 2465 | ir_ref_instruction(args, irb->current_basic_block); | |
| 2466 | ||
| 2467 | return &call_instruction->base; | |
| 2468 | } | |
| 2469 | ||
| 2445 | 2470 | static IrInstSrc *ir_build_call_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, |
| 2446 | 2471 | IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc **args_ptr, size_t args_len, |
| 2447 | 2472 | ResultLoc *result_loc) |
| ... | ... | @@ -6183,11 +6208,10 @@ static IrInstSrc *ir_gen_this(IrBuilderSrc *irb, Scope *orig_scope, AstNode *nod |
| 6183 | 6208 | static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *await_node, AstNode *call_node, |
| 6184 | 6209 | LVal lval, ResultLoc *result_loc) |
| 6185 | 6210 | { |
| 6186 | size_t arg_offset = 3; | |
| 6187 | if (call_node->data.fn_call_expr.params.length < arg_offset) { | |
| 6211 | if (call_node->data.fn_call_expr.params.length != 4) { | |
| 6188 | 6212 | add_node_error(irb->codegen, call_node, |
| 6189 | buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize, | |
| 6190 | arg_offset, call_node->data.fn_call_expr.params.length)); | |
| 6213 | buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize, | |
| 6214 | call_node->data.fn_call_expr.params.length)); | |
| 6191 | 6215 | return irb->codegen->invalid_inst_src; |
| 6192 | 6216 | } |
| 6193 | 6217 | |
| ... | ... | @@ -6206,20 +6230,37 @@ static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *aw |
| 6206 | 6230 | if (fn_ref == irb->codegen->invalid_inst_src) |
| 6207 | 6231 | return fn_ref; |
| 6208 | 6232 | |
| 6209 | size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset; | |
| 6210 | IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(arg_count); | |
| 6211 | for (size_t i = 0; i < arg_count; i += 1) { | |
| 6212 | AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset); | |
| 6213 | IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); | |
| 6214 | if (arg == irb->codegen->invalid_inst_src) | |
| 6215 | return arg; | |
| 6216 | args[i] = arg; | |
| 6217 | } | |
| 6218 | ||
| 6219 | 6233 | CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; |
| 6220 | 6234 | bool is_async_call_builtin = true; |
| 6221 | IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, | |
| 6222 | ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); | |
| 6235 | AstNode *args_node = call_node->data.fn_call_expr.params.at(3); | |
| 6236 | if (args_node->type == NodeTypeContainerInitExpr) { | |
| 6237 | if (args_node->data.container_init_expr.kind == ContainerInitKindArray || | |
| 6238 | args_node->data.container_init_expr.entries.length == 0) | |
| 6239 | { | |
| 6240 | size_t arg_count = args_node->data.container_init_expr.entries.length; | |
| 6241 | IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(arg_count); | |
| 6242 | for (size_t i = 0; i < arg_count; i += 1) { | |
| 6243 | AstNode *arg_node = args_node->data.container_init_expr.entries.at(i); | |
| 6244 | IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); | |
| 6245 | if (arg == irb->codegen->invalid_inst_src) | |
| 6246 | return arg; | |
| 6247 | args[i] = arg; | |
| 6248 | } | |
| 6249 | ||
| 6250 | IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, | |
| 6251 | ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); | |
| 6252 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | |
| 6253 | } else { | |
| 6254 | exec_add_error_node(irb->codegen, irb->exec, args_node, | |
| 6255 | buf_sprintf("TODO: @asyncCall with anon struct literal")); | |
| 6256 | return irb->codegen->invalid_inst_src; | |
| 6257 | } | |
| 6258 | } | |
| 6259 | IrInstSrc *args = ir_gen_node(irb, args_node, scope); | |
| 6260 | if (args == irb->codegen->invalid_inst_src) | |
| 6261 | return args; | |
| 6262 | ||
| 6263 | IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc); | |
| 6223 | 6264 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 6224 | 6265 | } |
| 6225 | 6266 | |
| ... | ... | @@ -20721,40 +20762,106 @@ static IrInstGen *ir_analyze_call_extra(IrAnalyze *ira, IrInst* source_instr, |
| 20721 | 20762 | modifier, stack, stack_src, false, args_ptr, args_len, nullptr, result_loc); |
| 20722 | 20763 | } |
| 20723 | 20764 | |
| 20724 | static IrInstGen *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstSrcCallExtra *instruction) { | |
| 20725 | IrInstGen *args = instruction->args->child; | |
| 20765 | static IrInstGen *ir_analyze_async_call_extra(IrAnalyze *ira, IrInst* source_instr, CallModifier modifier, | |
| 20766 | IrInstSrc *pass1_fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstGen **args_ptr, size_t args_len, ResultLoc *result_loc) | |
| 20767 | { | |
| 20768 | IrInstGen *fn_ref = pass1_fn_ref->child; | |
| 20769 | if (type_is_invalid(fn_ref->value->type)) | |
| 20770 | return ira->codegen->invalid_inst_gen; | |
| 20771 | ||
| 20772 | if (ir_should_inline(ira->old_irb.exec, source_instr->scope)) { | |
| 20773 | ir_add_error(ira, source_instr, buf_sprintf("TODO: comptime @asyncCall")); | |
| 20774 | return ira->codegen->invalid_inst_gen; | |
| 20775 | } | |
| 20776 | ||
| 20777 | IrInstGen *first_arg_ptr = nullptr; | |
| 20778 | IrInst *first_arg_ptr_src = nullptr; | |
| 20779 | ZigFn *fn = nullptr; | |
| 20780 | if (instr_is_comptime(fn_ref)) { | |
| 20781 | if (fn_ref->value->type->id == ZigTypeIdBoundFn) { | |
| 20782 | assert(fn_ref->value->special == ConstValSpecialStatic); | |
| 20783 | fn = fn_ref->value->data.x_bound_fn.fn; | |
| 20784 | first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; | |
| 20785 | first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; | |
| 20786 | if (type_is_invalid(first_arg_ptr->value->type)) | |
| 20787 | return ira->codegen->invalid_inst_gen; | |
| 20788 | } else { | |
| 20789 | fn = ir_resolve_fn(ira, fn_ref); | |
| 20790 | } | |
| 20791 | } | |
| 20792 | ||
| 20793 | IrInstGen *ret_ptr_uncasted = nullptr; | |
| 20794 | if (ret_ptr != nullptr) { | |
| 20795 | ret_ptr_uncasted = ret_ptr->child; | |
| 20796 | if (type_is_invalid(ret_ptr_uncasted->value->type)) | |
| 20797 | return ira->codegen->invalid_inst_gen; | |
| 20798 | } | |
| 20799 | ||
| 20800 | ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; | |
| 20801 | IrInstGen *casted_new_stack = analyze_casted_new_stack(ira, source_instr, new_stack->child, | |
| 20802 | &new_stack->base, true, fn); | |
| 20803 | if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) | |
| 20804 | return ira->codegen->invalid_inst_gen; | |
| 20805 | ||
| 20806 | return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr, first_arg_ptr_src, | |
| 20807 | modifier, casted_new_stack, &new_stack->base, true, args_ptr, args_len, ret_ptr_uncasted, result_loc); | |
| 20808 | } | |
| 20809 | ||
| 20810 | static bool ir_extract_tuple_call_args(IrAnalyze *ira, IrInst *source_instr, IrInstGen *args, IrInstGen ***args_ptr, size_t *args_len) { | |
| 20726 | 20811 | ZigType *args_type = args->value->type; |
| 20727 | 20812 | if (type_is_invalid(args_type)) |
| 20728 | return ira->codegen->invalid_inst_gen; | |
| 20813 | return false; | |
| 20729 | 20814 | |
| 20730 | 20815 | if (args_type->id != ZigTypeIdStruct) { |
| 20731 | 20816 | ir_add_error(ira, &args->base, |
| 20732 | 20817 | buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name))); |
| 20733 | return ira->codegen->invalid_inst_gen; | |
| 20818 | return false; | |
| 20734 | 20819 | } |
| 20735 | 20820 | |
| 20736 | IrInstGen **args_ptr = nullptr; | |
| 20737 | size_t args_len = 0; | |
| 20738 | ||
| 20739 | 20821 | if (is_tuple(args_type)) { |
| 20740 | args_len = args_type->data.structure.src_field_count; | |
| 20741 | args_ptr = heap::c_allocator.allocate<IrInstGen *>(args_len); | |
| 20742 | for (size_t i = 0; i < args_len; i += 1) { | |
| 20822 | *args_len = args_type->data.structure.src_field_count; | |
| 20823 | *args_ptr = heap::c_allocator.allocate<IrInstGen *>(*args_len); | |
| 20824 | for (size_t i = 0; i < *args_len; i += 1) { | |
| 20743 | 20825 | TypeStructField *arg_field = args_type->data.structure.fields[i]; |
| 20744 | args_ptr[i] = ir_analyze_struct_value_field_value(ira, &instruction->base.base, args, arg_field); | |
| 20745 | if (type_is_invalid(args_ptr[i]->value->type)) | |
| 20746 | return ira->codegen->invalid_inst_gen; | |
| 20826 | (*args_ptr)[i] = ir_analyze_struct_value_field_value(ira, source_instr, args, arg_field); | |
| 20827 | if (type_is_invalid((*args_ptr)[i]->value->type)) | |
| 20828 | return false; | |
| 20747 | 20829 | } |
| 20748 | 20830 | } else { |
| 20749 | 20831 | ir_add_error(ira, &args->base, buf_sprintf("TODO: struct args")); |
| 20832 | return false; | |
| 20833 | } | |
| 20834 | return true; | |
| 20835 | } | |
| 20836 | ||
| 20837 | static IrInstGen *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstSrcCallExtra *instruction) { | |
| 20838 | IrInstGen *args = instruction->args->child; | |
| 20839 | IrInstGen **args_ptr = nullptr; | |
| 20840 | size_t args_len = 0; | |
| 20841 | if (!ir_extract_tuple_call_args(ira, &instruction->base.base, args, &args_ptr, &args_len)) { | |
| 20750 | 20842 | return ira->codegen->invalid_inst_gen; |
| 20751 | 20843 | } |
| 20844 | ||
| 20752 | 20845 | IrInstGen *result = ir_analyze_call_extra(ira, &instruction->base.base, instruction->options, |
| 20753 | 20846 | instruction->fn_ref, args_ptr, args_len, instruction->result_loc); |
| 20754 | 20847 | heap::c_allocator.deallocate(args_ptr, args_len); |
| 20755 | 20848 | return result; |
| 20756 | 20849 | } |
| 20757 | 20850 | |
| 20851 | static IrInstGen *ir_analyze_instruction_async_call_extra(IrAnalyze *ira, IrInstSrcAsyncCallExtra *instruction) { | |
| 20852 | IrInstGen *args = instruction->args->child; | |
| 20853 | IrInstGen **args_ptr = nullptr; | |
| 20854 | size_t args_len = 0; | |
| 20855 | if (!ir_extract_tuple_call_args(ira, &instruction->base.base, args, &args_ptr, &args_len)) { | |
| 20856 | return ira->codegen->invalid_inst_gen; | |
| 20857 | } | |
| 20858 | ||
| 20859 | IrInstGen *result = ir_analyze_async_call_extra(ira, &instruction->base.base, instruction->modifier, | |
| 20860 | instruction->fn_ref, instruction->ret_ptr, instruction->new_stack, args_ptr, args_len, instruction->result_loc); | |
| 20861 | heap::c_allocator.deallocate(args_ptr, args_len); | |
| 20862 | return result; | |
| 20863 | } | |
| 20864 | ||
| 20758 | 20865 | static IrInstGen *ir_analyze_instruction_call_args(IrAnalyze *ira, IrInstSrcCallArgs *instruction) { |
| 20759 | 20866 | IrInstGen **args_ptr = heap::c_allocator.allocate<IrInstGen *>(instruction->args_len); |
| 20760 | 20867 | for (size_t i = 0; i < instruction->args_len; i += 1) { |
| ... | ... | @@ -31103,6 +31210,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc |
| 31103 | 31210 | return ir_analyze_instruction_call_args(ira, (IrInstSrcCallArgs *)instruction); |
| 31104 | 31211 | case IrInstSrcIdCallExtra: |
| 31105 | 31212 | return ir_analyze_instruction_call_extra(ira, (IrInstSrcCallExtra *)instruction); |
| 31213 | case IrInstSrcIdAsyncCallExtra: | |
| 31214 | return ir_analyze_instruction_async_call_extra(ira, (IrInstSrcAsyncCallExtra *)instruction); | |
| 31106 | 31215 | case IrInstSrcIdBr: |
| 31107 | 31216 | return ir_analyze_instruction_br(ira, (IrInstSrcBr *)instruction); |
| 31108 | 31217 | case IrInstSrcIdCondBr: |
| ... | ... | @@ -31612,6 +31721,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { |
| 31612 | 31721 | case IrInstSrcIdDeclVar: |
| 31613 | 31722 | case IrInstSrcIdStorePtr: |
| 31614 | 31723 | case IrInstSrcIdCallExtra: |
| 31724 | case IrInstSrcIdAsyncCallExtra: | |
| 31615 | 31725 | case IrInstSrcIdCall: |
| 31616 | 31726 | case IrInstSrcIdCallArgs: |
| 31617 | 31727 | case IrInstSrcIdReturn: |
src/ir_print.cpp+55-54| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | * See http://opensource.org/licenses/MIT |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | #include "all_types.hpp" | |
| 8 | 9 | #include "analyze.hpp" |
| 9 | 10 | #include "ir.hpp" |
| 10 | 11 | #include "ir_print.hpp" |
| ... | ... | @@ -55,6 +56,36 @@ struct IrPrintGen { |
| 55 | 56 | static void ir_print_other_inst_src(IrPrintSrc *irp, IrInstSrc *inst); |
| 56 | 57 | static void ir_print_other_inst_gen(IrPrintGen *irp, IrInstGen *inst); |
| 57 | 58 | |
| 59 | static void ir_print_call_modifier(FILE *f, CallModifier modifier) { | |
| 60 | switch (modifier) { | |
| 61 | case CallModifierNone: | |
| 62 | break; | |
| 63 | case CallModifierNoSuspend: | |
| 64 | fprintf(f, "nosuspend "); | |
| 65 | break; | |
| 66 | case CallModifierAsync: | |
| 67 | fprintf(f, "async "); | |
| 68 | break; | |
| 69 | case CallModifierNeverTail: | |
| 70 | fprintf(f, "notail "); | |
| 71 | break; | |
| 72 | case CallModifierNeverInline: | |
| 73 | fprintf(f, "noinline "); | |
| 74 | break; | |
| 75 | case CallModifierAlwaysTail: | |
| 76 | fprintf(f, "tail "); | |
| 77 | break; | |
| 78 | case CallModifierAlwaysInline: | |
| 79 | fprintf(f, "inline "); | |
| 80 | break; | |
| 81 | case CallModifierCompileTime: | |
| 82 | fprintf(f, "comptime "); | |
| 83 | break; | |
| 84 | case CallModifierBuiltin: | |
| 85 | zig_unreachable(); | |
| 86 | } | |
| 87 | } | |
| 88 | ||
| 58 | 89 | const char* ir_inst_src_type_str(IrInstSrcId id) { |
| 59 | 90 | switch (id) { |
| 60 | 91 | case IrInstSrcIdInvalid: |
| ... | ... | @@ -97,6 +128,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { |
| 97 | 128 | return "SrcVarPtr"; |
| 98 | 129 | case IrInstSrcIdCallExtra: |
| 99 | 130 | return "SrcCallExtra"; |
| 131 | case IrInstSrcIdAsyncCallExtra: | |
| 132 | return "SrcAsyncCallExtra"; | |
| 100 | 133 | case IrInstSrcIdCall: |
| 101 | 134 | return "SrcCall"; |
| 102 | 135 | case IrInstSrcIdCallArgs: |
| ... | ... | @@ -851,6 +884,23 @@ static void ir_print_call_extra(IrPrintSrc *irp, IrInstSrcCallExtra *instruction |
| 851 | 884 | ir_print_result_loc(irp, instruction->result_loc); |
| 852 | 885 | } |
| 853 | 886 | |
| 887 | static void ir_print_async_call_extra(IrPrintSrc *irp, IrInstSrcAsyncCallExtra *instruction) { | |
| 888 | fprintf(irp->f, "modifier="); | |
| 889 | ir_print_call_modifier(irp->f, instruction->modifier); | |
| 890 | fprintf(irp->f, ", fn="); | |
| 891 | ir_print_other_inst_src(irp, instruction->fn_ref); | |
| 892 | if (instruction->ret_ptr != nullptr) { | |
| 893 | fprintf(irp->f, ", ret_ptr="); | |
| 894 | ir_print_other_inst_src(irp, instruction->ret_ptr); | |
| 895 | } | |
| 896 | fprintf(irp->f, ", new_stack="); | |
| 897 | ir_print_other_inst_src(irp, instruction->new_stack); | |
| 898 | fprintf(irp->f, ", args="); | |
| 899 | ir_print_other_inst_src(irp, instruction->args); | |
| 900 | fprintf(irp->f, ", result="); | |
| 901 | ir_print_result_loc(irp, instruction->result_loc); | |
| 902 | } | |
| 903 | ||
| 854 | 904 | static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction) { |
| 855 | 905 | fprintf(irp->f, "opts="); |
| 856 | 906 | ir_print_other_inst_src(irp, instruction->options); |
| ... | ... | @@ -868,33 +918,7 @@ static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction) |
| 868 | 918 | } |
| 869 | 919 | |
| 870 | 920 | static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction) { |
| 871 | switch (call_instruction->modifier) { | |
| 872 | case CallModifierNone: | |
| 873 | break; | |
| 874 | case CallModifierNoSuspend: | |
| 875 | fprintf(irp->f, "nosuspend "); | |
| 876 | break; | |
| 877 | case CallModifierAsync: | |
| 878 | fprintf(irp->f, "async "); | |
| 879 | break; | |
| 880 | case CallModifierNeverTail: | |
| 881 | fprintf(irp->f, "notail "); | |
| 882 | break; | |
| 883 | case CallModifierNeverInline: | |
| 884 | fprintf(irp->f, "noinline "); | |
| 885 | break; | |
| 886 | case CallModifierAlwaysTail: | |
| 887 | fprintf(irp->f, "tail "); | |
| 888 | break; | |
| 889 | case CallModifierAlwaysInline: | |
| 890 | fprintf(irp->f, "inline "); | |
| 891 | break; | |
| 892 | case CallModifierCompileTime: | |
| 893 | fprintf(irp->f, "comptime "); | |
| 894 | break; | |
| 895 | case CallModifierBuiltin: | |
| 896 | zig_unreachable(); | |
| 897 | } | |
| 921 | ir_print_call_modifier(irp->f, call_instruction->modifier); | |
| 898 | 922 | if (call_instruction->fn_entry) { |
| 899 | 923 | fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); |
| 900 | 924 | } else { |
| ... | ... | @@ -913,33 +937,7 @@ static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction) |
| 913 | 937 | } |
| 914 | 938 | |
| 915 | 939 | static void ir_print_call_gen(IrPrintGen *irp, IrInstGenCall *call_instruction) { |
| 916 | switch (call_instruction->modifier) { | |
| 917 | case CallModifierNone: | |
| 918 | break; | |
| 919 | case CallModifierNoSuspend: | |
| 920 | fprintf(irp->f, "nosuspend "); | |
| 921 | break; | |
| 922 | case CallModifierAsync: | |
| 923 | fprintf(irp->f, "async "); | |
| 924 | break; | |
| 925 | case CallModifierNeverTail: | |
| 926 | fprintf(irp->f, "notail "); | |
| 927 | break; | |
| 928 | case CallModifierNeverInline: | |
| 929 | fprintf(irp->f, "noinline "); | |
| 930 | break; | |
| 931 | case CallModifierAlwaysTail: | |
| 932 | fprintf(irp->f, "tail "); | |
| 933 | break; | |
| 934 | case CallModifierAlwaysInline: | |
| 935 | fprintf(irp->f, "inline "); | |
| 936 | break; | |
| 937 | case CallModifierCompileTime: | |
| 938 | fprintf(irp->f, "comptime "); | |
| 939 | break; | |
| 940 | case CallModifierBuiltin: | |
| 941 | zig_unreachable(); | |
| 942 | } | |
| 940 | ir_print_call_modifier(irp->f, call_instruction->modifier); | |
| 943 | 941 | if (call_instruction->fn_entry) { |
| 944 | 942 | fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); |
| 945 | 943 | } else { |
| ... | ... | @@ -2619,6 +2617,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai |
| 2619 | 2617 | case IrInstSrcIdCallExtra: |
| 2620 | 2618 | ir_print_call_extra(irp, (IrInstSrcCallExtra *)instruction); |
| 2621 | 2619 | break; |
| 2620 | case IrInstSrcIdAsyncCallExtra: | |
| 2621 | ir_print_async_call_extra(irp, (IrInstSrcAsyncCallExtra *)instruction); | |
| 2622 | break; | |
| 2622 | 2623 | case IrInstSrcIdCall: |
| 2623 | 2624 | ir_print_call_src(irp, (IrInstSrcCall *)instruction); |
| 2624 | 2625 | break; |
test/compile_errors.zig+16-3| ... | ... | @@ -1144,13 +1144,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1144 | 1144 | "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'", |
| 1145 | 1145 | }); |
| 1146 | 1146 | |
| 1147 | cases.add("wrong type for argument tuple to @asyncCall", | |
| 1148 | \\export fn entry1() void { | |
| 1149 | \\ var frame: @Frame(foo) = undefined; | |
| 1150 | \\ @asyncCall(&frame, {}, foo, {}); | |
| 1151 | \\} | |
| 1152 | \\ | |
| 1153 | \\fn foo() i32 { | |
| 1154 | \\ return 0; | |
| 1155 | \\} | |
| 1156 | , &[_][]const u8{ | |
| 1157 | "tmp.zig:3:33: error: expected tuple or struct, found 'void'", | |
| 1158 | }); | |
| 1159 | ||
| 1147 | 1160 | cases.add("wrong type for result ptr to @asyncCall", |
| 1148 | 1161 | \\export fn entry() void { |
| 1149 | 1162 | \\ _ = async amain(); |
| 1150 | 1163 | \\} |
| 1151 | 1164 | \\fn amain() i32 { |
| 1152 | 1165 | \\ var frame: @Frame(foo) = undefined; |
| 1153 | \\ return await @asyncCall(&frame, false, foo); | |
| 1166 | \\ return await @asyncCall(&frame, false, foo, .{}); | |
| 1154 | 1167 | \\} |
| 1155 | 1168 | \\fn foo() i32 { |
| 1156 | 1169 | \\ return 1234; |
| ... | ... | @@ -1291,7 +1304,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1291 | 1304 | \\export fn entry() void { |
| 1292 | 1305 | \\ var ptr: fn () callconv(.Async) void = func; |
| 1293 | 1306 | \\ var bytes: [64]u8 = undefined; |
| 1294 | \\ _ = @asyncCall(&bytes, {}, ptr); | |
| 1307 | \\ _ = @asyncCall(&bytes, {}, ptr, .{}); | |
| 1295 | 1308 | \\} |
| 1296 | 1309 | \\fn func() callconv(.Async) void {} |
| 1297 | 1310 | , &[_][]const u8{ |
| ... | ... | @@ -1467,7 +1480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1467 | 1480 | \\export fn entry() void { |
| 1468 | 1481 | \\ var ptr = afunc; |
| 1469 | 1482 | \\ var bytes: [100]u8 align(16) = undefined; |
| 1470 | \\ _ = @asyncCall(&bytes, {}, ptr); | |
| 1483 | \\ _ = @asyncCall(&bytes, {}, ptr, .{}); | |
| 1471 | 1484 | \\} |
| 1472 | 1485 | \\fn afunc() void { } |
| 1473 | 1486 | , &[_][]const u8{ |
test/runtime_safety.zig+1-1| ... | ... | @@ -280,7 +280,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 280 | 280 | \\pub fn main() void { |
| 281 | 281 | \\ var bytes: [1]u8 align(16) = undefined; |
| 282 | 282 | \\ var ptr = other; |
| 283 | \\ var frame = @asyncCall(&bytes, {}, ptr); | |
| 283 | \\ var frame = @asyncCall(&bytes, {}, ptr, .{}); | |
| 284 | 284 | \\} |
| 285 | 285 | \\fn other() callconv(.Async) void { |
| 286 | 286 | \\ suspend; |
test/stage1/behavior/async_fn.zig+13-13| ... | ... | @@ -282,7 +282,7 @@ test "async fn pointer in a struct field" { |
| 282 | 282 | }; |
| 283 | 283 | var foo = Foo{ .bar = simpleAsyncFn2 }; |
| 284 | 284 | var bytes: [64]u8 align(16) = undefined; |
| 285 | const f = @asyncCall(&bytes, {}, foo.bar, &data); | |
| 285 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | |
| 286 | 286 | comptime expect(@TypeOf(f) == anyframe->void); |
| 287 | 287 | expect(data == 2); |
| 288 | 288 | resume f; |
| ... | ... | @@ -318,7 +318,7 @@ test "@asyncCall with return type" { |
| 318 | 318 | var foo = Foo{ .bar = Foo.middle }; |
| 319 | 319 | var bytes: [150]u8 align(16) = undefined; |
| 320 | 320 | var aresult: i32 = 0; |
| 321 | _ = @asyncCall(&bytes, &aresult, foo.bar); | |
| 321 | _ = @asyncCall(&bytes, &aresult, foo.bar, .{}); | |
| 322 | 322 | expect(aresult == 0); |
| 323 | 323 | resume Foo.global_frame; |
| 324 | 324 | expect(aresult == 1234); |
| ... | ... | @@ -332,7 +332,7 @@ test "async fn with inferred error set" { |
| 332 | 332 | var frame: [1]@Frame(middle) = undefined; |
| 333 | 333 | var fn_ptr = middle; |
| 334 | 334 | var result: @TypeOf(fn_ptr).ReturnType.ErrorSet!void = undefined; |
| 335 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr); | |
| 335 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); | |
| 336 | 336 | resume global_frame; |
| 337 | 337 | std.testing.expectError(error.Fail, result); |
| 338 | 338 | } |
| ... | ... | @@ -827,7 +827,7 @@ test "cast fn to async fn when it is inferred to be async" { |
| 827 | 827 | ptr = func; |
| 828 | 828 | var buf: [100]u8 align(16) = undefined; |
| 829 | 829 | var result: i32 = undefined; |
| 830 | const f = @asyncCall(&buf, &result, ptr); | |
| 830 | const f = @asyncCall(&buf, &result, ptr, .{}); | |
| 831 | 831 | _ = await f; |
| 832 | 832 | expect(result == 1234); |
| 833 | 833 | ok = true; |
| ... | ... | @@ -855,7 +855,7 @@ test "cast fn to async fn when it is inferred to be async, awaited directly" { |
| 855 | 855 | ptr = func; |
| 856 | 856 | var buf: [100]u8 align(16) = undefined; |
| 857 | 857 | var result: i32 = undefined; |
| 858 | _ = await @asyncCall(&buf, &result, ptr); | |
| 858 | _ = await @asyncCall(&buf, &result, ptr, .{}); | |
| 859 | 859 | expect(result == 1234); |
| 860 | 860 | ok = true; |
| 861 | 861 | } |
| ... | ... | @@ -951,7 +951,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { |
| 951 | 951 | fn doTheTest() void { |
| 952 | 952 | var frame: [1]@Frame(middle) = undefined; |
| 953 | 953 | var result: @TypeOf(middle).ReturnType.ErrorSet!void = undefined; |
| 954 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle); | |
| 954 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); | |
| 955 | 955 | resume global_frame; |
| 956 | 956 | std.testing.expectError(error.Fail, result); |
| 957 | 957 | } |
| ... | ... | @@ -982,7 +982,7 @@ test "@asyncCall with actual frame instead of byte buffer" { |
| 982 | 982 | }; |
| 983 | 983 | var frame: @Frame(S.func) = undefined; |
| 984 | 984 | var result: i32 = undefined; |
| 985 | const ptr = @asyncCall(&frame, &result, S.func); | |
| 985 | const ptr = @asyncCall(&frame, &result, S.func, .{}); | |
| 986 | 986 | resume ptr; |
| 987 | 987 | expect(result == 1234); |
| 988 | 988 | } |
| ... | ... | @@ -1005,7 +1005,7 @@ test "@asyncCall using the result location inside the frame" { |
| 1005 | 1005 | }; |
| 1006 | 1006 | var foo = Foo{ .bar = S.simple2 }; |
| 1007 | 1007 | var bytes: [64]u8 align(16) = undefined; |
| 1008 | const f = @asyncCall(&bytes, {}, foo.bar, &data); | |
| 1008 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | |
| 1009 | 1009 | comptime expect(@TypeOf(f) == anyframe->i32); |
| 1010 | 1010 | expect(data == 2); |
| 1011 | 1011 | resume f; |
| ... | ... | @@ -1042,7 +1042,7 @@ test "using @TypeOf on a generic function call" { |
| 1042 | 1042 | } |
| 1043 | 1043 | const F = @TypeOf(async amain(x - 1)); |
| 1044 | 1044 | const frame = @intToPtr(*F, @ptrToInt(&buf)); |
| 1045 | return await @asyncCall(frame, {}, amain, x - 1); | |
| 1045 | return await @asyncCall(frame, {}, amain, .{x - 1}); | |
| 1046 | 1046 | } |
| 1047 | 1047 | }; |
| 1048 | 1048 | _ = async S.amain(@as(u32, 1)); |
| ... | ... | @@ -1067,7 +1067,7 @@ test "recursive call of await @asyncCall with struct return type" { |
| 1067 | 1067 | } |
| 1068 | 1068 | const F = @TypeOf(async amain(x - 1)); |
| 1069 | 1069 | const frame = @intToPtr(*F, @ptrToInt(&buf)); |
| 1070 | return await @asyncCall(frame, {}, amain, x - 1); | |
| 1070 | return await @asyncCall(frame, {}, amain, .{x - 1}); | |
| 1071 | 1071 | } |
| 1072 | 1072 | |
| 1073 | 1073 | const Foo = struct { |
| ... | ... | @@ -1078,7 +1078,7 @@ test "recursive call of await @asyncCall with struct return type" { |
| 1078 | 1078 | }; |
| 1079 | 1079 | var res: S.Foo = undefined; |
| 1080 | 1080 | var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined; |
| 1081 | _ = @asyncCall(&frame, &res, S.amain, @as(u32, 1)); | |
| 1081 | _ = @asyncCall(&frame, &res, S.amain, .{@as(u32, 1)}); | |
| 1082 | 1082 | resume S.global_frame; |
| 1083 | 1083 | expect(S.global_ok); |
| 1084 | 1084 | expect(res.x == 1); |
| ... | ... | @@ -1377,7 +1377,7 @@ test "async function call resolves target fn frame, comptime func" { |
| 1377 | 1377 | fn foo() anyerror!void { |
| 1378 | 1378 | const stack_size = 1000; |
| 1379 | 1379 | var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; |
| 1380 | return await @asyncCall(&stack_frame, {}, bar); | |
| 1380 | return await @asyncCall(&stack_frame, {}, bar, .{}); | |
| 1381 | 1381 | } |
| 1382 | 1382 | |
| 1383 | 1383 | fn bar() anyerror!void { |
| ... | ... | @@ -1400,7 +1400,7 @@ test "async function call resolves target fn frame, runtime func" { |
| 1400 | 1400 | const stack_size = 1000; |
| 1401 | 1401 | var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; |
| 1402 | 1402 | var func: fn () callconv(.Async) anyerror!void = bar; |
| 1403 | return await @asyncCall(&stack_frame, {}, func); | |
| 1403 | return await @asyncCall(&stack_frame, {}, func, .{}); | |
| 1404 | 1404 | } |
| 1405 | 1405 | |
| 1406 | 1406 | fn bar() anyerror!void { |