Skip to content

Commit

Permalink
Add TupledFunction.untuple
Browse files Browse the repository at this point in the history
Also improve type inference of TupledFunction[F, G] when F is not yet inferred
  • Loading branch information
nicolasstucki committed May 28, 2019
1 parent a579756 commit e40963c
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 23 deletions.
13 changes: 13 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import collection.mutable
import Denotations.SingleDenotation
import util.SimpleIdentityMap

import scala.annotation.tailrec

object Definitions {

/** The maximum number of elements in a tuple or product.
Expand Down Expand Up @@ -1198,6 +1200,17 @@ class Definitions {
else TypeOps.nestedPairs(elems)
}

def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(implicit ctx: Context): Option[List[Type]] = {
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp match {
case _ if bound < 0 => Some(acc.reverse)
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)
case tp if tp.classSymbol == defn.UnitClass => Some(acc.reverse)
case _ => None
}
rec(tp.stripTypeVar, Nil, bound)
}

def isProductSubType(tp: Type)(implicit ctx: Context): Boolean =
tp.derivesFrom(ProductType.symbol)

Expand Down
51 changes: 34 additions & 17 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -711,23 +711,40 @@ trait Implicits { self: Typer =>

def synthesizedTupleFunction(formal: Type): Tree = {
formal match {
case AppliedType(_, funArgs @ fun :: tupled :: Nil) if defn.isFunctionType(fun) && defn.isFunctionType(tupled) =>
lazy val funTypes = fun.dropDependentRefinement.dealias.argInfos
lazy val tupledTypes = tupled.dropDependentRefinement.dealias.argInfos
if (
defn.isImplicitFunctionType(fun) == defn.isImplicitFunctionType(tupled) &&
tupledTypes.size == 2 &&
defn.tupleType(funTypes.init) =:= tupledTypes.head &&
funTypes.last =:= tupledTypes.last
) {
val arity = funTypes.size - 1
if (defn.isErasedFunctionType(fun))
EmptyTree // TODO support?
else if (arity <= Definitions.MaxImplementedFunctionArity)
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funArgs)
else
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(funArgs)
} else EmptyTree
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
def functionTypeEqual(baseFun: Type, actualArgs: List[Type], actualRet: Type, expected: Type) = {
expected =:= defn.FunctionOf(actualArgs, actualRet, defn.isImplicitFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
}
val arity: Int = {
if (defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun)) -1 // TODO support?
else if (defn.isFunctionType(fun)) {
// TupledFunction[(...) => R, ?]
fun.dropDependentRefinement.dealias.argInfos match {
case funArgs :+ funRet if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) => funArgs.size
case _ => -1
}
} else if (defn.isFunctionType(tupled)) {
// TupledFunction[?, ((...)) => R]
tupled.dropDependentRefinement.dealias.argInfos match {
case tupledArgs :: funRet :: Nil =>
defn.tupleTypes(tupledArgs) match {
case Some(tpes) if functionTypeEqual(tupled, tpes, funRet, fun) => tpes.size
case _ => -1
}
case _ => -1
}
}
else {
// TupledFunction[?, ?]
-1
}
}
if (arity == -1)
EmptyTree
else if (arity <= Definitions.MaxImplementedFunctionArity)
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funArgs)
else
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(funArgs)
case _ =>
EmptyTree
}
Expand Down
70 changes: 64 additions & 6 deletions library/src-3.x/scala/TupledFunction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,109 +10,167 @@ import scala.annotation.implicitNotFound
@implicitNotFound("${F} cannot be tupled as ${G}")
sealed trait TupledFunction[F, G] {
def tuple(f: F): G
def untuple(g: G): F
}

package internal {

object TupledFunction {

def tupledFunction0[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G =
((args: Unit) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G]
def tuple(f: F): G = ((args: Unit) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G]
def untuple(g: G): F = (() => g.asInstanceOf[Unit => Any].apply(())).asInstanceOf[F]
}

def tupledFunction1[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G =
((args: Tuple1[Any]) => f.asInstanceOf[Any => Any].apply(args._1)).asInstanceOf[G]
def tuple(f: F): G = ((args: Tuple1[Any]) => f.asInstanceOf[Any => Any].apply(args._1)).asInstanceOf[G]
def untuple(g: G): F = ((x1: Any) => g.asInstanceOf[Tuple1[_] => Any].apply(Tuple1(x1))).asInstanceOf[F]
}

def tupledFunction2[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function2[_, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F = Function.untupled(g.asInstanceOf[Tuple2[_, _] => Any]).asInstanceOf[F]
}

def tupledFunction3[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function3[_, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F = Function.untupled(g.asInstanceOf[Tuple3[_, _, _] => Any]).asInstanceOf[F]
}

def tupledFunction4[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function4[_, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F = Function.untupled(g.asInstanceOf[Tuple4[_, _, _, _] => Any]).asInstanceOf[F]
}

def tupledFunction5[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function5[_, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F = Function.untupled(g.asInstanceOf[Tuple5[_, _, _, _, _] => Any]).asInstanceOf[F]
}

def tupledFunction6[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function6[_, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any) =>
g.asInstanceOf[Tuple6[_, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6))).asInstanceOf[F]
}

def tupledFunction7[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function7[_, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any) =>
g.asInstanceOf[Tuple7[_, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7))).asInstanceOf[F]
}

def tupledFunction8[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function8[_, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any) =>
g.asInstanceOf[Tuple8[_, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8))).asInstanceOf[F]
}

def tupledFunction9[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function9[_, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any) =>
g.asInstanceOf[Tuple9[_, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9))).asInstanceOf[F]
}

def tupledFunction10[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function10[_, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any) =>
g.asInstanceOf[Tuple10[_, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10))).asInstanceOf[F]
}

def tupledFunction11[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function11[_, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any) =>
g.asInstanceOf[Tuple11[_, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11))).asInstanceOf[F]
}

def tupledFunction12[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function12[_, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any) =>
g.asInstanceOf[Tuple12[_, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12))).asInstanceOf[F]
}

def tupledFunction13[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function13[_, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any) =>
g.asInstanceOf[Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13))).asInstanceOf[F]
}

def tupledFunction14[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any) =>
g.asInstanceOf[Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14))).asInstanceOf[F]
}

def tupledFunction15[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any) =>
g.asInstanceOf[Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15))).asInstanceOf[F]
}

def tupledFunction16[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any) =>
g.asInstanceOf[Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16))).asInstanceOf[F]
}

def tupledFunction17[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any, x17: Any) =>
g.asInstanceOf[Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17))).asInstanceOf[F]
}

def tupledFunction18[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any, x17: Any, x18: Any) =>
g.asInstanceOf[Tuple18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18))).asInstanceOf[F]
}

def tupledFunction19[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any, x17: Any, x18: Any, x19: Any) =>
g.asInstanceOf[Tuple19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19))).asInstanceOf[F]
}

def tupledFunction20[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any, x17: Any, x18: Any, x19: Any, x20: Any) =>
g.asInstanceOf[Tuple20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20))).asInstanceOf[F]
}

def tupledFunction21[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any, x17: Any, x18: Any, x19: Any, x20: Any, x21: Any) =>
g.asInstanceOf[Tuple21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21))).asInstanceOf[F]
}

def tupledFunction22[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G = f.asInstanceOf[Function22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
def untuple(g: G): F =
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any, x13: Any, x14: Any, x15: Any, x16: Any, x17: Any, x18: Any, x19: Any, x20: Any, x21: Any, x22: Any) =>
g.asInstanceOf[Tuple22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22))).asInstanceOf[F]
}

def tupledFunctionXXL[F, G]: TupledFunction[F, G] = new TupledFunction {
def tuple(f: F): G =
((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G]
def tuple(f: F): G = ((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G]
def untuple(g: G): F = new FunctionXXL {
override def apply(xs: Array[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL(xs))
}.asInstanceOf[F]
}

}
Expand Down
Loading

0 comments on commit e40963c

Please sign in to comment.