Description
The following code typechecks, even though it looks like length
is accessed before it's imported:
val a: String = ""
val x = length
import a.length
val b = length
This happens because desugaring moves top-level definitions below everything else:
import a.length
final lazy module val test$package: test$package = new test$package()
final module class test$package() extends Object() { this: test$package.type =>
val a: String = ""
val x: Int = a.length()
val b: Int = a.length()
}
This behavior is not specified, https://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html simply states that "The compiler generates synthetic objects that wrap top-level definitions", but it doesn't say anything about statements being reordered (one could imagine the package object being defined above the other definitions, but then no import would be visible at all).
I think ideally we would prevent this code from typechecking, but it seems like that would require a much more involved desugaring of top-level definition, so short of that we should document the status quo.