Skip to content

Commit e40963c

Browse files
committed
Add TupledFunction.untuple
Also improve type inference of TupledFunction[F, G] when F is not yet inferred
1 parent a579756 commit e40963c

File tree

4 files changed

+219
-23
lines changed

4 files changed

+219
-23
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import collection.mutable
1010
import Denotations.SingleDenotation
1111
import util.SimpleIdentityMap
1212

13+
import scala.annotation.tailrec
14+
1315
object Definitions {
1416

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

1203+
def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(implicit ctx: Context): Option[List[Type]] = {
1204+
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp match {
1205+
case _ if bound < 0 => Some(acc.reverse)
1206+
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
1207+
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)
1208+
case tp if tp.classSymbol == defn.UnitClass => Some(acc.reverse)
1209+
case _ => None
1210+
}
1211+
rec(tp.stripTypeVar, Nil, bound)
1212+
}
1213+
12011214
def isProductSubType(tp: Type)(implicit ctx: Context): Boolean =
12021215
tp.derivesFrom(ProductType.symbol)
12031216

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -711,23 +711,40 @@ trait Implicits { self: Typer =>
711711

712712
def synthesizedTupleFunction(formal: Type): Tree = {
713713
formal match {
714-
case AppliedType(_, funArgs @ fun :: tupled :: Nil) if defn.isFunctionType(fun) && defn.isFunctionType(tupled) =>
715-
lazy val funTypes = fun.dropDependentRefinement.dealias.argInfos
716-
lazy val tupledTypes = tupled.dropDependentRefinement.dealias.argInfos
717-
if (
718-
defn.isImplicitFunctionType(fun) == defn.isImplicitFunctionType(tupled) &&
719-
tupledTypes.size == 2 &&
720-
defn.tupleType(funTypes.init) =:= tupledTypes.head &&
721-
funTypes.last =:= tupledTypes.last
722-
) {
723-
val arity = funTypes.size - 1
724-
if (defn.isErasedFunctionType(fun))
725-
EmptyTree // TODO support?
726-
else if (arity <= Definitions.MaxImplementedFunctionArity)
727-
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funArgs)
728-
else
729-
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(funArgs)
730-
} else EmptyTree
714+
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
715+
def functionTypeEqual(baseFun: Type, actualArgs: List[Type], actualRet: Type, expected: Type) = {
716+
expected =:= defn.FunctionOf(actualArgs, actualRet, defn.isImplicitFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
717+
}
718+
val arity: Int = {
719+
if (defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun)) -1 // TODO support?
720+
else if (defn.isFunctionType(fun)) {
721+
// TupledFunction[(...) => R, ?]
722+
fun.dropDependentRefinement.dealias.argInfos match {
723+
case funArgs :+ funRet if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) => funArgs.size
724+
case _ => -1
725+
}
726+
} else if (defn.isFunctionType(tupled)) {
727+
// TupledFunction[?, ((...)) => R]
728+
tupled.dropDependentRefinement.dealias.argInfos match {
729+
case tupledArgs :: funRet :: Nil =>
730+
defn.tupleTypes(tupledArgs) match {
731+
case Some(tpes) if functionTypeEqual(tupled, tpes, funRet, fun) => tpes.size
732+
case _ => -1
733+
}
734+
case _ => -1
735+
}
736+
}
737+
else {
738+
// TupledFunction[?, ?]
739+
-1
740+
}
741+
}
742+
if (arity == -1)
743+
EmptyTree
744+
else if (arity <= Definitions.MaxImplementedFunctionArity)
745+
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funArgs)
746+
else
747+
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(funArgs)
731748
case _ =>
732749
EmptyTree
733750
}

library/src-3.x/scala/TupledFunction.scala

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,109 +10,167 @@ import scala.annotation.implicitNotFound
1010
@implicitNotFound("${F} cannot be tupled as ${G}")
1111
sealed trait TupledFunction[F, G] {
1212
def tuple(f: F): G
13+
def untuple(g: G): F
1314
}
1415

