Consider following code:
object Main extends App {
object Project {
case class Config(rules: Seq[String] = Seq.empty)
}
import Project._
//case class Project(root: String, config: Config) // compiles fine
//case class Project(root: String, config: Project.Config = Project.Config()) // compiles fine
case class Project(root: String, config: Config = Config()) // error: not found: type Config
}
Why does the last version not compile (same with Config = Config.apply()
)?
It is not clear to me if this is a bug or not, but here is why it produces an error:
Consider this, which works:
import Project._
object Project {
case class Config()
}
case class Project(config: Config = Config())
When you add a default argument the compiler generates a method to calculate the value. When that value is a constructor default, that method is added to the companion object of the class. So the compiler will generate this method:
def <init>$default$1: Project.Config = Config()
Which will get added to your Project
object.
The Scala type checker generates an object tree of Contexts
. Each context has a reference to the context of it's outer scope. So the generated method gets a context and that generated method's outer scope is the Project
companion object.
When the type checker attempts to resolve Config()
it traverses all the enclosing contexts and cannot find Config
(I am not sure why, and this may be a bug).
Once it has exhausted the contexts it resolves the imports which has the import Project._
! The type checker is happy because it can now traverse the imports and find the apply method.
Now when you move the import below Project
:
object Project {
case class Config()
}
import Project._
case class Project(config: Config = Config())
In this case the imports available to the generated method does not have the Project._
import (this may also be a bug), I'm assuming because it's below the object definition which is where the generated method lives. The type checker then throws an error because it can't find Config
.
What appears to be happening is when the type checker is resolving Config()
it needs the import above the Project
companion object as it needs to process the import to be able to resolve it and unless the import is above Project
that import is not in scope.
For those who wish to debug further take a look at Contexts.lookupSymbol
which is where the lookup is happening
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With