8000 SI-10071 Separate compilation for varargs methods by dragos · Pull Request #5556 · scala/scala · GitHub
[go: up one dir, main page]

Skip to content

SI-10071 Separate compilation for varargs methods #5556

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

Merged
merged 3 commits into from
Nov 25, 2016

Conversation

dragos
Copy link
Contributor
@dragos dragos commented Nov 24, 2016

Make sure that methods annotated with varargs are properly mixed-in. This commit
splits the transformation into an info transformer (that works on all symbols, whether
they come from source or binary) and a tree transformer.

The gist of this is that the symbol-creation part of the code was moved to the UnCurry
info transformer, while tree operations remained in the tree transformer. The newly
created symbol is attached to the original method so that the tree transformer can still
retrieve the symbol.

A few fall outs:

  • I removed a local map that was identical to TypeParamsVarargsAttachment
  • moved the said attachment to StdAttachments so it’s visible between reflect.internal
    and nsc.transform
  • a couple more comments in UnCurry to honour the boy-scout rule

review by @lrytz

@scala-jenkins scala-jenkins added this to the 2.12.2 milestone Nov 24, 2016
@@ -67,8 +74,25 @@ trait UnCurry {
tp match {
case ClassInfoType(parents, decls, clazz) =>
val parents1 = parents mapConserve uncurry
if (parents1 eq parents) tp
else ClassInfoType(parents1, decls, clazz) // @MAT normalize in decls??
val varargOverloads = mutable.ListBuffer.empty[Symbol]
Copy link
Member
@retronym retronym Nov 24, 2016

Choose a reason for hiding this comment

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

You could skip the new logic here if clazz.isJavaDefined.

Copy link
Member

Choose a reason for hiding this comment

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

In fact, I think we could skip the rest of the info transform in that case. Worth an experiment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, I'll give it a go.

@@ -0,0 +1 @@
-sourcepath test/files/jvm/varargs-separate-bytecode/
Copy link
Member

Choose a reason for hiding this comment

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

I haven't seen this done before in partest. What's the intent? Is there a simpler way?

Copy link
Contributor Author
@dragos dragos Nov 24, 2016

Choose a reason for hiding this comment

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

You're right, it's being used in presentation compiler tests only. What I need is to make sure that AbstractProps is not compiled together with Props.scala. Is there a way to compile first one set of files and afterwards another set of files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, it looks like appending _1 and _2 to source files makes them compile in separate compiler runs, so my last commit simplifies the test to not use -sourcepath. I can squash the commits later, for the moment I'll keep them as separate, so reviewers can track what's new.

*
* @note The Java-style varargs method symbol is generated in the Uncurry info transformer. If the
* symbol can't be found this method reports a warning and carries on.
* @see [[scala.reflect.internal.transform.UnCurry]]
*/
private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = {
Copy link
Contributor Author
@dragos dragos Nov 24, 2016

Choose a reason for hiding this comment

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

This method signature is confusing, but I chose to keep things simple and I didn't touch it.

flatdd is not required since almost all the logic is based on Symbols and the two trees always have the same symbol. Additionally, the only legitimate use of a tree is in the call to newTyper(dd,..), though I'm not sure that there's no other way. If you have any suggestions here I'm happy to at least remove the extra parameter.

@@ -67,8 +74,29 @@ trait UnCurry {
tp match {
case ClassInfoType(parents, decls, clazz) =>
val parents1 = parents mapConserve uncurry
Copy link
Member

Choose a reason for hiding this comment

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

move this declaration into the else branch below?

// is anyway faster and safer
for (decl <- decls if decl.annotations.exists(_.symbol == VarargsClass)) {
if (mexists(decl.paramss)(sym => definitions.isRepeatedParamType(sym.tpe))) {
val forwarderSym = varargForwarderSym(clazz, decl, exitingPhase(phase)(decl.info))
Copy link
Member

Choose a reason for hiding this comment

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

nit, but this local isn't necessary IMO, the code would be clear without

@dragos
Copy link
Contributor Author
dragos commented Nov 24, 2016

Two things still pending:

  • do we do anything about the parameters of def addJavaVarargsForwarders? I'm fine to leave it as-is, just making sure you've seen my comment
  • squash, and how much?

Once this is in I will open a PR to backport the fix to 2.11.

for (decl <- decls if decl.annotations.exists(_.symbol == VarargsClass)) {
if (mexists(decl.paramss)(sym => definitions.isRepeatedParamType(sym.tpe))) {
varargOverloads += varargForwarderSym(clazz, decl, exitingPhase(phase)(decl.info))
}
Copy link
Member

Choose a reason for hiding this comment

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

could use exitingUncurry to be more explicit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately there is no such thing in scala.reflect.internal, only in the compiler cake.

Copy link
Member

Choose a reason for hiding this comment

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

ah yes :)

@lrytz
Copy link
Member
lrytz commented Nov 24, 2016

LGTM, thanks a lot! In terms of squashing I think one commit for the if (clazz.isJavaDefined) tp change (this one could go first), and a second with the rest.

@@ -65,18 +72,90 @@ trait UnCurry {
def apply(tp0: Type): Type = {
val tp = expandAlias(tp0)
tp match {
case ClassInfoType(parents, decls, clazz) =>
case ClassInfoType(parents, decls, clazz) if !clazz.isJavaDefined =>
Copy link
Member

Choose a reason for hiding this comment

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

This oversight has come up twice in a week, I've opened a ticket to audit the other info transformers for similar opportunities to do less work!

val mt = MethodType(ps, resTp)
val r = if (tps.isEmpty) mt else PolyType(tps, mt)
r.substSym(oldTps, tps)
}
Copy link
Member

Choose a reason for hiding this comment

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

This is old code, but it is using very low level means to build up the new method symbol. I believe we can just clone the original symbol to get this for free.

https://github.com/retronym/scala/compare/1a21cc667a6f33a576900ea024c3bb21df84638e...retronym:review/5556?expand=11a21cc667a6f33a576900ea024c3bb21df84638e

Passes at least sbt partest --grep varargs.

@lrytz Do you remember any gotchas in this code that justify the current approach?

Copy link
Member

Choose a reason for hiding this comment

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

no, your patch LGTM. @dragos you want to include it in this PR, maybe as a separate commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I'll add it as another commit and let the bot tell us what's going on

dragos and others added 3 commits November 25, 2016 10:50
Make sure that methods annotated with varargs are properly mixed-in. This commit
splits the transformation into an info transformer (that works on all symbols, whether
they come from source or binary) and a tree transformer.

The gist of this is that the symbol-creation part of the code was moved to the UnCurry
info transformer, while tree operations remained in the tree transformer. The newly
created symbol is attached to the original method so that the tree transformer can still
retrieve the symbol.

A few fall outs:

- I removed a local map that was identical to TypeParamsVarargsAttachment
- moved the said attachment to StdAttachments so it’s visible between reflect.internal
  and nsc.transform
- a couple more comments in UnCurry to honour the boy-scout rule
Cloning the original symbol in its entirety, rather than cloning
its type/value parameters individually. `cloneSymbol` takes care of
all the tricky substitutions for us!
@dragos
Copy link
Contributor Author
dragos commented Nov 25, 2016

If this is fine, I'd like to open the backport for 2.11.9. Can you please let me know if there's anything else here, or I can merge?

@lrytz
Copy link
Member
lrytz commented Nov 25, 2016

🚢 it!

@dragos dragos merged commit 690ba80 into scala:2.12.x Nov 25, 2016
@dragos
Copy link
Contributor Author
dragos commented Nov 25, 2016

Wohoo! Thanks for the speedy review!

9FF5

@dragos dragos deleted the ticket/10071 branch November 25, 2016 18:31
@SethTisue SethTisue modified the milestones: 2.12.1, 2.12.2 Nov 25, 2016
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.

5 participants
0