Skip to content

Fix enum-variant class names that collide with a same-named type - #151

Merged
chavic merged 1 commit into
Uniffi-Dart:mainfrom
DenisovAV:pr-fix-enum-collision
Aug 31, 2026
Merged

Fix enum-variant class names that collide with a same-named type#151
chavic merged 1 commit into
Uniffi-Dart:mainfrom
DenisovAV:pr-fix-enum-collision

Conversation

@DenisovAV

Copy link
Copy Markdown
Contributor

Problem

A data-carrying enum variant is rendered as a Dart class named {Variant}{Enum}. When that concatenation equals a real top-level type name, the generated file contains two declarations with the same name — a Dart compile error.

Concrete case (reduced from a real crate):

#[derive(uniffi::Record)]
pub struct FieldCondition { key: String }

#[derive(uniffi::Enum)]
pub enum Condition {
    Field { condition: FieldCondition },  // -> Dart class `FieldCondition`
}

The Field variant of Condition becomes class FieldCondition extends Condition, clashing with the FieldCondition record. dart analyze then reports duplicate_definition (and the FfiConverter's read dispatch calls .read on the wrong class). The same happens for a Named variant over a NamedVector type, etc.

Fix

Collect the top-level type names (records / enums / objects) and, only on collision, suffix the variant class with Variant (FieldConditionVariant). Non-colliding variants are unchanged, so existing generated APIs are untouched.

The name is produced by a single shared closure used both where the variant class is defined and where the enum's FfiConverter read dispatches to it — the two computed the name independently before, so fixing only the definition site left a dangling .read reference.

Test

Adds an enum_variant_collision fixture reproducing the clash (Condition::Field + record FieldCondition). It fails to compile without the fix (duplicate class) and round-trips with it. cargo test -p enum_variant_collision is green.

Note

Includes a small chore commit dropping a redundant & in a few format!/println! args — stable clippy 1.97+ added redundant reference in format! argument, which fails cargo clippy -- -D warnings on the current Testing CI for pre-existing code. Needed for green CI here; harmless to drop on rebase if it lands elsewhere first.

@chavic chavic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice work, thank you! One note for a possible follow-up, not for this PR: the reserved set does not contain the class names of other variants. Because of this, two variant classes from different enums can still collide, for example FieldA + Cond and Field + ACond. This case is rare, and the loop can cover it later.

@chavic

chavic commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

The one failed check is the flaky dart_async timing test, which #157 has now fixed on main. I queued a re-run of the failed job, but it tests the original merge snapshot from before #157. If it fails again, please rebase on main to pick up the fix. Everything else is green and there are no conflicts.

A data-carrying enum variant's Dart class is named `{Variant}{Enum}`. When that
concatenation equals a real top-level type name the file ends up with two
same-named declarations — a compile error. Real case: enum `Condition` variant
`Field` holding a record `FieldCondition` produces variant class `FieldCondition`,
clashing with the record; likewise a `Named` variant over a `NamedVector` type.

Collect the names of every type that emits a top-level Dart class — records,
enums, objects, and callback interfaces — and, only on collision, suffix the
variant class with `Variant`, looping (`Variant`, `Variant2`, ...) so a type
literally named `{base}Variant` can't reintroduce the duplicate. The name is
produced by one shared closure used both where the class is defined and where the
FfiConverter's `read` dispatches to it, so the two never drift.

Adds an `enum_variant_collision` fixture covering: a record collision that loops
past a second-order clash, a variant colliding with an enum type, and a
non-colliding control. It fails to compile without the fix and round-trips with it.
@DenisovAV
DenisovAV force-pushed the pr-fix-enum-collision branch from 904e1ec to 32e90aa Compare August 23, 2026 00:33
@chavic

chavic commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

@DenisovAV, thanks for the fix

@chavic
chavic merged commit 6754770 into Uniffi-Dart:main Aug 31, 2026
21 of 24 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