zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 88a5dc48733c5d2ce51acb7c6ad0d9f1cd9cbd5b (tree)
parent af9f80f2f7c4828b65fe075975fcd95982b1a7e3
Author: Motiejus <motiejus@jakstys.lt>
Date:   Sat,  7 Mar 2026 10:00:37 +0000

sema: port zirIsNonNull, zirIsNonErr handlers

Add handlers for ZIR instructions that check if optional/error union
values are non-null/non-error:
- ZIR_INST_IS_NON_NULL / IS_NON_NULL_PTR → AIR_INST_IS_NON_NULL
- ZIR_INST_IS_NON_ERR / IS_NON_ERR_PTR / RET_IS_NON_ERR → AIR_INST_IS_NON_ERR

zirIsNonNull also folds at comptime: opt_payload → true, null → false.

Add AIR_INST_IS_NON_NULL/PTR/ERR/ERR_PTR to semaTypeOf returning bool.

Ported from Sema.zig zirIsNonNull → analyzeIsNull(invert=true) and
zirIsNonErr.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
Mstage0/sema.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+), 0 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -576,6 +576,12 @@ static TypeIndex semaTypeOf(Sema* sema, AirInstRef ref) { case AIR_INST_MOD: case AIR_INST_REM: return semaTypeOf(sema, sema->air_inst_datas[inst_idx].bin_op.lhs); + // unary bool-result instructions. + case AIR_INST_IS_NON_NULL: + case AIR_INST_IS_NON_NULL_PTR: + case AIR_INST_IS_NON_ERR: + case AIR_INST_IS_NON_ERR_PTR: + return IP_INDEX_BOOL_TYPE; // cmp bin_op: result type is bool. case AIR_INST_CMP_LT: case AIR_INST_CMP_LTE: @@ -1218,6 +1224,45 @@ static AirInstRef zirBitNot(Sema* sema, SemaBlock* block, uint32_t inst) { return analyzeBitNot(sema, block, operand); } +// zirIsNonNull: handle is_non_null ZIR instruction. +// Ported from src/Sema.zig zirIsNonNull → analyzeIsNull(invert=true). +// Comptime: fold based on opt_payload vs null. +// Runtime: emit AIR_INST_IS_NON_NULL. +static AirInstRef zirIsNonNull(Sema* sema, SemaBlock* block, uint32_t inst) { + ZirInstRef operand_ref = sema->code.inst_datas[inst].un_node.operand; + AirInstRef operand = resolveInst(sema, operand_ref); + // Comptime fold: check if operand is a known optional value. + if (AIR_REF_IS_IP(operand)) { + InternPoolIndex op_ip = AIR_REF_TO_IP(operand); + if (op_ip < sema->ip->items_len) { + InternPoolKey key = sema->ip->items[op_ip]; + // opt_payload = non-null → true + if (key.tag == IP_KEY_OPT_PAYLOAD) + return AIR_REF_FROM_IP(IP_INDEX_BOOL_TRUE); + // null value → false (opt_null is not an IP_KEY type, but + // null literal is IP_INDEX_NULL_VALUE) + if (op_ip == IP_INDEX_NULL_VALUE) + return AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE); + } + } + AirInstData data; + memset(&data, 0, sizeof(data)); + data.un_op.operand = operand; + return semaAddInst(block, AIR_INST_IS_NON_NULL, data); +} + +// zirIsNonErr: handle is_non_err ZIR instruction. +// Ported from src/Sema.zig zirIsNonErr → analyzeIsErr(invert=true). +// Runtime: emit AIR_INST_IS_NON_ERR. +static AirInstRef zirIsNonErr(Sema* sema, SemaBlock* block, uint32_t inst) { + ZirInstRef operand_ref = sema->code.inst_datas[inst].un_node.operand; + AirInstRef operand = resolveInst(sema, operand_ref); + AirInstData data; + memset(&data, 0, sizeof(data)); + data.un_op.operand = operand; + return semaAddInst(block, AIR_INST_IS_NON_ERR, data); +} + // zirBoolNot: handle bool_not ZIR instruction. // Ported from src/Sema.zig zirBoolNot. static AirInstRef zirBoolNot(Sema* sema, SemaBlock* block, uint32_t inst) { @@ -12380,6 +12425,17 @@ bool analyzeBodyInner( instMapPut(&sema->inst_map, inst, zirBoolNot(sema, block, inst)); i++; continue; + case ZIR_INST_IS_NON_NULL: + case ZIR_INST_IS_NON_NULL_PTR: + instMapPut(&sema->inst_map, inst, zirIsNonNull(sema, block, inst)); + i++; + continue; + case ZIR_INST_IS_NON_ERR: + case ZIR_INST_IS_NON_ERR_PTR: + case ZIR_INST_RET_IS_NON_ERR: + instMapPut(&sema->inst_map, inst, zirIsNonErr(sema, block, inst)); + i++; + continue; case ZIR_INST_INT_FROM_BOOL: instMapPut( &sema->inst_map, inst, zirIntFromBool(sema, block, inst));