Skip to content

fix: disambiguate colliding WIT import names#1562

Draft
jsturtevant wants to merge 10 commits into
mainfrom
jsturtevant/component-util-collisions
Draft

fix: disambiguate colliding WIT import names#1562
jsturtevant wants to merge 10 commits into
mainfrom
jsturtevant/component-util-collisions

Conversation

@jsturtevant

@jsturtevant jsturtevant commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Stacks on #1331.

When two WIT packages export an interface with the same short name, the generated Rust trait has duplicate members and fails to compile. For example:

// a:pkg/types and b:pkg/types — both named "types"
world bindgen-test-cases {
    import a:pkg/types;
    import b:pkg/types;
}

After this fix, the full namespace is prepended per component to produce unique names:

impl BindgenTestCasesImports for MyHost {
    type APkgTypes = Self;   // was: type Types (duplicate!)
    fn a_pkg_types(&mut self) -> &mut Self { self }

    type BPkgTypes = Self;   // was: type Types (duplicate!)
    fn b_pkg_types(&mut self) -> &mut Self { self }
}

Two imports from the same package at different versions — the version is appended:

world my-component {
    import a:pkg/types@1.0.0;
    import a:pkg/types@2.0.0;
}
impl MyComponentImports for MyHost {
    type APkgTypesV100 = Self;
    fn a_pkg_types_v1_0_0(&mut self) -> &mut Self { self }

    type APkgTypesV200 = Self;
    fn a_pkg_types_v2_0_0(&mut self) -> &mut Self { self }
}

Also fixes a secondary collision where namespace components themselves contain hyphens (e.g. a:b-c/types vs a-b:c/types). Flat-joining with - collapsed both to ABCTypes; per-component first-letter capitalisation now gives ABcTypes vs AbCTypes.

@jsturtevant jsturtevant added the kind/bugfix For PRs that fix bugs label Jun 18, 2026
@jsturtevant jsturtevant marked this pull request as draft June 18, 2026 23:33
@jsturtevant

Copy link
Copy Markdown
Contributor Author

This will be ontop of #1331

@jsturtevant jsturtevant force-pushed the jsturtevant/component-util-collisions branch 2 times, most recently from 736b4f5 to 6ff506c Compare June 18, 2026 23:51
@jsturtevant jsturtevant changed the base branch from component-util-fixes to main June 19, 2026 15:36
When multiple WIT packages export an interface with the same name
(e.g. a:pkg/types and b:pkg/types), the generated Rust traits have
duplicate associated types and getters, causing compilation to fail.

Add collision detection that scans import declarations for duplicate
interface names. When a collision is found, the full namespace path is
prepended to produce unique names (e.g. APkgTypes vs BPkgTypes).
Apply this to host, guest, and runtime type generation, and extend it
to handle versioned import name collisions where two versioned imports
share the same namespace path.

Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Add deps/a-pkg/types.wit and deps/b-pkg/types.wit to the
bindgen-test-cases WIT fixture. Both define an interface named
"types", creating a name collision that exercises the disambiguation
logic added in the previous commit.

Extend the world to import both packages and add collision host tests
to the existing bindgen_test_cases test module, covering:
- distinct generated record types (collision_types_are_distinct)
- separate host trait impl per colliding interface (collision_host_impl_compiles)

Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
When two WIT packages differ only at the colon/slash boundary and both
components contain hyphens (e.g. a:b-c vs a-b:c), flat-joining the
namespace array with '-' produces the same string ('a-b-c') for both,
and thus the same disambiguated Rust type name.

Fix this by introducing component_first_camel(), which capitalizes only
the first letter of each namespace component (removing internal hyphens
without capitalizing sub-words). Concatenating per-component results
preserves boundary info: ['a', 'b-c'] -> 'ABcTypes' is distinct from
['a-b', 'c'] -> 'AbCTypes'. Getter names are unchanged.

Add a unit test covering the pathological case.

Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
@jsturtevant jsturtevant force-pushed the jsturtevant/component-util-collisions branch from 8541352 to 277b64c Compare June 19, 2026 15:58
Extends the bindgen-test-cases WIT fixture with four additional imports
to cover edge cases identified in code review:

- a:b-c/types and a-b:c/types (hyphenated namespace components): verify
  that packages whose namespace paths differ only by hyphen placement
  produce distinct Rust names. Flat-joining both with '-' gives the
  same 'a-b-c' string; the per-component strip-and-join approach
  produces 'ABcTypes'/'a_bc_types' vs 'AbCTypes'/'ab_c_types'.

- c:pkg/types@1.0.0 and c:pkg/types@2.0.0 (versioned): verify that
  two versions of the same package interface are disambiguated by
  appending the version: CPkgTypesV100 and CPkgTypesV200.

Also fixes the getter-name collision for hyphenated namespace components.
Previously the getter prefix was built with wn.namespaces.join("-"),
which is not injective: ["a", "b-c"] and ["a-b", "c"] both flatten to
"a-b-c" -> "a_b_c_types". The fix strips internal hyphens within each
component and joins at colon/slash boundaries with "_", giving
"a_bc_types" vs "ab_c_types".

New dep WIT packages:
  deps/a-bc/types.wit  (a:b-c)
  deps/ab-c/types.wit  (a-b:c)
  deps/c-pkg-v1/types.wit  (c:pkg@1.0.0)
  deps/c-pkg-v2/types.wit  (c:pkg@2.0.0)

New integration tests in bindgen_test_cases module:
  versioned_collision_types_are_distinct
  hyphenated_namespace_collision_types_are_distinct

Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bugfix For PRs that fix bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant