Skip to content

Implement Tuple operation directly in the compiler #6539

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 11 commits into from
Jun 6, 2019
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ class Definitions {
def TupleXXL_fromIterator(implicit ctx: Context): Symbol = TupleXXLModule.requiredMethod("fromIterator")

lazy val DynamicTupleModule: Symbol = ctx.requiredModule("scala.runtime.DynamicTuple")
lazy val DynamicTupleModuleClass: Symbol = DynamicTupleModule.moduleClass
lazy val DynamicTuple_consIterator: Symbol = DynamicTupleModule.requiredMethod("consIterator")
lazy val DynamicTuple_concatIterator: Symbol = DynamicTupleModule.requiredMethod("concatIterator")
lazy val DynamicTuple_dynamicApply: Symbol = DynamicTupleModule.requiredMethod("dynamicApply")
Expand Down
19 changes: 10 additions & 9 deletions compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
def phaseName: String = "genericTuples"

override def transformApply(tree: tpd.Apply)(implicit ctx: Context): tpd.Tree = {
if (tree.symbol == defn.DynamicTuple_dynamicCons) transformTupleCons(tree)
if (!tree.symbol.exists || tree.symbol.owner != defn.DynamicTupleModuleClass) super.transformApply(tree)
else if (tree.symbol == defn.DynamicTuple_dynamicCons) transformTupleCons(tree)
else if (tree.symbol == defn.DynamicTuple_dynamicTail) transformTupleTail(tree)
else if (tree.symbol == defn.DynamicTuple_dynamicSize) transformTupleSize(tree)
else if (tree.symbol == defn.DynamicTuple_dynamicConcat) transformTupleConcat(tree)
Expand All @@ -34,8 +35,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
}

private def transformTupleCons(tree: tpd.Apply)(implicit ctx: Context): Tree = {
val TypeApply(_, headType :: tailType :: Nil) = tree.fun
val tail :: head :: Nil = tree.args
val head :: tail :: Nil = tree.args
tupleTypes(tree.tpe) match {
case Some(tpes) =>
// Generate a the tuple directly with TupleN+1.apply
Expand All @@ -44,7 +44,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
// val t = tail
// TupleN+1(head, t._1, ..., t._n)
evalOnce(Typed(tail, TypeTree(defn.tupleType(tpes.tail)))) { tup =>
val elements = head :: (0 until size - 1).map(i => tup.select(nme.selectorName(i))).toList
val elements = head :: tupleSelectors(tup, size - 1)
knownTupleFromElements(tpes, elements)
}
} else {
Expand Down Expand Up @@ -77,7 +77,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
// val t = tup.asInstanceOf[TupleN[...]]
// TupleN-1(t._2, ..., t._n)
evalOnce(Typed(tup, TypeTree(defn.tupleType(tpes)))) { tup =>
val elements = (1 until size).map(i => tup.select(nme.selectorName(i))).toList
val elements = tupleSelectors(tup, size).tail
knownTupleFromElements(tpes.tail, elements)
}
} else if (size <= MaxTupleArity + 1) {
Expand Down Expand Up @@ -125,10 +125,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
evalOnce(Typed(self, TypeTree(defn.tupleType(tpes1)))) { self =>
evalOnce(Typed(that, TypeTree(defn.tupleType(tpes2)))) { that =>
val types = tpes1 ::: tpes2
val elements = {
(0 until n).map(i => self.select(nme.selectorName(i))) ++
(0 until m).map(i => that.select(nme.selectorName(i)))
}.toList
val elements = tupleSelectors(self, n) ::: tupleSelectors(that, m)
knownTupleFromElements(types, elements)
}
}
Expand Down Expand Up @@ -235,4 +232,8 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
}
rec(tp.stripTypeVar, Nil, bound)
}

private def tupleSelectors(tup: Tree, size: Int)(implicit ctx: Context): List[Tree] =
(0 until size).map(i => tup.select(nme.selectorName(i))).toList

}
2 changes: 1 addition & 1 deletion library/src-3.x/scala/Tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ sealed trait Tuple extends Any {
* This opteration is O(this.size)
*/
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
DynamicTuple.dynamicCons[This, H](this, x)
DynamicTuple.dynamicCons[H, This](x, this)

/** Return a new tuple by concatenating `this` tuple with `that` tuple.
* This opteration is O(this.size + that.size)
Expand Down
2 changes: 1 addition & 1 deletion library/src-3.x/scala/runtime/DynamicTuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ object DynamicTuple {
arr
}

def dynamicCons[This <: Tuple, H] (self: Tuple, x: H): H *: This = {
def dynamicCons[H, This <: Tuple](x: H, self: Tuple): H *: This = {
type Result = H *: This
(self: Any) match {
case () =>
Expand Down
4 changes: 2 additions & 2 deletions tests/run-with-compiler/staged-tuples/StagedTuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ object StagedTuple {
}

def consStaged[T <: Tuple & Singleton : Type, H : Type](self: Expr[T], x: Expr[H], tailSize: Option[Int]): Expr[H *: T] =
if (!specialize) '{dynamicCons[T, H]($self, $x)}
if (!specialize) '{dynamicCons[H, T]($x, $self)}
else {
val res = tailSize match {
case Some(0) =>
Expand All @@ -200,7 +200,7 @@ object StagedTuple {
case Some(n) =>
fromArrayStaged[H *: T]('{cons$Array($x, ${ toArrayStaged(self, tailSize) })}, Some(n + 1))
case _ =>
'{dynamicCons[T, H]($self, $x)}
'{dynamicCons[H, T]($x, $self)}
}
res.as[H *: T]
}
Expand Down