Skip to content

Make generated stunt names unique per constructed type - #317

Merged
kzu merged 1 commit into
mainfrom
alta/stout-gannet-qnx8
Oct 27, 2026
Merged

kzu merged 1 commit into
mainfrom
alta/stout-gannet-qnx8

Conversation

@kzu

@kzu kzu commented Oct 27, 2026

Copy link
Copy Markdown
Member

Generated stunt names only used simple type names, and array type arguments added nothing to the name. Different constructed types could therefore share one name: IList<int[]> and IList<string[]> (both IListOfStunt), IFoo<A.Bar> and IFoo<B.Bar>, or IFoo<Wrap<int>, string> and IFoo<Wrap<int, string>>. The generator deduplicated candidates by that name, so it generated only one of them, and the other call site failed at run time with a registry miss. Default-interface helper classes (DefaultIFooOfBar) had the same collision.

Changes

  • Array arguments are named: ArrayOfInt32, Array2DOfString, ArrayOfArrayOfInt32, in both NamingConvention and the run-time StuntNaming.
  • Deduplication uses run-time identity: NamingConvention.GetIdentity ignores type order, nullable annotations and tuple element names. So IFoo<(int a, int b)> and IFoo<(int, int)> still share one stunt.
  • Colliding names get a stable hash: when different types share a namespace-qualified name, all of them use GetUniqueName / GetUniqueDefaultImplementationName, which append an FNV-1a hash, for example IFooOfBarStunt_1a2b3c4d. Every colliding name gets the hash, so names don't depend on the order of the call sites. Names without a collision are unchanged.
  • Default helper collisions are found upfront: default helpers are named while stunts are processed in parallel, so their collisions are computed before processing and carried in ProcessorContext.AmbiguousDefaultImplementations.
  • One name per stunt: the stunt declaration, hint name and registration all use the name the generator chose.
  • Missing test attribute: added the missing [Fact] to StuntNamingTests.GenericOfTwoGenericNames, which never ran before.

Tests

  • StuntGeneratorTests.GeneratesConstructedTypesWithCollidingNames covers arrays (including rank 2), same-named arguments from different namespaces, ambiguous generic nesting, default members through the suffixed helpers, and tuple-name variants. It calls every factory and checks the returned stunt's type.
  • StuntNamingTests.ArrayArgumentNames covers the run-time names.
  • The full Stunts.UnitTests suite passes locally.

This pull request was created by CodeAlta, an AI coding agent.

@kzu
kzu enabled auto-merge (rebase) October 27, 2026 02:06
Stunt and default-interface helper names drop argument namespaces and
nesting, and array arguments added nothing to the name, so different
constructed types (IList<int[]>/IList<string[]>, IFoo<A.Bar>/IFoo<B.Bar>)
shared one name and the generator silently dropped all but one of them.

Deduplicate by run-time identity instead, name array arguments
(ArrayOfInt32, Array2DOfString), and append a stable hash to every name
that different types would share. Non-colliding names are unchanged.

Also add the missing [Fact] to StuntNamingTests.GenericOfTwoGenericNames.

Co-authored-by: CodeAlta <noreply@codealta.io>
Co-authored-by: Cursor <cursoragent@cursor.com>
@kzu
kzu force-pushed the alta/stout-gannet-qnx8 branch from 32e0e47 to e72783d Compare October 27, 2026 02:07
@kzu kzu added enhancement New feature or request bug Something isn't working and removed enhancement New feature or request labels Oct 27, 2026
@kzu
kzu merged commit 09ed419 into main Oct 27, 2026
5 checks passed
@kzu
kzu deleted the alta/stout-gannet-qnx8 branch October 27, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant