authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-24 18:21:51-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-24 18:28:32-04:00
log18af2f9a2764cc340571578d58cb2575faeccdc6
tree547d4c68ab6a6c062ce10bef556e9c92272e5a6e
parentb1c07c0ea9e351a43c9bc2fe747fc07c0a19e005

fix async fns with inferred error sets

closes #856

7 files changed, 89 insertions(+), 14 deletions(-)

src/all_types.hpp+11-1
...@@ -1251,7 +1251,10 @@ struct FnTableEntry {...@@ -1251,7 +1251,10 @@ struct FnTableEntry {
1251 ScopeBlock *def_scope; // parent is child_scope1251 ScopeBlock *def_scope; // parent is child_scope
1252 Buf symbol_name;1252 Buf symbol_name;
1253 TypeTableEntry *type_entry; // function type1253 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 bool is_test;1258 bool is_test;
1256 FnInline fn_inline;1259 FnInline fn_inline;
1257 FnAnalState anal_state;1260 FnAnalState anal_state;
...@@ -2035,6 +2038,7 @@ enum IrInstructionId {...@@ -2035,6 +2038,7 @@ enum IrInstructionId {
2035 IrInstructionIdPromiseResultType,2038 IrInstructionIdPromiseResultType,
2036 IrInstructionIdAwaitBookkeeping,2039 IrInstructionIdAwaitBookkeeping,
2037 IrInstructionIdSaveErrRetAddr,2040 IrInstructionIdSaveErrRetAddr,
2041 IrInstructionIdAddImplicitReturnType,
2038};2042};
20392043
2040struct IrInstruction {2044struct IrInstruction {
...@@ -2993,6 +2997,12 @@ struct IrInstructionSaveErrRetAddr {...@@ -2993,6 +2997,12 @@ struct IrInstructionSaveErrRetAddr {
2993 IrInstruction base;2997 IrInstruction base;
2994};2998};
29952999
3000struct IrInstructionAddImplicitReturnType {
3001 IrInstruction base;
3002
3003 IrInstruction *value;
3004};
3005
2996static const size_t slice_ptr_index = 0;3006static const size_t slice_ptr_index = 0;
2997static const size_t slice_len_index = 1;3007static const size_t slice_len_index = 1;
29983008
src/analyze.cpp+5-5
...@@ -3865,7 +3865,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3865,7 +3865,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38653865
3866 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,3866 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
3867 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);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;
38693869
3870 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {3870 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
3871 assert(g->errors.length > 0);3871 assert(g->errors.length > 0);
...@@ -3877,10 +3877,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3877,10 +3877,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
3877 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;3877 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
3878 if (return_err_set_type->data.error_set.infer_fn != nullptr) {3878 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
3879 TypeTableEntry *inferred_err_set_type;3879 TypeTableEntry *inferred_err_set_type;
3880 if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) {3880 if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) {
3881 inferred_err_set_type = fn_table_entry->implicit_return_type;3881 inferred_err_set_type = fn_table_entry->src_implicit_return_type;
3882 } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) {3882 } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) {
3883 inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type;3883 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
3884 } else {3884 } else {
3885 add_node_error(g, return_type_node,3885 add_node_error(g, return_type_node,
3886 buf_sprintf("function with inferred error set must return at least one possible error"));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,6 +658,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
658 if (node->data.fn_call_expr.is_builtin) {658 if (node->data.fn_call_expr.is_builtin) {
659 fprintf(ar->f, "@");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 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;670 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
662 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);671 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);
663 render_node_extra(ar, fn_ref_node, grouped);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,7 +1032,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1023 case NodeTypeUnwrapErrorExpr:1032 case NodeTypeUnwrapErrorExpr:
1024 {1033 {
1025 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);1034 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
1026 fprintf(ar->f, " %%%% ");1035 fprintf(ar->f, " catch ");
1027 if (node->data.unwrap_err_expr.symbol) {1036 if (node->data.unwrap_err_expr.symbol) {
1028 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;1037 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
1029 fprintf(ar->f, "|%s| ", buf_ptr(var_name));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,6 +4245,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4245 case IrInstructionIdErrorUnion:4245 case IrInstructionIdErrorUnion:
4246 case IrInstructionIdPromiseResultType:4246 case IrInstructionIdPromiseResultType:
4247 case IrInstructionIdAwaitBookkeeping:4247 case IrInstructionIdAwaitBookkeeping:
4248 case IrInstructionIdAddImplicitReturnType:
4248 zig_unreachable();4249 zig_unreachable();
42494250
4250 case IrInstructionIdReturn:4251 case IrInstructionIdReturn:
src/ir.cpp+40-5
...@@ -34,7 +34,7 @@ struct IrAnalyze {...@@ -34,7 +34,7 @@ struct IrAnalyze {
34 size_t old_bb_index;34 size_t old_bb_index;
35 size_t instruction_index;35 size_t instruction_index;
36 TypeTableEntry *explicit_return_type;36 TypeTableEntry *explicit_return_type;
37 ZigList<IrInstruction *> implicit_return_type_list;37 ZigList<IrInstruction *> src_implicit_return_type_list;
38 IrBasicBlock *const_predecessor_bb;38 IrBasicBlock *const_predecessor_bb;
39};39};
4040
...@@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *...@@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *
717 return IrInstructionIdSaveErrRetAddr;717 return IrInstructionIdSaveErrRetAddr;
718}718}
719719
720static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) {
721 return IrInstructionIdAddImplicitReturnType;
722}
723
720template<typename T>724template<typename T>
721static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {725static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
722 T *special_instruction = allocate<T>(1);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,6 +2691,17 @@ static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, A
2687 return &instruction->base;2691 return &instruction->base;
2688}2692}
26892693
2694static 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
2690static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2705static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2691 results[ReturnKindUnconditional] = 0;2706 results[ReturnKindUnconditional] = 0;
2692 results[ReturnKindError] = 0;2707 results[ReturnKindError] = 0;
...@@ -2767,6 +2782,8 @@ static bool exec_is_async(IrExecutable *exec) {...@@ -2767,6 +2782,8 @@ static bool exec_is_async(IrExecutable *exec) {
2767static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,2782static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
2768 bool is_generated_code)2783 bool is_generated_code)
2769{2784{
2785 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
2786
2770 bool is_async = exec_is_async(irb->exec);2787 bool is_async = exec_is_async(irb->exec);
2771 if (!is_async) {2788 if (!is_async) {
2772 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);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,6 +6416,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6399 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);6416 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
64006417
6401 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);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 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);6421 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
6403 ir_build_return(irb, scope, node, undef);6422 ir_build_return(irb, scope, node, undef);
64046423
...@@ -10108,13 +10127,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {...@@ -10108,13 +10127,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
10108 return result;10127 return result;
10109}10128}
1011010129
10130static 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
10111static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,10144static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
10112 IrInstructionReturn *return_instruction)10145 IrInstructionReturn *return_instruction)
10113{10146{
10114 IrInstruction *value = return_instruction->value->other;10147 IrInstruction *value = return_instruction->value->other;
10115 if (type_is_invalid(value->value.type))10148 if (type_is_invalid(value->value.type))
10116 return ir_unreach_error(ira);10149 return ir_unreach_error(ira);
10117 ira->implicit_return_type_list.append(value);
1011810150
10119 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);10151 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
10120 if (casted_value == ira->codegen->invalid_instruction)10152 if (casted_value == ira->codegen->invalid_instruction)
...@@ -18049,6 +18081,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -18049,6 +18081,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
18049 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);18081 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
18050 case IrInstructionIdSaveErrRetAddr:18082 case IrInstructionIdSaveErrRetAddr:
18051 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);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 zig_unreachable();18087 zig_unreachable();
18054}18088}
...@@ -18122,11 +18156,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -18122,11 +18156,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1812218156
18123 if (new_exec->invalid) {18157 if (new_exec->invalid) {
18124 return ira->codegen->builtin_types.entry_invalid;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 return codegen->builtin_types.entry_unreachable;18160 return codegen->builtin_types.entry_unreachable;
18127 } else {18161 } else {
18128 return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,18162 return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items,
18129 ira->implicit_return_type_list.length);18163 ira->src_implicit_return_type_list.length);
18130 }18164 }
18131}18165}
1813218166
...@@ -18175,6 +18209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18175,6 +18209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18175 case IrInstructionIdCoroAllocHelper:18209 case IrInstructionIdCoroAllocHelper:
18176 case IrInstructionIdAwaitBookkeeping:18210 case IrInstructionIdAwaitBookkeeping:
18177 case IrInstructionIdSaveErrRetAddr:18211 case IrInstructionIdSaveErrRetAddr:
18212 case IrInstructionIdAddImplicitReturnType:
18178 return true;18213 return true;
1817918214
18180 case IrInstructionIdPhi:18215 case IrInstructionIdPhi:
src/ir_print.cpp+11-2
...@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {...@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
201 if (call_instruction->is_async) {201 if (call_instruction->is_async) {
202 fprintf(irp->f, "async");202 fprintf(irp->f, "async");
203 if (call_instruction->async_allocator != nullptr) {203 if (call_instruction->async_allocator != nullptr) {
204 fprintf(irp->f, "(");204 fprintf(irp->f, "<");
205 ir_print_other_instruction(irp, call_instruction->async_allocator);205 ir_print_other_instruction(irp, call_instruction->async_allocator);
206 fprintf(irp->f, ")");206 fprintf(irp->f, ">");
207 }207 }
208 fprintf(irp->f, " ");208 fprintf(irp->f, " ");
209 }209 }
...@@ -1165,6 +1165,12 @@ static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr...@@ -1165,6 +1165,12 @@ static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr
1165 fprintf(irp->f, "@saveErrRetAddr()");1165 fprintf(irp->f, "@saveErrRetAddr()");
1166}1166}
11671167
1168static 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
1168static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1174static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1169 ir_print_prefix(irp, instruction);1175 ir_print_prefix(irp, instruction);
1170 switch (instruction->id) {1176 switch (instruction->id) {
...@@ -1539,6 +1545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1539,6 +1545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1539 case IrInstructionIdSaveErrRetAddr:1545 case IrInstructionIdSaveErrRetAddr:
1540 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);1546 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
1541 break;1547 break;
1548 case IrInstructionIdAddImplicitReturnType:
1549 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
1550 break;
1542 }1551 }
1543 fprintf(irp->f, "\n");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,3 +176,14 @@ async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
176 *y += 1;176 *y += 1;
177 suspend;177 suspend;
178}178}
179
180test "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
186async fn failing() !void {
187 suspend;
188 return error.Fail;
189}