The compiler cannot account for every path through a program. At that point it would essentially be actually running the program (and often multiple times) in order to calculate all possible types. In terms of theory, this is somewhat similar to the halting problem.
I think of it like this: you have static guarantees, and runtime guarantees. Static guarantees are known because of the way the program is structured (if-blocks, val instead of var, etc). These are often easy for the compiler to figure out. Runtime guarantees are known because of what the program actually does within its given structure. These are difficult or impossible for the compiler to know ahead of time. I'd say your example is a case of a runtime guarantee.
Try something like this:
fun foo(x: String?): String {
val local = x ?: "hello"
return local
}