Skip to content

Unions and closed types - #404

Merged
SimonCropp merged 3 commits into
mainfrom
unions-and-closed-types
Sep 11, 2026
Merged

SimonCropp merged 3 commits into
mainfrom
unions-and-closed-types

Conversation

@SimonCropp

Copy link
Copy Markdown
Member

No description provided.

Unions are a new runtime shape Argon did not understand: a union serialized
to the wrapper {"Value":42} and could not be deserialized at all. UnionConverter
now writes the bare active case with no wrapper and no discriminator, matching
System.Text.Json. Reading picks the case from the JSON value shape, and falls
back to comparing property names when several cases serialize as objects.
It ships as a built in converter, so the serializer core is untouched.

Closed hierarchies already round tripped through TypeNameHandling and a binder,
but only with assembly qualified names and manual setup. The new opt in
JsonSerializerSettings.InferClosedTypePolymorphism uses the derived types the
compiler records on the base to write and read a short $type discriminator,
with no binder required. Because the candidate set is fixed at compile time an
incoming discriminator can never name an arbitrary type, so the usual
TypeNameHandling warning about untrusted input does not apply.

Both compiler markers are matched by attribute full name rather than through a
type reference. Their definitions come from the target framework on net11 and
from a polyfill below it, and a polyfilled copy is internal to each assembly,
so Argon's own copy would never match a consumer's. This also means one code
path covers net462 through net11.0 with no conditional compilation.

PolyNullability is enabled because case nullability decides which case accepts
a null payload, and Polyfill gates NullabilityInfoContext behind that property.

The declared type computation in ShouldWriteType is extracted so the writer
hooks can reuse it; that refactor is behaviour preserving.
ArgonTests overrides Verify to 33.0.0-beta.8 while central package management
pins 32.0.0. Argon.FSharp.Tests and Benchmark.Tests reference ArgonTests, so
they saw the prerelease transitively alongside the centrally pinned 32.0.0 and
failed to restore with NU1109. Matching the override in both makes the whole
solution build and test again.
@SimonCropp SimonCropp added this to the 0.37.0 milestone Sep 11, 2026
@SimonCropp
SimonCropp merged commit 35de883 into main Sep 11, 2026
4 checks passed
@SimonCropp
SimonCropp deleted the unions-and-closed-types branch September 11, 2026 05:31
This was referenced Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant