zig

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

commit 7d03e6ebc1974770440c7349dcec02fa0c0ceb33 (tree)
parent a6e2b3fef2cfa181ae08af69290a09269858311d
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Thu, 26 Feb 2026 01:19:44 +0000

sema: add resolveBuiltinModuleChain for module-level IP entries

Port the module loading part of analyzeMemoizedState from
PerThread.zig. After the root module's exported function entries
($130-$134), the Zig compiler loads the builtin module chain:
  std → std/builtin.zig → compiler-generated builtin

This creates type_struct and ptr_nav entries $135-$139:
  $135 = type_struct (std/builtin.zig root)
  $136 = ptr_nav (builtin in std)
  $137 = type_struct (compiler-generated builtin)
  $138 = ptr_nav (builtin in std/builtin.zig)
  $139 = ptr_nav (std in std/builtin.zig)

Also adds findNavInNamespace helper for looking up Navs by name.

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

Diffstat:
Mstage0/sema.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 122 insertions(+), 0 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -2393,6 +2393,122 @@ static InternPoolIndex internNavPtr( return ipIntern(s_module_ip, key); } +// --- findNavInNamespace --- +// Look up a Nav by name in a namespace. The name is compared against +// the Nav's name string from the owning ZIR's string_bytes. +// Returns the Nav index, or UINT32_MAX if not found. + +static uint32_t findNavInNamespace(uint32_t ns_idx, const char* name) { + const SemaNamespace* ns = &s_namespaces[ns_idx]; + const Zir* zir = &s_loaded_modules[ns->file_idx].zir; + if (!s_loaded_modules[ns->file_idx].has_zir) + return UINT32_MAX; + + for (uint32_t i = 0; i < ns->pub_nav_count; i++) { + const Nav* nav = ipGetNav(ns->pub_navs[i]); + const char* nav_name = (const char*)&zir->string_bytes[nav->name]; + if (strcmp(nav_name, name) == 0) + return ns->pub_navs[i]; + } + for (uint32_t i = 0; i < ns->priv_nav_count; i++) { + const Nav* nav = ipGetNav(ns->priv_navs[i]); + const char* nav_name = (const char*)&zir->string_bytes[nav->name]; + if (strcmp(nav_name, name) == 0) + return ns->priv_navs[i]; + } + return UINT32_MAX; +} + +// Forward declaration for resolveModuleDeclImports (used below). +static void resolveModuleDeclImports(uint32_t file_idx, uint32_t depth); + +// --- resolveBuiltinModuleChain --- +// Ported from PerThread.zig analyzeMemoizedState (module loading part). +// After the root module and its direct imports are loaded, this function +// continues loading the module chain needed by @export resolution: +// std → std/builtin.zig → compiler-generated builtin → ... +// Creates type_struct and ptr_nav entries in the same order as the +// Zig compiler's demand-driven analysis. + +static void resolveBuiltinModuleChain(void) { + if (!s_module_ip || !s_global_module_root) + return; + + // Find std module among loaded modules. + uint32_t std_file_idx = UINT32_MAX; + for (uint32_t i = 0; i < s_num_loaded_modules; i++) { + const char* p = s_loaded_modules[i].path; + size_t plen = strlen(p); + // Match paths ending with "/std/std.zig" or "/std.zig" + if (plen >= 12 && strcmp(p + plen - 12, "/std/std.zig") == 0) { + std_file_idx = i; + break; + } + } + if (std_file_idx == UINT32_MAX) + return; + + // Find `builtin` Nav in std's namespace. + // In std.zig: `pub const builtin = @import("builtin.zig");` + uint32_t std_ns_idx = s_file_namespace[std_file_idx]; + uint32_t builtin_nav = findNavInNamespace(std_ns_idx, "builtin"); + if (builtin_nav == UINT32_MAX) + return; + + // Load std/builtin.zig → creates type_struct entry. + char builtin_path[1024]; + snprintf(builtin_path, sizeof(builtin_path), "%s/builtin.zig", + s_loaded_modules[std_file_idx].source_dir); + uint32_t builtin_file_idx = ensureFileAnalyzedC(builtin_path); + if (builtin_file_idx == UINT32_MAX) + return; + + // Create ptr_nav for `builtin` in std's namespace. + // Matches analyzeNavRefInner for the `builtin` declaration. + Nav* bNav = ipGetNav(builtin_nav); + bNav->resolved_type = s_file_root_type[builtin_file_idx]; + InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE); + (void)internNavPtr(ptr_type, 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. + InternPoolIndex cg_struct = createModuleStructType(); + + // We don't have a real file for this, but we need a namespace + // and file entry so ptr_nav entries work correctly. + if (s_num_loaded_modules < MAX_LOADED_MODULES) { + uint32_t cg_file_idx = s_num_loaded_modules++; + LoadedModule* cg_mod = &s_loaded_modules[cg_file_idx]; + memset(cg_mod, 0, sizeof(*cg_mod)); + snprintf(cg_mod->path, sizeof(cg_mod->path), "<builtin>"); + cg_mod->analyzed = true; + s_file_root_type[cg_file_idx] = cg_struct; + uint32_t cg_ns_idx = createNamespace(cg_struct, cg_file_idx); + s_file_namespace[cg_file_idx] = cg_ns_idx; + + // Resolve the `builtin` Nav in std/builtin.zig's namespace. + Nav* cgNav = ipGetNav(cg_builtin_nav); + cgNav->resolved_type = cg_struct; + (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); + } +} + // --- findDeclImportPathFromZir --- // Given a declaration ZIR instruction, check if its value body contains // a ZIR_INST_IMPORT. Returns the import path string, or NULL. @@ -6338,6 +6454,12 @@ 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 === for (uint32_t d = 0; d < decls_len; d++) { uint32_t decl_inst = decl_list[d];