microsoft / microsoft/typespec
[csharp] Generated back-compat overloads in ModelFactory can have non-compiling bodies after large signature changes
- Dominant language
- Java
- Stars
- 5.9k
- Forks
- 394
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 104
Description
## Bug
When generating C# back-compat overloads in `*ModelFactory` based on the previously-shipped contract, the generator can emit overloads whose **body does not compile** — the `return` expression forwards to the primary overload using arguments that are inconsistent with that primary overload's current parameter list (wrong types, missing/renamed parameters, named-then-positional ordering, etc.).
The signatures themselves are fine; only the bodies are wrong.
Encountered while migrating `Azure.ResourceManager.Compute` (Swagger → TypeSpec). After regeneration we observed **96 raw / 48 unique** compilation errors across **13 distinct factory methods**, all in EditorBrowsable(Never) back-compat overloads:
| C# error | Count | Example |
|---|---:|---|
| CS1739 (parameter name doesn't exist) | 78 | `'RestorePointData' has no parameter 'instantAccessDurationMinutes'` |
| CS1503 (cannot convert) | 12 | `cannot convert 'GalleryImageIdentifier' to 'SharedGalleryIdentifier'` |
| CS1744 (positional after named) | 6 | back-compat call passes `reservationType: default` then a positional arg |
100% of the broken methods carry `[EditorBrowsable(EditorBrowsableState.Never)]` (i.e. they are auto-generated back-compat shims, not user-authored code).
## Reproducer
`Azure.ResourceManager.Compute` migration branch (will share repo + branch on request).
Representative case — `CapacityReservationGroupData`:
**Primary overload (current generated, valid):**
```csharp
public static CapacityReservationGroupData CapacityReservationGroupData(
ResourceIdentifier id = default, string name = default, ResourceType resourceType = default, SystemData systemData = default,
IDictionary tags = default, AzureLocation location = default,
IEnumerable zones = default,
IEnumerable capacityReservations = default,
IEnumerable virtualMachinesAssociated = default,
CapacityReservationGroupInstanceView instanceView = default,
IEnumerable sharingSubscriptionIds = default,
CapacityReservationType? reservationType = default)
{ ... }
```
**Back-compat overload emitted by generator (does not compile):**
```csharp
[EditorBrowsable(EditorBrowsableState.Never)]
public static CapacityReservationGroupData CapacityReservationGroupData(
ResourceIdentifier id, string name, ResourceType resourceType, SystemData systemData,
IDictionary tags, AzureLocation location,
IEnumerable zones,
IEnumerable capacityReservations,
IEnumerable virtualMachinesAssociated,
CapacityReservationGroupInstanceView instanceView,
IEnumerable sharingSubscriptionIds)
{
return CapacityReservationGroupData(
id, name, resourceType, systemData, tags, location,
capacityReservations, virtualMachinesAssociated, instanceView,
reservationType: default, // CS1744 follows ↓
sharingSubscriptionIds, zones); // positional after named
}
```
Three distinct issues in this single body:
1. `zones` is passed last; in the primary it's the 7th parameter (after `location`).
2. `reservationType: default` is a named argument followed by positional arguments.
3. Several other methods (`RestorePointData`, `ManagedDiskData`, `CapacityReservationData`, `SharedGalleryImageData`, `SnapshotData`, `AvailabilitySetData/Patch`, `GalleryData/ImageData`, `ManagedDiskPatch`, `CapacityReservationGroupPatch`, `CapacityReservationPatch`) follow the same pattern with renamed/added parameters that the back-compat call site doesn't account for.
## Expected
For back-compat overload generation, **only emit the overload when the generator can produce a valid forwarding body.** If the parameter list of the current primary diverges in a way the generator can't reconcile (renames, type changes, removed parameters), it is more useful to **omit the overload** and let the SDK author add a hand-written back-compat shim, than to emit code that does not compile.
A "compiles or skips" guarantee on emitted back-compat overloads would dramatically reduce the manual cleanup cost during large migrations.
## Workaround used today
Exclude the entire generated `ArmComputeModelFactory.cs` from compilation via `` plus `[CodeGenSuppress]` for the affected overloads, and hand-author replacements in customization code. Both have to be re-evaluated each regen.
Contributor guide
Assessment
This issue has not been assessed yet.