skip icon indicating copy to clipboard operation
skip copied to clipboard

Error when bridging a protocol that implements Codable

Open piercifani opened this issue 2 months ago • 3 comments

Skip fails to generate JNI bindings for a hierarchy of protocols. I could isolate the issue and you can find a reproducible project here: protocols-errors.zip.

Error message looks something like this:

/Users/piercifani/Desktop/skip-errors/protocols-errors/travel-posters-model/.build/plugins/outputs/travel-posters-model/TravelPostersModel/destination/skipstone/TravelPostersModel/build/swift/plugins/outputs/swift/TravelPostersModel/destination/skipstone/SkipBridgeGenerated/Protocols_Bridge.swift:179:20: error: type 'UserDisplayable_BridgeImpl' does not conform to protocol 'Decodable'
/Users/piercifani/Desktop/skip-errors/protocols-errors/travel-posters-model/.build/plugins/outputs/travel-posters-model/TravelPostersModel/destination/skipstone/TravelPostersModel/build/swift/plugins/outputs/swift/TravelPostersModel/destination/skipstone/SkipBridgeGenerated/SceneApp_Bridge.swift:76:104: error: generic parameter 'ID' could not be inferred
/Users/piercifani/Desktop/skip-errors/protocols-errors/travel-posters-model/.build/plugins/outputs/travel-posters-model/TravelPostersModel/destination/skipstone/TravelPostersModel/build/swift/plugins/outputs/swift/TravelPostersModel/destination/skipstone/SkipBridgeGenerated/SceneApp_Bridge.swift:80:178: error: reference to member 'kotlincompat' cannot be resolved without a contextual type

piercifani avatar Oct 31 '25 11:10 piercifani

This feature currently blocks certain functionalities from being developed.

piercifani avatar Nov 10 '25 17:11 piercifani

The issue appears to be the protocol that conforms to Codable, which we don't support in bridged protocols (because we synthesize a concrete implementation of the protocol which wouldn't know how to decode or encode). Implementing support for this would be a significant project.

The best workaround I can offer is to massage your data model so the root protocol doesn't specify the Codable conformance, but instead conform to it at the implementation class/struct level (which we do support bridging), and then any protocol niceties that rely on it being Codable could be added via a conditional conformance check.

E.g., instead of:

public protocol PlatformCodableProtocol : Codable {
}

extension PlatformCodableProtocol {
    func someFunctionThatUsesCodability() {
        // …
    }
}

public protocol FuseSampleCodableProtocol: PlatformCodableProtocol {
    var i: Int { get set }
}

public class FuseSampleCodableImpl: FuseSampleCodableProtocol {
    public var i: Int

    public init(i: Int) {
        self.i = i
    }
}

You could do:

public protocol PlatformCodableProtocol {
}

extension PlatformCodableProtocol where Self: Codable {
    func someFunctionThatUsesCodability() {
        // …
    }
}

public protocol FuseSampleCodableProtocol: PlatformCodableProtocol {
    var i: Int { get set }
}

public class FuseSampleCodableImpl: FuseSampleCodableProtocol, Codable {
    public var i: Int

    public init(i: Int) {
        self.i = i
    }
}

marcprux avatar Nov 11 '25 23:11 marcprux

The workaround works. Requires a bunch of changes on the current codebase, but I think it's acceptable. Will circle back with the team. Thanks!

piercifani avatar Nov 12 '25 15:11 piercifani