authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-05 14:50:27-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-05 14:56:52-04:00
log2045b4d93240cd95eee7143f2cfc360eb63c5802
tree5ae5a1a453ecb8a82535b1be89822029606a9283
parent8f0df86937e140c11a1efc9f94c8ac0bd1b02e2c
signaturelock-open Commit is signed but in an unrecognized format.

prefer result type casting to peer type resolution

See #2749

4 files changed, 96 insertions(+), 15 deletions(-)

src/all_types.hpp+4
...@@ -47,6 +47,7 @@ struct ResultLoc;...@@ -47,6 +47,7 @@ struct ResultLoc;
47struct ResultLocPeer;47struct ResultLocPeer;
48struct ResultLocPeerParent;48struct ResultLocPeerParent;
49struct ResultLocBitCast;49struct ResultLocBitCast;
50struct ResultLocReturn;
5051
51enum PtrLen {52enum PtrLen {
52 PtrLenUnknown,53 PtrLenUnknown,
...@@ -3584,6 +3585,7 @@ struct IrInstructionAddImplicitReturnType {...@@ -3584,6 +3585,7 @@ struct IrInstructionAddImplicitReturnType {
3584 IrInstruction base;3585 IrInstruction base;
35853586
3586 IrInstruction *value;3587 IrInstruction *value;
3588 ResultLocReturn *result_loc_ret;
3587};3589};
35883590
3589// For float ops which take a single argument3591// For float ops which take a single argument
...@@ -3810,6 +3812,8 @@ struct ResultLocVar {...@@ -3810,6 +3812,8 @@ struct ResultLocVar {
38103812
3811struct ResultLocReturn {3813struct ResultLocReturn {
3812 ResultLoc base;3814 ResultLoc base;
3815
3816 bool implicit_return_type_done;
3813};3817};
38143818
3815struct IrSuspendPosition {3819struct IrSuspendPosition {
src/ir.cpp+62-15
...@@ -197,6 +197,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source...@@ -197,6 +197,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
197static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,197static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
198 IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,198 IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
199 LVal lval, ResultLoc *parent_result_loc);199 LVal lval, ResultLoc *parent_result_loc);
200static void ir_reset_result(ResultLoc *result_loc);
200201
201static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {202static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
202 assert(get_src_ptr_type(const_val->type) != nullptr);203 assert(get_src_ptr_type(const_val->type) != nullptr);
...@@ -3085,10 +3086,11 @@ static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, A...@@ -3085,10 +3086,11 @@ static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, A
3085}3086}
30863087
3087static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node,3088static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
3088 IrInstruction *value)3089 IrInstruction *value, ResultLocReturn *result_loc_ret)
3089{3090{
3090 IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node);3091 IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node);
3091 instruction->value = value;3092 instruction->value = value;
3093 instruction->result_loc_ret = result_loc_ret;
30923094
3093 ir_ref_instruction(value, irb->current_basic_block);3095 ir_ref_instruction(value, irb->current_basic_block);
30943096
...@@ -3505,7 +3507,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3505,7 +3507,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3505 return_value = ir_build_const_void(irb, scope, node);3507 return_value = ir_build_const_void(irb, scope, node);
3506 }3508 }
35073509
3508 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));3510 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value, result_loc_ret));
35093511
3510 size_t defer_counts[2];3512 size_t defer_counts[2];
3511 ir_count_defers(irb, scope, outer_scope, defer_counts);3513 ir_count_defers(irb, scope, outer_scope, defer_counts);
...@@ -3580,7 +3582,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3580,7 +3582,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3580 ir_set_cursor_at_end_and_append_block(irb, return_block);3582 ir_set_cursor_at_end_and_append_block(irb, return_block);
3581 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);3583 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3582 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);3584 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3583 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val));3585 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr));
3584 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,3586 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
3585 SpillIdRetErrCode);3587 SpillIdRetErrCode);
3586 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);3588 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
...@@ -3690,6 +3692,7 @@ static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {...@@ -3690,6 +3692,7 @@ static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
3690 result->base.id = ResultLocIdPeer;3692 result->base.id = ResultLocIdPeer;
3691 result->base.source_instruction = peer_parent->base.source_instruction;3693 result->base.source_instruction = peer_parent->base.source_instruction;
3692 result->parent = peer_parent;3694 result->parent = peer_parent;
3695 result->base.allow_write_through_const = peer_parent->parent->allow_write_through_const;
3693 return result;3696 return result;
3694}3697}
36953698
...@@ -3812,7 +3815,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3812,7 +3815,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3812 // no need for save_err_ret_addr because this cannot return error3815 // no need for save_err_ret_addr because this cannot return error
3813 // only generate unconditional defers3816 // only generate unconditional defers
38143817
3815 ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result));3818 ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result, nullptr));
3816 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);3819 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3817 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));3820 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
3818}3821}
...@@ -8207,7 +8210,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -8207,7 +8210,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
8207 }8210 }
82088211
8209 if (!instr_is_unreachable(result)) {8212 if (!instr_is_unreachable(result)) {
8210 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result));8213 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result, nullptr));
8211 // no need for save_err_ret_addr because this cannot return error8214 // no need for save_err_ret_addr because this cannot return error
8212 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));8215 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
8213 }8216 }
...@@ -12939,7 +12942,9 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze...@@ -12939,7 +12942,9 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze
12939 if (type_is_invalid(value->value.type))12942 if (type_is_invalid(value->value.type))
12940 return ir_unreach_error(ira);12943 return ir_unreach_error(ira);
1294112944
12942 ira->src_implicit_return_type_list.append(value);12945 if (instruction->result_loc_ret == nullptr || !instruction->result_loc_ret->implicit_return_type_done) {
12946 ira->src_implicit_return_type_list.append(value);
12947 }
1294312948
12944 return ir_const_void(ira, &instruction->base);12949 return ir_const_void(ira, &instruction->base);
12945}12950}
...@@ -14976,6 +14981,24 @@ static void set_up_result_loc_for_inferred_comptime(IrInstruction *ptr) {...@@ -14976,6 +14981,24 @@ static void set_up_result_loc_for_inferred_comptime(IrInstruction *ptr) {
14976 ptr->value.data.x_ptr.data.ref.pointee = undef_child;14981 ptr->value.data.x_ptr.data.ref.pointee = undef_child;
14977}14982}
1497814983
14984static bool ir_result_has_type(ResultLoc *result_loc) {
14985 switch (result_loc->id) {
14986 case ResultLocIdInvalid:
14987 case ResultLocIdPeerParent:
14988 zig_unreachable();
14989 case ResultLocIdNone:
14990 case ResultLocIdPeer:
14991 return false;
14992 case ResultLocIdReturn:
14993 case ResultLocIdInstruction:
14994 case ResultLocIdBitCast:
14995 return true;
14996 case ResultLocIdVar:
14997 return reinterpret_cast<ResultLocVar *>(result_loc)->var->decl_node->data.variable_declaration.type != nullptr;
14998 }
14999 zig_unreachable();
15000}
15001
14979// when calling this function, at the callsite must check for result type noreturn and propagate it up15002// when calling this function, at the callsite must check for result type noreturn and propagate it up
14980static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr,15003static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr,
14981 ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime)15004 ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime)
...@@ -15105,14 +15128,23 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe...@@ -15105,14 +15128,23 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
15105 bool is_comptime;15128 bool is_comptime;
15106 if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_comptime))15129 if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_comptime))
15107 return ira->codegen->invalid_instruction;15130 return ira->codegen->invalid_instruction;
15108 peer_parent->skipped = is_comptime;15131 if (is_comptime) {
15109 if (peer_parent->skipped) {15132 peer_parent->skipped = true;
15110 if (non_null_comptime) {15133 if (non_null_comptime) {
15111 return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,15134 return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
15112 value_type, value, force_runtime, non_null_comptime, true);15135 value_type, value, force_runtime, non_null_comptime, true);
15113 }15136 }
15114 return nullptr;15137 return nullptr;
15115 }15138 }
15139 if (ir_result_has_type(peer_parent->parent)) {
15140 if (peer_parent->parent->id == ResultLocIdReturn && value != nullptr) {
15141 reinterpret_cast<ResultLocReturn *>(peer_parent->parent)->implicit_return_type_done = true;
15142 ira->src_implicit_return_type_list.append(value);
15143 }
15144 peer_parent->skipped = true;
15145 return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
15146 value_type, value, force_runtime, true, true);
15147 }
1511615148
15117 if (peer_parent->resolved_type == nullptr) {15149 if (peer_parent->resolved_type == nullptr) {
15118 if (peer_parent->end_bb->suspend_instruction_ref == nullptr) {15150 if (peer_parent->end_bb->suspend_instruction_ref == nullptr) {
...@@ -15322,9 +15354,11 @@ static void ir_reset_result(ResultLoc *result_loc) {...@@ -15322,9 +15354,11 @@ static void ir_reset_result(ResultLoc *result_loc) {
15322 alloca_src->base.child = nullptr;15354 alloca_src->base.child = nullptr;
15323 break;15355 break;
15324 }15356 }
15357 case ResultLocIdReturn:
15358 reinterpret_cast<ResultLocReturn *>(result_loc)->implicit_return_type_done = false;
15359 break;
15325 case ResultLocIdPeer:15360 case ResultLocIdPeer:
15326 case ResultLocIdNone:15361 case ResultLocIdNone:
15327 case ResultLocIdReturn:
15328 case ResultLocIdInstruction:15362 case ResultLocIdInstruction:
15329 case ResultLocIdBitCast:15363 case ResultLocIdBitCast:
15330 break;15364 break;
...@@ -16880,10 +16914,21 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh...@@ -16880,10 +16914,21 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
16880 return new_incoming_values.at(0);16914 return new_incoming_values.at(0);
16881 }16915 }
1688216916
16883 ZigType *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, nullptr,16917 ZigType *resolved_type;
16884 new_incoming_values.items, new_incoming_values.length);16918 if (peer_parent != nullptr && ir_result_has_type(peer_parent->parent)) {
16885 if (type_is_invalid(resolved_type))16919 if (peer_parent->parent->id == ResultLocIdReturn) {
16886 return ira->codegen->invalid_instruction;16920 resolved_type = ira->explicit_return_type;
16921 } else {
16922 ZigType *resolved_loc_ptr_type = peer_parent->parent->resolved_loc->value.type;
16923 ir_assert(resolved_loc_ptr_type->id == ZigTypeIdPointer, &phi_instruction->base);
16924 resolved_type = resolved_loc_ptr_type->data.pointer.child_type;
16925 }
16926 } else {
16927 resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, nullptr,
16928 new_incoming_values.items, new_incoming_values.length);
16929 if (type_is_invalid(resolved_type))
16930 return ira->codegen->invalid_instruction;
16931 }
1688716932
16888 switch (type_has_one_possible_value(ira->codegen, resolved_type)) {16933 switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
16889 case OnePossibleValueInvalid:16934 case OnePossibleValueInvalid:
...@@ -25055,7 +25100,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct...@@ -25055,7 +25100,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
25055 if (result_loc->value.type->id == ZigTypeIdUnreachable)25100 if (result_loc->value.type->id == ZigTypeIdUnreachable)
25056 return result_loc;25101 return result_loc;
2505725102
25058 if (!was_written) {25103 if (!was_written || instruction->result_loc->id == ResultLocIdPeer) {
25059 IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value,25104 IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value,
25060 instruction->result_loc->allow_write_through_const);25105 instruction->result_loc->allow_write_through_const);
25061 if (type_is_invalid(store_ptr->value.type)) {25106 if (type_is_invalid(store_ptr->value.type)) {
...@@ -25063,7 +25108,9 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct...@@ -25063,7 +25108,9 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
25063 }25108 }
25064 }25109 }
2506525110
25066 if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {25111 if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer &&
25112 instruction->result_loc->id != ResultLocIdPeer)
25113 {
25067 if (instr_is_comptime(value)) {25114 if (instr_is_comptime(value)) {
25068 result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;25115 result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
25069 } else {25116 } else {
test/stage1/behavior/if.zig+12
...@@ -74,3 +74,15 @@ test "const result loc, runtime if cond, else unreachable" {...@@ -74,3 +74,15 @@ test "const result loc, runtime if cond, else unreachable" {
74 const x = if (t) Num.Two else unreachable;74 const x = if (t) Num.Two else unreachable;
75 if (x != .Two) @compileError("bad");75 if (x != .Two) @compileError("bad");
76}76}
77
78test "if prongs cast to expected type instead of peer type resolution" {
79 const S = struct {
80 fn doTheTest(f: bool) void {
81 var x: i32 = 0;
82 x = if (f) 1 else 2;
83 expect(x == 2);
84 }
85 };
86 S.doTheTest(false);
87 comptime S.doTheTest(false);
88}
test/stage1/behavior/struct.zig+18
...@@ -640,3 +640,21 @@ test "zero-bit field in packed struct" {...@@ -640,3 +640,21 @@ test "zero-bit field in packed struct" {
640 };640 };
641 var x: S = undefined;641 var x: S = undefined;
642}642}
643
644test "struct field init with catch" {
645 const S = struct {
646 fn doTheTest() void {
647 var x: anyerror!isize = 1;
648 var req = Foo{
649 .field = x catch undefined,
650 };
651 expect(req.field == 1);
652 }
653
654 pub const Foo = extern struct {
655 field: isize,
656 };
657 };
658 S.doTheTest();
659 comptime S.doTheTest();
660}