fix(rust): type union base properties on variants that have no own properties - #17660
fix(rust): type union base properties on variants that have no own properties#17660wiebren wants to merge 1 commit into
Conversation
…operties
A discriminated union's base properties are referenced on every variant by the
generated constructors and discriminant-switching getters, but the variant
struct itself was emitted as an empty braced variant when the variant had no
own properties (a noProperties variant, or an inlined referenced object with
an empty property list). The enum then fails to compile:
error[E0559]: variant `...` has no field named `message`
error[E0026]: variant `...` does not have a field named `message`
The committed property-access seed output already exhibits this: its `Empty`
variant is generated as `Empty {}` while `get_normal()`/`get_foo()` match
`Self::Empty { normal, .. }`, so the crate does not build.
Emit the base properties on those variants too, and let the noProperties
constructor accept them. Adds the rust-union-base-properties seed fixture
covering a union with base properties whose variants include an inlined
empty object and a noProperties variant; both affected fixtures now compile
and pass cargo test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CxDNCjqJycKTfzVWg2SeTJ
There was a problem hiding this comment.
AI Review Summary
Straightforward generator fix: empty union variants now carry the union's base properties, matching what the getters/constructors already assume. Seed fixtures regenerated and a new test definition added. One thing worth double-checking: the generated ValidationError variant in the new fixture emits #[serde(default)] field: String before message, which suggests base-property ordering/serde attributes may still be inconsistent, but that's pre-existing behavior outside these lines.
- 🔵 1 suggestion(s)
To request another review, comment /ai-review on this pull request.
| if (this.unionTypeDeclaration.baseProperties.length > 0) { | ||
| // Base properties are typed on every variant (getters and | ||
| // constructors reference them), so they must be present even | ||
| // when the inlined type has no own properties. | ||
| writer.writeLine(` ${variantName} {`); | ||
| this.generateBaseProperties(writer); | ||
| writer.writeLine(` },`); | ||
| } else { | ||
| // Empty type: generate empty struct variant | ||
| writer.writeLine(` ${variantName} {},`); | ||
| } |
There was a problem hiding this comment.
🔵 suggestion
This block is now identical to the noProperties branch above (lines 307-317). Worth extracting a small helper, e.g. writeEmptyVariant(writer, variantName), so the two paths can't drift.
There was a problem hiding this comment.
🔍 Devin Review: 1 flag
Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
Description
Linear ticket: n/a — found while running one OpenAPI document through fern's SDK generators
and comparing what each one produces.
A discriminated union with base properties generates constructors and discriminant-switching
getters that reference those properties on every variant — but the variant struct itself
is emitted as an empty braced variant whenever the variant has no properties of its own. The
enum then cannot compile:
An error taxonomy is the natural way to hit this: a union of error subtypes shares a base
message, and for many subtypes the type name is the information — they add no fields oftheir own. One such union with nine message-only subtypes produced 18 compile errors in the
generated crate.
The repository's own seed output already exhibits the bug: the committed
seed/rust-sdk/property-accesscrate does not build —Root cause
In
generators/rust/model/src/union/UnionGenerator.tstwo variant-emission paths skipgenerateBaseProperties():noPropertiesvariant shape, andsamePropertiesAsObjectvariant whose referenced object has an empty propertylist.
Both write
Variant {},. Everything else already treats base properties as present on everyvariant:
generateImplementationBlockemitsSelf::Variant { field, .. }match arms for eachbase-property getter across all variants, and the constructor for the empty inlined case
already assigns the base fields into the variant it just declared without them (that is the
E0559 above).
Changes Made
Variant {}form when the union declares no base properties.
noPropertiesconstructor accept the base properties, mirroring what the emptyinlined-object constructor already does.
rust-union-base-propertiestest definition (language-prefixed, so only the rustgenerators run it): a union with a base
messagewhose variants include an inlined objectwith an empty property list, an inlined object with its own property, and a
noPropertiesvariant.
property-access,rust-union-base-properties).No other fixture output changes.
Testing
pnpm seed test --generator rust-sdk— 149/149 pass with the change.cargo build+cargo teston both affected fixtures:property-accesserror[E0026]×2, does not buildrust-union-base-propertieserror[E0559],error[E0026]×2, does not buildpnpm turbo run test --filter @fern-api/rust-model --filter @fern-api/rust-sdk— all unittests pass.
Generated with Claude Code