This has been bugging me for a couple hours, especially since this is possible:
val x: Any = "string"
require(x is String)
val len = x.length
The compiler is clearly able to understand these, so this is likely a limitation of the contracts themselves.
I've spent a while now trying to come up with some workarounds. For reference:
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?) {
contract {
returns() implies T::class.isInstance(value))
}
if(value !is T){
throw java.lang.IllegalArgumentException("Incorrect type");
}
}
"Unsupported construct"
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?, condition: Boolean = value is T) {
contract {
returns() implies condition
}
if(!condition)
throw IllegalArgumentException("Incorrect type");
}
Compiles, but doesn't enable smart cast. The original motivation behind that one was placing a boolean in front of the contract, but contracts need to be the first part of a function, which made that impossible. You might as well remove the contract; it's useless in this case.
This was my last try:
@UseExperimental(ExperimentalContracts::class)
inline fun assertIsInstance(value: Any?, cls: KClass<out Any>) {
contract {
returns() implies (cls.isInstance(value))
}
if(!cls.isInstance(value))
throw IllegalArgumentException("");
}
Another "unsupported construct".
Somehow I ended up with this:
@UseExperimental(ExperimentalContracts::class)
inline fun assertIsInstance(value: Any?) {
contract {
returns() implies (value.hashCode() == 0)
}
if(value.hashCode() != 0)
throw java.lang.IllegalArgumentException();
}
But this gives a new error: only references to parameters are allowed in contract description
.
TL;DR:
It doesn't look like you can. Sneaking it in like I did in the second example doesn't trigger smart cast, and the rest don't work due to various compiler errors.
At least for now, there doesn't appear to be a way. You could of course open an issue in the Kotlin repo and ask for something like this, but for now, it doesn't appear to be possible.