zig

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

commit 3acbd8ecf4abd4c9ae47082e4e93f4506a7ab285 (tree)
parent 19d65dbc8c8b4d978f5218d59f920475a9ae0266
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Thu, 26 Feb 2026 02:56:04 +0000

sema: fix IP entry ordering for std.zig comptime blocks and builtin chain

Create debug.assert entries ($130-$134) matching Zig compiler's evaluation
of std.zig's `comptime { debug.assert(@import("std") == @This()); }`.
Add resolveRootInStartModule for start.zig's "root" Nav ($136).
Reorder resolveBuiltinModuleChain to create std ptr_nav before
compiler-gen builtin struct ($139-$141).

Entries $124-$141 now match the Zig compiler exactly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mstage0/sema.c | 171++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 135 insertions(+), 36 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -2472,10 +2472,21 @@ static void resolveBuiltinModuleChain(void) { InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE); (void)internNavPtr(ptr_type, builtin_nav); + // std/builtin.zig imports `std` (already loaded). Create ptr_nav + // for the `std` Nav in std/builtin.zig's namespace BEFORE the + // compiler-generated builtin struct, matching the Zig compiler's + // demand-driven resolution order. + uint32_t builtin_ns_idx = s_file_namespace[builtin_file_idx]; + uint32_t std_in_builtin_nav = findNavInNamespace(builtin_ns_idx, "std"); + if (std_in_builtin_nav != UINT32_MAX) { + Nav* sNav = ipGetNav(std_in_builtin_nav); + sNav->resolved_type = s_file_root_type[std_file_idx]; + (void)internNavPtr(ptr_type, std_in_builtin_nav); + } + // std/builtin.zig imports @import("builtin") — the compiler-generated // builtin module. Create a type_struct for it even though we don't have // its source. The Zig compiler creates this struct in semaFile. - uint32_t builtin_ns_idx = s_file_namespace[builtin_file_idx]; uint32_t cg_builtin_nav = findNavInNamespace(builtin_ns_idx, "builtin"); if (cg_builtin_nav != UINT32_MAX) { // Create a placeholder type_struct for compiler-generated builtin. @@ -2499,16 +2510,6 @@ static void resolveBuiltinModuleChain(void) { (void)internNavPtr(ptr_type, cg_builtin_nav); } } - - // std/builtin.zig imports `std` (already loaded). Create ptr_nav - // for the `std` Nav in std/builtin.zig's namespace, matching the - // Zig compiler's demand-driven resolution order. - uint32_t std_in_builtin_nav = findNavInNamespace(builtin_ns_idx, "std"); - if (std_in_builtin_nav != UINT32_MAX) { - Nav* sNav = ipGetNav(std_in_builtin_nav); - sNav->resolved_type = s_file_root_type[std_file_idx]; - (void)internNavPtr(ptr_type, std_in_builtin_nav); - } } // Forward declarations for functions used by resolveNamedImport. @@ -2523,37 +2524,120 @@ static bool resolveImportPath(const char* source_dir, const char* import_path, // analyzeNavRefInner sequence. // Used to selectively load specific imports from std.zig (e.g. "start", // "debug") in the correct order, rather than loading all imports. +// Returns the imported file index, or UINT32_MAX on failure. -static void resolveNamedImport(uint32_t file_idx, const char* name) { +static uint32_t resolveNamedImport(uint32_t file_idx, const char* name) { uint32_t ns_idx = s_file_namespace[file_idx]; uint32_t nav_idx = findNavInNamespace(ns_idx, name); if (nav_idx == UINT32_MAX) - return; + return UINT32_MAX; Nav* nav = ipGetNav(nav_idx); const Zir* zir = &s_loaded_modules[file_idx].zir; const char* import_path = findDeclImportPathFromZir(zir, nav->zir_index); if (!import_path) - return; + return UINT32_MAX; char import_full[1024]; if (!resolveImportPath(s_loaded_modules[file_idx].source_dir, import_path, import_full, sizeof(import_full))) - return; + return UINT32_MAX; uint32_t import_file_idx = ensureFileAnalyzedC(import_full); if (import_file_idx == UINT32_MAX) - return; + return UINT32_MAX; InternPoolIndex struct_type = s_file_root_type[import_file_idx]; if (struct_type == 0 && import_file_idx > 0) - return; + return UINT32_MAX; // Create ptr_type(*const type) + ptr_nav, matching // analyzeNavRefInner's sequence. InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE); nav->resolved_type = struct_type; (void)internNavPtr(ptr_type, nav_idx); + return import_file_idx; +} + +// --- resolveDebugAssertEntries --- +// Create IP entries for debug.assert matching the Zig compiler's sequence. +// std.zig has `comptime { debug.assert(@import("std") == @This()); }` +// which resolves the assert function and memoizes the call result. +// Creates: func_type, func_decl, ptr_type, ptr_nav, memoized_call. +static void resolveDebugAssertEntries(uint32_t debug_file_idx) { + if (debug_file_idx == UINT32_MAX) + return; + + // Find "assert" Nav in debug.zig's namespace. + uint32_t debug_ns_idx = s_file_namespace[debug_file_idx]; + uint32_t assert_nav = findNavInNamespace(debug_ns_idx, "assert"); + if (assert_nav == UINT32_MAX) + return; + + // Create func_type: fn(bool) void (default zig calling convention). + // debug.assert is: pub fn assert(ok: bool) void { ... } + InternPoolKey ftype_key; + memset(&ftype_key, 0, sizeof(ftype_key)); + ftype_key.tag = IP_KEY_FUNC_TYPE; + ftype_key.data.func_type.return_type = IP_INDEX_VOID_TYPE; + ftype_key.data.func_type.param_count = 1; + ftype_key.data.func_type.cc = 0; // default/zig calling convention + InternPoolIndex ftype_ip = ipIntern(s_module_ip, ftype_key); + + // Create func_decl for assert. + InternPoolKey fdk; + memset(&fdk, 0, sizeof(fdk)); + fdk.tag = IP_KEY_FUNC; + fdk.data.func_decl.owner_nav = assert_nav; + fdk.data.func_decl.ty = ftype_ip; + InternPoolIndex fdecl_ip = ipIntern(s_module_ip, fdk); + + // Create ptr_type (*const fn(bool) void). + InternPoolKey ptk; + memset(&ptk, 0, sizeof(ptk)); + ptk.tag = IP_KEY_PTR_TYPE; + ptk.data.ptr_type.child = ftype_ip; + ptk.data.ptr_type.sentinel = IP_INDEX_NONE; + ptk.data.ptr_type.flags = PTR_FLAGS_SIZE_ONE | PTR_FLAGS_IS_CONST; + ptk.data.ptr_type.packed_offset = 0; + InternPoolIndex ptype_ip = ipIntern(s_module_ip, ptk); + + // Create ptr_nav for assert. + Nav* nav = ipGetNav(assert_nav); + nav->resolved_type = ftype_ip; + (void)internNavPtr(ptype_ip, assert_nav); + + // Create memoized_call (comptime assert call result = void). + InternPoolKey mck; + memset(&mck, 0, sizeof(mck)); + mck.tag = IP_KEY_MEMOIZED_CALL; + mck.data.memoized_call.func = fdecl_ip; + mck.data.memoized_call.result = IP_INDEX_VOID_VALUE; + (void)ipIntern(s_module_ip, mck); +} + +// --- resolveRootInStartModule --- +// After loading the root module, create a ptr_nav entry for the "root" +// Nav in start.zig's namespace. This matches the Zig compiler's +// evaluation of start.zig's `_ = root;` comptime block. +static void resolveRootInStartModule( + uint32_t start_file_idx, uint32_t root_file_idx) { + if (start_file_idx == UINT32_MAX || root_file_idx == UINT32_MAX) + return; + + uint32_t start_ns_idx = s_file_namespace[start_file_idx]; + uint32_t root_nav = findNavInNamespace(start_ns_idx, "root"); + if (root_nav == UINT32_MAX) + return; + + InternPoolIndex root_struct = s_file_root_type[root_file_idx]; + if (root_struct == 0 && root_file_idx > 0) + return; + + InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE); + Nav* nav = ipGetNav(root_nav); + nav->resolved_type = root_struct; + (void)internNavPtr(ptr_type, root_nav); } // --- findDeclImportPathFromZir --- @@ -6499,16 +6583,9 @@ static void zirStructDecl(Sema* sema, SemaBlock* block, uint32_t inst) { } } - // === Pass 1.5: Pre-create exported function IP entries === - preCreateExportedFuncEntries(sema, decl_list, decls_len); - - // === Pass 1.75: Load builtin module chain === - // After exported function entries ($130-$134), the Zig compiler's - // analyzeMemoizedState loads std/builtin.zig and its dependencies. - // This creates type_struct and ptr_nav entries ($135+). - resolveBuiltinModuleChain(); - // === Pass 2: Process comptime and function bodies === + // Note: preCreateExportedFuncEntries and resolveBuiltinModuleChain + // were moved to semaAnalyze to match the Zig compiler's entry order. for (uint32_t d = 0; d < decls_len; d++) { uint32_t decl_inst = decl_list[d]; uint32_t payload @@ -9391,26 +9468,42 @@ SemaFuncAirList semaAnalyze(Sema* sema) { // this order so that InternPool indices agree. if (sema->code.inst_len > 0 && sema->source_dir) { if (sema->module_root) { - // Load std.zig first, matching the Zig compiler's order. - // The Zig compiler creates: + // Match the Zig compiler's module loading order. + // std.zig's comptime blocks force loading start.zig and + // debug.zig, then debug.assert entries are created, then + // the root module is loaded. + // + // Zig compiler sequence: // $124 = std.zig struct - // $125 = start.zig struct (from std's imports) + // $125 = start.zig struct (std comptime: _ = start) // $126 = ptr_type(*const type) // $127 = ptr_nav (start in std) - // $128 = debug.zig struct (from std's imports) + // $128 = debug.zig struct (std comptime: debug.assert) // $129 = ptr_nav (debug in std) - // ... + // $130 = func_type fn(bool) void (debug.assert type) + // $131 = func_decl (debug.assert) + // $132 = ptr_type (*const fn) + // $133 = ptr_nav (assert in debug) + // $134 = memoized_call (assert result = void) // $135 = root module struct + // $136 = ptr_nav (root in start.zig) + // $137+ = std/builtin.zig chain char std_path[1024]; snprintf(std_path, sizeof(std_path), "%s/lib/std/std.zig", sema->module_root); uint32_t std_file_idx = ensureFileAnalyzedC(std_path); - // Load start.zig and debug.zig from std's namespace, - // matching the Zig compiler's work queue processing order. + uint32_t start_file_idx = UINT32_MAX; + uint32_t debug_file_idx = UINT32_MAX; if (std_file_idx != UINT32_MAX) { - resolveNamedImport(std_file_idx, "start"); - resolveNamedImport(std_file_idx, "debug"); + // Load start.zig and debug.zig from std's namespace, + // matching the Zig compiler's work queue processing. + start_file_idx = resolveNamedImport(std_file_idx, "start"); + debug_file_idx = resolveNamedImport(std_file_idx, "debug"); + + // Create debug.assert entries ($130-$134), matching + // std.zig's comptime { debug.assert(...) } block. + resolveDebugAssertEntries(debug_file_idx); } // Register the root module at the next available file_idx. @@ -9424,7 +9517,13 @@ SemaFuncAirList semaAnalyze(Sema* sema) { root_mod->analyzed = true; s_root_file_idx = root_file_idx; (void)createFileRootStructC(root_file_idx, &sema->code); - resolveModuleDeclImports(root_file_idx, 2); + + // Create ptr_nav for "root" in start.zig ($136), + // matching start.zig's comptime { _ = root; }. + resolveRootInStartModule(start_file_idx, root_file_idx); + + // Load std/builtin.zig chain ($137+). + resolveBuiltinModuleChain(); } else { // No module root — root module is file_idx=0. if (s_num_loaded_modules == 0) {