authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-09-15 13:43:22+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-28 02:24:59+00:00
log05b445a276536f6d62c20786d816f9f6444d20d8
treeb68085bc0ea55e0816018a70c726ba1a0aa5c663
parente9f3d18b57d973b795354dab8541ea2c4277d022

Sema: add missing coercion to bool for condbr_inline

Also, start using labeled switch statements when dispatching maybe-runtime instructions like condbr to comptime-only variants like condbr_inline. This can't be merged until we get a zig1.wasm update due to #21385. Resolves: #21405

2 files changed, 33 insertions(+), 92 deletions(-)

src/Sema.zig+27-91
...@@ -1043,7 +1043,7 @@ fn analyzeBodyInner(...@@ -1043,7 +1043,7 @@ fn analyzeBodyInner(
1043 }, inst });1043 }, inst });
1044 }1044 }
10451045
1046 const air_inst: Air.Inst.Ref = switch (tags[@intFromEnum(inst)]) {1046 const air_inst: Air.Inst.Ref = inst: switch (tags[@intFromEnum(inst)]) {
1047 // zig fmt: off1047 // zig fmt: off
1048 .alloc => try sema.zirAlloc(block, inst),1048 .alloc => try sema.zirAlloc(block, inst),
1049 .alloc_inferred => try sema.zirAllocInferred(block, true),1049 .alloc_inferred => try sema.zirAllocInferred(block, true),
...@@ -1591,56 +1591,19 @@ fn analyzeBodyInner(...@@ -1591,56 +1591,19 @@ fn analyzeBodyInner(
1591 try sema.zirSwitchContinue(block, inst);1591 try sema.zirSwitchContinue(block, inst);
1592 break;1592 break;
1593 },1593 },
1594 .loop => blk: {
1595 if (!block.is_comptime) break :blk try sema.zirLoop(block, inst);
1596 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220
1597 const inst_data = datas[@intFromEnum(inst)].pl_node;
1598 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
1599 const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
16001594
1601 // Create a temporary child block so that this loop is properly1595 .loop => if (block.is_comptime) {
1602 // labeled for any .restore_err_ret_index instructions1596 continue :inst .block_inline;
1603 var child_block = block.makeSubBlock();1597 } else try sema.zirLoop(block, inst),
16041598
1605 var label: Block.Label = .{1599 .block => if (block.is_comptime) {
1606 .zir_block = inst,1600 continue :inst .block_inline;
1607 .merges = undefined,1601 } else try sema.zirBlock(block, inst, false),
1608 };
1609 child_block.label = &label;
1610
1611 // Write these instructions directly into the parent block
1612 child_block.instructions = block.instructions;
1613 defer block.instructions = child_block.instructions;
1614
1615 const result = try sema.analyzeInlineBody(&child_block, inline_body, inst) orelse break;
1616 break :blk result;
1617 },
1618 .block, .block_comptime => blk: {
1619 if (!block.is_comptime) {
1620 break :blk try sema.zirBlock(block, inst, tags[@intFromEnum(inst)] == .block_comptime);
1621 }
1622 // Same as `block_inline`. TODO https://github.com/ziglang/zig/issues/8220
1623 const inst_data = datas[@intFromEnum(inst)].pl_node;
1624 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
1625 const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
16261602
1627 // Create a temporary child block so that this block is properly1603 .block_comptime => if (block.is_comptime) {
1628 // labeled for any .restore_err_ret_index instructions1604 continue :inst .block_inline;
1629 var child_block = block.makeSubBlock();1605 } else try sema.zirBlock(block, inst, true),
16301606
1631 var label: Block.Label = .{
1632 .zir_block = inst,
1633 .merges = undefined,
1634 };
1635 child_block.label = &label;
1636
1637 // Write these instructions directly into the parent block
1638 child_block.instructions = block.instructions;
1639 defer block.instructions = child_block.instructions;
1640
1641 const result = try sema.analyzeInlineBody(&child_block, inline_body, inst) orelse break;
1642 break :blk result;
1643 },
1644 .block_inline => blk: {1607 .block_inline => blk: {
1645 // Directly analyze the block body without introducing a new block.1608 // Directly analyze the block body without introducing a new block.
1646 // However, in the case of a corresponding break_inline which reaches1609 // However, in the case of a corresponding break_inline which reaches
...@@ -1749,32 +1712,13 @@ fn analyzeBodyInner(...@@ -1749,32 +1712,13 @@ fn analyzeBodyInner(
1749 return error.ComptimeBreak;1712 return error.ComptimeBreak;
1750 }1713 }
1751 },1714 },
1752 .condbr => blk: {1715 .condbr => if (block.is_comptime) {
1753 if (!block.is_comptime) {1716 continue :inst .condbr_inline;
1754 try sema.zirCondbr(block, inst);1717 } else {
1755 break;1718 try sema.zirCondbr(block, inst);
1756 }1719 break;
1757 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
1758 const inst_data = datas[@intFromEnum(inst)].pl_node;
1759 const cond_src = block.src(.{ .node_offset_if_cond = inst_data.src_node });
1760 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
1761 const then_body = sema.code.bodySlice(extra.end, extra.data.then_body_len);
1762 const else_body = sema.code.bodySlice(
1763 extra.end + then_body.len,
1764 extra.data.else_body_len,
1765 );
1766 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, .{
1767 .needed_comptime_reason = "condition in comptime branch must be comptime-known",
1768 .block_comptime_reason = block.comptime_reason,
1769 });
1770 const inline_body = if (cond.toBool()) then_body else else_body;
1771
1772 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
1773
1774 const result = try sema.analyzeInlineBody(block, inline_body, inst) orelse break;
1775 break :blk result;
1776 },1720 },
1777 .condbr_inline => blk: {1721 .condbr_inline => {
1778 const inst_data = datas[@intFromEnum(inst)].pl_node;1722 const inst_data = datas[@intFromEnum(inst)].pl_node;
1779 const cond_src = block.src(.{ .node_offset_if_cond = inst_data.src_node });1723 const cond_src = block.src(.{ .node_offset_if_cond = inst_data.src_node });
1780 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);1724 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
...@@ -1783,18 +1727,20 @@ fn analyzeBodyInner(...@@ -1783,18 +1727,20 @@ fn analyzeBodyInner(
1783 extra.end + then_body.len,1727 extra.end + then_body.len,
1784 extra.data.else_body_len,1728 extra.data.else_body_len,
1785 );1729 );
1786 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, .{1730 const uncasted_cond = try sema.resolveInst(extra.data.condition);
1731 const cond = try sema.coerce(block, Type.bool, uncasted_cond, cond_src);
1732 const cond_val = try sema.resolveConstDefinedValue(block, cond_src, cond, .{
1787 .needed_comptime_reason = "condition in comptime branch must be comptime-known",1733 .needed_comptime_reason = "condition in comptime branch must be comptime-known",
1788 .block_comptime_reason = block.comptime_reason,1734 .block_comptime_reason = block.comptime_reason,
1789 });1735 });
1790 const inline_body = if (cond.toBool()) then_body else else_body;1736 const inline_body = if (cond_val.toBool()) then_body else else_body;
17911737
1792 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);1738 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
1793 const old_runtime_index = block.runtime_index;1739 const old_runtime_index = block.runtime_index;
1794 defer block.runtime_index = old_runtime_index;1740 defer block.runtime_index = old_runtime_index;
17951741
1796 const result = try sema.analyzeInlineBody(block, inline_body, inst) orelse break;1742 const result = try sema.analyzeInlineBody(block, inline_body, inst) orelse break;
1797 break :blk result;1743 break :inst result;
1798 },1744 },
1799 .@"try" => blk: {1745 .@"try" => blk: {
1800 if (!block.is_comptime) break :blk try sema.zirTry(block, inst);1746 if (!block.is_comptime) break :blk try sema.zirTry(block, inst);
...@@ -2251,18 +2197,6 @@ fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Val...@@ -2251,18 +2197,6 @@ fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Val
2251 return val;2197 return val;
2252}2198}
22532199
2254/// Returns a compile error if the value has tag `variable`.
2255fn resolveInstConst(
2256 sema: *Sema,
2257 block: *Block,
2258 src: LazySrcLoc,
2259 zir_ref: Zir.Inst.Ref,
2260 reason: NeededComptimeReason,
2261) CompileError!Value {
2262 const air_ref = try sema.resolveInst(zir_ref);
2263 return sema.resolveConstDefinedValue(block, src, air_ref, reason);
2264}
2265
2266/// Value Tag may be `undef` or `variable`.2200/// Value Tag may be `undef` or `variable`.
2267pub fn resolveFinalDeclValue(2201pub fn resolveFinalDeclValue(
2268 sema: *Sema,2202 sema: *Sema,
...@@ -26824,12 +26758,14 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -26824,12 +26758,14 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
26824 } else if (extra.data.bits.has_ret_ty_ref) blk: {26758 } else if (extra.data.bits.has_ret_ty_ref) blk: {
26825 const ret_ty_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);26759 const ret_ty_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
26826 extra_index += 1;26760 extra_index += 1;
26827 const ret_ty_val = sema.resolveInstConst(block, ret_src, ret_ty_ref, .{26761 const ret_ty_air_ref = sema.resolveInst(ret_ty_ref) catch |err| switch (err) {
26762 error.GenericPoison => break :blk Type.generic_poison,
26763 else => |e| return e,
26764 };
26765 const ret_ty_val = sema.resolveConstDefinedValue(block, ret_src, ret_ty_air_ref, .{
26828 .needed_comptime_reason = "return type must be comptime-known",26766 .needed_comptime_reason = "return type must be comptime-known",
26829 }) catch |err| switch (err) {26767 }) catch |err| switch (err) {
26830 error.GenericPoison => {26768 error.GenericPoison => break :blk Type.generic_poison,
26831 break :blk Type.generic_poison;
26832 },
26833 else => |e| return e,26769 else => |e| return e,
26834 };26770 };
26835 break :blk ret_ty_val.toType();26771 break :blk ret_ty_val.toType();
test/cases/compile_errors/if_condition_is_bool_not_int.zig+6-1
...@@ -1,9 +1,14 @@...@@ -1,9 +1,14 @@
1export fn f() void {1export fn foo() void {
2 if (0) {}2 if (0) {}
3}3}
44
5export fn bar() void {
6 comptime if (0) {};
7}
8
5// error9// error
6// backend=stage210// backend=stage2
7// target=native11// target=native
8//12//
9// :2:9: error: expected type 'bool', found 'comptime_int'13// :2:9: error: expected type 'bool', found 'comptime_int'
14// :6:18: error: expected type 'bool', found 'comptime_int'