zig_compare_air: add module_root parameter to widen import resolution
Hardcoding the module root to dirname(src_path) caused "import of file
outside module path" for any @import("../...") in corpus files. Add an
optional module_root parameter so stages_test can symlink to the repo
root, allowing all relative imports to resolve within the module path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -142,11 +142,13 @@ const AirComparer = struct {
|
||||
|
||||
export fn zig_compare_air(
|
||||
src_path_ptr: [*:0]const u8,
|
||||
module_root_ptr: ?[*:0]const u8,
|
||||
c_funcs_raw: ?*const anyopaque,
|
||||
c_func_count: u32,
|
||||
) CompareResult {
|
||||
return zigCompareAirImpl(
|
||||
std.mem.span(src_path_ptr),
|
||||
if (module_root_ptr) |p| std.mem.span(p) else null,
|
||||
@ptrCast(@alignCast(c_funcs_raw)),
|
||||
c_func_count,
|
||||
) catch |err| {
|
||||
@@ -166,6 +168,7 @@ fn errResult(msg: []const u8) CompareResult {
|
||||
|
||||
fn zigCompareAirImpl(
|
||||
src_path: []const u8,
|
||||
module_root_opt: ?[]const u8,
|
||||
c_funcs: ?[*]const CSemaFuncAir,
|
||||
c_func_count: u32,
|
||||
) !CompareResult {
|
||||
@@ -210,14 +213,22 @@ fn zigCompareAirImpl(
|
||||
// This avoids root mismatches in isNested checks, and also avoids resolving
|
||||
// symlinks — the caller may use a directory symlink to keep the module root
|
||||
// outside lib/std/ while preserving relative import resolution.
|
||||
const src_dir = std.fs.path.dirname(src_path) orelse ".";
|
||||
const src_basename = std.fs.path.basename(src_path);
|
||||
const src_dir = module_root_opt orelse (std.fs.path.dirname(src_path) orelse ".");
|
||||
const root_src_path = if (module_root_opt) |mr| blk: {
|
||||
// src_path is "module_root/relative/path.zig" — strip module_root prefix
|
||||
if (std.mem.startsWith(u8, src_path, mr)) {
|
||||
var rest = src_path[mr.len..];
|
||||
if (rest.len > 0 and rest[0] == std.fs.path.sep) rest = rest[1..];
|
||||
break :blk rest;
|
||||
}
|
||||
break :blk std.fs.path.basename(src_path); // fallback
|
||||
} else std.fs.path.basename(src_path);
|
||||
const root_path = try Compilation.Path.fromUnresolved(arena, dirs, &.{src_dir});
|
||||
|
||||
const root_mod = try Package.Module.create(arena, .{
|
||||
.paths = .{
|
||||
.root = root_path,
|
||||
.root_src_path = src_basename,
|
||||
.root_src_path = root_src_path,
|
||||
},
|
||||
.fully_qualified_name = "root",
|
||||
.cc_argv = &.{},
|
||||
|
||||
@@ -11,7 +11,7 @@ typedef struct {
|
||||
} AirCompareResult;
|
||||
|
||||
// c_funcs: pointer to SemaFuncAir array (from sema.h). Passed as void* to avoid header dep.
|
||||
extern AirCompareResult zig_compare_air(const char* src_path, const void* c_funcs, uint32_t c_func_count);
|
||||
extern AirCompareResult zig_compare_air(const char* src_path, const char* module_root, const void* c_funcs, uint32_t c_func_count);
|
||||
extern void zig_compare_result_free(AirCompareResult* result);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@ const AirCompareResult = extern struct {
|
||||
matched_count: u32,
|
||||
error_msg: ?[*:0]u8,
|
||||
};
|
||||
extern fn zig_compare_air([*:0]const u8, ?*const anyopaque, u32) AirCompareResult;
|
||||
extern fn zig_compare_air([*:0]const u8, ?[*:0]const u8, ?*const anyopaque, u32) AirCompareResult;
|
||||
extern fn zig_compare_result_free(*AirCompareResult) void;
|
||||
|
||||
// Helper to convert C #define integer constants (c_int) to u32 for comparison
|
||||
@@ -245,7 +245,7 @@ fn semaAirRawCheck(source: [:0]const u8) !void {
|
||||
}
|
||||
defer std.fs.cwd().deleteFile(tmp_path) catch {};
|
||||
|
||||
var cmp_result = zig_compare_air(tmp_path, @ptrCast(result.c_func_air_list.items), result.c_func_air_list.len);
|
||||
var cmp_result = zig_compare_air(tmp_path, null, @ptrCast(result.c_func_air_list.items), result.c_func_air_list.len);
|
||||
defer zig_compare_result_free(&cmp_result);
|
||||
if (cmp_result.error_msg) |e| {
|
||||
std.debug.print("zig_compare_air error: {s}\n", .{std.mem.span(e)});
|
||||
|
||||
@@ -13,7 +13,7 @@ const AirCompareResult = extern struct {
|
||||
matched_count: u32,
|
||||
error_msg: ?[*:0]u8,
|
||||
};
|
||||
extern fn zig_compare_air([*:0]const u8, ?*const anyopaque, u32) AirCompareResult;
|
||||
extern fn zig_compare_air([*:0]const u8, ?[*:0]const u8, ?*const anyopaque, u32) AirCompareResult;
|
||||
extern fn zig_compare_result_free(*AirCompareResult) void;
|
||||
|
||||
test "stages: corpus" {
|
||||
@@ -71,22 +71,29 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8)
|
||||
var c_func_air_list = sc.semaAnalyze(&c_sema);
|
||||
defer sc.semaFuncAirListDeinit(&c_func_air_list);
|
||||
|
||||
// Symlink the original file's directory to avoid module path conflicts
|
||||
// (source files inside lib/std/ conflict with the 'std' module)
|
||||
// while preserving relative import resolution for subdirectory imports.
|
||||
// Symlink to the repo root so all relative imports resolve within
|
||||
// the module root, while keeping logical paths under .zig-cache/tmp/
|
||||
// to avoid 'std' module conflicts with lib/std/.
|
||||
const this_dir = comptime std.fs.path.dirname(@src().file) orelse ".";
|
||||
const original_dir = comptime std.fs.path.dirname(this_dir ++ "/" ++ path) orelse ".";
|
||||
const symlink_path = ".zig-cache/tmp/zig0_test";
|
||||
|
||||
const abs_original_dir = std.fs.cwd().realpathAlloc(gpa, original_dir) catch return error.ResolvePath;
|
||||
defer gpa.free(abs_original_dir);
|
||||
// All corpus paths start with "../"; strip to get repo-relative path.
|
||||
const repo_relative = comptime blk: {
|
||||
if (!std.mem.startsWith(u8, path, "../"))
|
||||
@compileError("corpus path must start with '../'");
|
||||
break :blk path["../".len..];
|
||||
};
|
||||
|
||||
const abs_repo_root = std.fs.cwd().realpathAlloc(gpa, comptime this_dir ++ "/..") catch return error.ResolvePath;
|
||||
defer gpa.free(abs_repo_root);
|
||||
|
||||
std.fs.cwd().deleteFile(symlink_path) catch {};
|
||||
std.fs.cwd().symLink(abs_original_dir, symlink_path, .{ .is_directory = true }) catch return error.SymlinkCreate;
|
||||
std.fs.cwd().symLink(abs_repo_root, symlink_path, .{ .is_directory = true }) catch return error.SymlinkCreate;
|
||||
defer std.fs.cwd().deleteFile(symlink_path) catch {};
|
||||
|
||||
const test_src: [:0]const u8 = symlink_path ++ "/" ++ comptime std.fs.path.basename(path);
|
||||
var cmp_result = zig_compare_air(test_src.ptr, @ptrCast(c_func_air_list.items), c_func_air_list.len);
|
||||
const test_src: [:0]const u8 = symlink_path ++ "/" ++ repo_relative;
|
||||
const module_root: [:0]const u8 = symlink_path;
|
||||
var cmp_result = zig_compare_air(test_src.ptr, module_root.ptr, @ptrCast(c_func_air_list.items), c_func_air_list.len);
|
||||
defer zig_compare_result_free(&cmp_result);
|
||||
if (cmp_result.error_msg) |e| {
|
||||
std.debug.print("zig_compare_air error: {s}\n", .{std.mem.span(e)});
|
||||
@@ -104,7 +111,7 @@ const last_successful_corpus = "../lib/std/crypto/codecs.zig";
|
||||
// find ../{lib,src} -name '*.zig' | xargs -n1 stat -c "%s %n" | sort -n | awk '{printf " \""$2"\", // "$1"\n"}'
|
||||
const corpus_files = .{
|
||||
"../lib/std/crypto/codecs.zig", // 165
|
||||
//"../lib/std/os/uefi/tables/table_header.zig", // 214
|
||||
"../lib/std/os/uefi/tables/table_header.zig", // 214
|
||||
//"../lib/std/zig/llvm.zig", // 247
|
||||
//"../lib/compiler_rt/neghf2.zig", // 265
|
||||
//"../lib/compiler_rt/negxf2.zig", // 265
|
||||
|
||||
Reference in New Issue
Block a user