Skip to content

Commit c6aaaaf

Browse files
committed
Add TupledFunction to abstract over function arities
Add tests
1 parent e81fa4a commit c6aaaaf

17 files changed

+542
-3
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object Definitions {
2424
* The limit 22 is chosen for Scala2x interop. It could be something
2525
* else without affecting the set of programs that can be compiled.
2626
*/
27-
val MaxImplementedFunctionArity: Int = 22
27+
val MaxImplementedFunctionArity: Int = MaxTupleArity
2828
}
2929

3030
/** A class defining symbols and types of standard definitions
@@ -795,6 +795,13 @@ class Definitions {
795795
def TupleXXL_apply(implicit ctx: Context): Symbol =
796796
TupleXXLModule.info.member(nme.apply).requiredSymbol("method", nme.apply, TupleXXLModule)(_.info.isVarArgsMethod)
797797

798+
lazy val TupledFunctionTypeRef: TypeRef = ctx.requiredClassRef("scala.TupledFunction")
799+
def TupleFunctionClass(implicit ctx: Context): ClassSymbol = TupledFunctionTypeRef.symbol.asClass
800+
801+
lazy val InternalTupledFunctionTypeRef: TypeRef = ctx.requiredClassRef("scala.internal.TupledFunction")
802+
def InternalTupleFunctionClass(implicit ctx: Context): ClassSymbol = InternalTupledFunctionTypeRef.symbol.asClass
803+
def InternalTupleFunctionModule(implicit ctx: Context): Symbol = ctx.requiredModule("scala.internal.TupledFunction")
804+
798805
// Annotation base classes
799806
lazy val AnnotationType: TypeRef = ctx.requiredClassRef("scala.annotation.Annotation")
800807
def AnnotationClass(implicit ctx: Context): ClassSymbol = AnnotationType.symbol.asClass
@@ -1187,7 +1194,7 @@ class Definitions {
11871194

11881195
def tupleType(elems: List[Type]): Type = {
11891196
val arity = elems.length
1190-
if (arity <= MaxTupleArity && TupleType(arity) != null) TupleType(arity).appliedTo(elems)
1197+
if (0 < arity && arity <= MaxTupleArity && TupleType(arity) != null) TupleType(arity).appliedTo(elems)
11911198
else TypeOps.nestedPairs(elems)
11921199
}
11931200

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,26 @@ trait Implicits { self: Typer =>
709709
if (ctx.inInlineMethod || enclosingInlineds.nonEmpty) ref(defn.TastyReflection_macroContext)
710710
else EmptyTree
711711

712+
def synthesizedTupleFunction(formal: Type): Tree = {
713+
formal match {
714+
case AppliedType(_, fun :: args :: ret :: Nil) if defn.isFunctionType(fun) =>
715+
val funTypes = fun.dropDependentRefinement.dealias.argInfos
716+
if (defn.tupleType(funTypes.init) =:= args && funTypes.last =:= ret) {
717+
val arity = funTypes.size - 1
718+
if (defn.isErasedFunctionType(fun))
719+
EmptyTree // TODO support?
720+
else if (defn.isImplicitFunctionType(fun))
721+
EmptyTree // TODO support
722+
else if (arity <= Definitions.MaxImplementedFunctionArity)
723+
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funTypes)
724+
else
725+
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(fun :: args :: ret :: Nil)
726+
} else EmptyTree
727+
case _ =>
728+
EmptyTree
729+
}
730+
}
731+
712732
/** If `formal` is of the form Eql[T, U], try to synthesize an
713733
* `Eql.eqlAny[T, U]` as solution.
714734
*/
@@ -828,7 +848,8 @@ trait Implicits { self: Typer =>
828848
trySpecialCase(defn.GenericClass, synthesizedGeneric,
829849
trySpecialCase(defn.TastyReflectionClass, synthesizedTastyContext,
830850
trySpecialCase(defn.EqlClass, synthesizedEq,
831-
trySpecialCase(defn.ValueOfClass, synthesizedValueOf, failed))))))
851+
trySpecialCase(defn.TupleFunctionClass, synthesizedTupleFunction,
852+
trySpecialCase(defn.ValueOfClass, synthesizedValueOf, failed)))))))
832853
}
833854
}
834855

library/src-3.x/dotty/DottyPredef.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,12 @@ object DottyPredef {
3737
}
3838