1516
package internal {
1617

1718
object TupledFunction {
1819

1920
def tupledFunction0[F, G]: TupledFunction[F, G] = new TupledFunction {
20-
def tuple(f: F): G =
21-
((args: Unit) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G]
21+
def tuple(f: F): G = ((args: Unit) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G]
22+
def untuple(g: G): F = (() => g.asInstanceOf[Unit => Any].apply(())).asInstanceOf[F]
2223
}
2324

2425
def tupledFunction1[F, G]: TupledFunction[F, G] = new TupledFunction {
25-
def tuple(f: F): G =
26-
((args: Tuple1[Any]) => f.asInstanceOf[Any => Any].apply(args._1)).asInstanceOf[G]
26+
def tuple(f: F): G = ((args: Tuple1[Any]) => f.asInstanceOf[Any => Any].apply(args._1)).asInstanceOf[G]
27+
def untuple(g: G): F = ((x1: Any) => g.asInstanceOf[Tuple1[_] => Any].apply(Tuple1(x1))).asInstanceOf[F]
2728
}
2829

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

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

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

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

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

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

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

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

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

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

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

7399
def tupledFunction13[F, G]: TupledFunction[F, G] = new TupledFunction {
74100
def tuple(f: F): G = f.asInstanceOf[Function13[_, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
101+
def untuple(g: G): F =
102+
((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) =>
103+
g.asInstanceOf[Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13))).asInstanceOf[F]
75104
}
76105

77106
def tupledFunction14[F, G]: TupledFunction[F, G] = new TupledFunction {
78107
def tuple(f: F): G = f.asInstanceOf[Function14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
108+
def untuple(g: G): F =
109+
((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) =>
110+
g.asInstanceOf[Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14))).asInstanceOf[F]
79111
}
80112

81113
def tupledFunction15[F, G]: TupledFunction[F, G] = new TupledFunction {
82114
def tuple(f: F): G = f.asInstanceOf[Function15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
115+
def untuple(g: G): F =
116+
((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) =>
117+
g.asInstanceOf[Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15))).asInstanceOf[F]
83118
}
84119

85120
def tupledFunction16[F, G]: TupledFunction[F, G] = new TupledFunction {
86121
def tuple(f: F): G = f.asInstanceOf[Function16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
122+
def untuple(g: G): F =
123+
((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) =>
124+
g.asInstanceOf[Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16))).asInstanceOf[F]
87125
}
88126

89127
def tupledFunction17[F, G]: TupledFunction[F, G] = new TupledFunction {
90128
def tuple(f: F): G = f.asInstanceOf[Function17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
129+
def untuple(g: G): F =
130+
((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) =>
131+
g.asInstanceOf[Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17))).asInstanceOf[F]
91132
}
92133

93134
def tupledFunction18[F, G]: TupledFunction[F, G] = new TupledFunction {
94135
def tuple(f: F): G = f.asInstanceOf[Function18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
136+
def untuple(g: G): F =
137+
((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) =>
138+
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]
95139
}
96140

97141
def tupledFunction19[F, G]: TupledFunction[F, G] = new TupledFunction {
98142
def tuple(f: F): G = f.asInstanceOf[Function19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
143+
def untuple(g: G): F =
144+
((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) =>
145+
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]
99146
}
100147

101148
def tupledFunction20[F, G]: TupledFunction[F, G] = new TupledFunction {
102149
def tuple(f: F): G = f.asInstanceOf[Function20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
150+
def untuple(g: G): F =
151+
((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) =>
152+
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]
103153
}
104154

105155
def tupledFunction21[F, G]: TupledFunction[F, G] = new TupledFunction {
106156
def tuple(f: F): G = f.asInstanceOf[Function21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
157+
def untuple(g: G): F =
158+
((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) =>
159+
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]
107160
}
108161

109162
def tupledFunction22[F, G]: TupledFunction[F, G] = new TupledFunction {
110163
def tuple(f: F): G = f.asInstanceOf[Function22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G]
164+
def untuple(g: G): F =
165+
((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) =>
166+
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]
111167
}
112168

113169
def tupledFunctionXXL[F, G]: TupledFunction[F, G] = new TupledFunction {
114-
def tuple(f: F): G =
115-
((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G]
170+
def tuple(f: F): G = ((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G]
171+
def untuple(g: G): F = new FunctionXXL {
172+
override def apply(xs: Array[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL(xs))
173+
}.asInstanceOf[F]
116174
}
117175

118176
}

0 commit comments

Comments
 (0)