Home > other >  Generic parameter 'T' could not be inferred when using a guard statement to unwrap a gener
Generic parameter 'T' could not be inferred when using a guard statement to unwrap a gener

Time:01-15

I'm trying to use a generic modular function within Combine, but I'm getting the error that generic could not be inferred.

func foo<T>(data: T) -> AnyPublisher<Bool, MyError> {
    
}

func bar<T>(data: T) -> AnyPublisher<String, MyError> {
    Deferred { [weak self] () -> AnyPublisher<Bool, MyError> in
        guard let foo = self?.foo else { // error here
            return Fail(error: .someError)
                .eraseToAnyPublisher()
        }
        
        return foo(data)
    }
    .eraseToAnyPublisher()
    .flatMap { [weak self] (value) -> AnyPublisher<String, MyError> in
        Future<String, MyError> { [weak self] promise in
            // do something with the returned value 
            promise(.success("Success"))
        }
        .eraseToAnyPublisher()
    }
    .eraseToAnyPublisher()
}

enum MyError: Error {
    case someError
}

I'm getting the error when I'm trying to unwrap a function using a guard statement. T doesn't have constraints because it could be multiple disparate types like Data or UIImage which gets type checked within the foo function.

CodePudding user response:

When you have a problem like this, simplify. We can reduce the phenomenon to a very simple case:

class MyClass {
    func foo<T>(data: T) -> Void { }
    func bar<T>(data: T) -> Void {
        let foo = self.foo // error
    }
}

Now, the first thing to realize is that you have two separate T placeholders. You say T with regard to foo and with regard to bar, but they have no relation to one another. We can rewrite more clearly:

class MyClass {
    func foo<FooDataType>(data: FooDataType) -> Void { }
    func bar<BarDataType>(data: BarDataType) -> Void {
        let foo = self.foo // error: Generic parameter 'FooDataType' could not be inferred
    }
}

Now it's clear what the problem is, because we know which placeholder the compiler is having trouble with. When you look at it that way, you realize that FooDataType is entirely confined to foo. How would bar know what type this is going to be?

If your idea is that they should be the same type, then say so. Make the class the generic, not the individual functions:

class MyClass<T> {
    func foo(data: T) -> Void { }
    func bar(data: T) -> Void {
        let foo = self.foo // fine
    }
}
  •  Tags:  
  • Related