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;
4747struct ResultLocPeer;
4848struct ResultLocPeerParent;
4949struct ResultLocBitCast;
50struct ResultLocReturn;
5051
5152enum PtrLen {
5253 PtrLenUnknown,
......@@ -3584,6 +3585,7 @@ struct IrInstructionAddImplicitReturnType {
35843585 IrInstruction base;
35853586
35863587 IrInstruction *value;
3588 ResultLocReturn *result_loc_ret;
35873589};
35883590
35893591// For float ops which take a single argument
......@@ -3810,6 +3812,8 @@ struct ResultLocVar {
38103812
38113813struct ResultLocReturn {
38123814 ResultLoc base;
3815
3816 bool implicit_return_type_done;
38133817};
38143818
38153819struct IrSuspendPosition {
src/ir.cpp+62-15
......@@ -197,6 +197,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
197197static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
198198 IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
199199 LVal lval, ResultLoc *parent_result_loc);
200static void ir_reset_result(ResultLoc *result_loc);
200201
201202static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
202203 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
30853086}
30863087
30873088static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
3088 IrInstruction *value)
3089 IrInstruction *value, ResultLocReturn *result_loc_ret)
30893090{
30903091 IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node);
30913092 instruction->value = value;
3093 instruction->result_loc_ret = result_loc_ret;
30923094
30933095 ir_ref_instruction(value, irb->current_basic_block);
30943096
......@@ -3505,7 +3507,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
35053507 return_value = ir_build_const_void(irb, scope, node);
35063508 }
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
35103512 size_t defer_counts[2];
35113513 ir_count_defers(irb, scope, outer_scope, defer_counts);
......@@ -3580,7 +3582,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
35803582 ir_set_cursor_at_end_and_append_block(irb, return_block);
35813583 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
35823584 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));
35843586 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
35853587 SpillIdRetErrCode);
35863588 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
......@@ -3690,6 +3692,7 @@ static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
36903692 result->base.id = ResultLocIdPeer;
36913693 result->base.source_instruction = peer_parent->base.source_instruction;
36923694 result->parent = peer_parent;
3695 result->base.allow_write_through_const = peer_parent->parent->allow_write_through_const;
36933696 return result;
36943697}
36953698
......@@ -3812,7 +3815,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
38123815 // no need for save_err_ret_addr because this cannot return error
38133816 // 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));
38163819 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
38173820 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
38183821}
......@@ -8207,7 +8210,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
82078210 }
82088211
82098212 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));
82118214 // no need for save_err_ret_addr because this cannot return error
82128215 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
82138216 }
......@@ -12939,7 +12942,9 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze
1293912942 if (type_is_invalid(value->value.type))
1294012943 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
1294412949 return ir_const_void(ira, &instruction->base);
1294512950}
......@@ -14976,6 +14981,24 @@ static void set_up_result_loc_for_inferred_comptime(IrInstruction *ptr) {
1497614981 ptr->value.data.x_ptr.data.ref.pointee = undef_child;
1497714982}
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
1497915002// when calling this function, at the callsite must check for result type noreturn and propagate it up
1498015003static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr,
1498115004 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
1510515128 bool is_comptime;
1510615129 if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_comptime))
1510715130 return ira->codegen->invalid_instruction;
15108 peer_parent->skipped = is_comptime;
15109 if (peer_parent->skipped) {
15131 if (is_comptime) {
15132 peer_parent->skipped = true;
1511015133 if (non_null_comptime) {
1511115134 return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
1511215135 value_type, value, force_runtime, non_null_comptime, true);
1511315136 }
1511415137 return nullptr;
1511515138 }
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
1511715149 if (peer_parent->resolved_type == nullptr) {
1511815150 if (peer_parent->end_bb->suspend_instruction_ref == nullptr) {
......@@ -15322,9 +15354,11 @@ static void ir_reset_result(ResultLoc *result_loc) {
1532215354 alloca_src->base.child = nullptr;
1532315355 break;
1532415356 }
15357 case ResultLocIdReturn:
15358 reinterpret_cast<ResultLocReturn *>(result_loc)->implicit_return_type_done = false;
15359 break;
1532515360 case ResultLocIdPeer:
1532615361 case ResultLocIdNone:
15327 case ResultLocIdReturn:
1532815362 case ResultLocIdInstruction:
1532915363 case ResultLocIdBitCast:
1533015364 break;
......@@ -16880,10 +16914,21 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
1688016914 return new_incoming_values.at(0);
1688116915 }
1688216916
16883 ZigType *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, nullptr,
16884 new_incoming_values.items, new_incoming_values.length);
16885 if (type_is_invalid(resolved_type))
16886 return ira->codegen->invalid_instruction;
16917 ZigType *resolved_type;
16918 if (peer_parent != nullptr && ir_result_has_type(peer_parent->parent)) {
16919 if (peer_parent->parent->id == ResultLocIdReturn) {
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
1688816933 switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
1688916934 case OnePossibleValueInvalid:
......@@ -25055,7 +25100,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
2505525100 if (result_loc->value.type->id == ZigTypeIdUnreachable)
2505625101 return result_loc;
2505725102
25058 if (!was_written) {
25103 if (!was_written || instruction->result_loc->id == ResultLocIdPeer) {
2505925104 IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value,
2506025105 instruction->result_loc->allow_write_through_const);
2506125106 if (type_is_invalid(store_ptr->value.type)) {
......@@ -25063,7 +25108,9 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
2506325108 }
2506425109 }
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 {
2506725114 if (instr_is_comptime(value)) {
2506825115 result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
2506925116 } else {
test/stage1/behavior/if.zig+12
......@@ -74,3 +74,15 @@ test "const result loc, runtime if cond, else unreachable" {
7474 const x = if (t) Num.Two else unreachable;
7575 if (x != .Two) @compileError("bad");
7676}
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" {
640640 };
641641 var x: S = undefined;
642642}
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}