Skip to content

fix(optimizer): exclude abstract polymorphic variants - #319

Merged
Bergmann89 merged 1 commit into
Bergmann89:masterfrom
sundermann:fix/abstract-dynamic-choices
Nov 12, 2026
Merged

Bergmann89 merged 1 commit into
Bergmann89:masterfrom
sundermann:fix/abstract-dynamic-choices

Conversation

@sundermann

@sundermann sundermann commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Fixes CONVERT_DYNAMIC_TO_CHOICE exposing abstract schema types and elements as constructible enum variants.

Changes

  • Exclude abstract descendants and substitution-group members while retaining concrete descendants, including leaves beneath abstract intermediate types.
  • Filter only the choice being converted, preserving unconverted dynamic types and their boxed-dyn trait implementations and supertraits. Cache abstract identifiers before conversion to keep individual, bulk, and mixed conversions independent of order.
  • Represent types without concrete alternatives as uninhabited types, including XML serialization and deserialization in flattened and wrapped layouts.
  • Preserve element names, namespaces, and root state through unflattened dynamic content. Wrappers pass caller context unchanged; their content enum chooses the caller's name for type-identified alternatives or the schema's substitution tag.
  • Add an XSD fixture and compiled type and quick-xml snapshots with and without FLATTEN_CONTENT, with unreachable_code denied. Cover nested and standalone concrete XML round trips, rejection of abstract tags and types, and empty choices. Metadata regressions cover conversion order and preserving unconverted dynamic types.
  • Omit unused root context and helper parameter bindings from empty-enum XML implementations. Keep snapshot-covered assertions in the compiled fixtures rather than duplicate token-string tests, and leave the release changelog unchanged.

Generated API changes: enums lose invalid abstract variants, and abstract types without concrete descendants can no longer be instantiated as empty structs. A required field of an uninhabited type also makes its containing type impossible to construct.

Checklist

  • Tests for the change (a bug fix has a test that fails without the fix)
  • Changed snapshots are regenerated with update-expectations and reviewed
  • cargo fmt, cargo clippy and cargo test pass (see CONTRIBUTING.md)
  • cargo build -p benchmark --release and release runs of read_write, bpmn, and vsme pass
  • Breaking changes of the public API or the generated code are described above

@Bergmann89 Bergmann89 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Hey @sundermann,

Thanks, the core fix looks right to me: abstract complex types and abstract elements are both caught, concrete leaves under an abstract intermediate survive, and computing the abstract set up front really makes the conversion order-independent. The onix snapshot changes are all explained by the removed abstract XHTML heads.

A few things before merging:

  • Missing test for the generated serializer/deserializer. The new tests use Config::test_default(), which only renders the types, so the quick_xml code for the new empty enums is never generated or compiled. In the flattened case next_event renders match *self.value {} followed by more code, which will most likely trigger unreachable_code. Please add a feature test under tests/feature/ with schema.xsd + compiled expected/default.rs / expected/quick_xml.rs, with and without FLATTEN_CONTENT, plus a read test that a concrete member round-trips and an abstract tag is rejected.
  • Converting a single type affects other dynamic types. remove_abstract_derived_types (dynamic_to_choice.rs) strips abstract entries from every dynamic type, not just the one being converted. For a type that stays dynamic, this drops trait impls and supertraits from the boxed-dyn output. Please touch only the types being converted.

Nits: add an empty /// line before the new doc lines in dynamic_to_choice.rs:20, and the comment at complex.rs:292 mostly repeats the condition.

@sundermann
sundermann force-pushed the fix/abstract-dynamic-choices branch 2 times, most recently from 9fc5a5d to 6e2099e Compare November 11, 2026 20:49
@sundermann

Copy link
Copy Markdown
Contributor Author

@Bergmann89 Thanks! I revisited the PR and adressed the feedback, should be good now

@Bergmann89 Bergmann89 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks, that looks great now! The new feature test with the read tests is exactly what I was looking for, and the conversion only touches the converted types now.

I added the last small things as suggestions, then it's ready to merge.

Comment thread README.md Resolved
Dynamic-to-choice conversion exposes abstract type records and abstract
substitution group members as constructible enum variants. Cache abstract
identifiers before conversion and filter only the choice being built,
leaving unconverted boxed-dyn types and their inheritance traits intact.

Keep results without concrete alternatives as empty choices and retain
their uninhabited enum content when flattening is disabled. Generate
exhaustive XML serializers and deserializers for those empty enums, without
unused helper bindings or XML root context.

Forward element names, namespaces and root state through unflattened
dynamic content so concrete values serialize consistently in both layouts.
Generated enums no longer expose abstract variants, and types without
concrete alternatives can no longer be instantiated as empty structs.
Required fields of these uninhabited types make their parents uninhabited
as well.
@sundermann
sundermann force-pushed the fix/abstract-dynamic-choices branch from 6e2099e to dc3cd25 Compare November 11, 2026 23:11
@Bergmann89
Bergmann89 merged commit 9e721cd into Bergmann89:master Nov 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants