zig

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

commit 0047dc8086d8c2d52358af18b66ffa440834bcce (tree)
parent 200d465dbbb0f1736fd6a0414922ce2a79894156
Author: Motiejus <motiejus@jakstys.lt>
Date:   Sun,  1 Mar 2026 13:53:08 +0000

sema: unify corpus — one array, one counter, all stages

Merge sema_unit_tests into the main corpus.files array. All files now
go through the full stages_test.zig pipeline: parser → ZIR → sema,
with bidirectional AIR comparison.

This fixes a gap where sema unit tests skipped ZIR validation and
used a different sema setup (no source_dir), hiding bugs.

Changes:
- corpus.zig: merge sema_unit_tests into files, remove
  num_sema_passing
- stages_test.zig: handle stage0/ paths (no module_root)
- sema_test.zig: remove corpus test (now in stages_test)
- build.zig: remove sema_unit_tests loop from addAirGen
- sema.c: remove is_exported filter from zirFunc — analyze all
  functions with bodies

num_passing = 3 (first 3 lib/ files with no functions).

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

Diffstat:
Mbuild.zig | 6+-----
Mstage0/corpus.zig | 5-----
Mstage0/sema.c | 17+++--------------
Mstage0/sema_test.zig | 30+-----------------------------
Mstage0/stages_test.zig | 18+++++++++++-------
5 files changed, 16 insertions(+), 60 deletions(-)

diff --git a/build.zig b/build.zig @@ -1750,16 +1750,12 @@ fn addAirGen( const air_dir = gen_run.addOutputDirectoryArg("air"); // Add non-lib/std/ corpus files as name/path pairs. // lib/std/ files are compiled via std.zig root inside air_gen. + // stage0/sema_tests/ files are also included (standalone compilation). for (corpus.files) |path| { if (std.mem.startsWith(u8, path, "lib/std/")) continue; gen_run.addArg(path); gen_run.addFileArg(b.path(path)); } - // Add sema unit test files. - for (corpus.sema_unit_tests) |path| { - gen_run.addArg(path); - gen_run.addFileArg(b.path(path)); - } return .{ .step = &gen_run.step, .air_dir = air_dir }; } diff --git a/stage0/corpus.zig b/stage0/corpus.zig @@ -777,11 +777,6 @@ pub const files = [_][]const u8{ "lib/std/unicode/throughput_test.zig", "lib/std/crypto/benchmark.zig", "lib/std/math/float.zig", -}; - -pub const num_sema_passing: usize = 2; - -pub const sema_unit_tests = [_][]const u8{ "stage0/sema_tests/empty.zig", "stage0/sema_tests/const_decl.zig", "stage0/sema_tests/empty_void_function.zig", diff --git a/stage0/sema.c b/stage0/sema.c @@ -8282,23 +8282,13 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, // The function body is analyzed in a fresh AIR context; the resulting // per-function Air is appended to sema->func_air_list. static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) { - // Only analyze exported functions with bodies. + // Analyze all functions with bodies. + // Ported from src/Sema.zig zirFunc: the Zig compiler resolves all + // reachable functions, not just exported ones. FuncZirInfo fi = parseFuncZir(sema, inst); if (fi.body_len == 0 || !sema->func_air_list) return; - bool is_exported = sema->cur_decl_is_export; - if (!is_exported) { - for (uint32_t e = 0; e < sema->num_exported_decl_names; e++) { - if (s_exported_decl_names[e] == sema->cur_decl_name) { - is_exported = true; - break; - } - } - } - if (!is_exported) - return; - // Create function type and func_decl IP entries before analyzing // the function body. This matches the Zig compiler's processing // where ensureNavValUpToDate creates these entries during @export @@ -8558,7 +8548,6 @@ static void zirStructDecl(Sema* sema, SemaBlock* block, uint32_t inst) { decls_len = sema->code.extra[extra_index]; extra_index++; } - extra_index += captures_len * 2; // skip captures if (has_backing_int) { diff --git a/stage0/sema_test.zig b/stage0/sema_test.zig @@ -889,32 +889,4 @@ fn airCompareOne(name: []const u8, a: PrecomputedFunc, b: PrecomputedFunc, zig_i } } -const corpus = @import("corpus.zig"); - -test "sema air: unit tests" { - @setEvalBranchQuota(corpus.sema_unit_tests.len * 100); - inline for (corpus.sema_unit_tests[0..corpus.num_sema_passing]) |path| { - const source: [:0]const u8 = @embedFile("../" ++ path); - - var c_ast = c.astParse(source.ptr, @intCast(source.len)); - defer c.astDeinit(&c_ast); - var c_zir = c.astGen(&c_ast); - defer c.zirDeinit(&c_zir); - var c_ip = c.ipInit(); - defer c.ipDeinit(&c_ip); - var c_sema: c.Sema = undefined; - c.semaInit(&c_sema, &c_ip, c_zir); - defer c.semaDeinit(&c_sema); - c_sema.root_fqn = comptime pathStem(path); - var c_func_air_list = c.semaAnalyze(&c_sema); - defer c.semaFuncAirListDeinit(&c_func_air_list); - - const air_data = @import("air_data").getData(path); - const precomputed = try parsePrecomputedAir(air_data); - defer freePrecomputedAir(precomputed); - airComparePrecomputed(precomputed, c_func_air_list) catch { - std.debug.print("FAIL: {s}\n", .{path}); - return error.TestFailed; - }; - } -} +// Sema unit tests are now in corpus.files and tested through stages_test.zig. diff --git a/stage0/stages_test.zig b/stage0/stages_test.zig @@ -11,7 +11,7 @@ const sc = sema_test.c; const corpus = @import("corpus.zig"); test "stages: corpus" { - @setEvalBranchQuota(corpus.files.len * 2); + @setEvalBranchQuota(corpus.files.len * 100); const gpa = std.testing.allocator; inline for (corpus.files[0..corpus.num_passing]) |path| { stagesCheck(gpa, path, @embedFile("../" ++ path)) catch { @@ -73,17 +73,21 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8) var c_sema: sc.Sema = undefined; sc.semaInit(&c_sema, &c_ip, @bitCast(c_zir)); defer sc.semaDeinit(&c_sema); - c_sema.source_dir = source_dir_path.ptr; - c_sema.module_root = module_root_path.ptr; // Pre-generated AIR uses ReleaseSmall (strip=true), so match it. c_sema.strip = true; - // Set root_fqn and module_prefix so C sema FQNs match Zig's. - // lib/std/ files: "std.{prefix}.func" (std.zig compiled as root) - // other files: "{stem}.func" (standalone compilation) - if (comptime std.mem.startsWith(u8, path, "lib/std/")) { + // Set source_dir, module_root, root_fqn based on path prefix. + if (comptime std.mem.startsWith(u8, path, "stage0/")) { + // Sema unit tests: standalone files, no std resolution. + c_sema.source_dir = source_dir_path.ptr; + c_sema.root_fqn = comptime sema_test.pathStem(path); + } else if (comptime std.mem.startsWith(u8, path, "lib/std/")) { + c_sema.source_dir = source_dir_path.ptr; + c_sema.module_root = module_root_path.ptr; c_sema.root_fqn = "std"; c_sema.module_prefix = sema_test.pathToModulePrefix(path); } else { + c_sema.source_dir = source_dir_path.ptr; + c_sema.module_root = module_root_path.ptr; c_sema.root_fqn = comptime sema_test.pathStem(path); } var c_func_air_list = sc.semaAnalyze(&c_sema);