From 48bebda68704692d42da9005359fc97699d65f57 Mon Sep 17 00:00:00 2001 From: Charles KWON OhJun Date: Thu, 28 May 2026 14:33:20 +0900 Subject: [PATCH] fix(gengo): hoist every BEGINDUMP-supplied import, not just fmt/strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit doGenerate's deferred-imports patch handled only "fmt" and "strings" — enough for inline RTL but a dead end for #pragma BEGINDUMP blocks that import third-party / private packages (e.g. solmade's internal/dartapi). hoistGoImports() registered every imported path in g.imports correctly, but the final placeholder replacement never emitted them, so the generated .go file's import block stayed incomplete and `go build` failed with "undefined: dartapi". Now every entry of g.imports that isn't already in the header gets appended to the DEFERRED_IMPORTS substitution. Sorted output for stable diffs. Verified: a 4-line BEGINDUMP block in /tmp/poc_dartapi.prg that imports "encoding/json" + "gitea.fivego.org/kwon_ai/solmade/internal/dartapi" now compiles into a single 23 MB binary that calls dartapi.AllAliases() at run time and returns the real count (3). Full Five regression: go test compiler/, compat 56/56, std.ch 17/17, FRB 7/7 all pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- compiler/gengo/gengo.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/gengo/gengo.go b/compiler/gengo/gengo.go index 28e72e8..82025af 100644 --- a/compiler/gengo/gengo.go +++ b/compiler/gengo/gengo.go @@ -180,14 +180,29 @@ func doGenerate(file *ast.File, debug, library bool) string { } g.emitSymCache() - // Patch deferred imports: inline RTL may add "fmt"/"strings" after header was emitted. + // Patch deferred imports: emitDecl may add to g.imports after the + // header was written. The common cases are inline RTL pulling in + // "fmt"/"strings", but #pragma BEGINDUMP blocks can also hoist + // third-party / private modules (e.g. solmade's internal/dartapi). + // Dump every import not already in the header so external Go + // packages used inside BEGINDUMP actually link. result := g.buf.String() - var deferred string - if g.imports["fmt"] && !strings.Contains(result, "\"fmt\"") { - deferred += "\t\"fmt\"\n" + var deferredLines []string + for imp := range g.imports { + if strings.Contains(result, "\""+imp+"\"") { + continue // already emitted in the initial import block + } + if alias, ok := g.importAlias[imp]; ok && alias != "" { + deferredLines = append(deferredLines, fmt.Sprintf("\t%s %q", alias, imp)) + } else { + deferredLines = append(deferredLines, fmt.Sprintf("\t%q", imp)) + } } - if g.imports["strings"] && !strings.Contains(result, "\"strings\"") { - deferred += "\t\"strings\"\n" + // Sorted for deterministic diffs. + sort.Strings(deferredLines) + deferred := strings.Join(deferredLines, "\n") + if deferred != "" { + deferred += "\n" } result = strings.Replace(result, "\t/*DEFERRED_IMPORTS*/\n", deferred, 1) // Patch guards