-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add Missing parents to companions classes in stdlib-bootsrapped #17978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Missing parents to companions classes in stdlib-bootsrapped #17978
Conversation
4c2b322
to
18d9e48
Compare
18d9e48
to
4d7789d
Compare
&& sym.companionClass.derivesFrom(defn.SerializableClass) | ||
then | ||
// Add Serializable to companion objects of serializable classes | ||
sym.info = sym.info match |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting sym.info
like this does not seem right to me. Normally changes to the info
of symbols must be done in an InfoTransform
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the info update. It should be fine not to patch those infos while compiling the stdlib as we do not really use those parents. We also only pickle the tree, which means that the unpickled info will have the correct info.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er, that seems worse to me. Now the symbol table and the trees are not consistent with each other. That's something that should turn up in Ycheck
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I added an InfoTransformer to PostTyper.
ProblemMatcher.make(ProblemKind.MissingParent, "scala.collection.Searching.Found$"), | ||
ProblemMatcher.make(ProblemKind.MissingParent, "scala.collection.Searching.InsertionPoint$"), | ||
ProblemMatcher.make(ProblemKind.MissingParent, "scala.jdk.FunctionWrappers.AsJava*$"), | ||
ProblemMatcher.make(ProblemKind.MissingParent, "scala.jdk.FunctionWrappers.FromJava*$"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like these come from the fact that their companion class is a case class
and therefore automatically serializable as well. Perhaps that means that Serializable
is added to case classes later? If yes, it would probably make sense to make the objects Serializable
in the same phase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those where actually missing AbstractFunction1
. I miscategorized them back when I could not see which parents where missing in the TASTy-MiMa error message.
9584c5e
to
a880f0b
Compare
a880f0b
to
94ff3f2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but perhaps double-check on Monday at the dotty meeting whether it is acceptable to make PostTyper
an InfoTransformer
.
} | ||
|
||
protected override def infoMayChange(sym: Symbol)(using Context): Boolean = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest factoring that out ina @ThreadUnsafe lazy val
@threadunsafe lazy val compiledStdLib = ctx.settings.Yscala2Stdlib.value
1e81135
to
5ffa8ff
Compare
5ffa8ff
to
cc749e6
Compare
@@ -440,6 +441,8 @@ object desugar { | |||
|
|||
/** The expansion of a class definition. See inline comments for what is involved */ | |||
def classDef(cdef: TypeDef)(using Context): Tree = { | |||
@threadUnsafe lazy val compilingScala2StdLib = ctx.settings.Yscala2Stdlib.value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that will gain you anything to make it a lazy val, since that also adds inefficiency. If you want maximal performance, I'd do this:
val caseClassInScala2StdLib = isClaseClass && ctx.settings.Yscala2Stdlib.value
after isCaseCass
is defined. But it's probably overkill, and we can just test the settings repeatedly.
class PostTyperTransformer extends Transformer { | ||
class PostTyperTransformer(@constructorOnly ictx: Context) extends Transformer { | ||
|
||
@threadUnsafe private val compilingScala2StdLib = ictx.settings.Yscala2Stdlib.value(using ictx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no @threadUnsafe
needed here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not move the val
outside PostTyperTransformer
? Then you don't need to pass a context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not have access to any context outside of PostTyperTransformer
. I could have moved it into newTransformer
. But now there is a better solution.
if !sym.derivesFrom(defn.SerializableClass) | ||
&& sym.companionClass.derivesFrom(defn.SerializableClass) | ||
then | ||
info.derivedClassInfo(declaredParents = info.parents :+ defn.SerializableType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Should we do that as well in Scala 3? (during desugar or Typer). I mean, if a class is Serializable should we automatically make the companion Serializable as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every object
defined in Scala 3 extends Serializable in the bytecode, even if the user didn't ask for it: https://github.com/lampepfl/dotty/blob/76505f8017db9bd3409947869988ff352e17a40a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala#L251-L269
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize Scala 2 had special logic for making the companion extend Serializable in Typer if the class itself does, I guess we could do the same for better source compatibility but otherwise it wouldn't matter.
} | ||
|
||
protected override def infoMayChange(sym: Symbol)(using Context): Boolean = | ||
ctx.settings.Yscala2Stdlib.value && sym.isAllOf(ModuleClass, butNot = Package) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you do need the cache since infoMayChange
is much hotter than the other code where you check for compilingScala2StdLib
. But moving compilingScala2StdLib
to be a field of PostTyper
is sufficient. The problem is that PostTyper
does not take a context. So you probably need something like this:
private var myCompilingScala2StdLib: Boolean = false
private var compilingScala2StdLibKnown = false
def compilingScala2StdLib(using Context): Boolean =
if !compilingScala2StdLibKnown then
myCompilingScala2StdLib = ctx.settings.Yscala2Stdlib.value
compilingScala2StdLibKnown = true
myCompilingScala2StdLib
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That did not work. The issue is that infoMayChange
may be called with contexts that have different values of ctx.settings.Yscala2Stdlib.value
. The instance of PostTyper
is reused across compilation runs.
I found a simpler and more performant solution using
private var compilingScala2StdLib = false
override def initContext(ctx: FreshContext): Unit =
compilingScala2StdLib = ctx.settings.Yscala2Stdlib.value(using ctx)
The tricky part was to find when a context could have a different value of ctx.settings.Yscala2Stdlib.value
. The initContext
seems to be called once before we run the compilation pipeline runPhases
. The setting should be known at that time and it seems to be the option that changes this field the minimum amount of times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I forgot about initContext
! Agreed, this is the best solution.
2163be7
to
8b9d06f
Compare
8b9d06f
to
5079be7
Compare
No description provided.