Skip to content

Commit bde9a79

Browse files
committed
Revert "Remove TupledFunction"
This reverts commit f4e1ca4.
1 parent 4c7ec9b commit bde9a79

21 files changed

+315
-1
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,10 @@ class Definitions {
888888
lazy val RuntimeTuples_isInstanceOfEmptyTuple: Symbol = RuntimeTuplesModule.requiredMethod("isInstanceOfEmptyTuple")
889889
lazy val RuntimeTuples_isInstanceOfNonEmptyTuple: Symbol = RuntimeTuplesModule.requiredMethod("isInstanceOfNonEmptyTuple")
890890

891+
@tu lazy val TupledFunctionTypeRef: TypeRef = requiredClassRef("scala.util.TupledFunction")
892+
def TupledFunctionClass(using Context): ClassSymbol = TupledFunctionTypeRef.symbol.asClass
893+
def RuntimeTupleFunctionsModule(using Context): Symbol = requiredModule("scala.runtime.TupledFunctions")
894+
891895
// Annotation base classes
892896
@tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation")
893897
@tu lazy val ClassfileAnnotationClass: ClassSymbol = requiredClass("scala.annotation.ClassfileAnnotation")

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,50 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
7878
}
7979
end synthesizedTypeTest
8080

81+
val synthesizedTupleFunction: SpecialHandler = (formal, span) =>
82+
formal match
83+
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
84+
def functionTypeEqual(baseFun: Type, actualArgs: List[Type],
85+
actualRet: Type, expected: Type) =
86+
expected =:= defn.FunctionOf(actualArgs, actualRet,
87+
defn.isContextFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
88+
val arity: Int =
89+
if defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun) then -1 // TODO support?
90+
else if defn.isFunctionType(fun) then
91+
// TupledFunction[(...) => R, ?]
92+
fun.dropDependentRefinement.dealias.argInfos match
93+
case funArgs :+ funRet
94+
if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) =>
95+
// TupledFunction[(...funArgs...) => funRet, ?]
96+
funArgs.size
97+
case _ => -1
98+
else if defn.isFunctionType(tupled) then
99+
// TupledFunction[?, (...) => R]
100+
tupled.dropDependentRefinement.dealias.argInfos match
101+
case tupledArgs :: funRet :: Nil =>
102+
defn.tupleTypes(tupledArgs.dealias) match
103+
case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
104+
// TupledFunction[?, ((...funArgs...)) => funRet]
105+
funArgs.size
106+
case _ => -1
107+
case _ => -1
108+
else
109+
// TupledFunction[?, ?]
110+
-1
111+
if arity == -1 then
112+
EmptyTree
113+
else if arity <= Definitions.MaxImplementedFunctionArity then
114+
ref(defn.RuntimeTupleFunctionsModule)
115+
.select(s"tupledFunction$arity".toTermName)
116+
.appliedToTypes(funArgs)
117+
else
118+
ref(defn.RuntimeTupleFunctionsModule)
119+
.select("tupledFunctionXXL".toTermName)
120+
.appliedToTypes(funArgs)
121+
case _ =>
122+
EmptyTree
123+
end synthesizedTupleFunction
124+
81125
/** If `formal` is of the form CanEqual[T, U], try to synthesize an
82126
* `CanEqual.canEqualAny[T, U]` as solution.
83127
*/
@@ -483,6 +527,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
483527
defn.TypeTestClass -> synthesizedTypeTest,
484528
defn.CanEqualClass -> synthesizedCanEqual,
485529
defn.ValueOfClass -> synthesizedValueOf,
530+
defn.TupledFunctionClass -> synthesizedTupleFunction,
486531
defn.Mirror_ProductClass -> synthesizedProductMirror,
487532
defn.Mirror_SumClass -> synthesizedSumMirror,
488533
defn.MirrorClass -> synthesizedMirror,
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
layout: doc-page
3+
title: "Tupled Function"
4+
---
5+
6+
Tupled Function
7+
----------------------
8+
9+
With functions bounded to arities up to 22 it was possible to generalize some operation on all function types using overloading.
10+
Now that we have functions and tuples generalized to [arities above 22](../dropped-features/limit22.md) overloading is not an option anymore.
11+
The type class `TupleFunction` provides a way to abstract directly over a function of any arity converting it to an equivalent function that receives all arguments in a single tuple.
12+
13+
```scala
14+
/** Type class relating a `FunctionN[..., R]` with an equivalent tupled function `Function1[TupleN[...], R]`
15+
*
16+
* @tparam F a function type
17+
* @tparam G a tupled function type (function of arity 1 receiving a tuple as argument)
18+
*/
19+
@implicitNotFound("${F} cannot be tupled as ${G}")
20+
sealed trait TupledFunction[F, G] {
21+
def tupled(f: F): G
22+
def untupled(g: G): F
23+
}
24+
```
25+
26+
The compiler will synthesize an instance of `TupledFunction[F, G]` if:
27+
28+
* `F` is a function type of arity `N`
29+
* `G` is a function with a single tuple argument of size `N` and its types are equal to the arguments of `F`
30+
* The return type of `F` is equal to the return type of `G`
31+
* `F` and `G` are the same sort of function (both are `(...) => R` or both are `(...) ?=> R`)
32+
* If only one of `F` or `G` is instantiated the second one is inferred.
33+
34+
Examples
35+
--------
36+
`TupledFunction` can be used to generalize the `Function1.tupled`, ... `Function22.tupled` methods to functions of any arities.
37+
The following defines `tupled` as [extension method](../contextual/extension-methods.html) ([full example](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-tupled.scala)).
38+
39+
```scala
40+
/** Creates a tupled version of this function: instead of N arguments,
41+
* it accepts a single [[scala.Tuple]] with N elements as argument.
42+
*
43+
* @tparam F the function type
44+
* @tparam Args the tuple type with the same types as the function arguments of F
45+
* @tparam R the return type of F
46+
*/
47+
extension [F, Args <: Tuple, R](f: F)
48+
def tupled(using tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f)
49+
```
50+
51+
`TupledFunction` can be used to generalize the `Function.untupled` to a function of any arities ([full example](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-untupled.scala))
52+
53+
```scala
54+
/** Creates an untupled version of this function: instead of a single argument of type [[scala.Tuple]] with N elements,
55+
* it accepts N arguments.
56+
*
57+
* This is a generalization of [[scala.Function.untupled]] that work on functions of any arity
58+
*
59+
* @tparam F the function type
60+
* @tparam Args the tuple type with the same types as the function arguments of F
61+
* @tparam R the return type of F
62+
*/
63+
extension [F, Args <: Tuple, R](f: Args => R)
64+
def untupled(using tf: TupledFunction[F, Args => R]): F = tf.untupled(f)
65+
```
66+
67+
`TupledFunction` can also be used to generalize the [`Tuple1.compose`](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-compose.scala) and [`Tuple1.andThen`](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-andThen.scala) methods to compose functions of larger arities and with functions that return tuples.
68+
69+
```scala
70+
/** Composes two instances of TupledFunction into a new TupledFunction, with this function applied last.
71+
*
72+
* @tparam F a function type
73+
* @tparam G a function type
74+
* @tparam FArgs the tuple type with the same types as the function arguments of F and return type of G
75+
* @tparam GArgs the tuple type with the same types as the function arguments of G
76+
* @tparam R the return type of F
77+
*/
78+
extension [F, G, FArgs <: Tuple, GArgs <: Tuple, R](f: F)
79+
def compose(g: G)(using tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = {
80+
(x: GArgs) => tf.tupled(f)(tg.tupled(g)(x))
81+
}
82+
```

