I've cut my code down to the following simplest version to show the problem. I'm not sure why Swift is complaining.
Why does DatabaseGateway
need to conform to protocol Something
???
struct Database {}
open class DatabaseGateway {
let database: Database
public init() {
database = Database()
}
}
struct FilterParameter<T> {}
protocol Something {
associatedtype T: RawRepresentable where T.RawValue == String
var filterParameter: FilterParameter<T> { get }
}
enum VoteTable {}
extension VoteTable {
enum Field: String {
case value = "value"
}
}
final class User: DatabaseGateway, Something {
let filterParameter = FilterParameter<VoteTable.Field>()
}
final class Poll: DatabaseGateway, Something {
let filterParameter = FilterParameter<VoteTable.Field>()
}
struct VoteRecordFilter {
let parameters: [Parameter]
init(parameter: Parameter) {
self.init(parameters: [parameter])
}
init(parameters: [Parameter]) {
self.parameters = parameters
}
init<S: Something>(parameters: [S]) where S.T == VoteTable.Field {
self.init(parameters: parameters.map({
$0.filterParameter
}))
}
typealias Parameter = FilterParameter<VoteTable.Field>
}
extension Poll {
func voteSubmitted(user: User) async throws -> Bool {
let filter = VoteRecordFilter(parameters: [self, user]) // Initializer 'init(parameters:)' requires that 'DatabaseGateway' conform to 'Something'
return true
}
}
The initialiser you want to call takes a type parameter S
. What should S
be, in the call VoteRecordFilter(parameters: [self, user])
?
[self, user]
is neither a [Poll]
nor a [User]
. Swift infers the expression's type to be [DatabaseGateway]
, and tries to use DatabaseGateway
for S
. DatabaseGateway
does not conform to Something
, hence the error. In fact, there is no type S
that allows [self, user]
to be passed to parameters:
.
Instead of making it generic, you can take an array of existential types,
init(parameters: [any Something<VoteTable.Field>]) {
self.init(parameters: parameters.map(\.filterParameter))
}
You should also add T
as the primary associated type of Something
for the Something<VoteTable.Field>
to work.
protocol Something<T> { // add '<T>' here
associatedtype T: RawRepresentable where T.RawValue == String
var filterParameter: FilterParameter<T> { get }
}