microsoft / microsoft/typespec

[MRW Serialization] Emit JsonModelWriteCore and explicit interface members for abstract discriminated base models with known subtypes

Open
#10,797 2 comments 0 reactions 1 assignee Claimed by @live1206 View on GitHub
bug emitter:client:csharp
Dominant language
Java
Stars
5.9k
Forks
394
Avg merge
1d 23h
Merged PRs (30d)
104

Description

## Description

When a model is an abstract discriminated base with known derived types (via `discriminatedSubtypes`) but does NOT extend a system type (like `ResourceData` or `TrackedResourceData`), `MrwSerializationTypeDefinition` does not emit:

- `JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)` (protected virtual)
- `void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)` (explicit interface)
- `BinaryData IPersistableModel.Write(ModelReaderWriterOptions options)` (explicit interface)
- `T IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options)` (explicit interface)
- `string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options)` (explicit interface)

The model **does** emit:
- `PersistableModelCreateCore`
- `PersistableModelWriteCore`
- `JsonModelCreateCore`
- `Deserialize` (static)

## Impact

Derived types call `base.JsonModelWriteCore(writer, options)` to serialize base properties (discriminator, raw data). Without the base method, the generated code fails to compile.

The explicit interface implementations are needed so that the model satisfies the `IJsonModel` and `IPersistableModel` contracts required by the `ModelReaderWriter` framework.

## Expected Behavior

For abstract discriminated base models with known subtypes, `MrwSerializationTypeDefinition` should emit all serialization methods (both `*Core` methods and explicit interface implementations), regardless of whether the model extends a system type.

## Current Workaround

The Azure Management Generator (`InheritableSystemObjectModelVisitor`) defensively adds these methods via the visitor pattern if they are missing from MTG output. See: https://github.com/Azure/azure-sdk-for-net/issues/59437

## Minimum Reproduction

```typespec
import "@azure-tools/typespec-azure-resource-manager";

using Azure.ResourceManager;

@armProviderNamespace
@service(#{title: "TestService"})
@versioned(Versions)
@armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5)
namespace TestService;

enum Versions {
v2024_01_01: "2024-01-01",
}

interface Operations extends Azure.ResourceManager.Operations {}

// A tracked resource that references a standalone polymorphic model
model TestResource is TrackedResource {
...ResourceNameParameter;
}

model TestResourceProperties {
identifier: ResourceIdentifier;
}

@armResourceOperations
interface TestResources {
get is ArmResourceRead;
createOrUpdate is ArmResourceCreateOrReplaceAsync;
}

// Standalone discriminated base - NOT extending any system type (ResourceData, etc.)
// Has known derived types via @discriminator
@discriminator("type")
model ResourceIdentifier {
type: string;
}

// Known derived type - this creates discriminatedSubtypes on the base
model AzureResourceIdentifier extends ResourceIdentifier {
type: "AzureResource";
azureResourceId: string;
}
```

### Steps to reproduce

1. Compile the above TypeSpec with the C# management emitter
2. Check the generated `ResourceIdentifier.Serialization.cs`
3. Observe that `JsonModelWriteCore`, `IJsonModel.Write`, `IPersistableModel.Write/Create/GetFormatFromOptions` are missing
4. The generated `UnknownResourceIdentifier.Serialization.cs` (or `AzureResourceIdentifier.Serialization.cs`) calls `base.JsonModelWriteCore(writer, options)` which fails to compile

### Key difference from working cases

- `LimitJsonObject` (discriminated base **without** known subtypes in TypeSpec) → works correctly, all methods emitted
- `PolyDevice` (discriminated base extending `DiscriminatedExtensionResource` system type) → works correctly via `InheritableSystemObjectModelVisitor`
- **This case**: discriminated base **with** known subtypes, **not** extending system type → missing methods

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.