From 43a30e727d171f42f5edf4d3e225f0d4d3fbf2d7 Mon Sep 17 00:00:00 2001 From: agra Date: Tue, 19 May 2026 11:51:20 +0300 Subject: [PATCH] imports: read resolved C-import paths after mutation, not before MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Latent bug from the stdlib-path resolution introduced in 4849cfb. The earlier shape captured `const ci = decl.data.c_import_decl;` BEFORE mutating `decl.data.c_import_decl.{sources,includes}` with the resolved paths, then passed the stale `ci.includes` to `c_import.processCImport`. Result: `#include "vendors/..."` paths that resolved via the stdlib branch (i.e. only existed under sx/library/vendors/) reached clang as the original unresolved string and failed to parse — silently producing no synthesized `#foreign` decls. `#source` survived because the source list is re-read from decl.data later (collectCImportSources walks the AST), so it picked up the mutated value. Only `#include`'s synthesis path was broken. Fix: do the resolution first inside its own scope, then re-bind `ci` from `decl.data.c_import_decl` so the include list passed to processCImport sees the resolved paths. Caught by ffi-07 baseline (next commit) — the test deliberately puts its C helper only under library/vendors/ so the path is findable solely via the stdlib chain. --- src/imports.zig | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/imports.zig b/src/imports.zig index 1c1761e..25c909b 100644 --- a/src/imports.zig +++ b/src/imports.zig @@ -200,27 +200,29 @@ pub fn resolveImports( for (root.data.root.decls) |decl| { if (decl.data == .c_import_decl) { - const ci = decl.data.c_import_decl; - // Resolve `#source` / `#include` paths through the same chain // as `#import`: importing-file's directory → CWD → stdlib // search paths. This lets sx-library modules ship their own // C helpers (e.g. the Android JNI insets bridge) without // forcing every consumer to vendor an identically-named copy. - if (ci.sources.len > 0) { - var resolved = try allocator.alloc([]const u8, ci.sources.len); - for (ci.sources, 0..) |raw_src, idx| { - resolved[idx] = try resolveImportPath(allocator, io, base_dir, raw_src, null, stdlib_paths); + { + const ci_pre = decl.data.c_import_decl; + if (ci_pre.sources.len > 0) { + var resolved = try allocator.alloc([]const u8, ci_pre.sources.len); + for (ci_pre.sources, 0..) |raw_src, idx| { + resolved[idx] = try resolveImportPath(allocator, io, base_dir, raw_src, null, stdlib_paths); + } + decl.data.c_import_decl.sources = resolved; } - decl.data.c_import_decl.sources = resolved; - } - if (ci.includes.len > 0) { - var resolved = try allocator.alloc([]const u8, ci.includes.len); - for (ci.includes, 0..) |raw_inc, idx| { - resolved[idx] = try resolveImportPath(allocator, io, base_dir, raw_inc, null, stdlib_paths); + if (ci_pre.includes.len > 0) { + var resolved = try allocator.alloc([]const u8, ci_pre.includes.len); + for (ci_pre.includes, 0..) |raw_inc, idx| { + resolved[idx] = try resolveImportPath(allocator, io, base_dir, raw_inc, null, stdlib_paths); + } + decl.data.c_import_decl.includes = resolved; } - decl.data.c_import_decl.includes = resolved; } + const ci = decl.data.c_import_decl; // Parse headers to get synthetic function declarations const result = c_import.processCImport(