diff --git a/src/verbose_air.zig b/src/verbose_air.zig index 1fd81f49c6..0eb65f550f 100644 --- a/src/verbose_air.zig +++ b/src/verbose_air.zig @@ -204,11 +204,14 @@ fn zigCompareAirImpl( .is_test = false, }); - // Split src_path into directory and filename for the Module. + // Construct the module root path through fromUnresolved so it gets the same + // canonical root (.zig_lib, .local_cache, etc.) as file paths computed later. + // 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 abs_src_dir = try std.fs.cwd().realpathAlloc(arena, src_dir); - const root_path: Compilation.Path = .{ .root = .none, .sub_path = abs_src_dir }; + const root_path = try Compilation.Path.fromUnresolved(arena, dirs, &.{src_dir}); const root_mod = try Package.Module.create(arena, .{ .paths = .{ diff --git a/stage0/stages_test.zig b/stage0/stages_test.zig index 49d6555a91..a2f62affcf 100644 --- a/stage0/stages_test.zig +++ b/stage0/stages_test.zig @@ -20,14 +20,14 @@ test "stages: corpus" { @setEvalBranchQuota(corpus_files.len * 2); const gpa = std.testing.allocator; inline for (corpus_files) |path| { - stagesCheck(gpa, @embedFile(path)) catch { + stagesCheck(gpa, path, @embedFile(path)) catch { std.debug.print("FAIL: {s}\n", .{path}); return error.TestFailed; }; } } -fn stagesCheck(gpa: Allocator, source: [:0]const u8) !void { +fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8) !void { // Parse once with C parser var c_ast = c.astParse(source.ptr, @intCast(source.len)); defer c.astDeinit(&c_ast); @@ -71,17 +71,22 @@ fn stagesCheck(gpa: Allocator, source: [:0]const u8) !void { var c_func_air_list = sc.semaAnalyze(&c_sema); defer sc.semaFuncAirListDeinit(&c_func_air_list); - // Write source to a temp file to avoid module path conflicts - // (source files inside lib/std/ conflict with the 'std' module). - const tmp_path = "/tmp/zig0_stages_test_tmp.zig"; - { - const f = std.fs.cwd().createFile(tmp_path, .{}) catch return error.TmpFileCreate; - defer f.close(); - f.writeAll(source) catch return error.TmpFileWrite; - } - defer std.fs.cwd().deleteFile(tmp_path) catch {}; + // 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. + 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"; - var cmp_result = zig_compare_air(tmp_path, @ptrCast(c_func_air_list.items), c_func_air_list.len); + const abs_original_dir = std.fs.cwd().realpathAlloc(gpa, original_dir) catch return error.ResolvePath; + defer gpa.free(abs_original_dir); + + std.fs.cwd().deleteFile(symlink_path) catch {}; + std.fs.cwd().symLink(abs_original_dir, 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); 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)});