| author | |
| committer | |
| log | 18af2f9a2764cc340571578d58cb2575faeccdc6 |
| tree | 547d4c68ab6a6c062ce10bef556e9c92272e5a6e |
| parent | b1c07c0ea9e351a43c9bc2fe747fc07c0a19e005 |
closes #8567 files changed, 89 insertions(+), 14 deletions(-)
src/all_types.hpp+11-1| ... | ... | @@ -1251,7 +1251,10 @@ struct FnTableEntry { |
| 1251 | 1251 | ScopeBlock *def_scope; // parent is child_scope |
| 1252 | 1252 | Buf symbol_name; |
| 1253 | 1253 | TypeTableEntry *type_entry; // function type |
| 1254 | TypeTableEntry *implicit_return_type; | |
| 1254 | // in the case of normal functions this is the implicit return type | |
| 1255 | // in the case of async functions this is the implicit return type according to the | |
| 1256 | // zig source code, not according to zig ir | |
| 1257 | TypeTableEntry *src_implicit_return_type; | |
| 1255 | 1258 | bool is_test; |
| 1256 | 1259 | FnInline fn_inline; |
| 1257 | 1260 | FnAnalState anal_state; |
| ... | ... | @@ -2035,6 +2038,7 @@ enum IrInstructionId { |
| 2035 | 2038 | IrInstructionIdPromiseResultType, |
| 2036 | 2039 | IrInstructionIdAwaitBookkeeping, |
| 2037 | 2040 | IrInstructionIdSaveErrRetAddr, |
| 2041 | IrInstructionIdAddImplicitReturnType, | |
| 2038 | 2042 | }; |
| 2039 | 2043 | |
| 2040 | 2044 | struct IrInstruction { |
| ... | ... | @@ -2993,6 +2997,12 @@ struct IrInstructionSaveErrRetAddr { |
| 2993 | 2997 | IrInstruction base; |
| 2994 | 2998 | }; |
| 2995 | 2999 | |
| 3000 | struct IrInstructionAddImplicitReturnType { | |
| 3001 | IrInstruction base; | |
| 3002 | ||
| 3003 | IrInstruction *value; | |
| 3004 | }; | |
| 3005 | ||
| 2996 | 3006 | static const size_t slice_ptr_index = 0; |
| 2997 | 3007 | static const size_t slice_len_index = 1; |
| 2998 | 3008 |
src/analyze.cpp+5-5| ... | ... | @@ -3865,7 +3865,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3865 | 3865 | |
| 3866 | 3866 | TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, |
| 3867 | 3867 | &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3868 | fn_table_entry->implicit_return_type = block_return_type; | |
| 3868 | fn_table_entry->src_implicit_return_type = block_return_type; | |
| 3869 | 3869 | |
| 3870 | 3870 | if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) { |
| 3871 | 3871 | assert(g->errors.length > 0); |
| ... | ... | @@ -3877,10 +3877,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3877 | 3877 | TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; |
| 3878 | 3878 | if (return_err_set_type->data.error_set.infer_fn != nullptr) { |
| 3879 | 3879 | TypeTableEntry *inferred_err_set_type; |
| 3880 | if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) { | |
| 3881 | inferred_err_set_type = fn_table_entry->implicit_return_type; | |
| 3882 | } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3883 | inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type; | |
| 3880 | if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) { | |
| 3881 | inferred_err_set_type = fn_table_entry->src_implicit_return_type; | |
| 3882 | } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3883 | inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type; | |
| 3884 | 3884 | } else { |
| 3885 | 3885 | add_node_error(g, return_type_node, |
| 3886 | 3886 | buf_sprintf("function with inferred error set must return at least one possible error")); |
src/ast_render.cpp+10-1| ... | ... | @@ -658,6 +658,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 658 | 658 | if (node->data.fn_call_expr.is_builtin) { |
| 659 | 659 | fprintf(ar->f, "@"); |
| 660 | 660 | } |
| 661 | if (node->data.fn_call_expr.is_async) { | |
| 662 | fprintf(ar->f, "async"); | |
| 663 | if (node->data.fn_call_expr.async_allocator != nullptr) { | |
| 664 | fprintf(ar->f, "<"); | |
| 665 | render_node_extra(ar, node->data.fn_call_expr.async_allocator, true); | |
| 666 | fprintf(ar->f, ">"); | |
| 667 | } | |
| 668 | fprintf(ar->f, " "); | |
| 669 | } | |
| 661 | 670 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 662 | 671 | bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); |
| 663 | 672 | render_node_extra(ar, fn_ref_node, grouped); |
| ... | ... | @@ -1023,7 +1032,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1023 | 1032 | case NodeTypeUnwrapErrorExpr: |
| 1024 | 1033 | { |
| 1025 | 1034 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); |
| 1026 | fprintf(ar->f, " %%%% "); | |
| 1035 | fprintf(ar->f, " catch "); | |
| 1027 | 1036 | if (node->data.unwrap_err_expr.symbol) { |
| 1028 | 1037 | Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol; |
| 1029 | 1038 | fprintf(ar->f, "|%s| ", buf_ptr(var_name)); |
src/codegen.cpp+1| ... | ... | @@ -4245,6 +4245,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4245 | 4245 | case IrInstructionIdErrorUnion: |
| 4246 | 4246 | case IrInstructionIdPromiseResultType: |
| 4247 | 4247 | case IrInstructionIdAwaitBookkeeping: |
| 4248 | case IrInstructionIdAddImplicitReturnType: | |
| 4248 | 4249 | zig_unreachable(); |
| 4249 | 4250 | |
| 4250 | 4251 | case IrInstructionIdReturn: |
src/ir.cpp+40-5| ... | ... | @@ -34,7 +34,7 @@ struct IrAnalyze { |
| 34 | 34 | size_t old_bb_index; |
| 35 | 35 | size_t instruction_index; |
| 36 | 36 | TypeTableEntry *explicit_return_type; |
| 37 | ZigList<IrInstruction *> implicit_return_type_list; | |
| 37 | ZigList<IrInstruction *> src_implicit_return_type_list; | |
| 38 | 38 | IrBasicBlock *const_predecessor_bb; |
| 39 | 39 | }; |
| 40 | 40 | |
| ... | ... | @@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr * |
| 717 | 717 | return IrInstructionIdSaveErrRetAddr; |
| 718 | 718 | } |
| 719 | 719 | |
| 720 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) { | |
| 721 | return IrInstructionIdAddImplicitReturnType; | |
| 722 | } | |
| 723 | ||
| 720 | 724 | template<typename T> |
| 721 | 725 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 722 | 726 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2687,6 +2691,17 @@ static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, A |
| 2687 | 2691 | return &instruction->base; |
| 2688 | 2692 | } |
| 2689 | 2693 | |
| 2694 | static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2695 | IrInstruction *value) | |
| 2696 | { | |
| 2697 | IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node); | |
| 2698 | instruction->value = value; | |
| 2699 | ||
| 2700 | ir_ref_instruction(value, irb->current_basic_block); | |
| 2701 | ||
| 2702 | return &instruction->base; | |
| 2703 | } | |
| 2704 | ||
| 2690 | 2705 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2691 | 2706 | results[ReturnKindUnconditional] = 0; |
| 2692 | 2707 | results[ReturnKindError] = 0; |
| ... | ... | @@ -2767,6 +2782,8 @@ static bool exec_is_async(IrExecutable *exec) { |
| 2767 | 2782 | static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value, |
| 2768 | 2783 | bool is_generated_code) |
| 2769 | 2784 | { |
| 2785 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value)); | |
| 2786 | ||
| 2770 | 2787 | bool is_async = exec_is_async(irb->exec); |
| 2771 | 2788 | if (!is_async) { |
| 2772 | 2789 | IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value); |
| ... | ... | @@ -6399,6 +6416,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6399 | 6416 | ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); |
| 6400 | 6417 | |
| 6401 | 6418 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); |
| 6419 | // we can return undefined here, because the caller passes a pointer to the error struct field | |
| 6420 | // in the error union result, and we populate it in case of allocation failure. | |
| 6402 | 6421 | IrInstruction *undef = ir_build_const_undefined(irb, scope, node); |
| 6403 | 6422 | ir_build_return(irb, scope, node, undef); |
| 6404 | 6423 | |
| ... | ... | @@ -10108,13 +10127,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 10108 | 10127 | return result; |
| 10109 | 10128 | } |
| 10110 | 10129 | |
| 10130 | static TypeTableEntry *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira, | |
| 10131 | IrInstructionAddImplicitReturnType *instruction) | |
| 10132 | { | |
| 10133 | IrInstruction *value = instruction->value->other; | |
| 10134 | if (type_is_invalid(value->value.type)) | |
| 10135 | return ir_unreach_error(ira); | |
| 10136 | ||
| 10137 | ira->src_implicit_return_type_list.append(value); | |
| 10138 | ||
| 10139 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 10140 | out_val->type = ira->codegen->builtin_types.entry_void; | |
| 10141 | return out_val->type; | |
| 10142 | } | |
| 10143 | ||
| 10111 | 10144 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, |
| 10112 | 10145 | IrInstructionReturn *return_instruction) |
| 10113 | 10146 | { |
| 10114 | 10147 | IrInstruction *value = return_instruction->value->other; |
| 10115 | 10148 | if (type_is_invalid(value->value.type)) |
| 10116 | 10149 | return ir_unreach_error(ira); |
| 10117 | ira->implicit_return_type_list.append(value); | |
| 10118 | 10150 | |
| 10119 | 10151 | IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); |
| 10120 | 10152 | if (casted_value == ira->codegen->invalid_instruction) |
| ... | ... | @@ -18049,6 +18081,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 18049 | 18081 | return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction); |
| 18050 | 18082 | case IrInstructionIdSaveErrRetAddr: |
| 18051 | 18083 | return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); |
| 18084 | case IrInstructionIdAddImplicitReturnType: | |
| 18085 | return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction); | |
| 18052 | 18086 | } |
| 18053 | 18087 | zig_unreachable(); |
| 18054 | 18088 | } |
| ... | ... | @@ -18122,11 +18156,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl |
| 18122 | 18156 | |
| 18123 | 18157 | if (new_exec->invalid) { |
| 18124 | 18158 | return ira->codegen->builtin_types.entry_invalid; |
| 18125 | } else if (ira->implicit_return_type_list.length == 0) { | |
| 18159 | } else if (ira->src_implicit_return_type_list.length == 0) { | |
| 18126 | 18160 | return codegen->builtin_types.entry_unreachable; |
| 18127 | 18161 | } else { |
| 18128 | return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items, | |
| 18129 | ira->implicit_return_type_list.length); | |
| 18162 | return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items, | |
| 18163 | ira->src_implicit_return_type_list.length); | |
| 18130 | 18164 | } |
| 18131 | 18165 | } |
| 18132 | 18166 | |
| ... | ... | @@ -18175,6 +18209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18175 | 18209 | case IrInstructionIdCoroAllocHelper: |
| 18176 | 18210 | case IrInstructionIdAwaitBookkeeping: |
| 18177 | 18211 | case IrInstructionIdSaveErrRetAddr: |
| 18212 | case IrInstructionIdAddImplicitReturnType: | |
| 18178 | 18213 | return true; |
| 18179 | 18214 | |
| 18180 | 18215 | case IrInstructionIdPhi: |
src/ir_print.cpp+11-2| ... | ... | @@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) { |
| 201 | 201 | if (call_instruction->is_async) { |
| 202 | 202 | fprintf(irp->f, "async"); |
| 203 | 203 | if (call_instruction->async_allocator != nullptr) { |
| 204 | fprintf(irp->f, "("); | |
| 204 | fprintf(irp->f, "<"); | |
| 205 | 205 | ir_print_other_instruction(irp, call_instruction->async_allocator); |
| 206 | fprintf(irp->f, ")"); | |
| 206 | fprintf(irp->f, ">"); | |
| 207 | 207 | } |
| 208 | 208 | fprintf(irp->f, " "); |
| 209 | 209 | } |
| ... | ... | @@ -1165,6 +1165,12 @@ static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr |
| 1165 | 1165 | fprintf(irp->f, "@saveErrRetAddr()"); |
| 1166 | 1166 | } |
| 1167 | 1167 | |
| 1168 | static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImplicitReturnType *instruction) { | |
| 1169 | fprintf(irp->f, "@addImplicitReturnType("); | |
| 1170 | ir_print_other_instruction(irp, instruction->value); | |
| 1171 | fprintf(irp->f, ")"); | |
| 1172 | } | |
| 1173 | ||
| 1168 | 1174 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1169 | 1175 | ir_print_prefix(irp, instruction); |
| 1170 | 1176 | switch (instruction->id) { |
| ... | ... | @@ -1539,6 +1545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1539 | 1545 | case IrInstructionIdSaveErrRetAddr: |
| 1540 | 1546 | ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction); |
| 1541 | 1547 | break; |
| 1548 | case IrInstructionIdAddImplicitReturnType: | |
| 1549 | ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction); | |
| 1550 | break; | |
| 1542 | 1551 | } |
| 1543 | 1552 | fprintf(irp->f, "\n"); |
| 1544 | 1553 | } |
test/cases/coroutines.zig+11| ... | ... | @@ -176,3 +176,14 @@ async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void { |
| 176 | 176 | *y += 1; |
| 177 | 177 | suspend; |
| 178 | 178 | } |
| 179 | ||
| 180 | test "async fn with inferred error set" { | |
| 181 | const p = (async<std.debug.global_allocator> failing()) catch unreachable; | |
| 182 | resume p; | |
| 183 | cancel p; | |
| 184 | } | |
| 185 | ||
| 186 | async fn failing() !void { | |
| 187 | suspend; | |
| 188 | return error.Fail; | |
| 189 | } |