Tom De Decker
11/04/2024, 1:43 PMfun <T> test(bar: T) {
var foo = bar
if (foo is Boolean) {
foo = !foo
}
println(foo)
}Tom De Decker
11/04/2024, 1:44 PMfoo = !foo line:
Type mismatch.
Required: T
Found: BooleanEduardo
11/04/2024, 1:44 PMfoo has the same type of bar, so it's a TEduardo
11/04/2024, 1:45 PMJoffrey
11/04/2024, 1:46 PMfoo is T. I guess what happens is that the smart cast only applies to the scope of the if, but doesn't apply to the declaration that's outside this scope.Eduardo
11/04/2024, 1:49 PMfoo is being reassigned inside the if block, if we define a new var, it compiles
fun <T> test(bar: T) {
val foo = bar
if (foo is Boolean) {
val foo2 = !foo
}
println(foo)
}Joffrey
11/04/2024, 1:49 PMfoo is smart cast. The problem is the assignment to the variable from the outer scope. I fail to see a case where the assignment wouldn't be valid, but I guess that's just a limitation of the type checker (it doesn't deduce from the condition that the foo variable's type can be assigned boolean values).Tom De Decker
11/04/2024, 1:51 PMfoo = !foo as T)Joffrey
11/04/2024, 1:52 PMif, the type of the foo variable is still T because you should still be able to assign other `T`s to it, regardless of the current value's type.
The information that the type checker is missing is that T is assignable from Boolean.Tom De Decker
11/04/2024, 1:53 PMHuib Donkers
11/04/2024, 3:28 PMThe information that the type checker is missing is that... which may not be trivial to deduce. I think it only works becauseis assignable fromT.Boolean
Boolean cannot be inherited from. Example where the assignment would (and should) fail:
interface A
interface B {
operator fun not() = object : B {}
}
class AB: A, B
fun <T: A> test(bar: T) {
val foo = bar
if (foo is B) {
val foo2 = !foo
println(foo2 is A) // false
foo = foo2 // fails
}
}Joffrey
11/04/2024, 3:31 PMBoolean to find it 😆)Tom De Decker
11/04/2024, 3:33 PM