-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Conversation
@@ -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] |
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.
You could skip the new logic here if clazz.isJavaDefined
.
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.
In fact, I think we could skip the rest of the info transform in that case. Worth an experiment.
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.
Good idea, I'll give it a go.
@@ -0,0 +1 @@ | |||
-sourcepath test/files/jvm/varargs-separate-bytecode/ |
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 haven't seen this done before in partest. What's the intent? Is there a simpler way?
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.
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?
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.
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 = { |
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.
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 |
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.
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)) |
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.
nit, but this local isn't necessary IMO, the code would be clear without
Two things still pending:
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)) | ||
} |
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.
could use exitingUncurry
to be more explicit
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.
Unfortunately there is no such thing in scala.reflect.internal
, only in the compiler cake.
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 yes :)
LGTM, thanks a lot! In terms of squashing I think one commit for the |
@@ -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 => |
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.
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) | ||
} |
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.
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.
Passes at least sbt partest --grep varargs
.
@lrytz Do you remember any gotchas in this code that justify the current approach?
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, your patch LGTM. @dragos you want to include it in this PR, maybe as a separate commit?
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.
Ok, I'll add it as another commit and let the bot tell us what's going on
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!
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? |
🚢 it! |
Wohoo! Thanks for the speedy review! |
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:
and nsc.transform
review by @lrytz