commit 894d54af1f8326fdd87f177f60741c3d51dfa76e (tree)
parent 13ac71a9fad738fd5d74cb69afcc686ad530d349
Author: Motiejus <motiejus@jakstys.lt>
Date: Sun, 1 Mar 2026 20:58:03 +0000
stage0: pass tests 21-28, fix shift type dedup, update CLAUDE.md
Fix bit_shift_right/left by removing redundant shift type coercion from
zirShl (AstGen already handles it via typeof_log2_int_type +
as_shift_operand). Use ipForceIntern in zirTypeofLog2IntType and
semaCoerceIntRef to match Zig compiler's sharded IP behavior.
Improve return type resolution in ensureNavValUpToDate to handle
compound types via resolveZirTypeRef/resolveZirTypeInst.
Update CLAUDE.md: add "No workarounds" rule, remove stale status section.
num_passing: 21 -> 29
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
3 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/stage0/CLAUDE.md b/stage0/CLAUDE.md
@@ -56,6 +56,15 @@ Everything else must be computed by porting the upstream functions that
produce the values. Do not hand-code enum tags, field indices, type indices,
or any values that come from running upstream logic.
+### No workarounds — always port
+
+When a test fails, the only correct response is to port the upstream
+implementation that makes it pass. Never work around a failure by
+rearranging tests, skipping tests, adjusting test ordering, adding
+special-case hacks, or any other technique that increases `num_passing`
+without fixing the underlying missing functionality. Every `num_passing`
+increment must represent genuinely ported upstream behavior.
+
### When you see a gap
When a test mismatch shows the C sema has fewer InternPool entries than
@@ -122,9 +131,6 @@ C and Zig AIR must match byte-by-byte except:
## Cleaning up
-Update `stage0/CLAUDE.md` with brief current status (num_passing, next
-blocker) when meaningful progress is made. Keep it concise.
-
Before committing, ensure the branch stays green:
1. Ensure `num_passing` in `stage0/corpus.zig` only covers tests that actually
@@ -170,36 +176,3 @@ Go back and fix it — never commit with fewer passing tests than before.
```
Compare C sema IP entries against the Zig compiler's dump above.
-## Current status (2026-03-01)
-
-**num_passing = 5.** Tests 0-4 pass (empty, const_decl, empty_void_function,
-type_identity_fn, reify_int).
-
-**Next blocker: return_integer.zig** (index 5). `export fn f() u32 { return 42; }`
-interns 42:u32 at IP index 216 in the Zig compiler (func_ip=217). C sema
-creates only 153 entries, putting 42:u32 at index 152 (gap = 64).
-
-**IP dump command (must match test's strip mode):**
-```
-./zig-out/bin/zig build-obj stage0/sema_tests/return_integer.zig \
- --verbose-intern-pool -target wasm32-wasi -fno-emit-bin -OReleaseSafe -fstrip
-```
-
-**IP alignment progress:** Gap reduced from 64 to 3 entries.
-- $124-$134: match (module loading + memoized_call)
-- $135-$143: module chain (C sema creates 9 entries with 4 struct_types;
- reference creates 7 entries with 3 struct_types interleaved with ptr_navs)
-- $144+: analyzeMemoizedStateC resolves Signedness through SourceLocation
- (first 6 builtins), creating CallingConvention enum + values and other
- builtin type entries. memoized_limit=6 gives closest match.
-- Remaining gap: 3 entries (C sema 42:u32 at IP 213, reference at IP 216)
-
-**Fixed:** CG builtin namespace collision — std/builtin.zig and CG builtin
-shared same namespace index; added `has_zir` check in `ensureNavValUpToDate`
-to distinguish them.
-
-**Next steps:** Close the remaining 3-entry gap. The module chain creates
-1 extra struct_type in the C sema (4 vs 3 in reference). The reference
-interleaves struct_type/ptr_nav pairs while C sema batches them. Fix the
-module loading order in `resolveModuleDeclImports` and the root module
-creation sequence to match the reference interleaving.
diff --git a/stage0/corpus.zig b/stage0/corpus.zig
@@ -3,7 +3,7 @@
/// `num_passing` controls how many files are tested and pre-generated.
/// Both build.zig and stages_test.zig import this file.
/// To enable more tests: just increment `num_passing`.
-pub const num_passing: usize = 21;
+pub const num_passing: usize = 29;
pub const files = [_][]const u8{
"stage0/sema_tests/empty.zig",
diff --git a/stage0/sema.c b/stage0/sema.c
@@ -682,6 +682,12 @@ static AirInstRef semaCoerceIntRef(
return air_ref; // already the right type
// Create a new IP entry with the target type but same value.
+ // Use ipForceIntern to skip deduplication: the Zig compiler's
+ // sharded IP creates separate entries in different shards (e.g.
+ // CallingConvention enum values in the memoized shard vs function
+ // body values in the function shard). The C sema's single IP
+ // would incorrectly deduplicate, returning an index from the
+ // memoized state instead of creating a new function-local entry.
InternPoolKey new_key;
memset(&new_key, 0, sizeof(new_key));
new_key.tag = IP_KEY_INT;
@@ -689,7 +695,7 @@ static AirInstRef semaCoerceIntRef(
new_key.data.int_val.value_lo = key.data.int_val.value_lo;
new_key.data.int_val.value_hi = key.data.int_val.value_hi;
new_key.data.int_val.is_negative = key.data.int_val.is_negative;
- uint32_t new_ip_idx = ipIntern(sema->ip, new_key);
+ uint32_t new_ip_idx = ipForceIntern(sema->ip, new_key);
return AIR_REF_FROM_IP(new_ip_idx);
}
@@ -1695,13 +1701,17 @@ static void zirTypeofLog2IntType(Sema* sema, uint32_t inst) {
count++;
s >>= 1;
}
- // Intern the log2 integer type.
+ // Create the log2 integer type. Use ipForceIntern to match the Zig
+ // compiler's sharded IP: upstream creates a fresh entry in the
+ // function-local shard even if the same type exists elsewhere
+ // (e.g. u5 may already exist from CallingConvention enum resolution
+ // in a different shard).
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_INT_TYPE;
key.data.int_type.bits = count;
key.data.int_type.signedness = 0; // unsigned
- InternPoolIndex ty_idx = ipIntern(sema->ip, key);
+ InternPoolIndex ty_idx = ipForceIntern(sema->ip, key);
instMapPut(&sema->inst_map, inst, AIR_REF_FROM_IP(ty_idx));
}
@@ -1752,6 +1762,10 @@ static AirInstRef zirShl(
return internComptimeInt(sema, lhs_ty, r_lo, r_hi);
}
+ // The rhs is already coerced to the correct shift type by
+ // typeof_log2_int_type + as_shift_operand ZIR instructions
+ // (AstGen forces the coercion before the shl/shr instruction).
+
AirInstData data;
memset(&data, 0, sizeof(data));
data.bin_op.lhs = lhs;
@@ -4771,12 +4785,25 @@ static InternPoolIndex ensureNavValUpToDate(uint32_t nav_idx) {
FuncZirInfo fi = parseFuncZir(&tmp_sema, inst);
semaDeinit(&tmp_sema);
- // Parse return type.
+ // Parse return type. Use resolveZirTypeRef to handle
+ // compound types (pointers, optionals, etc.) that require
+ // creating IP entries, matching the Zig compiler which
+ // creates these entries before the func_type.
InternPoolIndex ret_ty = IP_INDEX_VOID_TYPE;
if (fi.ret_ty_body_len == 1) {
uint32_t ret_ref = zir->extra[fi.ret_ty_ref_pos];
- if (ret_ref < ZIR_REF_START_INDEX)
- ret_ty = ret_ref;
+ InternPoolIndex resolved
+ = resolveZirTypeRef(zir, ret_ref, ns_idx, file_idx);
+ if (resolved != IP_INDEX_NONE)
+ ret_ty = resolved;
+ } else if (fi.ret_ty_body_len == 2) {
+ // 2-instruction body: type instruction + break_inline.
+ // Resolve the first instruction as a type.
+ uint32_t type_inst = zir->extra[fi.ret_ty_ref_pos];
+ InternPoolIndex resolved
+ = resolveZirTypeInst(zir, type_inst, ns_idx, file_idx);
+ if (resolved != IP_INDEX_NONE)
+ ret_ty = resolved;
}
// Count parameters from param_block.