Error when bridging a protocol that implements Codable
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
This feature currently blocks certain functionalities from being developed.
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
}
}
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!