The problem is how generics work.
class Foo { fun <T> T.foo(that: T): T = throw Exception() init { "str" foo 42 } }
This works because the compiler can find a T that matches both the signature of the function and the arguments: it is Any , and the function turns into this:
fun Any.foo(that: Any): Any = ...
String is now a subtype of Any , Int is a subtype of Any , so this function applies to arguments.
But in the first example:
class Foo<T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } }
Everything is different. There is no such T Let naive and try Any :
fun Foo<Any>.plus(that: Foo<Any>): Foo<Any> = ...
Now Foo is invariant in T , so Foo<Int> is not a subtype of Foo<Any> , and in fact there is no type T except Int , which will make Foo<T> supertype of Foo<Int> . So T must be exactly Int , but it must also be exactly String by the same logic (due to the second argument), so there is no solution, and the function is not applicable.
You can make it work by making a co-variant of Foo in T :
class Foo<out T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } }
This imposes some restrictions on the possible signatures of Foo members, but if you are okay with them, this fixes your problem.
Take a look at this link for more details: http://kotlinlang.org/docs/reference/generics.html