Deterministic Output
Reference index · Summary of this topic
Converter output is byte-reproducible: converting the same Go source with the same converter build produces byte-identical C# every run. This is a hard guarantee the goldens, the full-conversion error measurements, and any future release tag all rest on. Three mechanisms enforce it:
- Files convert sequentially, in sorted-filename order. The per-file visitors share package-level state claimed at
visit time —
initΔNmodule-initializer indices, blank-identifier temp numbering (_ᴛN), and imported collision-rename visibility — so converting files in concurrent goroutines would make claim order follow goroutine scheduling: a file could mark an importedpackage_info.cs“parsed” before the parse finished, and a concurrently-converting file would skip the wait and emit an imported renamed const bare (abi.Stringinstead ofabi.ΔString— a compile error that comes and goes with scheduling). Sequential conversion costs nothing measurable: a conversion’s time is dominated bygo/packagestype-graph loading, not emission. - The stdlib conversion queue is deterministic and dependency-complete. The topological sort walks sorted roots
(map-iteration roots would make unrelated packages’ order flip run-to-run), and a GOROOT-vendored dependency
(imported as
golang.org/x/…but keyed on disk asvendor/golang.org/x/…) is resolved to its vendored key. A dropped vendored edge would let an importer (e.g.x/text/secure/bidirule) convert before its dependency (x/text/unicode/bidi), whosepackage_info.cs— the source of imported collision-rename aliases likebidiꓸClass— would not exist yet at that point. - Multi-box re-alias emission is sorted. A multi-assignment that repoints several pointer boxes (
(Ꮡx, Ꮡy) = (Ꮡy, Ꮡx)) emits its independentn = ref Ꮡn.DerefOrNull()refreshers in sorted name order (the set backing them is a map;src/go2cs/visitAssignStmt.go,sortedLeftExprs).