3939
inline def the[T] given (x: T): x.type = x
40+
41+
/** Creates a tupled version of this function: instead of N arguments,
42+
* it accepts a single [[scala.Tuple]] argument.
43+
*/
44+
def (f: F) tupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args, R]): Args => R = {
45+
x => tf.applyFunctionTo(f, x)
46+
}
47+
4048
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package scala
2+
3+
import scala.annotation.implicitNotFound
4+
5+
@implicitNotFound("${F} cannot be tupled as ${Args} => ${R}")
6+
trait TupledFunction[F, Args <: Tuple, R] {
7+
def applyFunctionTo(f: F, args: Args): R
8+
}
9+
10+
object TupledFunction {
11+
12+
/** Apply this function to with each element of the tuple as a parameter */
13+
def (f: F) apply[F, Args <: Tuple, R](args: Args) given (tf: TupledFunction[F, Args, R]): R =
14+
tf.applyFunctionTo(f, args)
15+
16+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package scala.internal
2+
3+
object TupledFunction {
4+
5+
def tupledFunction0[R]: TupledFunction[() => R, Unit, R] = new TupledFunction {
6+
def applyFunctionTo(f: () => R, args: Unit): R = f()
7+
}
8+
9+
def tupledFunction1[T1, R]: TupledFunction[T1 => R, Tuple1[T1], R] = new TupledFunction {
10+
def applyFunctionTo(f: T1 => R, args: Tuple1[T1]): R = f(args._1)
11+
}
12+
13+
def tupledFunction2[T1, T2, R]: TupledFunction[(T1, T2) => R, Tuple2[T1, T2], R] = new TupledFunction {
14+
def applyFunctionTo(f: (T1, T2) => R, args: Tuple2[T1, T2]): R = f(args._1, args._2)
15+
}
16+
17+
def tupledFunction3[T1, T2, T3, R]: TupledFunction[(T1, T2, T3) => R, Tuple3[T1, T2, T3], R] = new TupledFunction {
18+
def applyFunctionTo(f: (T1, T2, T3) => R, args: Tuple3[T1, T2, T3]): R = f(args._1, args._2, args._3)
19+
}
20+
21+
def tupledFunction4[T1, T2, T3, T4, R]: TupledFunction[(T1, T2, T3, T4) => R, Tuple4[T1, T2, T3, T4], R] = new TupledFunction {
22+
def applyFunctionTo(f: (T1, T2, T3, T4) => R, args: Tuple4[T1, T2, T3, T4]): R = f(args._1, args._2, args._3, args._4)
23+
}
24+
25+
def tupledFunction5[T1, T2, T3, T4, T5, R]: TupledFunction[(T1, T2, T3, T4, T5) => R, Tuple5[T1, T2, T3, T4, T5], R] = new TupledFunction {
26+
def applyFunctionTo(f: (T1, T2, T3, T4, T5) => R, args: Tuple5[T1, T2, T3, T4, T5]): R = f(args._1, args._2, args._3, args._4, args._5)
27+
}
28+
29+
def tupledFunction6[T1, T2, T3, T4, T5, T6, R]: TupledFunction[(T1, T2, T3, T4, T5, T6) => R, Tuple6[T1, T2, T3, T4, T5, T6], R] = new TupledFunction {
30+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6) => R, args: Tuple6[T1, T2, T3, T4, T5, T6]): R =
31+
f(args._1, args._2, args._3, args._4, args._5, args._6)
32+
}
33+
34+
def tupledFunction7[T1, T2, T3, T4, T5, T6, T7, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7) => R, Tuple7[T1, T2, T3, T4, T5, T6, T7], R] = new TupledFunction {
35+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7) => R, args: Tuple7[T1, T2, T3, T4, T5, T6, T7]): R =
36+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7)
37+
}
38+
39+
def tupledFunction8[T1, T2, T3, T4, T5, T6, T7, T8, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8) => R, Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], R] = new TupledFunction {
40+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8) => R, args: Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]): R =
41+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8)
42+
}
43+
44+
def tupledFunction9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9) => R, Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], R] = new TupledFunction {
45+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9) => R, args: Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]): R =
46+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9)
47+
}
48+
49+
def tupledFunction10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) => R, Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], R] = new TupledFunction {
50+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) => R, args: Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]): R =
51+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10)
52+
}
53+
54+
def tupledFunction11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) => R, Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], R] = new TupledFunction {
55+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) => R, args: Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]): R =
56+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11)
57+
}
58+
59+
def tupledFunction12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) => R, Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], R] = new TupledFunction {
60+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) => R, args: Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]): R =
61+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12)
62+
}
63+
64+
def tupledFunction13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) => R, Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], R] = new TupledFunction {
65+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) => R, args: Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]): R =
66+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13)
67+
}
68+
69+
def tupledFunction14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) => R, Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], R] = new TupledFunction {
70+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) => R, args: Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]): R =
71+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14)
72+
}
73+
74+
def tupledFunction15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) => R, Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], R] = new TupledFunction {
75+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) => R, args: Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]): R =
76+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15)
77+
}
78+
79+
def tupledFunction16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) => R, Tuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16], R] = new TupledFunction {
80+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) => R, args: Tuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]): R =
81+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16)
82+
}
83+
84+
def tupledFunction17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17) => R, Tuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17], R] = new TupledFunction {
85+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17) => R, args: Tuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]): R =
86+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16, args._17)
87+
}
88+
89+
def tupledFunction18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18) => R, Tuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18], R] = new TupledFunction {
90+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18) => R, args: Tuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]): R =
91+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16, args._17, args._18)
92+
}
93+
94+
def tupledFunction19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19) => R, Tuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19], R] = new TupledFunction {
95+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19) => R, args: Tuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]): R =
96+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16, args._17, args._18, args._19)
97+
}
98+
99+
def tupledFunction20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20) => R, Tuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20], R] = new TupledFunction {
100+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20) => R, args: Tuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]): R =
101+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16, args._17, args._18, args._19, args._20)
102+
}
103+
104+
def tupledFunction21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21) => R, Tuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21], R] = new TupledFunction {
105+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21) => R, args: Tuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]): R =
106+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16, args._17, args._18, args._19, args._20, args._21)
107+
}
108+
109+
def tupledFunction22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, R]: TupledFunction[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22) => R, Tuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22], R] = new TupledFunction {
110+
def applyFunctionTo(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22) => R, args: Tuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]): R =
111+
f(args._1, args._2, args._3, args._4, args._5, args._6, args._7, args._8, args._9, args._10, args._11, args._12, args._13, args._14, args._15, args._16, args._17, args._18, args._19, args._20, args._21, args._22)
112+
}
113+
114+
def tupledFunctionXXL[F, Args <: Tuple, R]: TupledFunction[F, Args, R] = new TupledFunction {
115+
def applyFunctionTo(f: F, args: Args): R =
116+
f.asInstanceOf[FunctionXXL].apply(args.asInstanceOf[TupleXXL].elems).asInstanceOf[R]
117+
}
118+
119+
}

0 commit comments

Comments
 (0)