Skip to content

Expand back-compat property type preservation to all public model properties#10413

Open
Copilot wants to merge 10 commits intomainfrom
copilot/expand-back-compat-support
Open

Expand back-compat property type preservation to all public model properties#10413
Copilot wants to merge 10 commits intomainfrom
copilot/expand-back-compat-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 17, 2026

  • Add BuildPropertiesForBackCompatibility virtual hook on TypeProvider
  • Move ModelProvider back-compat property logic into the new hook
  • Always preserve the last contract's property type when it differs from the current spec
  • Invoke BuildPropertiesForBackCompatibility from ProcessTypeForBackCompatibility so it runs after all visitors
  • Update tests to call ProcessTypeForBackCompatibility to trigger property back-compat
  • Add tests covering nullable scalar, nullable enum, and top-level type-name change cases
  • Update backward-compatibility.md Model Properties section
  • Sync with latest main

Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/33d000a2-d811-4f6c-a72b-359b57cee1a2

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Apr 17, 2026
Copilot AI changed the title [WIP] Expand property back compat support for all model properties Expand back-compat property type preservation to all public model properties Apr 17, 2026
Copilot AI requested a review from jorgerangel-msft April 17, 2026 18:09
@JoshLove-msft JoshLove-msft marked this pull request as ready for review April 17, 2026 21:37
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 17, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@10413

commit: 4584e8b

Comment thread packages/http-client-csharp/generator/docs/backward-compatibility.md Outdated
Comment thread packages/http-client-csharp/generator/docs/backward-compatibility.md Outdated
Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/e014a173-0713-44e4-a0b5-4ce8f896d407

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
- The generator compares property types against the `LastContractView`
- For read-write lists and dictionaries, if the previous type was different, the previous type is retained
- The generator compares property types against the `LastContractView`.
- If the previous type is logically compatible with the new type (same top-level name, with matching generic argument names), the previous type is retained. This covers read-write collection wrapper changes (e.g. `IList<T>` ↔ `IReadOnlyList<T>`) as well as nullability changes on scalars, enums, and models.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this is no longer the case - sync from main

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify what you'd like changed here? Line 168 describes the unified rule introduced by this PR (collection wrapper changes + nullability), and main hasn't moved since I last synced it (ab5caa4 is still tip for this file). If you'd prefer I drop the "Implementation Details" bullet list entirely — keeping just the two scenario sections above — happy to do that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main has moved since you last synced @copilot

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, sorry — I missed 38a8c7a (the revert of #10319). Merged main in 6275b90 and dropped the AreNamesEqual generic-argument check from the collection branch so it matches main's behavior (override on any inequality). Updated the doc accordingly. Non-collection properties still use the conservative top-level-name-match rule for the new nullability case.

…n back-compat)

Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/1cb571b4-94fe-450a-bda0-73a4c98e8f9f

Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
@JoshLove-msft
Copy link
Copy Markdown
Contributor

@copilot sync from main and resolve all merge issues

…ompat-support

# Conflicts:
#	packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs

Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 18, 2026

@copilot sync from main and resolve all merge issues

Synced from main in 7c64485. Resolved the conflict in ModelProvider.cs (kept the version that routes properties through the new BuildPropertiesForBackCompatibility hook instead of the inline back-compat block). All 80 ModelProviderTests still pass.

// argument names) to match. This ensures we only override when the types are
// logically the same (e.g. differ only in nullability) and never when the
// underlying type has genuinely changed (e.g. string to int).
if (outputProperty.Type.AreNamesEqual(candidate))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot why wouldn't we just always enforce the existing type in the back compat scenario? Users can work around this with custom code if they need to.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — done in 86c40d0. TryGetLastContractPropertyTypeOverride now always returns the last contract's type whenever it differs from the new spec, with no collection-vs-scalar or AreNamesEqual branching. Updated the previously-negative test (BackCompat_ScalarPropertyTypeOverriddenWhenTypeNameDiffers) to assert the override now applies even when the top-level name changes (stringint is preserved as string), and rewrote the docs to describe the unconditional behavior. All 1317 generator tests pass.

Copilot AI and others added 2 commits April 20, 2026 22:34
…ompat-support

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/ceb10cde-230f-420c-9ac3-076d097c12b6

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 20, 2026

@copilot sync from main and resolve all merge issues

Synced with main in f4cdb93 — merged cleanly, no conflicts. All 80 ModelProviderTests still pass.

…onditional preservation

Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/aa2dc7c2-4537-41bc-823e-a6c608afa956

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
/// underlying type, etc.). Users can override this behavior with custom code if they
/// want the new spec's type instead.
/// </summary>
protected internal override IReadOnlyList<PropertyProvider> BuildPropertiesForBackCompatibility(IEnumerable<PropertyProvider> originalProperties)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this needs to run after all visitors have run.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the call from BuildProperties into ProcessTypeForBackCompatibility in 0f006de — it now runs alongside the existing methods/constructors back-compat passes, after all visitors have completed (per CSharpGen.cs line 79–82). Updated the affected ModelProviderTests to trigger ProcessTypeForBackCompatibility explicitly. All 1421 generator tests + 1311 ClientModel tests pass.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Not sure if that is the issue, but seeing a regression where the known azure type property serialization is not applied for nullable AzureLocation.
https://github.com/Azure/azure-sdk-for-net/blob/main/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownAzureTypes.cs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's very likely caused by the move. Before, back-compat ran inside BuildProperties and the Azure visitor ran after it, re-stamping outputProperty.Type with the AzureLocation TypeProvider's CSharpType (which carries the Implementation/known-Azure-type metadata that MRW serializer codegen keys off of). Now back-compat runs after the visitor and wholesale replaces outputProperty.Type with lastContractPropertyType from LastContractPropertiesMap — that one is built by reflecting over the previous binary, so it's a "raw" framework CSharpType without the TypeProvider association. The serializer then doesn't recognize it as a known Azure type.

A targeted fix: when lastContractPropertyType and outputProperty.Type have the same underlying name/namespace and only differ in nullability (or collection wrapping), keep the visitor's outputProperty.Type and just adjust nullability/wrapping on it (preserving the Implementation). When they differ in the underlying type (the stringint scenario), fall back to wholesale replacement as today.

Want me to go that route, or do you have a different shape in mind? If you can point me at a small failing test (or the exact property/type pairing), I can verify locally before pushing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand Property Back Compat Support for All Model Properties

3 participants