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:
| M | stage0/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];