Repository navigation
Reuse shared content types instead of duplicating them per owner - #290
Merged
Merged
Conversation
When two complex types reference the same `xs:group`, the optimizer merges the identical content meta types and the second `resolve_typedefs` run rewrites both parents to the same content ident. The generator then threw that ident away: `ComplexData::new_complex` read the content type only for its shape, so `new_enum` and `new_struct` synthesized a fresh content type named after each parent, re-creating the duplication after the optimizer had already removed it. `REMOVE_DUPLICATES` was never at fault. The generator now references the shared content type through the existing `StructMode::Content` seam whenever the content meta type has more than one owner. Mixed content stays excluded, because the optimizer already rewrites it to a `Text` element and sharing it would apply `Mixed<..>` a second time. Sharing the type creates a reference cycle that the boxing analysis did not model before: `need_box` never traversed the complex type to content type edge, which was harmless while every content type was nested below its only owner. It now recurses into the shared content type when the type is reached directly, otherwise a recursive schema with a `1..1` group reference emits types of infinite size. A shared content ident set precomputed once on `State` keeps the added lookups off the hot path. Tests cover the reported schema, the `1..1` variant that exercises the boxing path, a quick_xml round trip, and a recursive schema generated with `Generate::All` whose expectation fails to compile if the boxing regresses.
`simplify_mixed_type` rewrites mixed content into explicit `Text` elements and clears `ComplexMeta::is_mixed` afterwards, but left `GroupMeta::is_mixed` set. The flag was stale from that point on: the text content is explicit, so nothing downstream should still treat the group as mixed. `remove_duplicates` runs before this pass and never observes the change. The generator reads the flag when it decides whether a content type may be shared between complex types, so a stale flag kept groups out of the sharing that are not mixed any more. In `onix` this affected a group with 30 owners, which now collapses into one shared type; `xccdf_1_2` shows the same pattern.
`need_box` terminated on `All`, `Choice` and `Sequence`, so the lookahead never walked a group's element list. That was harmless while every content type was nested below its only owner, because such a type can not close a loop on its own. Shared content types can, and a loop that runs through two different shared content types needs two group hops to be seen. Without the traversal the generator emits unboxed variants for such a loop and the generated code does not compile at all. The walk only follows elements that are referenced directly, so a `Vec` or `Option` in the loop still ends it, and it only extends paths that already crossed a shared content edge. No existing expectation changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two complex types referencing the same
xs:groupproduced two structurallyidentical content enums instead of one shared type.
REMOVE_DUPLICATESwas never at fault: it merges the content meta typescorrectly and
resolve_typedefspoints both parents at the same ident. Thegenerator then discarded that ident and synthesized a fresh
<Parent>Contentcopy per owner, undoing the optimizer's work.
Commits
fix. A content type with more than one owner is now referenced through the
existing
StructMode::Contentseam. Sharing makes a reference cycle real,so
need_boxlearned the complex type to content type edge.GroupMeta::is_mixedkept non-mixed groups out of the sharing. Unblocks anonixgroup with 30 owners.through two distinct shared content types needs two group hops to be
visible to
need_box.Impact
Generated output changes for
REMOVE_DUPLICATESusers, so this needs atleast a minor bump. +161/-32 lines of source across five files, all under
pipeline/. Expectations shrink by ~23k lines net (ofd,xml_schema,onix,xccdf_1_2); inonix33 duplicate content enums collapse into 4.Public API unchanged.
Tests
New
shared_group_contentcase with six variants: the reported schema,1..1, mixed content, a recursive schema and a two-group cycle (bothGenerate::All, the repo's first such coverage), plus a quick_xml roundtrip. Each expectation is paired with an
include!block, so a missingBoxfails to compile rather than to diff. Every case verified to go red without
its fix.
Related to #289