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 {
12511251 ScopeBlock *def_scope; // parent is child_scope
12521252 Buf symbol_name;
12531253 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;
12551258 bool is_test;
12561259 FnInline fn_inline;
12571260 FnAnalState anal_state;
......@@ -2035,6 +2038,7 @@ enum IrInstructionId {
20352038 IrInstructionIdPromiseResultType,
20362039 IrInstructionIdAwaitBookkeeping,
20372040 IrInstructionIdSaveErrRetAddr,
2041 IrInstructionIdAddImplicitReturnType,
20382042};
20392043
20402044struct IrInstruction {
......@@ -2993,6 +2997,12 @@ struct IrInstructionSaveErrRetAddr {
29932997 IrInstruction base;
29942998};
29952999
3000struct IrInstructionAddImplicitReturnType {
3001 IrInstruction base;
3002
3003 IrInstruction *value;
3004};
3005
29963006static const size_t slice_ptr_index = 0;
29973007static 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
38653865
38663866 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
38673867 &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
38703870 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
38713871 assert(g->errors.length > 0);
......@@ -3877,10 +3877,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38773877 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
38783878 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
38793879 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;
38843884 } else {
38853885 add_node_error(g, return_type_node,
38863886 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) {
658658 if (node->data.fn_call_expr.is_builtin) {
659659 fprintf(ar->f, "@");
660660 }
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 }
661670 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
662671 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);
663672 render_node_extra(ar, fn_ref_node, grouped);
......@@ -1023,7 +1032,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
10231032 case NodeTypeUnwrapErrorExpr:
10241033 {
10251034 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
1026 fprintf(ar->f, " %%%% ");
1035 fprintf(ar->f, " catch ");
10271036 if (node->data.unwrap_err_expr.symbol) {
10281037 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
10291038 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,
42454245 case IrInstructionIdErrorUnion:
42464246 case IrInstructionIdPromiseResultType:
42474247 case IrInstructionIdAwaitBookkeeping:
4248 case IrInstructionIdAddImplicitReturnType:
42484249 zig_unreachable();
42494250
42504251 case IrInstructionIdReturn:
src/ir.cpp+40-5
......@@ -34,7 +34,7 @@ struct IrAnalyze {
3434 size_t old_bb_index;
3535 size_t instruction_index;
3636 TypeTableEntry *explicit_return_type;
37 ZigList<IrInstruction *> implicit_return_type_list;
37 ZigList<IrInstruction *> src_implicit_return_type_list;
3838 IrBasicBlock *const_predecessor_bb;
3939};
4040
......@@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *
717717 return IrInstructionIdSaveErrRetAddr;
718718}
719719
720static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) {
721 return IrInstructionIdAddImplicitReturnType;
722}
723
720724template<typename T>
721725static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
722726 T *special_instruction = allocate<T>(1);
......@@ -2687,6 +2691,17 @@ static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, A
26872691 return &instruction->base;
26882692}
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
26902705static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
26912706 results[ReturnKindUnconditional] = 0;
26922707 results[ReturnKindError] = 0;
......@@ -2767,6 +2782,8 @@ static bool exec_is_async(IrExecutable *exec) {
27672782static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
27682783 bool is_generated_code)
27692784{
2785 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
2786
27702787 bool is_async = exec_is_async(irb->exec);
27712788 if (!is_async) {
27722789 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
63996416 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
64006417
64016418 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.
64026421 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
64036422 ir_build_return(irb, scope, node, undef);
64046423
......@@ -10108,13 +10127,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
1010810127 return result;
1010910128}
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
1011110144static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
1011210145 IrInstructionReturn *return_instruction)
1011310146{
1011410147 IrInstruction *value = return_instruction->value->other;
1011510148 if (type_is_invalid(value->value.type))
1011610149 return ir_unreach_error(ira);
10117 ira->implicit_return_type_list.append(value);
1011810150
1011910151 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
1012010152 if (casted_value == ira->codegen->invalid_instruction)
......@@ -18049,6 +18081,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1804918081 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
1805018082 case IrInstructionIdSaveErrRetAddr:
1805118083 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);
1805218086 }
1805318087 zig_unreachable();
1805418088}
......@@ -18122,11 +18156,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1812218156
1812318157 if (new_exec->invalid) {
1812418158 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) {
1812618160 return codegen->builtin_types.entry_unreachable;
1812718161 } 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);
1813018164 }
1813118165}
1813218166
......@@ -18175,6 +18209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1817518209 case IrInstructionIdCoroAllocHelper:
1817618210 case IrInstructionIdAwaitBookkeeping:
1817718211 case IrInstructionIdSaveErrRetAddr:
18212 case IrInstructionIdAddImplicitReturnType:
1817818213 return true;
1817918214
1818018215 case IrInstructionIdPhi:
src/ir_print.cpp+11-2
......@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
201201 if (call_instruction->is_async) {
202202 fprintf(irp->f, "async");
203203 if (call_instruction->async_allocator != nullptr) {
204 fprintf(irp->f, "(");
204 fprintf(irp->f, "<");
205205 ir_print_other_instruction(irp, call_instruction->async_allocator);
206 fprintf(irp->f, ")");
206 fprintf(irp->f, ">");
207207 }
208208 fprintf(irp->f, " ");
209209 }
......@@ -1165,6 +1165,12 @@ static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr
11651165 fprintf(irp->f, "@saveErrRetAddr()");
11661166}
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
11681174static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11691175 ir_print_prefix(irp, instruction);
11701176 switch (instruction->id) {
......@@ -1539,6 +1545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15391545 case IrInstructionIdSaveErrRetAddr:
15401546 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
15411547 break;
1548 case IrInstructionIdAddImplicitReturnType:
1549 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
1550 break;
15421551 }
15431552 fprintf(irp->f, "\n");
15441553}
test/cases/coroutines.zig+11
......@@ -176,3 +176,14 @@ async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
176176 *y += 1;
177177 suspend;
178178}
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}