feat: back compat support for method param types - #11296
Conversation
44edb35 to
547a347
Compare
|
No changes needing a change description found. |
commit: |
There was a problem hiding this comment.
Pull request overview
This PR extends the C# generator’s method back-compat logic to handle additional signature evolution cases (beyond “new optional parameters”), specifically around nullable value-type parameters becoming non-nullable and nullable optional parameters becoming required, while adding targeted unit/golden tests and logging categories.
Changes:
- Add generation of hidden back-compat overloads for
T? -> Tvalue-type parameter nullability removal and for nullable parameters that changed from optional to required (via reduced-arity overloads). - Introduce signature comparison that can optionally include nullability, and use it to avoid duplicate/incorrect overload classification.
- Add/extend tests and expected outputs covering the new back-compat scenarios and cross-pass interactions.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/BackCompatHelperTests.cs | New unit tests for the new back-compat detection helpers. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs | New integration/golden-style tests validating emitted overloads for the new scenarios. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityUnwrapsRelaxedNullableSharedParameterInOptionalOverload/NullabilityAndOptionalChangeType.cs | Last-contract source stub used by the new cross-pass test. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityUnwrapsRelaxedNullableSharedParameterInOptionalOverload.cs | Expected generated output for the cross-pass case (unwrap .Value forwarding). |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityAddsOverloadForRelaxedNullableValueTypeParameter/NullabilityChangeType.cs | Last-contract source stub for the T? -> T overload case. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityAddsOverloadForRelaxedNullableValueTypeParameter.cs | Expected generated output for the nullability-change overload. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityAddsOverloadForNullableParameterThatBecameRequired/OptionalityChangeType.cs | Last-contract source stub for the optional-to-required nullable parameter case. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityAddsOverloadForNullableParameterThatBecameRequired.cs | Expected generated output for the reduced-arity optionality-restoration overload. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs | Core implementation: unified overload selection + new detection/build helpers + improved logging. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs | Switch to the new unified back-compat overload entrypoint. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/MethodSignatureBase.cs | Add a comparer variant that includes nullability in parameter type matching. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/CSharpType.cs | Add AreNamesEqual(..., checkNullability) helper to support nullability-aware comparisons. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/EmitterRpc/Emitter.cs | Map new back-compat categories to readable debug strings. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/EmitterRpc/BackCompatibilityChangeCategory.cs | Add new categories for nullability-change and optionality-restoration overload additions. |
547a347 to
81b8e36
Compare
cfdda3d to
6545e48
Compare
de5576d to
1b0fe92
Compare
a633f67 to
36c4c3e
Compare
739515f to
7947cde
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs:376
- Same accessibility check issue for candidates:
candidateIsAccessibledoesn’t excludePrivate-flagged modifiers. UseMethodProviderHelpers.IsPublicApisoprivate protectedcandidates don’t participate in match selection.
var candidateSignature = candidate.Signature;
bool candidateIsAccessible = (candidateSignature.Modifiers & (MethodSignatureModifiers.Public | MethodSignatureModifiers.Protected)) != 0;
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs:362
AddBackCompatOverloadstreats any method withPublicorProtectedflags as eligible, but it doesn’t excludePrivate(e.g.private protected), unlike the new centralizedMethodProviderHelpers.IsPublicApicheck used elsewhere. This can cause back-compat overloads to be generated for non-public-API methods.
if ((previousSignature.Modifiers & (MethodSignatureModifiers.Public | MethodSignatureModifiers.Protected)) == 0 ||
!currentMethodsByName.TryGetValue(previousSignature.Name, out var candidates))
packages/http-client-csharp/generator/docs/backward-compatibility.md:968
- This statement is no longer accurate now that some back-compat overloads intentionally preserve defaults (e.g., when the current method makes all previous parameters required, or for certain nullability/optionality shims). Consider rewording to indicate defaults are stripped only when needed to avoid ambiguity.
7947cde to
b950ce2
Compare
b950ce2 to
df62996
Compare
…ract service methods Reject back-compat overload candidates whose static modifier differs from the previous signature (a previous static method could otherwise match a current instance method and emit `this.Method(...)` inside a static shim, CS0026), and skip restoring abstract methods entirely since a delegating shim requires a body that an abstract method cannot have. Map IMethodSymbol.IsAbstract onto the method signature so the model faithfully represents abstract methods. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 52760796-5a02-48e0-a9c2-9f8dc95a87f5
Extends method back-compat to preserve source + binary compatibility when a service method's parameters evolve. For each public/protected last-contract method that changed in a recoverable way, a hidden (EditorBrowsable.Never) overload reproducing the previous signature is generated that delegates to the current method.
Scenarios now supported:
T?→T) — adds a hidden overload with the previous nullable signature that forwards via.Value, guarded byArgument.AssertNotNull(also covers extensible enums, matched by name).fixes: #11223