Home > Software design >  Type inference failed. MutableMap<Class<out AbsViewModel>, Provider<AbsViewModel>>
Type inference failed. MutableMap<Class<out AbsViewModel>, Provider<AbsViewModel>>

Time:10-13

kotlin 1.5 changes a type inference warning (present in 1.4) into an error. Is there anyway to ignore the error in 1.5? Currently, I need to downgrade to 1.4 to compile the code.

"Type inference failed. The value of the type parameter K should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly."

--> providerMap[modelClass]

class ViewModelFactory @Inject constructor(private val providerMap: MutableMap<Class<out AbsViewModel>, Provider<AbsViewModel>>) : ViewModelProvider.Factory {
    @Suppress("TYPE_INFERENCE_ONLY_INPUT_TYPES_WARNING", "UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        (providerMap[modelClass]?.get() as? T)?.let { return it }
        throw Exception("Could not find view model for ${modelClass.canonicalName}")
    }

}

CodePudding user response:

class ViewModelFactory @Inject constructor(
    private val providerMap: MutableMap<Class<out AbsViewModel>,
            Provider<AbsViewModel>>) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        (providerMap[modelClass as Class<out AbsViewModel>]?.get() as? T)?.let { return it }
        throw Exception("Could not find view model for ${modelClass.canonicalName}")
    }
}

CodePudding user response:

Either make the input type of your Map key Class a wildcard:

class ViewModelFactory @Inject constructor(
    private val providerMap: MutableMap<Class<*>,
            Provider<AbsViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        @Suppress("UNCHECKED_CAST")
        (providerMap[modelClass]?.get() as? T)?.let { return it }
        throw Exception("Could not find view model for ${modelClass.canonicalName}")
    }
}

Or if you prefer to enforce the type in the constructor, cast the key:

class ViewModelFactory @Inject constructor(
    private val providerMap: MutableMap<Class<out AbsViewModel>,
            Provider<AbsViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        @Suppress("UNCHECKED_CAST")
        (providerMap[modelClass as Class<AbsViewModel>]?.get() as? T)?.let { return it }
        throw Exception("Could not find view model for ${modelClass.canonicalName}")
    }
}

And either way you can simplify your return/throw using ?: instead of ?.let:

return providerMap[modelClass]?.get() as? T 
    ?: error("Could not find view model for ${modelClass.canonicalName}")
  • Related