nandi/rustnimpublic Fork
⑂ d553b29
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Record the flat-namespace limit found by the dependency run

Every input file's items go into one Nim module, and the type tables are keyed
by bare name while `fns` is keyed by `(module, name)`. Across 356 dependency
crates that is 14,714 distinct type names of which 1,575 are defined more than
once -- `Output` 8,963 times, `Error` 3,372.

Found where `color_quant`'s `type Color = Quad<i32>` replaced `anstyle`'s
`enum Color`, after which anstyle's own `match` was a pattern against `Quad`.

Written down rather than fixed: the remedy is to key the type tables the way
`fns` is already keyed and qualify emitted names on collision, which reshapes
the lowering rather than patching it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T13:39:18-07:00 Browse files
d553b29 parent: 8194456
modified DESIGN.md +39 -0
@@ -1268,3 +1268,42 @@ this, because handling it needs a whole-program view: the disambiguation has
12681268 to be consistent across every use, and which of a colliding pair gets renamed
12691269 cannot be decided one identifier at a time. Untouched for now, and recorded so
12701270 it is not rediscovered as a mystery.
1271+
1272+### The flat namespace does not survive a dependency graph
1273+
1274+rustnim puts every input file's items into one Nim module. With a handful of
1275+files that is the right call — it is what makes cross-file calls work without
1276+modelling Rust's module system. With 357 crates it breaks, and the way it
1277+breaks is worth being precise about.
1278+
1279+`self.fns` is keyed by `(module, name)`. `self.structs`, `self.enums`,
1280+`self.aliases` and `self.methods` are keyed by the bare name. So a type in one
1281+crate silently replaces a same-named type in another. The case that found it:
1282+
1283+```rust
1284+// anstyle
1285+pub enum Color { Ansi(AnsiColor), Ansi256(..), Rgb(..) }
1286+// color_quant
1287+type Color = Quad<i32>;
1288+```
1289+
1290+`color_quant`'s alias wins, and `anstyle`'s `match self { Color::Ansi(c) => .. }`
1291+is then a pattern against `Quad`. rustnim says so and stops, which is the
1292+founding rule working — but it stops on a name clash, not on anything about
1293+the program.
1294+
1295+Counting across the 356 dependency crates: **14,714 distinct type names, of
1296+which 1,575 are defined in more than one place.** `Output` appears 8,963
1297+times, `Error` 3,372, `Item` 1,838. This is not a tail to chip away at; it is
1298+the normal shape of a Rust dependency graph, where every crate is its own
1299+namespace.
1300+
1301+Separately, 29 of those names collide only under *Nim's* identifier equality
1302+(case-insensitive after the first character, underscore-insensitive) — the
1303+hazard recorded above, at graph scale.
1304+
1305+The fix is the one already used for functions: key the type tables by
1306+`(module, name)`, resolve by preferring the current module and then a unique
1307+global match, and qualify the emitted Nim name where a bare one would clash.
1308+That is a real change to the shape of the lowering, not an incremental patch,
1309+which is why it is written down here rather than attempted in passing.
@@ -1268,3 +1268,42 @@ this, because handling it needs a whole-program view: the disambiguation has
1268 to be consistent across every use, and which of a colliding pair gets renamed1268 to be consistent across every use, and which of a colliding pair gets renamed
1269 cannot be decided one identifier at a time. Untouched for now, and recorded so1269 cannot be decided one identifier at a time. Untouched for now, and recorded so
1270 it is not rediscovered as a mystery.1270 it is not rediscovered as a mystery.
1271+
1272+### The flat namespace does not survive a dependency graph
1273+
1274+rustnim puts every input file's items into one Nim module. With a handful of
1275+files that is the right call — it is what makes cross-file calls work without
1276+modelling Rust's module system. With 357 crates it breaks, and the way it
1277+breaks is worth being precise about.
1278+
1279+`self.fns` is keyed by `(module, name)`. `self.structs`, `self.enums`,
1280+`self.aliases` and `self.methods` are keyed by the bare name. So a type in one
1281+crate silently replaces a same-named type in another. The case that found it:
1282+
1283+```rust
1284+// anstyle
1285+pub enum Color { Ansi(AnsiColor), Ansi256(..), Rgb(..) }
1286+// color_quant
1287+type Color = Quad<i32>;
1288+```
1289+
1290+`color_quant`'s alias wins, and `anstyle`'s `match self { Color::Ansi(c) => .. }`
1291+is then a pattern against `Quad`. rustnim says so and stops, which is the
1292+founding rule working — but it stops on a name clash, not on anything about
1293+the program.
1294+
1295+Counting across the 356 dependency crates: **14,714 distinct type names, of
1296+which 1,575 are defined in more than one place.** `Output` appears 8,963
1297+times, `Error` 3,372, `Item` 1,838. This is not a tail to chip away at; it is
1298+the normal shape of a Rust dependency graph, where every crate is its own
1299+namespace.
1300+
1301+Separately, 29 of those names collide only under *Nim's* identifier equality
1302+(case-insensitive after the first character, underscore-insensitive) — the
1303+hazard recorded above, at graph scale.
1304+
1305+The fix is the one already used for functions: key the type tables by
1306+`(module, name)`, resolve by preferring the current module and then a unique
1307+global match, and qualify the emitted Nim name where a bare one would clash.
1308+That is a real change to the shape of the lowering, not an incremental patch,
1309+which is why it is written down here rather than attempted in passing.