Skip to content

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

Conversation

nicolasstucki
Copy link
Contributor

No description provided.

@nicolasstucki nicolasstucki self-assigned this Jun 15, 2023
@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch 4 times, most recently from 4c2b322 to 18d9e48 Compare June 15, 2023 13:03
@nicolasstucki nicolasstucki changed the title Add Serialize to companions of serializable classes in stdlib-bootsrapped Add Missing parents to companions classes in stdlib-bootsrapped Jun 15, 2023
@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch 2 times, most recently from 18d9e48 to 4d7789d Compare June 16, 2023 07:44
@nicolasstucki nicolasstucki marked this pull request as ready for review June 19, 2023 07:51
@nicolasstucki nicolasstucki requested a review from sjrd June 19, 2023 07:53
@nicolasstucki nicolasstucki assigned sjrd and unassigned nicolasstucki Jun 19, 2023
&& sym.companionClass.derivesFrom(defn.SerializableClass)
then
// Add Serializable to companion objects of serializable classes
sym.info = sym.info match
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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*$"),
Copy link
Member

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.

Copy link
Contributor Author

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.

@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch 2 times, most recently from 9584c5e to a880f0b Compare June 20, 2023 13:38
@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch from a880f0b to 94ff3f2 Compare June 23, 2023 13:45
Copy link
Member

@sjrd sjrd left a 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.

@nicolasstucki nicolasstucki self-assigned this Jun 23, 2023
}

protected override def infoMayChange(sym: Symbol)(using Context): Boolean =
Copy link
Contributor

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 

@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch from 1e81135 to 5ffa8ff Compare June 26, 2023 12:57
@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch from 5ffa8ff to cc749e6 Compare June 26, 2023 13:00
@nicolasstucki nicolasstucki assigned odersky and unassigned sjrd and nicolasstucki Jun 26, 2023
@nicolasstucki nicolasstucki requested a review from odersky June 26, 2023 14:52
@@ -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
Copy link
Contributor

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no @threadUnsafe needed here

Copy link
Contributor

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.

Copy link
Contributor Author

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)
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. We should check if this change was intentional. @sjrd @smarter do you have more details about this?

Copy link
Member

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

Copy link
Member

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)
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@odersky odersky assigned nicolasstucki and unassigned odersky Jun 27, 2023
@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch 2 times, most recently from 2163be7 to 8b9d06f Compare June 28, 2023 08:32
@nicolasstucki nicolasstucki force-pushed the add-serializable-to-objects-in-stdlib-bootsrapped branch from 8b9d06f to 5079be7 Compare June 28, 2023 08:36
@odersky odersky assigned nicolasstucki and unassigned odersky Jun 30, 2023
@nicolasstucki nicolasstucki merged commit 9e06db7 into scala:main Jun 30, 2023
@nicolasstucki nicolasstucki deleted the add-serializable-to-objects-in-stdlib-bootsrapped branch June 30, 2023 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants