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: Boolean
Eduardo
11/04/2024, 1:44 PMfoo
has the same type of bar
, so it's a T
Eduardo
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