ir: whole-program passes pin the source context per decl (fix 0122)

convergeClosureShapeSets, checkErrorFlow, and the unknown-type loop ran
under whatever current_source_file the previous phase left behind —
closure-literal annotations resolved (and reject/unknown-type
diagnostics rendered) against an arbitrary module. Latent while std.sx
was a single file (the ambient happened to be the main file); the
re-export facade restructure exposed it. Each walk now pins
setCurrentSourceFile per decl / per fn (body.source_file is already
stamped by resolveImports). Coverage: examples 0129/1047/1049/1052/
1053/1056 against the facade std.sx. Gates: zbt 426/426, suite 588/588.
This commit is contained in:
agra
2026-06-11 19:24:46 +03:00
parent 721369a711
commit 340be402a5
4 changed files with 84 additions and 0 deletions

View File

@@ -71,12 +71,19 @@ pub const ErrorFlow = struct {
/// this conservative check would over-reject), so they are skipped.
pub fn checkErrorFlow(self: ErrorFlow, decls: []const *const Node) void {
if (self.l.diagnostics == null) return;
const saved_file = self.l.current_source_file;
defer self.l.setCurrentSourceFile(saved_file);
for (decls) |decl| {
if (self.l.main_file) |mf| {
if (decl.source_file) |sf| {
if (!std.mem.eql(u8, sf, mf)) continue;
}
}
// Pin the visibility context (and diagnostic rendering) to the
// decl's own module — the flow walk resolves types via
// inferExprType, and the ambient file the previous phase left
// behind is arbitrary (issue 0122).
if (decl.source_file) |sf| self.l.setCurrentSourceFile(sf);
switch (decl.data) {
.fn_decl => |fd| self.analyzeFnBody(fd.body),
.const_decl => |cd| {