Semantic Diff

#9301 Keep a namespaced package's dev modules out of its namespace

3 commits

9523348b1b8aef3e12ae1688f3e22dfa52368483..pr-9301

a559fd009 · cknitt + Claude · Nov 14, 2026, 08:57 UTC

Keep a namespaced package's dev modules out of its namespace

Why

The namespace map aliased every module of a package, its dev modules too. A package that opened a dependency's namespace got the dependency's dev modules in scope, which shadowed its own modules of the same name (#9089, #6679). The namespace map also depended on the dev modules, so a dev test that used the namespace entry was a dependency cycle.

The namespace map now holds only the regular modules. The dev modules get a second map, Ns-dev, which only the package's own dev modules open. bsc takes the alias targets from the map's file name, so it is dev/Ns.mlmap, compiled with -o Ns-dev. The new bsc flag -bs-open-alias-map opens it without recording its interface CRC, as -bs-ns does for the namespace; otherwise adding a dev module would break every dev module compiled against the previous dev map. The module graph and the editor analysis follow the same rule.

removedDiagnostic open of a dependency's namespace

// provider/test/Config.res (dev): let other = 2// consumer/test/Config.res (dev): let get = () => 3// consumer/test/Check.res (dev):open Providerlet value = Config.get()
diagnostic
Before
The value get can't be found in Config

removedDiagnostic dev test using the namespace entry

diagnostic
Before
Can't continue... Found a circular dependency in your code:@Provider (provider namespace map) → Provider.Local (provider/test/Local.res) → Entry (provider/src/Entry.res) → @Provider (provider namespace map)

modifiedRepresentation namespace maps of provider

text
Before
After
lib/rescript/Provider.mlmap: Config Local Public lib/rescript/Provider.mlmap: Publiclib/rescript/dev/Provider.mlmap (compiled to Provider-dev): Config Local

Fixes #9089

Review

  • Why a compiler flag and not a graph node for the dev map? The dev map only holds aliases, whose targets are recorded themselves, so its CRC does not need recording, the same reasoning as for -bs-ns. A graph node would recompile every dev module whenever one is added.
ebf93b752 · cknitt + Claude · Nov 14, 2026, 09:10 UTC

Give the output namespace and the alias maps separate flags fields

Clflags.dont_record_crc_unit did two jobs: it named the outputs (Config-Ns) and kept the namespace's CRC out of the recorded imports. It is now Clflags.namespace, for the names only. -bs-ns adds the namespace to Clflags.alias_maps like -bs-open-alias-map, and Env.imports skips exactly the alias maps. The command line and the outputs are unchanged.

80e2db1e9 · cknitt + Claude · Nov 14, 2026, 09:19 UTC

Open the dev map in the editor analysis for dev files only

Codex review: the analysis opened the dev map for every file of the package, so completion in a regular module suggested dev modules that the compiler now rejects there. The package keeps the dev map's open apart, and get_package adds it only for a file in a dev source directory, as the compiler does.