Fix imported module bindings shadowing shadowable builtins
## Summary Imported modules can mis-resolve a module-local binding that has the same name as a shadowable builtin. A direct call to the imported user binding works, but another exported function from the same module can lower its internal bare reference to the builtin instead. Issue reported by Greg ([@prosumma](https://gitlab.com/prosumma)) This currently affects both execution backends: - `kit check` accepts the program. - `kit run` calls the direct imported binding correctly, then fails inside the indirect call with `[E003] Type mismatch`. - `kit build` compiles successfully, but the compiled binary prints the wrong value for the indirect call. ## Minimal Reproduction Create these two files in a scratch directory. `lib_map.kit`: ```kit module Lib_map export map = fn(f, p, s: String) => match p s | Ok (o, r) -> Ok (f o, r) | Err e -> Err e export wrap = fn(p, s: String) => map (fn(o) => o) p s export cp = fn(s: String) => Ok (7, s) ``` `use_map.kit`: ```kit module Main import "./lib_map.kit".{wrap, cp, map} main = fn(-env: Env) => println (map (fn(o) => o) cp "x") println (wrap cp "x") main ``` Run: ```bash zig build run -- check use_map.kit --no-spinner zig build run -- run use_map.kit zig build run -- build use_map.kit -o use_map_bin --no-spinner ./use_map_bin ``` ## Actual Behavior Observed against the current Zig implementation: ```text check: passes cleanly run: Ok((7, x)) [E003] Type mismatch build output: Ok((7, x)) [] ``` The lowered IL for `wrap` contains a builtin call: ```text v6 = builtin:map(anon_2, v3, v5) ``` The direct call from the importing file lowers to the imported user binding, so the failure is specifically inside the imported module's own internal reference. ## Expected Behavior Both calls should resolve to the exported user-defined `map` binding and both backends should print: ```text Ok((7, x)) Ok((7, x)) ``` `kit check`, `kit run`, and `kit build` should agree. ## Suspected Cause The issue appears to be in IL lowering for path imports: - while loading imports, module declarations are ignored so exports remain unqualified; - `export map = ...` registers a bare global named `map`; - later, `emitCall` sees a bare global named `map` and converts it to the builtin `map`; - the direct import path still has a path-qualified imported binding, which is why `map ...` in the importer works while `wrap`'s internal `map ...` does not. `map` should remain shadowable; adding it to the unshadowable builtin list would be the wrong fix because functional packages legitimately export combinators named `map`. ## Proposed Solution Fix the resolver/lowering root cause so imported module internals resolve module-local top-level bindings before builtin fallback. A focused approach: 1. When lowering a path-imported module, register module-local top-level bindings under a unique module/path-scoped internal global as well as any exported public name. 2. Make `registered_globals` for the imported module map the bare source name, such as `map`, to that scoped internal global while lowering other functions from the same module. 3. Ensure `emitCall` only emits a builtin call for bare builtin names that were not resolved to a user-defined/scoped registered global first. 4. Keep direct imports using the existing path-qualified export binding so multiple imported modules can export the same name without collision. ## Regression Coverage Add a two-file regression fixture matching the reproduction above. Acceptance criteria: - `zig build run -- check use_map.kit --no-spinner` passes. - `zig build run -- run use_map.kit` prints `Ok((7, x))` twice. - `zig build run -- build use_map.kit -o use_map_bin --no-spinner && ./use_map_bin` prints `Ok((7, x))` twice. - `zig build run -- il use_map.kit` does not lower `wrap`'s internal call as `builtin:map`.
issue