https://kotlinlang.org logo
#compiler
Title
# compiler
j

Johann Beleites

07/20/2022, 1:38 PM
Take the following code snippet:
Copy code
abstract class Base {
    open fun foo() = "Base"
}
class A: Base()
class B: Base() {
    override fun foo() = "B"
}

fun main(vararg args: String) {
    val foo: Base = B()
    if (foo is B) println(foo.foo())
}
The call to
foo.foo()
in the main method results in
B
to be printed, as expected. However, when I try to resolve
foo.foo()
using the compiler, it resolves it to the implementation in
Base
. This can be observed as well when pasting the code into IntelliJ and
Ctrl + clicking
on
foo.foo()
call. If I change the line to
println((foo as B).foo())
the static resolution works as expected and resolves to the implementation in
B
. I don't know how exactly smart casts work internally, however, shouldn't the compiler resolve to
B#foo
in both cases?
m

mcpiroman

07/21/2022, 7:19 AM
Apparently static resolution works just on static types, excluding smart casts which is quite a different thing. So the compiler is not smart at all here, it just uses the static (declared or inferred) type of the variable.
d

dmitriy.novozhilov

07/21/2022, 7:44 AM
If in call
x.foo()
receiver has smartcast, compiler will look for function
foo
firstly in scope of original type and then in scope of smartcasted type. If function
foo
was found in both scopes and function from
B
is not more specific than from
A
(by signature), then compiler will chose function from original type Lack of such mechanism may lead to issues like that: https://youtrack.jetbrains.com/issue/KT-51460