- Extend ret_ty_body pre-resolution from >2 to >1 instructions,
removing the special-case 2-inst handler in analyzeFuncBodyAndRecord.
All multi-instruction return type bodies now use analyzeBodyInner.
- Generalize builtin_value handler with name table for all 12 types.
- Port zirDeclLiteralComptime for resolving decl_literal ZIR.
Namespace/nav resolution for builtin types is UNIMPLEMENTED.
- Remove hardcoded strcmp dispatch in resolveCgBuiltinField — CG
builtin fields are resolved via normal ZIR evaluation path.
- Add param→arg bindings to inst_map BEFORE analyzing ret_ty body
in semaAnalyzeCall, so @TypeOf(a) etc. can resolve param references
(ported from Sema.zig:7393).
- Replace all silent VOID_VALUE returns for compile-error paths
with SEMA_FAIL macro; replace unimplemented paths with UNIMPLEMENTED.
- Add export_fn_bitcast and xor_const sema tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add zirPtrType handler for comptime blocks using resolveInst-based
element type resolution (unlike resolveZirPtrTypeInst which uses ZIR).
Add optional_type handler for comptime blocks.
Generalize builtin_value handler with name table mapping all 12 type
kinds, and call ensureNavValUpToDate for unresolved navs.
Fix resolveStructFieldInitsC to skip pre-interned default values
(void, true, false, etc.) instead of crashing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port resolveCgBuiltinField handlers for all CG builtin fields accessed
during start.zig comptime evaluation: output_mode, mode, unwind_tables,
wasi_exec_model, code_model, abi, and boolean fields (link_libc,
link_libcpp, single_threaded, strip_debug_info, etc.).
Port zirHasDecl (@hasDecl builtin) which resolves the container type's
namespace and looks up the decl name from the ZIR STR instruction.
Fix comptimeFieldCall arg body resolution, std_file_idx ordering,
nav name string table lookup, and resolveEnumFieldInBuiltin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive audit found 32 silent passthroughs where unimplemented code
paths returned default values (VOID_TYPE, VOID_VALUE, TYPE_NONE, 0, etc.)
instead of crashing. Every one now calls UNIMPLEMENTED() so failures are
caught immediately rather than propagating corrupt state.
Key changes:
- semaTypeOf: crash on unhandled AIR tags instead of returning TYPE_NONE
- semaCoerce/resolvePeerTypes: crash on unhandled type combinations
- ptrChildType: crash on non-pointer types
- resolveZirTypeInst/resolveZirRefValue: crash on unhandled ZIR tags
- resolveEnumDeclFromZir: crash on unresolvable field values
- resolveStructFieldTypesC/InitsC: crash on capacity limits (>64/>32 fields)
- registerStructTypeFromZir: crash on >4 fields, inst-ref types, overflow
- resolveUnionFullyC: crash on >256 fields, tag enum overflow
- semaAnalyzeCall: crash on call/deferred body table overflow (>16)
- analyzeFuncBodyAndRecord: crash on non-C calling conventions,
unhandled 2-inst ret type
- semaResolveSwitchComptime: crash when no case matches and no else
- zirBitSizeOf: crash on unrecognized types (arrays, structs, etc.)
- evalCrossModuleDeclValue: crash on body-completed-without-break
- ZIR_INST_STR: crash on strings >= 256 bytes
- zirEnumFromInt: crash on runtime dest type
- zirTypeofLog2IntType: crash on non-integer operand
- isComparableType: crash on ordering comparison (eq_only=false)
- getParamBody: crash on unexpected ZIR tag
- resolveZirPtrTypeInst: crash on align/addrspace/bit_range
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all 42 SET_ERROR/has_compile_errors patterns with UNIMPLEMENTED(),
which calls fprintf+exit(1) and uses while(1) to satisfy TCC's control-flow
analysis (TCC does not recognize exit() as noreturn).
Remove both bail-out checks on has_compile_errors. Since zig0 only processes
valid, compiling Zig code, any previously-silent error path is a bug in the
C implementation and should crash immediately rather than propagate corrupt
state.
Add UNIMPLEMENTED to 9 silent void returns identified as unimplemented paths:
zirBitcast, zirAsNode, semaAnalyzeCall (x2), @This fallback, zirRetType,
zirElemType, zirRef, zirOptionalPayload.
num_passing stays at 0 until zirFieldValComptime is implemented for the
builtin zig_backend field, which every corpus file exercises.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of returning void values for unimplemented code paths (which
hides bugs), crash immediately with file/line info. This is simpler
than SET_ERROR + has_compile_errors propagation and makes missing
functionality immediately visible.
num_passing reduced to 0: zirFieldValComptime crashes on builtin
module's zig_backend field, which is hit by every corpus file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- zirShl SHR_EXACT: extend exact shift overflow check to also cover
SHR_EXACT (shift right must not lose non-zero bits)
(Sema.zig zirShr exact validation)
- zirBlockComptime: when body completes without break, set
has_compile_errors and map to void instead of leaving unmapped.
Ported from Sema.zig block_comptime semantics (break required).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirIsNonErr: validate that operand is error union type before emitting
AIR_INST_IS_NON_ERR. Ported from Sema.zig zirIsNonErr line 18294
(checkErrorType: "expected error union type").
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add isNumericType/isComparableType helpers for type validation, and
use them in arithmetic and comparison operations:
New helpers:
- isNumericType: checks if type is int or float (for arithmetic ops)
- isComparableType: checks if type supports comparison operators
(isSelfComparable equivalent from Sema.zig line 16620)
Error markers added:
- analyzeArithmetic emit_runtime: validate peer type is numeric
(Sema.zig checkArithmeticOp)
- zirCmp runtime: validate peer type is comparable
(Sema.zig analyzeCmp line 16620)
- zirCmpEq runtime: validate peer type is comparable for ==, !=
- zirShl: for SHL_EXACT comptime, error if non-zero bits shifted out
(Sema.zig lines 13943-13978: "exact shift left overflowed")
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Continue adding sema->has_compile_errors = true for invalid type paths:
- analyzeBitNot: validate runtime (non-IP) operand is int/bool
(Sema.zig zirBitNot line 14261)
- zirBoolNot: validate operand is bool type for runtime path
(Sema.zig zirBoolNot lines 18050-18055)
- zirNegateWrap: validate operand is int/float type
(Sema.zig zirNegateWrap lines 15006-15009)
- zirAbs: validate operand is numeric type for runtime path
(Sema.zig zirAbs lines 20288-20296)
- zirMinMax: validate peer type is numeric for runtime path
(Sema.zig analyzeMinMax line 24684: checkNumericType)
- zirRetNode: error if fn_ret_ty == TYPE_NONE (unresolved return type)
(Sema.zig zirRetNode: fn_ret_ty must be known before coercion)
- zirIsNonNull: validate operand is optional/nullable type
(Sema.zig zirIsNonNull line 18247: checkNullableType)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Continue adding sema->has_compile_errors = true for silent failures:
- zirReifyComptime: error for TypeInfo variants other than .int
(Sema.zig zirReify lines 20430-20955 handles 15+ variants;
C only handles .int)
- zirFieldPtr: error when struct type unresolvable or field not found
(Sema.zig fieldPtr: field lookup failure is a compile error)
- zirErrUnionPayload: change silent void to error when operand is
not error union type (Sema.zig lines 8645-8648)
- zirErrUnionCode: same validation (Sema.zig lines 8794-8797)
- zirOptionalPayload: error when comptime operand type is not optional
(Sema.zig lines 8587-8608: failWithExpectedOptionalType)
- zirBitSizeOf: error for fn/noreturn/undefined types
(Sema.zig lines 16765-16771: "no size available for type")
- zirAlloc: error when variable type doesn't resolve to IP value
(Sema.zig zirAlloc: type must be resolvable at comptime)
- zirIntFromEnum: error when runtime operand is not enum/union type
(Sema.zig lines 8373-8393)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Continue adding sema->has_compile_errors = true for paths where
C silently returns wrong values:
- zirBitSizeOf: error for fn/noreturn/undefined types
(Sema.zig lines 16765-16771: "no size available for type")
- zirOptionalPayload: error when comptime operand is not optional type
(Sema.zig lines 8587-8608: failWithExpectedOptionalType)
- zirErrUnionPayload: error when operand is not error union type
(Sema.zig lines 8645-8648)
- zirErrUnionCode: same validation
(Sema.zig lines 8794-8797)
- zirIntFromEnum: error when runtime operand is not enum/union type
(Sema.zig lines 8373-8393)
- analyzeTyOpCast: validate src/dst are integer types for
AIR_INST_INTCAST and AIR_INST_TRUNC (Sema.zig line 9834);
keep same-type elision only for TRUNC (not INTCAST)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Systematically add sema->has_compile_errors = true for paths where
the C port either silently returns wrong values or is unimplemented
for valid Zig inputs. This makes failures explicit rather than
producing mysterious wrong AIR/IP output.
Changes:
- zirRetImplicit: error if function has non-void return type
(Sema.zig lines 18700-18710)
- zirDiv: error on signed integer with plain / operator
(Sema.zig lines 15129-15135: must use @divTrunc/@divFloor/@divExact)
- zirByteSwap: error if operand is not integer type; error if
bits % 8 != 0 (Sema.zig lines 22956-22964)
- analyzeBitNot: error if operand is not int or bool type
(Sema.zig line 14261)
- zirBitReverse: error if operand is not integer type
(Sema.zig line 22980)
- zirBitCount: error if operand is not integer type
(Sema.zig line 22905)
- zirBitwise: error if peer type is not int/bool
(Sema.zig lines 14218-14222)
- zirBitcast: error for comptime-only or void dest types
(Sema.zig lines 9894-9956)
- zirNegate: error on unsigned integer type
(Sema.zig lines 14973-14978)
- zirFloatCast: error if src/dest is not a float type
(Sema.zig lines 10046-10065)
- zirRef: error for runtime ref path (not yet implemented)
(Sema.zig analyzeRef)
- zirLoad: error for comptime load from comptime-known pointer
(Sema.zig analyzeLoad lines 31443-31447)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add handlers for @intFromEnum and @enumFromInt:
zirIntFromEnum: if operand is a comptime enum_tag IP entry, returns
the underlying int_val directly. Runtime fallback: bitcast to
operand type.
zirEnumFromInt: if operand is a comptime int and destination is an
enum type, creates an enum_tag IP entry. Runtime fallback: bitcast
to dest enum type.
Ported from Sema.zig zirIntFromEnum and zirEnumFromInt.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add runtime handlers for error union unwrapping instructions:
- ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE/PTR → AIR_INST_UNWRAP_ERRUNION_PAYLOAD
- ZIR_INST_ERR_UNION_CODE/PTR → AIR_INST_UNWRAP_ERRUNION_ERR
Both extract the error union's payload or error set type and emit
the corresponding AIR instruction. Previously falling through to
default (void mapping).
Add UNWRAP_ERRUNION_* tags to semaTypeOf ty_op group.
Ported from Sema.zig zirErrUnionPayload → analyzeErrUnionPayload
and zirErrUnionCode.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add no-op instMapPut handlers (mapped to IP_INDEX_VOID_VALUE) for
validation-only instructions that produce no meaningful value:
- ZIR_INST_VALIDATE_ARRAY_INIT_TY/RESULT_TY/REF_TY
- ZIR_INST_VALIDATE_DESTRUCTURE
- ZIR_INST_VALIDATE_PTR_ARRAY_INIT
- ZIR_INST_ENSURE_RESULT_NON_ERROR
- ZIR_INST_ENSURE_ERR_UNION_PAYLOAD_VOID
These were previously falling through to the default case (void mapping)
and are now explicitly handled as no-ops.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add handler for ZIR_INST_BIT_REVERSE which was previously falling
through to default void mapping.
Comptime folding: reverses each bit in the 128-bit representation
of the integer value. Runtime fallback: emits AIR_INST_BIT_REVERSE.
Ported from Sema.zig zirBitReverse → arith.bitReverse.
Also adds AIR_INST_BIT_REVERSE to semaTypeOf ty_op group.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add handlers for the remaining division/modulo ZIR instructions that
were previously falling through to the default void mapping.
Each function handles:
- Comptime integer folding with proper sign-magnitude arithmetic
- Runtime fallback via the corresponding AIR instruction
zirDivTrunc: truncation division (rounds toward zero)
zirDivFloor: floor division (rounds toward negative infinity)
zirDivExact: exact division (same as trunc; assumes no remainder)
zirMod: @mod — result has sign of denominator
zirRem: @rem — result has sign of numerator
zirModRem: plain '%' operator (delegates to zirRem)
Ported from src/Sema.zig zirDivTrunc/zirDivFloor/zirDivExact/
zirMod/zirRem/zirModRem.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previously zirCoercePtrElemTy was a no-op (returned value unchanged).
Now it resolves the pointer type from the LHS, extracts the element
type, and coerces the RHS value to that element type.
Handles the .one pointer case from Sema.zig: if the element type is
known and is not anyopaque/void, coerce the value. Preserves no-op
behavior for other pointer sizes or unresolvable types.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previously, zirOptionalPayload only handled comptime optional
unwrapping. Runtime optional values (AIR instructions) returned
void instead of emitting proper AIR code.
Add runtime path: if operand is a runtime AIR instruction with
optional type, get the payload child type and emit
AIR_INST_OPTIONAL_PAYLOAD with ty_op layout.
Also add AIR_INST_OPTIONAL_PAYLOAD to semaTypeOf ty_op group.
Ported from Sema.zig zirOptionalPayload runtime path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When coercing comptime_int to bool, produce the correct bool constant
(IP_INDEX_BOOL_TRUE/FALSE) instead of trying to create an IP_KEY_INT
entry with bool type (which wouldn't match the pre-interned bool constants).
Ported from Sema.zig coerce comptime_int → bool path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are comptime-known floats (IP_KEY_FLOAT),
comparison operations now fold to bool constants at compile time.
- zirCmp: adds float fold before integer fold for LT/LTE/GT/GTE
- zirCmpEq: adds float fold before integer fold for EQ/NEQ
Ported from Sema.zig cmpNumeric → compareScalars for comptime floats.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Fixes a case where comptime_int + concrete_float would not fold at
comptime: after coercion, both become float IP entries, but the
pre-coercion float check had already passed without folding.
Added a second float fold check after resolvePeerTypes+coerce, so
mixed comptime_int/float operations fold correctly.
Ported from Sema.zig analyzeArithmetic which calls resolveValue on
the coerced operands.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both @min/@max operands are comptime-known floats (IP_KEY_FLOAT),
fold the result at compile time. Result type is the wider of the two
float types, or comptime_float if both are comptime_float.
Ported from Sema.zig analyzeMinMax → Value.numberMin/Max.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are comptime-known float values (IP_KEY_FLOAT),
compute the division result at compile time and return the folded
float value. Matches Sema.zig zirDiv → arith.div() for comptime
float operands.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are comptime-known floats (IP_KEY_FLOAT entries,
including comptime_float and concrete float types), fold the result
at comptime instead of emitting a runtime AIR instruction.
Ported from Sema.zig analyzeArithmetic: resolveValue(casted_lhs/rhs)
path which evaluates comptime values via arith.add/sub/mul.
Handles ADD, SUB, MUL variants (including wrap/sat) for both
comptime_float × comptime_float and concrete float × float. Result
type is the wider of the two float types.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When semaCoerce encounters comptime_int → concrete float (or
comptime_float), it was incorrectly calling semaCoerceIntRef which
produces an IP_KEY_INT entry with a float type — wrong.
Fix by detecting the float target first: convert the integer value
to a double and intern an IP_KEY_FLOAT entry. This matches Sema.zig
coerce comptime_int → float path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are concrete float types (e.g. f32 + f64),
resolvePeerTypes returned the lhs type regardless of width.
Ported from Sema.zig peer_resolve_float strategy: return the
wider float type.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirNegate and zirNegateWrap: extend the float detection to include
IP_INDEX_COMPTIME_FLOAT_TYPE. Previously floatBits() returned 0 for
comptime_float, causing negate to fall through to integer path.
This fixes -(comptime_float) and -(comptime_float) wrap.
zirAbs: similarly extend float check to include comptime_float so
@abs on comptime_float values is properly folded at comptime.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The comptime equality check compared only lo/hi magnitude fields,
ignoring is_negative. This meant (-5) == 5 would return true.
Fix by also checking lhs_neg == rhs_neg. Zero is never negative
(internComptimeInt already clears neg for zero values), so this
handles the -0 == 0 edge case correctly.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The comptime folding path in zirCmp used unsigned comparison of
the magnitude fields (lo/hi), ignoring the is_negative sign flag.
This gave wrong results for mixed-sign comparisons like (-5) < 3.
Replace with a proper signed 128-bit comparison that:
- If signs differ: negative < positive
- Both non-negative: compare magnitudes in ascending order
- Both negative: compare magnitudes in descending order (larger mag = smaller value)
Also derive equality separately for LTE/GTE cases.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirAbs now folds @abs for comptime_int operands: absolute value is
simply clearing the is_negative flag. This matches Sema.zig which
treats comptime_int like float/comptime_float (result_ty = operand_ty)
and calls maybeConstantUnaryMath(Value.abs).
Also fold @abs for comptime-known typed signed integers: since the
result type is already unsigned, we just intern the magnitude (lo/hi)
with the unsigned result type and is_negative=false.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirBoolBr: after analyzing the RHS body, if the result is
comptime-known and equals the short-circuit value (true for or,
false for and), fold the whole expression to the comptime result.
This matches Sema.zig lines 18167-18173.
zirTypeofBuiltin: set want_safety=false on the typeof block, matching
Sema.zig line 17941 which explicitly disables safety in typeof blocks.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Several comptime folding paths in sema.c ignored the is_negative flag
of sign-magnitude InternPool integers:
- internComptimeInt: add `neg` parameter (was hardcoded false).
- analyzeArithmetic: implement sign-aware add/sub/mul via addSignedMag128
helper. add(a,b) handles mixed signs by subtracting smaller magnitude;
sub(a,b) = add(a,-b); mul result_neg = lhs_neg XOR rhs_neg.
- zirDiv: pass correct sign to result (lhs_neg != rhs_neg).
- zirShl/zirShr: preserve lhs sign through comptime shift.
- zirMinMax: use isComptimeIntWide (128-bit) instead of isComptimeInt
(64-bit) and implement full 128-bit signed comparison.
- semaTypeOf: add DIV_FLOOR, DIV_EXACT, DIV_FLOAT_OPTIMIZED, MOD, REM
to the bin_op type-from-lhs group.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Simplify the 128-bit case in zirByteSwap comptime folding:
- r_lo byte b ← val_hi byte (7-b)
- r_hi byte b ← val_lo byte (7-b)
Previous code had a dead `src < 8` check (always false).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add the float-to-integer coercion path: convert the float value to an
integer (truncating toward zero) and intern it with the target type.
Previously, comptime_float coercion to integer types was silently
ignored, returning the original float ref unchanged.
Also restructure the comptime_float case to explicitly separate
float→float from float→int paths.
Matches src/Sema.zig coerce: getCoerced(val, dst_ty) for float→int.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known integer operands (64-bit case), compute the quotient
at comptime instead of emitting AIR. Matches src/Sema.zig zirDiv: arith.div
for comptime-known values.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known float operands, compute -val at comptime instead of
emitting AIR_INST_NEG. Matches src/Sema.zig zirNegate: arith.negateFloat
for comptime values, preserving negative zero semantics.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known float operands, compute abs(val) at comptime
instead of emitting AIR. Matches src/Sema.zig zirAbs: maybeConstantUnaryMath
with Value.abs. Also extends to comptime_float type.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known integer operands with bit-aligned widths, compute
the byte-swapped value at comptime rather than emitting AIR.
Matches src/Sema.zig zirByteSwap: arith.byteSwap() comptime path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For float operands, create IP_KEY_FLOAT(0.0) instead of IP_KEY_INT(0).
The previous code created an int zero with a float type, which is an
invalid IP entry. Matches src/Sema.zig zirNegateWrap: pt.intValue()
returns the appropriate zero for the scalar type.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Match upstream Sema.zig zirBitwise structure: resolve peer types and
coerce operands FIRST, then attempt comptime folding on the coerced
values. This ensures typed IP entries (e.g. u16(3)) are created as
side effects of coercion, matching Zig's IP entry sequence.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Implement runtime while/for loop handling:
- Reserve block_inst (outer) + loop_inst (inner) in advance
- Analyze loop body in loop_block
- If body ends noreturn: copy instructions to child_block (no repeat)
- Otherwise: add repeat instruction, set up loop_inst body in air_extra
- Resolve outer block via label merges (handles break-from-loop)
Matches src/Sema.zig zirLoop decomposition.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Use resolveZirTypeRef instead of returning void for instruction refs
in the single-instruction return type body case. This handles ptr_type,
int_type, array_type, etc. Matches upstream's resolveType call in zirFunc.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>