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:
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);