Skip to content

Fix #2004: Add forwarders to XXL functions apply method #2511

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 1 commit into from
May 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class Compiler {
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives
new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method
new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package dotty.tools.dotc
package transform

import core._
import Constants.Constant
import Contexts.Context
import Flags._
import Definitions._
import DenotTransformers._
import StdNames._
import Symbols._
import TreeTransforms._
import Types._


/** This phase adds forwarder for XXL functions `apply` methods that are implemented with a method
* with explicit parameters (not in Array[Object]).
*
* In particular for every method
* `def apply(x1: T1, ... xn: Tn): R` in class `M` subtype of `FunctionN[T1, ..., Tn, R]` with `N` > 22
* a forwarder
* `def apply(xs: Array[Object]): R = this.apply(xs(0).asInstanceOf[T1], ..., xs(n-1).asInstanceOf[Tn]).asInstanceOf[R]`
* is generated.
*/
class FunctionXXLForwarders extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
import ast.tpd._

override def phaseName: String = "functionXXLForwarders"

override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo): Template = {

def forwarderRhs(receiver: Tree, xsTree: Tree): Tree = {
val argsApply = ref(xsTree.symbol).select(nme.apply)
var idx = -1
val argss = receiver.tpe.widenDealias.paramInfoss.map(_.map { param =>
idx += 1
argsApply.appliedToArgs(List(Literal(Constant(idx)))).asInstance(param)
})
ref(receiver.symbol).appliedToArgss(argss).asInstance(defn.ObjectType)
}

val forwarders =
for {
tree <- if (impl.symbol.owner.is(Trait)) Nil else impl.body
if tree.symbol.is(Method) && tree.symbol.name == nme.apply &&
tree.symbol.signature.paramsSig.size > MaxImplementedFunctionArity &&
tree.symbol.allOverriddenSymbols.exists(sym => defn.isXXLFunctionClass(sym.owner))
} yield {
val xsType = defn.ArrayType.appliedTo(List(defn.ObjectType))
val methType = MethodType(List(nme.args))(_ => List(xsType), _ => defn.ObjectType)
val meth = ctx.newSymbol(tree.symbol.owner, nme.apply, Synthetic | Method, methType)
DefDef(meth, paramss => forwarderRhs(tree, paramss.head.head))
}

cpy.Template(impl)(body = forwarders ::: impl.body)
}

}
3 changes: 2 additions & 1 deletion tests/run/i2004.check
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
1
2
67
12 changes: 10 additions & 2 deletions tests/run/i2004.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
object Test {
def main(args: Array[String]) = {
val f: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int =

val f: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = new Fun26
println(f.apply(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))

val g: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int =
{
(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int) =>
x1
}
println(f.apply(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))
println(g.apply(67, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))

}
}

class Fun26 extends Function26[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int] {
def apply(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int): Int = x2
}
2 changes: 2 additions & 0 deletions tests/run/i2004b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
4
3
26 changes: 26 additions & 0 deletions tests/run/i2004b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
object Test {
def main(args: Array[String]) = {
val f: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = new Fun26_1
println(f.apply(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))

val g: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = new Fun26_2
println(g.apply(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))
}
}


class Fun26_1 extends Fun26_t {
override def apply(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int): Int = x4
}

class Fun26_2 extends Fun26_c {
override def apply(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int): Int = x3
}

trait Fun26_t extends Function26[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int] {
def apply(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int): Int = x2
}

trait Fun26_c extends Function26[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int] {
def apply(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int): Int = x2
}