Swift Generics: Cannot Convert Value of Type to Expected Argument Type

Swift generics error: Cannot convert value of type 'Type T ' to expected argument type 'Type _ '

You are using a non-generic concrete type MyModel in a generic function, that doesn't work.

You could do something like this

class Test {
func test<T: MyProcotol>(item: T, completion: (Result<T>) -> Void) {
let result : Result<T> = .success(value: item)
completion(result)
}
}

Cannot convert value of type 'T?' to expected argument type 'T?'

You need to use an associatedtype in your protocol so all functions/variables in the protocol uses the same type because otherwise each function with a <T> will be using a different type

Example (simplified

protocol PostDataProviderProtocol{
associatedtype T

func getItemAt(index:Int)-> T?
func replaceItemAt(index:Int, item:T?)
}

Then in your class you can use it as

class BaseDataProvider<SomeType> {
internal var _itemsPerPage:Int = 0
internal var _page:Int = 0
internal var _endpoint:String = ""
internal var cachedData:[SomeType?] = []
}

extension BaseDataProvider: PostDataProviderProtocol {
typealias T = SomeType

func hasNext() -> Bool {
true
}

func getItemAt(index: Int) -> T? {
self.cachedData[index]
}

func getItems() -> [T] {
return self.cachedData as! [T]
}

}

Swift: cannot convert value of type 'SomeType T ' to expected argument type 'SomeType _ '

The following code worked for me.

struct PageData<T> {
let item: T
let pageNumber: Int
}

protocol PagedServiceProvider: class {
associatedtype T
var pageData: PageData<T>? { get set }
func fetchPage(page: Int, completion: @escaping (PageData<T>?) -> Void)
}

class TestPagedServiceProvider: PagedServiceProvider {

var pageData: PageData<String>?

func fetchPage(page: Int, completion: @escaping (PageData<String>?) -> Void) {
completion(pageData)
}

}

Swift generic func cannot convert value of type to expected argument type

That's a compiler bug. Had the same issue when Xcode 10 came out.
Adapt your method to the following:

func importArray<T: ImportableUniqueObject>(from exercisesDict: [[String: Any]], transaction: BaseDataTransaction) -> [T] where T.ImportSource == [String: Any] {
let managedObjects = try? transaction.importUniqueObjects(Into<T>(), sourceArray: jsonObjects)
}

Though I recommend do not do force-try when importing.

Also see: https://bugs.swift.org/browse/SR-8945

Swift Generics: Cannot convert value of type to expected argument type

Swift 4.1 Update

This is a bug that was fixed in this pull request, which will make it into the release of Swift 4.1. Your code now compiles as expected in a 4.1 snapshot.


Pre Swift 4.1

This just looks like you're just stretching the compiler too far.

  • It can deal with conversions from arrays of sub-typed elements to arrays of super-typed elements, e.g [A] to [SomeProtocol] – this is covariance. It's worth noting that arrays have always been an edge case here, as arbitrary generics are invariant. Certain collections, such as Array, just get special treatment from the compiler allowing for covariance.

  • It can deal with conversions of functions with super-typed parameters to functions with sub-typed parameters, e.g (SomeProtocol) -> Void to (A) -> Void – this is contravariance.

However it appears that it currently cannot do both in one go (but really it should be able to; feel free to file a bug).

For what it's worth, this has nothing to do with generics, the following reproduces the same behaviour:

protocol SomeProtocol {}
class A : SomeProtocol {}

func f1(listener: (A) -> Void) {}
func f2(listener: ([A]) -> Void) {}
func f3(listener: () -> [SomeProtocol]) {}

func g() {

let l1: (SomeProtocol) -> Void = { _ in }
f1(listener: l1) // NO ERROR

let l2: ([SomeProtocol]) -> Void = { _ in }
f2(listener: l2)
// COMPILER ERROR: Cannot convert value of type '([SomeProtocol]) -> Void' to
// expected argument type '([A]) -> Void'

// it's the same story for function return types
let l3: () -> [A] = { [] }
f3(listener: l3)
// COMPILER ERROR: Cannot convert value of type '() -> [A]' to
// expected argument type '() -> [SomeProtocol]'
}

Until fixed, one solution in this case is to simply use a closure expression to act as a trampoline between the two function types:

// converting a ([SomeProtocol]) -> Void to a ([A]) -> Void.
// compiler infers closure expression to be of type ([A]) -> Void, and in the
// implementation, $0 gets implicitly converted from [A] to [SomeProtocol].
f2(listener: { l2($0) })

// converting a () -> [A] to a () -> [SomeProtocol].
// compiler infers closure expression to be of type () -> [SomeProtocol], and in the
// implementation, the result of l3 gets implicitly converted from [A] to [SomeProtocol]
f3(listener: { l3() })

And, applied to your code:

f2(ofType: A.self, listener: { l2($0) })

This works because the compiler infers the closure expression to be of type ([T]?) -> Void, which can be passed to f2. In the implementation of the closure, the compiler then performs an implicit conversion of $0 from [T]? to [SomeProtocol]?.

And, as Dominik is hinting at, this trampoline could also be done as an additional overload of f2:

func f2<T : SomeProtocol>(ofType type: T.Type, listener: ([SomeProtocol]?) -> Void) {
// pass a closure expression of type ([T]?) -> Void to the original f2, we then
// deal with the conversion from [T]? to [SomeProtocol]? in the closure.
// (and by "we", I mean the compiler, implicitly)
f2(ofType: type, listener: { (arr: [T]?) in listener(arr) })
}

Allowing you to once again call it as f2(ofType: A.self, listener: l2).

Cannot convert value of generic associated type of protocol to expected argument type

The generic T in your function and the associated type T in your protocol aren't the same T. Inside the function, T is referring to the type that is implementing the protocol so the associatedtype is T.T inside of the function. Your arrays and the return value would have to be using T.T.

This also means that you will need an additional parameter to your function because the [[T.T]] return value isn't enough for the compiler to infer what type T is.

This should work (I changed the generic parameter to U because all the Ts are confusing):

func dataSource<U: UniqueInit>(initializer: U.Type, nrRowsInSection: Int...) -> [[U.T]] {
var result: [[U.T]] = []
for nrRows in nrRowsInSection {
var row: [U.T] = []
for _ in 0 ..< nrRows {
row.append(U.uniqueInit())
}
result.append(row)
}
return result
}

Alternatively, you could define your function as an extension on UniqueInit which would eliminate the need for the generics:

extension UniqueInit {
func dataSource(nrRowsInSection: Int...) -> [[T]] {
var result: [[T]] = []
for nrRows in nrRowsInSection {
var row: [T] = []
for _ in 0 ..< nrRows {
row.append(Self.uniqueInit())
}
result.append(row)
}
return result
}
}

Cannot convert value of type 'MyEnum T.Type ' to expected argument type 'MyEnum _ '

The error occurs because NetworkResponse expects an instance of T, while the mock tries to provide the actual T.

So, you need to somehow provide an instance, however this cannot be generated by the mock as it doesn't have enough information about how to construct an instance.

I recommend injecting the success value from the outside, when creating the mock. You can do this either by making the mock class generic, or by making the Mode enum generic. Below is a sample implementation for the latter:

class MockUrlSessionProvider: ProviderProtocol {

// making the enum generic, to support injecting the success value
enum Mode<T> {
case success(T)
case empty
case fail
}

// need to have this as `Any` to cover all possible T generic arguments
private var mode: Any

// however the initializer can be very specific
init<T>(mode: Mode<T>) {
self.mode = mode
}

func request<T>(type: T.Type, service: ServiceProtocol, completion: @escaping (NetworkResponse<T>) -> Void) where T: Decodable {
// if the mock was not properly configured, do nothing
guard let mode = mode as? Mode<T> else { return }
// alternatively you force cast and have the unit test crash, this should help catching early configuration issues
// let mode = mode as! Mode<T>

switch mode {
case let .success(value): completion(NetworkResponse.success(value))
case .empty: completion(.failure(.noData))
case .fail: completion(.failure(.unknown("Error")))
}

}
}

Cannot convert value of type '(Store).Type' to expected argument type 'Binding C '

Case sensitivity matters. You mean store, the StoreViewModel instance and not the type of self. Further the purpose of a ForEach expression is to iterate an array (presumably item(s)).

First of all to avoid more confusion rename item in StoreViewModel as its plural form

class StoreViewModel: ObservableObject{

@Published var items: [String] = []
@Published var amount: [String] = []

}

Then replace

ForEach((Store), id: \.self){ item in

with

ForEach(store.items, id: \.self){ item in


Related Topics



Leave a reply



Submit