gevartosky · GitHub

Commits on Jul 24, 2026

  1. Don't JNI-bridge generic @inline(__always) functions (#260)

    * Don't JNI-bridge generic @inline(__always) functions
    A generic `@inline(__always)` function is emitted as a Kotlin
    `inline fun <reified T>`, which has no JVM-callable method. The bridge
    generator nonetheless emitted a `getMethodID(...)!` JNI lookup for it,
    so the force-unwrap trapped at class load ("Unexpectedly found nil while
    unwrapping an Optional value") for any native-Swift-on-Android caller.
    This reproduces whenever the reified method lives on an `open` class that
    has a subclass (the method is then lifted to a top-level `inline fun
    <reified T>` extension and bridged via `getStaticMethodID`) — the root
    cause behind skiptools/skip-firebase#81 and the still-open #91.
    Return nil from `KotlinFunctionDeclaration.checkBridgable` for a generic
    `@inline(__always)` function so it is not JNI-bridged. Native-Swift
    callers use the `@inline(__always)` Swift body directly (inlined); Kotlin
    callers use the `inline fun <reified T>`. An inline reified function was
    never JNI-callable to begin with, so nothing is lost.
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    * Also skip bridging SKIP DECLARE'd inline-reified functions
    A `// SKIP DECLARE: ... inline fun <reified T> ...` override produces the
    same JVM-uncallable Kotlin as @inline(__always) but carries no structured
    attribute, so the attribute guard alone left the crash reachable via
    skip-firebase's FirestoreDecoder.decode(from:) (called from the inlined
    body of DocumentSnapshot.decoded()) — i.e. #91 was not fully closed.
    Also bail out of bridging when the declaration override is an inline
    reified function.
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ---------
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Configuration menu

    Browse the repository at this point in the history

  2. Apply spread operator when delegating variadic static funcs to compan…

    …ion (#261)
    A public/internal static function is emitted as an `override` on the type's
    `companion object` plus a delegating `open fun` on `CompanionClass` that calls
    back into the concrete implementation. For a variadic parameter the delegating
    member is declared `vararg`, but `appendCompanionClassDelegatingMember` forwarded
    the argument by bare name, so inside the delegate the parameter has its Array
    type and Kotlin rejects the call:
        Argument type mismatch: actual type is 'kotlin.Array<...>',
        but 'kotlin.String' was expected.
    Prefix the forwarded argument with the spread ("*") operator when the parameter
    is variadic, for both the labeled and unlabeled argument forms.
    Fixes #64.
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Configuration menu

    Browse the repository at this point in the history

  3. Escape invalid characters in file-derived bridge function names (#262)

    When a bridged Swift file has no owning type, the generated `@_cdecl`
    bridging code derives its symbol from the file name (`<FileName>Kt`). The
    JNI symbol string is escaped via `cdeclEscaped`, but the Swift function
    name reused the raw file name. A file such as `Model+Bridging.swift`
    therefore produced an uncompilable Swift declaration:
        func Model+BridgingKt_Swift_i(...)   // '+' is not valid in an identifier
    Decouple the raw type name (used to compute the JNI symbol) from an
    escaped one used for the Swift identifier, applying the same JNI-style
    codepoint escaping (`+` -> `_0002b`) that the symbol side already uses.
    The generated function becomes `Model_0002bBridgingKt_Swift_i`, matching
    the escaping of its `@_cdecl` symbol.
    Fixes #63.
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Configuration menu

    Browse the repository at this point in the history

  4. Use Swift-identifier escaping for file-derived bridge function names (#…

    …263)
    Follow-up to #262. That change escaped the Swift `@_cdecl` function name
    derived from a source file name via `cdeclEscaped`, but `cdeclEscaped` is
    a JNI-symbol escaper, not a Swift-identifier escaper — the two have
    different rules, so reusing it leaves two cases wrong:
    - `.` is preserved by `cdeclEscaped` (it is a separator callers handle),
      but a `.` is invalid in a Swift identifier. A file such as
      `Model.generated.swift` still produces an uncompilable declaration:
          func Model.generatedKt_Swift_i(...)   // '.' is not valid
    - `_` is valid in a Swift identifier but `cdeclEscaped` mangles it to
      `_1`, so `Model_Extensions.swift` needlessly yields
      `Model_1ExtensionsKt_Swift_i` on the Swift side.
    Add a dedicated `swiftIdentifierEscaped` that leaves ASCII alphanumerics
    and `_` untouched and hex-escapes everything else, and apply it to the
    Swift function name only; the JNI symbol keeps `cdeclEscaped`. The `+`
    case from #262 is unchanged (both escapers map `+` to `_0002b`). Also
    corrects the `cdeclEscaped` doc comment, which claimed `.` -> `_` while
    the code preserves `.`.
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Configuration menu

    Browse the repository at this point in the history

  5. Configuration menu

    Browse the repository at this point in the history

Read the original on github.com ↗