Skip to content

kotlin: use renamed names for struct and enum field types - #1309

Open
MaxFreedomPollard wants to merge 1 commit into
rust-diplomat:mainfrom
MaxFreedomPollard:fix/kotlin-renamed-field-types
Open

MaxFreedomPollard wants to merge 1 commit into
rust-diplomat:mainfrom
MaxFreedomPollard:fix/kotlin-renamed-field-types

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

If a struct field's type is a renamed struct or enum, the Kotlin backend generates code that does not compile. For example, with a module-level rename:

#[diplomat::bridge]
#[diplomat::attr(kotlin, rename = "Renamed{0}")]
mod ffi {
    pub struct Inner {
        pub x: i32,
    }

    pub enum Color {
        Red,
        Green,
    }

    pub struct Outer {
        pub inner: Inner,
        pub color: Color,
    }
}

the classes come out as RenamedInner, RenamedInnerNative and RenamedColor, but RenamedOuter.kt still uses the Rust names in two places:

internal var inner: InnerNative = RenamedInnerNative();
// ...
val color: RenamedColor = Color.fromNative(nativeStruct.color)

The cause is two helpers in tool/src/kotlin/formatter.rs that read .name directly. #1069 moved the rest of the backend over to fmt_type_name, but these two were left:

  • fmt_struct_field_type_native, Type::Struct arm: this gives the field's JNA type. It also names the Option...Native wrapper for DiplomatOption<Inner> fields and, through gen_kt_to_c_for_type, for Option<Inner> method parameters. Those break the same way, as OptionInnerNative.
  • fmt_struct_field_native_to_kt, Type::Enum arm: this generates the enum's fromNative conversion.

The neighbouring helpers fmt_field_default and fmt_struct_field_type_kt already call fmt_type_name. That is why the declared type and the initializer above disagree.

The fix calls fmt_type_name in both arms. Types without a rename produce the same output as before. Nothing in feature_tests or example has a struct field or DiplomatOption parameter of a renamed type, so the checked-in bindings do not change.

test_struct_field_renamed_types in the formatter tests builds a struct with a renamed struct field, a renamed enum field, and DiplomatOption fields of each. It checks the strings both helpers return.

This has not been compiled or run locally, because I don't have a Rust toolchain on this machine. I checked the change and the expected strings by reading the formatter, Struct.kt.jinja and Option.kt.jinja, and laid out the new code by hand to match rustfmt. CI will be its first build.

🤖 Generated with Claude Code

A struct field whose type is a renamed struct or enum produced Kotlin
that does not compile. The renamed type's own classes are generated
under the renamed name (`RenamedInnerNative`, `OptionRenamedInnerNative`,
`RenamedEnum`), but two helpers in tool/src/kotlin/formatter.rs built the
name from the Rust identifier instead:

- `fmt_struct_field_type_native` declared a struct-typed field as
  `InnerNative` and a `DiplomatOption<Inner>` field as
  `OptionInnerNative`, while `fmt_field_default` initialised the
  struct-typed field with `RenamedInnerNative()`. `gen_kt_to_c_for_type`
  also uses this helper to name the option wrapper for `DiplomatOption`
  parameters, so a method taking `Option<Inner>` broke the same way.
- `fmt_struct_field_native_to_kt` converted an enum-typed field with
  `MyEnum.fromNative(...)`, while `fmt_struct_field_type_kt` declared it
  as `RenamedEnum`.

These are the two places rust-diplomat#1069 did not switch over to `fmt_type_name`.
Use `fmt_type_name` in both. Types without a rename format exactly as
before, and no struct field or `DiplomatOption` parameter in
feature_tests or example has a renamed type, so no generated bindings
change.

Adds `test_struct_field_renamed_types`, which checks both helpers on a
struct with renamed struct, enum and `DiplomatOption` fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Manishearth

Manishearth commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Hm, did none of our existing feature_tests hit this already? We have a lot of renaming tests; do we need more?

On balance I'd probably prefer a feature_test test (i.e. code in feature_tests that exercises this) instead of an in-code test. We try to keep those to insta tests most of the time.

This branch has not been deployed

No deployments
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