diff --git a/stage0/CLAUDE.md b/stage0/CLAUDE.md index cb715709d1..e4055869e9 100644 --- a/stage0/CLAUDE.md +++ b/stage0/CLAUDE.md @@ -121,6 +121,25 @@ entries so that IP indices in the function body AIR match. verify progress after each batch, not to plan the entire implementation upfront. +### Anti-pattern: analysis paralysis / proving work unnecessary + +When the gap is large (hundreds of entries), the temptation is to spend rounds +analyzing whether the entries are "really needed" or whether a shortcut exists. +**This is always wrong.** The entries are needed — the test comparison is +byte-for-byte with no IP base adjustment. + +Signs you are bailing out: +- Asking "does the AIR actually reference non-pre-interned IP indices?" +- Exploring "what if we DON'T create module-level entries?" +- Running verbose-air dumps to prove the function body is simple +- Suggesting the IP count "might not matter" + +The correct response to a large gap: +1. Fix the immediate crash/assertion (e.g. increase buffer sizes) +2. Port the next upstream function that creates entries +3. Test, measure gap reduction, commit +4. Repeat + ## AIR comparison exceptions C and Zig AIR must match byte-by-byte except: diff --git a/stage0/sema.c b/stage0/sema.c index 3da00ada7d..4a0b3f88c3 100644 --- a/stage0/sema.c +++ b/stage0/sema.c @@ -39,7 +39,7 @@ static uint32_t s_exported_decl_names[MAX_EXPORTED_DECL_NAMES]; // Zig compiler's module-level analysis. Each imported file module gets // a type_struct IP entry, created lazily when the module is first // accessed during semantic analysis. -#define MAX_LOADED_MODULES 256 +#define MAX_LOADED_MODULES 512 typedef struct { char path[1024]; // canonical file path char source_dir[1024]; // directory containing this file @@ -59,7 +59,7 @@ static InternPool* s_module_ip; // IP for struct type creation // --- Namespace storage --- // Ported from Zcu.Namespace. -#define MAX_NAMESPACES 128 +#define MAX_NAMESPACES 512 static SemaNamespace s_namespaces[MAX_NAMESPACES]; static uint32_t s_num_namespaces; @@ -2453,10 +2453,21 @@ static bool resolveImportPath(const char* source_dir, const char* import_path, if (rel[0] == '.' && rel[1] == '/') rel += 2; + // Relative or absolute paths: resolve from source_dir. if (import_path[0] == '.' || import_path[0] == '/') { snprintf(out_full, out_size, "%s/%s", source_dir, rel); return true; } + + // Imports with a file extension (e.g. "BitStack.zig") are resolved + // relative to the current module's source directory. + const char* dot = strrchr(import_path, '.'); + if (dot && strcmp(dot, ".zig") == 0) { + snprintf(out_full, out_size, "%s/%s", source_dir, import_path); + return true; + } + + // Bare module names (e.g. "std") resolve via module_root. if (s_global_module_root) { snprintf(out_full, out_size, "%s/lib/%s/%s.zig", s_global_module_root, import_path, import_path); @@ -9025,7 +9036,7 @@ SemaFuncAirList semaAnalyze(Sema* sema) { s_loaded_modules[0].has_zir = true; s_loaded_modules[0].analyzed = true; (void)createFileRootStructC(0, &sema->code); - resolveModuleDeclImports(0, 3); + resolveModuleDeclImports(0, 2); } // If we have ZIR instructions, attempt to analyze the main struct diff --git a/stage0/sema.h b/stage0/sema.h index 9f279413a7..89e38196f1 100644 --- a/stage0/sema.h +++ b/stage0/sema.h @@ -113,7 +113,7 @@ typedef struct { // Groups declarations by owning type (file root struct, etc.). // Ported from Zcu.Namespace. -#define SEMA_NS_MAX_NAVS 256 +#define SEMA_NS_MAX_NAVS 1024 #define SEMA_NS_MAX_COMPTIME 64 typedef struct { diff --git a/stage0/zig0.c b/stage0/zig0.c index 041457c31b..344f6248f4 100644 --- a/stage0/zig0.c +++ b/stage0/zig0.c @@ -15,8 +15,9 @@ // - code = 0: program successfully terminated. // - code = 1: panicked, panic message in msg. Caller should free msg. // - code = 2: interpreter error, error in msg. Caller should free msg. -static int zig0Run(const char* program, bool verbose_air, - bool verbose_intern_pool, char** msg) { +static int zig0Run(const char* program, const char* source_dir, + const char* module_root, bool verbose_air, bool verbose_intern_pool, + char** msg) { uint32_t len = (uint32_t)strlen(program); Ast ast = astParse(program, len); if (ast.has_error) { @@ -46,6 +47,8 @@ static int zig0Run(const char* program, bool verbose_air, InternPool ip = ipInit(); Sema sema; semaInit(&sema, &ip, zir); + sema.source_dir = source_dir; + sema.module_root = module_root; SemaFuncAirList func_airs = semaAnalyze(&sema); if (verbose_intern_pool) verboseIpPrint(stderr, &ip); @@ -98,7 +101,37 @@ int zig0RunFile(const char* fname, bool verbose_air, bool verbose_intern_pool, fclose(f); program[fsize] = 0; - int code = zig0Run(program, verbose_air, verbose_intern_pool, msg); + // Compute source_dir (dirname of fname) for import resolution. + char source_dir[1024] = { 0 }; + { + const char* last_slash = strrchr(fname, '/'); + if (last_slash) { + size_t len = (size_t)(last_slash - fname); + if (len >= sizeof(source_dir)) + len = sizeof(source_dir) - 1; + memcpy(source_dir, fname, len); + source_dir[len] = '\0'; + } + } + + // Derive module_root: walk up from source_dir to find the repo root. + // For paths like .../lib/compiler_rt/neghf2.zig, module_root is the + // directory containing "lib/". Heuristic: strip /lib/... suffix. + char module_root[1024] = { 0 }; + { + const char* lib_pos = strstr(source_dir, "/lib/"); + if (lib_pos) { + size_t len = (size_t)(lib_pos - source_dir); + if (len >= sizeof(module_root)) + len = sizeof(module_root) - 1; + memcpy(module_root, source_dir, len); + module_root[len] = '\0'; + } + } + + int code + = zig0Run(program, source_dir, module_root[0] ? module_root : NULL, + verbose_air, verbose_intern_pool, msg); free(program); return code; }