How prevent type inference?


#1

Sorry for my English. I would like to use function test with parameter value exactly type of some property. But it declared as out R, and compiler inference type to Any if types is distinct.
For example:

open class Foo(var barInt: Int)

// public interface KProperty1<T, out R> : KProperty<R>, (T) -> R

fun <E : Foo, T> test(field: kotlin.reflect.KProperty1<E, T>, value: T) {}

fun main(args: Array<String>) {
    test(Foo::barInt, 12345) // ok
    test(Foo::barInt, "NotInt") // ok! Type T is Any, but I would like compile error
}

What can be done?


#2

As far as I know it is not possible yet. There are a few internal annotations used for this in the standard library but they are not publicly usable. There is another discussion with the same problem here where Ilya explains this


TL;DR of it: they know that this is useful but have not made it public yet because they are not sure of the design of those annotations.


#3

I will wait. Thank you very much for your answer.


#4

I found temporary workaround for those who are ready to possible future refactoring.
It may be kotlin compiler or ide bug:

  1. Create file kotlin/internal/Annotations.kt in source root of your project:
package kotlin.internal

@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
annotation class Exact
  1. Add compiler command line parameter: -Xallow-kotlin-package
  2. Using this annotation:
import kotlin.internal.Exact

open class Foo(val barInt: Int)

// public interface KProperty1<T, out R> : KProperty<R>, (T) -> R

fun <E : Foo, T> test(field: kotlin.reflect.KProperty1<E, @Exact T>, value: T): T = TODO()


fun main(args: Array<String>) {
    test(Foo::barInt, 123) // ok
    test(Foo::barInt, "NotInt") // expected compile error:
    /*
        Error:(13, 5) Kotlin: Type inference failed: Cannot infer type parameter T in fun <E : Foo, T> test(field: KProperty1<E, T>, value: T): T
        None of the following substitutions
        (KProperty1<Foo, Int>,Int)
        (KProperty1<Foo, String>,String)
        can be applied to
        (KProperty1<Foo, Int>,String)
    */
}

Inference with unexpected outcome
Kotlinx metadata, get Metadata Annotation processor
#5

That is amazing :smile: love it


#6

Maybe I’m wrong, but that looks like a dirty hack to me.

Is this supposed to be done? And why would one even need @Exact? I want my compilers to be always exact!


#7

I guess it is, so I would not rely on this in production code.

The @Exact annotation means, that the compiler will only accept arguments with the exact type.

fun <A, B: List<A>>foo(a: A, list: B) {}

foo(1, listOf(1, 2, 3)) // this should always work
foo(1, lisOf(true, false))  // this also works: B is now List<Any> and A is Any

fun <A> bar(a: A, list: List<A>) {}  // has the same results

With the @Exact annotation the kotlin standard library forces this to work in a way where when a is an integer the list also needs to be a list of integers.
That way you can create functions like contains.

Ok it uses another internal annotation but the idea is the same. This is also the reason I guess why they are still internal. They are not that obvious to use and the design for them is not yet settled enough to make them public.


#8

Interesting.
Thanks for the explanation!