docs/sidebar.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ sidebar:
116116
- page: docs/reference/experimental/named-typeargs.md
117117
- page: docs/reference/experimental/numeric-literals.md
118118
- page: docs/reference/experimental/explicit-nulls.md
119+
- page: docs/reference/other-new-features/tupled-function.md
119120
- page: docs/reference/syntax.md
120121
- title: Language Versions
121122
index: docs/reference/language-versions/language-versions.md
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package scala.runtime
2+
3+
import scala.util.TupledFunction
4+
5+
object TupledFunctions {
6+
7+
def tupledFunction0[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
8+
tupledImpl = (f: F) => ((args: EmptyTuple) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G],
9+
untupledImpl = (g: G) => (() => g.asInstanceOf[EmptyTuple => Any].apply(EmptyTuple)).asInstanceOf[F]
10+
)
11+
12+
def tupledFunction1[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
13+
tupledImpl = (f: F) => ((args: Tuple1[Any]) => f.asInstanceOf[Any => Any].apply(args._1)).asInstanceOf[G],
14+
untupledImpl = (g: G) => ((x1: Any) => g.asInstanceOf[Tuple1[_] => Any].apply(Tuple1(x1))).asInstanceOf[F]
15+
)
16+
17+
def tupledFunction2[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
18+
tupledImpl = (f: F) => f.asInstanceOf[Function2[_, _, _]].tupled.asInstanceOf[G],
19+
untupledImpl = (g: G) => Function.untupled(g.asInstanceOf[Tuple2[_, _] => Any]).asInstanceOf[F]
20+
)
21+
22+
def tupledFunction3[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
23+
tupledImpl = (f: F) => f.asInstanceOf[Function3[_, _, _, _]].tupled.asInstanceOf[G],
24+
untupledImpl = (g: G) => Function.untupled(g.asInstanceOf[Tuple3[_, _, _] => Any]).asInstanceOf[F]
25+
)
26+
27+
def tupledFunction4[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
28+
tupledImpl = (f: F) => f.asInstanceOf[Function4[_, _, _, _, _]].tupled.asInstanceOf[G],
29+
untupledImpl = (g: G) => Function.untupled(g.asInstanceOf[Tuple4[_, _, _, _] => Any]).asInstanceOf[F]
30+
)
31+
32+
def tupledFunction5[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
33+
tupledImpl = (f: F) => f.asInstanceOf[Function5[_, _, _, _, _, _]].tupled.asInstanceOf[G],
34+
untupledImpl = (g: G) => Function.untupled(g.asInstanceOf[Tuple5[_, _, _, _, _] => Any]).asInstanceOf[F]
35+
)
36+
37+
def tupledFunction6[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
38+
tupledImpl = (f: F) => f.asInstanceOf[Function6[_, _, _, _, _, _, _]].tupled.asInstanceOf[G],
39+
untupledImpl = (g: G) =>
40+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any) =>
41+
g.asInstanceOf[Tuple6[_, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6))).asInstanceOf[F]
42+
)
43+
44+
def tupledFunction7[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
45+
tupledImpl = (f: F) => f.asInstanceOf[Function7[_, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
46+
untupledImpl = (g: G) =>
47+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any) =>
48+
g.asInstanceOf[Tuple7[_, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7))).asInstanceOf[F]
49+
)
50+
51+
def tupledFunction8[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
52+
tupledImpl = (f: F) => f.asInstanceOf[Function8[_, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
53+
untupledImpl = (g: G) =>
54+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any) =>
55+
g.asInstanceOf[Tuple8[_, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8))).asInstanceOf[F]
56+
)
57+
58+
def tupledFunction9[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
59+
tupledImpl = (f: F) => f.asInstanceOf[Function9[_, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
60+
untupledImpl = (g: G) =>
61+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any) =>
62+
g.asInstanceOf[Tuple9[_, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9))).asInstanceOf[F]
63+
)
64+
65+
def tupledFunction10[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
66+
tupledImpl = (f: F) => f.asInstanceOf[Function10[_, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
67+
untupledImpl = (g: G) =>
68+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any) =>
69+
g.asInstanceOf[Tuple10[_, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10))).asInstanceOf[F]
70+
)
71+
72+
def tupledFunction11[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
73+
tupledImpl = (f: F) => f.asInstanceOf[Function11[_, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
74+
untupledImpl = (g: G) =>
75+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any) =>
76+
g.asInstanceOf[Tuple11[_, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11))).asInstanceOf[F]
77+
)
78+
79+
def tupledFunction12[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
80+
tupledImpl = (f: F) => f.asInstanceOf[Function12[_, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
81+
untupledImpl = (g: G) =>
82+
((x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any, x9: Any, x10: Any, x11: Any, x12: Any) =>
83+
g.asInstanceOf[Tuple12[_, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12))).asInstanceOf[F]
84+
)
85+
86+
def tupledFunction13[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
87+
tupledImpl = (f: F) => f.asInstanceOf[Function13[_, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
88+
untupledImpl = (g: G) =>
89+
((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) =>
90+
g.asInstanceOf[Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13))).asInstanceOf[F]
91+
)
92+
93+
def tupledFunction14[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
94+
tupledImpl = (f: F) => f.asInstanceOf[Function14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
95+
untupledImpl = (g: G) =>
96+
((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) =>
97+
g.asInstanceOf[Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14))).asInstanceOf[F]
98+
)
99+
100+
def tupledFunction15[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
101+
tupledImpl = (f: F) => f.asInstanceOf[Function15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
102+
untupledImpl = (g: G) =>
103+
((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) =>
104+
g.asInstanceOf[Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15))).asInstanceOf[F]
105+
)
106+
107+
def tupledFunction16[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
108+
tupledImpl = (f: F) => f.asInstanceOf[Function16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
109+
untupledImpl = (g: G) =>
110+
((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) =>
111+
g.asInstanceOf[Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16))).asInstanceOf[F]
112+
)
113+
114+
def tupledFunction17[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
115+
tupledImpl = (f: F) => f.asInstanceOf[Function17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
116+
untupledImpl = (g: G) =>
117+
((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) =>
118+
g.asInstanceOf[Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Any].apply((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17))).asInstanceOf[F]
119+
)
120+
121+
def tupledFunction18[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
122+
tupledImpl = (f: F) => f.asInstanceOf[Function18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
123+
untupledImpl = (g: G) =>
124+
((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) =>
125+
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]
126+
)
127+
128+
def tupledFunction19[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
129+
tupledImpl = (f: F) => f.asInstanceOf[Function19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
130+
untupledImpl = (g: G) =>
131+
((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) =>
132+
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]
133+
)
134+
135+
def tupledFunction20[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
136+
tupledImpl = (f: F) => f.asInstanceOf[Function20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
137+
untupledImpl = (g: G) =>
138+
((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) =>
139+
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]
140+
)
141+
142+
def tupledFunction21[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
143+
tupledImpl = (f: F) => f.asInstanceOf[Function21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
144+
untupledImpl = (g: G) =>
145+
((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) =>
146+
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]
147+
)
148+
149+
def tupledFunction22[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
150+
tupledImpl = (f: F) => f.asInstanceOf[Function22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G],
151+
untupledImpl = (g: G) =>
152+
((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) =>
153+
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]
154+
)
155+
156+
def tupledFunctionXXL[F, G]: TupledFunction[F, G] = TupledFunction[F, G](
157+
tupledImpl = (f: F) => ((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G],
158+
untupledImpl = (g: G) => new FunctionXXL {
159+
override def apply(xs: IArray[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL.fromIArray(xs))
160+
}.asInstanceOf[F]
161+
)
162+
163+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package scala.util
2+
3+
import scala.annotation.implicitNotFound
4+
5+
/** Type class relating a `FunctionN[..., R]` with an equivalent tupled function `Function1[TupleN[...], R]`
6+
*
7+
* @tparam F a function type
8+
* @tparam G a tupled function type (function of arity 1 receiving a tuple as argument)
9+
*/
10+
@implicitNotFound("${F} cannot be tupled as ${G}")
11+
sealed trait TupledFunction[F, G]:
12+
def tupled(f: F): G
13+
def untupled(g: G): F
14+
15+
private[scala] object TupledFunction:
16+
def apply[F, G](tupledImpl: F => G, untupledImpl: G => F): TupledFunction[F, G] =
17+
new TupledFunction[F, G]:
18+
def tupled(f: F): G = tupledImpl(f)
19+
def untupled(g: G): F = untupledImpl(g)

0 commit comments

Comments
 (0)