Skip to content

Support message types from referenced assemblies as nested fields and union members (F1) - #8534

Merged
Aaronontheweb merged 1 commit into
feature/serialization-v2-generator-locationsfrom
feature/serialization-v2-metadata-schemas
Sep 11, 2026
Merged

Aaronontheweb merged 1 commit into
feature/serialization-v2-generator-locationsfrom
feature/serialization-v2-metadata-schemas

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Sep 9, 2026 •

Copy link
Copy Markdown
Member

Stack, bottom to top: S1 #8525 -> S2 #8526 -> S3 #8527 -> object elements #8528 -> S4 #8530 -> S5 #8532 -> S6 #8533 -> F1 #8534 -> F2 #8536 -> F3 #8537 -> S7 #8538. Each PR is one commit on top of the one below it. This PR is F1, the first feature step.

What changes

A serializer can now use message types declared in a referenced assembly as nested field types and as union members. Before, both cases failed, and with the wrong diagnostic id. The design record is Decisions 16 to 21 in openspec/changes/messagepack-sourcegen-validation/design.md.

  • Schemas from metadata. A new step, MetadataSchemas, finds the referenced types the local messages and serializers name, reads each one's [AkkaSerializable] and [AkkaField] attributes from metadata, and builds its schema with the same code local types use. The schema is identical to what the other assembly's own generator saw. It follows nested references breadth-first. Its output is a table of plain values keyed by TypeKey, and it feeds the resolve step directly.
  • Caching holds. The step runs on every edit, but its output compares equal whenever the set of referenced type keys is unchanged, so resolve and emit stay cached. Two scenarios prove it: an unrelated edit regenerates nothing, and an edit to the referencing message regenerates only its serializer.
  • AKKASG039, referenced type or member is not accessible. An error at the local property or union member, naming the upstream type and member. It fires for an internal type without InternalsVisibleTo, or a property with a restricted getter. One limit is in the design record: Roslyn's metadata reader hides a member this compilation cannot see at all, so a wholly inaccessible property drops out of the schema silently. A restricted getter on a visible property is caught.
  • The two wrong ids are gone. A nested type from a referenced assembly reported AKKASG023 and a union member reported AKKASG015. Both cases now succeed. A referenced type that is not marked stays an error with the existing cross-assembly hint.
  • Golden output. A new corpus case covers a nested type and a union member from a referenced assembly, and a generic definition from a referenced assembly closed locally. The emitted code matches the local case byte for byte except for the namespace. No existing golden, wire, or model snapshot changed.
  • Docs. The guide's cross-assembly section now describes what works and where errors show up. Decision 16 gets a short addendum, and its task is marked done.

Baseline cases

CrossAssemblyBaselineSpec pins six cross-assembly behaviors with diagrams. Cases 1 (nested field type) and 2 (union member) flip to success, and their diagrams are rewritten. The plan listed case 5 as a third flip; that was a numbering slip, since the generic-definition case already worked. Cases 3 to 6 stay for F2 and F3.

Cost

Base is the S6 tip. The corpus has no referenced-assembly types, so every row should be flat, and it is. A first cut allocated up to 18 percent more on some rows because the reference walk was an iterator method, which allocates its state machine even when it yields nothing. It now writes into a reused set.

Row Base (S6) This PR
Fresh driver, full corpus 22.8 ms, 18.93 MB 22.3 ms, 18.93 MB
Warm driver, one field renamed 16.1 ms, 9.51 MB 16.1 ms, 9.51 MB
Warm driver, comment edit 8.6 ms, 3.54 MB 8.8 ms, 3.55 MB
Warm driver, unrelated file edited 7.2 ms, 3.52 MB 7.4 ms, 3.52 MB

How it was checked

334 tests pass (327 plus 2 golden, 3 for AKKASG039, 2 caching scenarios). Generator and Akka.Remote build with warnings as errors. No public API change. cspell passes on the guide.

@Aaronontheweb
Aaronontheweb added this pull request to stack #8531 September 9, 2026 13:28
@Aaronontheweb
Aaronontheweb force-pushed the feature/serialization-v2-metadata-schemas branch from 03b9da8 to d20f28f Compare September 9, 2026 13:32
@Aaronontheweb Aaronontheweb changed the title Serialization.V2: schemas from metadata for referenced-assembly types (Decision 16, F1) Support message types from referenced assemblies as nested fields and union members (F1) Sep 9, 2026
@Aaronontheweb
Aaronontheweb force-pushed the feature/serialization-v2-metadata-schemas branch from d20f28f to ecfce84 Compare September 9, 2026 17:15
@Aaronontheweb
Aaronontheweb force-pushed the feature/serialization-v2-metadata-schemas branch from ecfce84 to 2b4ab8e Compare September 9, 2026 18:08
@Aaronontheweb
Aaronontheweb force-pushed the feature/serialization-v2-metadata-schemas branch from 2b4ab8e to 74ca4c2 Compare September 9, 2026 22:52
@Aaronontheweb
Aaronontheweb force-pushed the feature/serialization-v2-metadata-schemas branch from 74ca4c2 to 7ecd49f Compare September 10, 2026 23:44
… (Decision 16)

Adds a per-compilation metadata-schema stage (ComputeMetadataSchemas) that
reads a nested field's or a union member's schema from a referenced
assembly's compiled metadata, through the same ExtractMessageCore routine
a local type uses. Fills the gap CrossAssemblyBaselineSpec pinned for
those two cases; a closed generic's own definition already worked this
way. Local declarations keep priority over a metadata schema on any key
collision.

Adds AKKASG039 for a referenced type that is [AkkaSerializable] but not
accessible from the local compilation (or one of its own [AkkaField]
properties, or a type it itself nests), reported at the local reference
site with both the directly-named type and the actual failing
type/member.

Flips CrossAssemblyBaselineSpec's nested-field and union-member cases
from a pinned failure to a pinned success and adds three AKKASG039 cases
(a non-public property, an internal union member, and a failure one
level down). Adds cross-assembly golden-output coverage proving the
emitted helpers are byte-identical to the same declarations made
locally, and two incremental-caching scenarios proving a metadata schema
does not defeat caching for an edit it does not care about.

Updates the user guide with a new Cross-Assembly Types section and
records the implementation choices not covered by the design text as an
addendum under Decision 16.
@Aaronontheweb
Aaronontheweb force-pushed the feature/serialization-v2-metadata-schemas branch from 7ecd49f to 7848e9b Compare September 11, 2026 15:05
@Aaronontheweb
Aaronontheweb merged commit 9e21298 into dev Sep 11, 2026
17 checks passed
@Aaronontheweb
Aaronontheweb deleted the feature/serialization-v2-metadata-schemas branch September 11, 2026 17:29
Aaronontheweb added a commit that referenced this pull request Oct 2, 2026
…sted message types (#8721)

Docs no longer say an object collection element is unsupported (#8528).
AKKASG007 and AKKASG015 cross-assembly text no longer says the generator
cannot read a schema from a referenced assembly (#8534, #8537).
New AKKASG045 reports an [AkkaSerializable] type that is private or
protected, or nested in one, instead of CS0122 in generated code.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant