Context
When a public property is a TypeSpec union, the C# emitter renders it as BinaryData and records the union item types as metadata on the CSharpType. ProviderReferenceMapAnalyzer treats those union item types as references, which keeps the variant models from being removed as unreferenced.
This is deliberate and explicitly tested. ProviderReferenceMapAnalyzerTests.BinaryDataUnionPropertyDoesNotPublicizeInternalUnionMembers, added in #11288 ("Fix C# reference-map accessibility for hidden union types"), covers an internal variant reachable only through a public BinaryData union property:
Assert.IsTrue(internalVariant.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal));
Assert.IsFalse(internalVariant.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public));
Assert.IsTrue(ProviderReferenceMapAnalyzer.ShouldWriteProvider(internalVariant));
So the analyzer keeps the variant while refusing to publicize it. UnionItemTypeReferenceKind.MetadataOnly is the opt-out, asserted by the sibling test MetadataOnlyUnionPropertyDoesNotReferenceUnionMember.
The question
For a variant that stays internal, keeping it looks like dead weight:
- Consumers cannot name or construct the type, so it cannot be passed to the
BinaryData property it exists for.
- Nothing else in the generated library references it.
- It still costs generated source, assembly size, and a
[ModelReaderWriterBuildable] entry in the MRW context.
A concrete example is Azure.AI.Projects.Agents, where DeclarativeAgentDefinition.ToolChoice is a public BinaryData union whose variants all land as internal in the OpenAI namespace — roughly 20 model classes plus serialization and context entries that no consumer can use. See Azure/azure-sdk-for-net#62649 and the discussion on #11839.
Ask
Determine whether there is a functional reason for retaining internal union variants, for example:
- serialization or
ModelReaderWriter round-tripping that resolves them by name or through the MRW context,
- polymorphic deserialization of the discriminated hierarchy behind the union,
- internal client code paths that construct them,
- or a deliberate choice to keep the type available for future public exposure / customization.
If a real dependency exists, document it next to the union handling in ProviderReferenceMapAnalyzer so it is not mistaken for an oversight. If not, consider treating an internal-only union variant the same as MetadataOnly so it is removed, and update the BinaryDataUnionPropertyDoesNotPublicizeInternalUnionMembers expectation accordingly.
Note this is independent of API compatibility processing. It reproduces on a freshly generated library with a public BinaryData union over internal variants.
Related
Context
When a public property is a TypeSpec union, the C# emitter renders it as
BinaryDataand records the union item types as metadata on theCSharpType.ProviderReferenceMapAnalyzertreats those union item types as references, which keeps the variant models from being removed as unreferenced.This is deliberate and explicitly tested.
ProviderReferenceMapAnalyzerTests.BinaryDataUnionPropertyDoesNotPublicizeInternalUnionMembers, added in #11288 ("Fix C# reference-map accessibility for hidden union types"), covers an internal variant reachable only through a publicBinaryDataunion property:So the analyzer keeps the variant while refusing to publicize it.
UnionItemTypeReferenceKind.MetadataOnlyis the opt-out, asserted by the sibling testMetadataOnlyUnionPropertyDoesNotReferenceUnionMember.The question
For a variant that stays internal, keeping it looks like dead weight:
BinaryDataproperty it exists for.[ModelReaderWriterBuildable]entry in the MRW context.A concrete example is
Azure.AI.Projects.Agents, whereDeclarativeAgentDefinition.ToolChoiceis a publicBinaryDataunion whose variants all land asinternalin theOpenAInamespace — roughly 20 model classes plus serialization and context entries that no consumer can use. See Azure/azure-sdk-for-net#62649 and the discussion on #11839.Ask
Determine whether there is a functional reason for retaining internal union variants, for example:
ModelReaderWriterround-tripping that resolves them by name or through the MRW context,If a real dependency exists, document it next to the union handling in
ProviderReferenceMapAnalyzerso it is not mistaken for an oversight. If not, consider treating an internal-only union variant the same asMetadataOnlyso it is removed, and update theBinaryDataUnionPropertyDoesNotPublicizeInternalUnionMembersexpectation accordingly.Note this is independent of API compatibility processing. It reproduces on a freshly generated library with a public
BinaryDataunion over internal variants.Related