authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-02-06 22:11:41+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-06 21:26:26-05:00
logfd1284ebd07ded1c67bbaff4c14f093051e56f59
tree3ceb66a3288aae5aa8495ff00e7af89c9561f134
parentadc9a282d8b3cbe58e07c965fe40fb1dd8666bd7

stage2: apply type coercion in if expressions

When setting the break value in an if expression we must explicitly check if a result location type coercion that needs to happen. This was already done for switch expression, so let's just imitate that check and fix for if expressions. To make this possible, we now also propagate `rl_ty_inst` to sub scopes.

2 files changed, 40 insertions(+), 8 deletions(-)

src/AstGen.zig+34-8
...@@ -5118,8 +5118,10 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5118,8 +5118,10 @@ fn setCondBrPayloadElideBlockStorePtr(
5118 const astgen = then_scope.astgen;5118 const astgen = then_scope.astgen;
5119 const then_body = then_scope.instructionsSliceUpto(else_scope);5119 const then_body = then_scope.instructionsSliceUpto(else_scope);
5120 const else_body = else_scope.instructionsSlice();5120 const else_body = else_scope.instructionsSlice();
5121 const then_body_len = @intCast(u32, then_body.len + @boolToInt(then_break != 0));5121 const has_then_break = then_break != 0;
5122 const else_body_len = @intCast(u32, else_body.len + @boolToInt(else_break != 0));5122 const has_else_break = else_break != 0;
5123 const then_body_len = @intCast(u32, then_body.len + @boolToInt(has_then_break));
5124 const else_body_len = @intCast(u32, else_body.len + @boolToInt(has_else_break));
5123 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +5125 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
5124 then_body_len + else_body_len);5126 then_body_len + else_body_len);
51255127
...@@ -5135,26 +5137,49 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5135,26 +5137,49 @@ fn setCondBrPayloadElideBlockStorePtr(
5135 const then_body_len_index = condbr_pl + 1;5137 const then_body_len_index = condbr_pl + 1;
5136 const else_body_len_index = condbr_pl + 2;5138 const else_body_len_index = condbr_pl + 2;
51375139
5140 // The break instructions need to have their operands coerced if the
5141 // switch's result location is a `ty`. In this case we overwrite the
5142 // `store_to_block_ptr` instruction with an `as` instruction and repurpose
5143 // it as the break operand.
5138 for (then_body) |src_inst| {5144 for (then_body) |src_inst| {
5139 if (zir_tags[src_inst] == .store_to_block_ptr) {5145 if (zir_tags[src_inst] == .store_to_block_ptr and
5140 if (zir_datas[src_inst].bin.lhs == block_ptr) {5146 zir_datas[src_inst].bin.lhs == block_ptr)
5147 {
5148 if (then_scope.rl_ty_inst != .none and has_then_break) {
5149 zir_tags[src_inst] = .as;
5150 zir_datas[src_inst].bin = .{
5151 .lhs = then_scope.rl_ty_inst,
5152 .rhs = zir_datas[then_break].@"break".operand,
5153 };
5154 zir_datas[then_break].@"break".operand = indexToRef(src_inst);
5155 } else {
5141 astgen.extra.items[then_body_len_index] -= 1;5156 astgen.extra.items[then_body_len_index] -= 1;
5142 continue;5157 continue;
5143 }5158 }
5144 }5159 }
5145 astgen.extra.appendAssumeCapacity(src_inst);5160 astgen.extra.appendAssumeCapacity(src_inst);
5146 }5161 }
5147 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break);5162 if (has_then_break) astgen.extra.appendAssumeCapacity(then_break);
5163
5148 for (else_body) |src_inst| {5164 for (else_body) |src_inst| {
5149 if (zir_tags[src_inst] == .store_to_block_ptr) {5165 if (zir_tags[src_inst] == .store_to_block_ptr and
5150 if (zir_datas[src_inst].bin.lhs == block_ptr) {5166 zir_datas[src_inst].bin.lhs == block_ptr)
5167 {
5168 if (else_scope.rl_ty_inst != .none and has_else_break) {
5169 zir_tags[src_inst] = .as;
5170 zir_datas[src_inst].bin = .{
5171 .lhs = else_scope.rl_ty_inst,
5172 .rhs = zir_datas[else_break].@"break".operand,
5173 };
5174 zir_datas[else_break].@"break".operand = indexToRef(src_inst);
5175 } else {
5151 astgen.extra.items[else_body_len_index] -= 1;5176 astgen.extra.items[else_body_len_index] -= 1;
5152 continue;5177 continue;
5153 }5178 }
5154 }5179 }
5155 astgen.extra.appendAssumeCapacity(src_inst);5180 astgen.extra.appendAssumeCapacity(src_inst);
5156 }5181 }
5157 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break);5182 if (has_else_break) astgen.extra.appendAssumeCapacity(else_break);
5158}5183}
51595184
5160fn whileExpr(5185fn whileExpr(
...@@ -9460,6 +9485,7 @@ const GenZir = struct {...@@ -9460,6 +9485,7 @@ const GenZir = struct {
9460 .decl_node_index = gz.decl_node_index,9485 .decl_node_index = gz.decl_node_index,
9461 .decl_line = gz.decl_line,9486 .decl_line = gz.decl_line,
9462 .parent = scope,9487 .parent = scope,
9488 .rl_ty_inst = gz.rl_ty_inst,
9463 .astgen = gz.astgen,9489 .astgen = gz.astgen,
9464 .suspend_node = gz.suspend_node,9490 .suspend_node = gz.suspend_node,
9465 .nosuspend_node = gz.nosuspend_node,9491 .nosuspend_node = gz.nosuspend_node,
test/behavior/basic.zig+6
...@@ -693,3 +693,9 @@ test "variable name containing underscores does not shadow int primitive" {...@@ -693,3 +693,9 @@ test "variable name containing underscores does not shadow int primitive" {
693 _ = u6__4;693 _ = u6__4;
694 _ = i2_04_8;694 _ = i2_04_8;
695}695}
696
697test "if expression type coercion" {
698 var cond: bool = true;
699 const x: u16 = if (cond) 1 else 0;
700 try expect(@as(u16, x) == 1);
701}