diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 27d34b00cf9f..f24bc65b7ae1 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -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. @@ -24,7 +26,7 @@ object Definitions { * The limit 22 is chosen for Scala2x interop. It could be something * else without affecting the set of programs that can be compiled. */ - val MaxImplementedFunctionArity: Int = 22 + val MaxImplementedFunctionArity: Int = MaxTupleArity } /** A class defining symbols and types of standard definitions @@ -795,6 +797,13 @@ class Definitions { def TupleXXL_apply(implicit ctx: Context): Symbol = TupleXXLModule.info.member(nme.apply).requiredSymbol("method", nme.apply, TupleXXLModule)(_.info.isVarArgsMethod) + lazy val TupledFunctionTypeRef: TypeRef = ctx.requiredClassRef("scala.TupledFunction") + def TupledFunctionClass(implicit ctx: Context): ClassSymbol = TupledFunctionTypeRef.symbol.asClass + + lazy val InternalTupledFunctionTypeRef: TypeRef = ctx.requiredClassRef("scala.internal.TupledFunction") + def InternalTupleFunctionClass(implicit ctx: Context): ClassSymbol = InternalTupledFunctionTypeRef.symbol.asClass + def InternalTupleFunctionModule(implicit ctx: Context): Symbol = ctx.requiredModule("scala.internal.TupledFunction") + // Annotation base classes lazy val AnnotationType: TypeRef = ctx.requiredClassRef("scala.annotation.Annotation") def AnnotationClass(implicit ctx: Context): ClassSymbol = AnnotationType.symbol.asClass @@ -1187,10 +1196,21 @@ class Definitions { def tupleType(elems: List[Type]): Type = { val arity = elems.length - if (arity <= MaxTupleArity && TupleType(arity) != null) TupleType(arity).appliedTo(elems) + if (0 < arity && arity <= MaxTupleArity && TupleType(arity) != null) TupleType(arity).appliedTo(elems) 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) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 72d97dc4bb28..af7d0c31d621 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -709,6 +709,51 @@ trait Implicits { self: Typer => if (ctx.inInlineMethod || enclosingInlineds.nonEmpty) ref(defn.TastyReflection_macroContext) else EmptyTree + def synthesizedTupleFunction(formal: Type): Tree = { + formal match { + 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) => + // TupledFunction[(...funArgs...) => funRet, ?] + 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(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) => + // TupledFunction[?, ((...funArgs...)) => funRet] + funArgs.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 + } + } + /** If `formal` is of the form Eql[T, U], try to synthesize an * `Eql.eqlAny[T, U]` as solution. */ @@ -828,7 +873,8 @@ trait Implicits { self: Typer => trySpecialCase(defn.GenericClass, synthesizedGeneric, trySpecialCase(defn.TastyReflectionClass, synthesizedTastyContext, trySpecialCase(defn.EqlClass, synthesizedEq, - trySpecialCase(defn.ValueOfClass, synthesizedValueOf, failed)))))) + trySpecialCase(defn.TupledFunctionClass, synthesizedTupleFunction, + trySpecialCase(defn.ValueOfClass, synthesizedValueOf, failed))))))) } } diff --git a/docs/docs/reference/dropped-features/limit22.md b/docs/docs/reference/dropped-features/limit22.md index 285dcb543629..ed1fe7e44435 100644 --- a/docs/docs/reference/dropped-features/limit22.md +++ b/docs/docs/reference/dropped-features/limit22.md @@ -7,7 +7,8 @@ The limits of 22 for the maximal number of parameters of function types and the maximal number of fields in tuple types have been dropped. Functions can now have an arbitrary number of -parameters. Functions beyond Function22 are represented with a new trait -`scala.FunctionXXL`. +parameters. Functions beyond Function22 are erased to a new trait +`scala.FunctionXXL` and tuples beyond Tuple22 are erased to a new trait `scala.TupleXXL`. +Both of these are implemented using arrays. Tuples can also have an arbitrary number of fields. Furthermore, they support generic operation such as concatenation and indexing. diff --git a/docs/docs/reference/other-new-features/tupled-function.md b/docs/docs/reference/other-new-features/tupled-function.md new file mode 100644 index 000000000000..fa7d94f36951 --- /dev/null +++ b/docs/docs/reference/other-new-features/tupled-function.md @@ -0,0 +1,78 @@ +--- +layout: doc-page +title: "Tupled Function" +--- + +Tupled Function +---------------------- + +With functions bounded to arities up to 22 it was possible to generalize some operation on all function types using overloading. +Now that we have functions and tuples generalized to [arities above 22](https://dotty.epfl.ch/docs/reference/dropped-features/limit22.html) overloading is not an option anymore. +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. + +```scala +/** Type class relating a `FunctionN[..., R]` with an equivalent tupled function `Function1[TupleN[...], R]` + * + * @tparam F a function type + * @tparam G a tupled function type (function of arity 1 receiving a tuple as argument) + */ +@implicitNotFound("${F} cannot be tupled as ${G}") +sealed trait TupledFunction[F, G] { + def tupled(f: F): G + def untupled(g: G): F +} +``` + +The compiler will synthesize an instance of `TupledFunction[F, G]` if: + +* `F` is a function type of arity `N` +* `G` is a function with a single tuple argument of size `N` and it's types are equal to the arguments of `F` +* The return type of `F` is equal to the return type of `G` +* `F` and `G` are the same kind of function (both are `(...) => R` or both are `given (...) => R`) +* If only one of `F` or `G` is instantiated the second one is inferred. + +Examples +-------- +`TupledFunction` can be used to generalize the `Function1.tupled`, ... `Function22.tupled` methods to functions of any arities ([full example](https://github.com/lampepfl/dotty/tests/run/tupled-function-tupled.scala)) + +```scala +/** Creates a tupled version of this function: instead of N arguments, + * it accepts a single [[scala.Tuple]] argument. + * + * @tparam F the function type + * @tparam Args the tuple type with the same types as the function arguments of F + * @tparam R the return type of F + */ +def (f: F) tupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f) +``` + +`TupledFunction` can be used to generalize the `Function.untupled` methods to functions of any arities ([full example](https://github.com/lampepfl/dotty/tests/run/tupled-function-untupled.scala)) + +```scala +/** Creates an untupled version of this function: instead of single [[scala.Tuple]] argument, + * it accepts a N arguments. + * + * This is a generalization of [[scala.Function.untupled]] that work on functions of any arity + * + * @tparam F the function type + * @tparam Args the tuple type with the same types as the function arguments of F + * @tparam R the return type of F + */ +def (f: Args => R) untupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): F = tf.untupled(f) +``` + +`TupledFunction` can also be used to generalize the [`Tuple1.compose`](https://github.com/lampepfl/dotty/tests/run/tupled-function-compose.scala) and [`Tuple1.andThen`](https://github.com/lampepfl/dotty/tests/run/tupled-function-andThen.scala) methods to compose functions of larger arities and with functions that return tuples. + +```scala +/** Composes two instances of TupledFunctions in a new TupledFunctions, with this function applied last + * + * @tparam F a function type + * @tparam G a function type + * @tparam FArgs the tuple type with the same types as the function arguments of F and return type of G + * @tparam GArgs the tuple type with the same types as the function arguments of G + * @tparam R the return type of F + */ +def (f: F) compose[F, G, FArgs <: Tuple, GArgs <: Tuple, R](g: G) given (tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = { + (x: GArgs) => tf.tupled(f)(tg.tupled(g)(x)) +} +``` diff --git a/docs/sidebar.yml b/docs/sidebar.yml index a25063ae4746..97255e850254 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -89,6 +89,8 @@ sidebar: url: docs/reference/other-new-features/erased-terms.html - title: Kind Polymorphism url: docs/reference/other-new-features/kind-polymorphism.html + - title: Tupled Function + url: docs/reference/other-new-features/tupled-function.html - title: Other Changed Features subsection: - title: Volatile Lazy Vals diff --git a/library/src-3.x/dotty/DottyPredef.scala b/library/src-3.x/dotty/DottyPredef.scala index 49f275b0c98a..cdfa72ec1882 100644 --- a/library/src-3.x/dotty/DottyPredef.scala +++ b/library/src-3.x/dotty/DottyPredef.scala @@ -37,4 +37,5 @@ object DottyPredef { } inline def the[T] given (x: T): x.type = x + } diff --git a/library/src-3.x/scala/TupledFunction.scala b/library/src-3.x/scala/TupledFunction.scala new file mode 100644 index 000000000000..ceba68089b8c --- /dev/null +++ b/library/src-3.x/scala/TupledFunction.scala @@ -0,0 +1,178 @@ +package scala + +import scala.annotation.implicitNotFound + +/** Type class relating a `FunctionN[..., R]` with an equivalent tupled function `Function1[TupleN[...], R]` + * + * @tparam F a function type + * @tparam G a tupled function type (function of arity 1 receiving a tuple as argument) + */ +@implicitNotFound("${F} cannot be tupled as ${G}") +sealed trait TupledFunction[F, G] { + def tupled(f: F): G + def untupled(g: G): F +} + +package internal { + + object TupledFunction { + + def tupledFunction0[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = ((args: Unit) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G] + def untupled(g: G): F = (() => g.asInstanceOf[Unit => Any].apply(())).asInstanceOf[F] + } + + def tupledFunction1[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = ((args: Tuple1[Any]) => f.asInstanceOf[Any => Any].apply(args._1)).asInstanceOf[G] + def untupled(g: G): F = ((x1: Any) => g.asInstanceOf[Tuple1[_] => Any].apply(Tuple1(x1))).asInstanceOf[F] + } + + def tupledFunction2[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = f.asInstanceOf[Function2[_, _, _]].tupled.asInstanceOf[G] + def untupled(g: G): F = Function.untupled(g.asInstanceOf[Tuple2[_, _] => Any]).asInstanceOf[F] + } + + def tupledFunction3[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = f.asInstanceOf[Function3[_, _, _, _]].tupled.asInstanceOf[G] + def untupled(g: G): F = Function.untupled(g.asInstanceOf[Tuple3[_, _, _] => Any]).asInstanceOf[F] + } + + def tupledFunction4[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = f.asInstanceOf[Function4[_, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(g: G): F = Function.untupled(g.asInstanceOf[Tuple4[_, _, _, _] => Any]).asInstanceOf[F] + } + + def tupledFunction5[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = f.asInstanceOf[Function5[_, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(g: G): F = Function.untupled(g.asInstanceOf[Tuple5[_, _, _, _, _] => Any]).asInstanceOf[F] + } + + def tupledFunction6[F, G]: TupledFunction[F, G] = new TupledFunction { + def tupled(f: F): G = f.asInstanceOf[Function6[_, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function7[_, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function8[_, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function9[_, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function10[_, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function11[_, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function12[_, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function13[_, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = f.asInstanceOf[Function22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]].tupled.asInstanceOf[G] + def untupled(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 tupled(f: F): G = ((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G] + def untupled(g: G): F = new FunctionXXL { + override def apply(xs: Array[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL(xs)) + }.asInstanceOf[F] + } + + } + +} \ No newline at end of file diff --git a/tests/neg/tupled-function-instances.scala b/tests/neg/tupled-function-instances.scala new file mode 100644 index 000000000000..75f3c7b27869 --- /dev/null +++ b/tests/neg/tupled-function-instances.scala @@ -0,0 +1,74 @@ +object Test { + def main(args: Array[String]): Unit = { + type T + type R + + the[TupledFunction[Nothing, ((T, T, T)) => R]] // error + the[TupledFunction[Any, ((T, T, T)) => R]] // error + the[TupledFunction[Tuple1[Int], ((T, T, T)) => R]] // error + + the[TupledFunction[(T, T, T))=> R, Nothing]] // error + the[TupledFunction[(T, T, T) => R, Any]] // error + the[TupledFunction[((T, T, T)) => R, Tuple1[Int]]] // error + + the[TupledFunction[() => R, () => R]] // error + the[TupledFunction[() => Unit, () => Unit]] // error + the[TupledFunction[(T, T, T) => R, () => R]] // error + the[TupledFunction[(T, T, T) => R, (T, T) => R]] // error + + the[TupledFunction[(T, T, T) => R, given ((T, T, T)) => R]] // error + the[TupledFunction[given (T, T, T) => R, ((T, T, T)) => R]] // error + + the[TupledFunction[erased T => R, erased Tuple1[T] => R]] // error + the[TupledFunction[erased (T, T) => R, erased ((T, T)) => R]] // error + the[TupledFunction[erased (T, T, T) => R, erased ((T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T) => R, erased ((T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T) => R, erased ((T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + + the[TupledFunction[given erased T => R, given erased Tuple1[T] => R]] // error + the[TupledFunction[given erased (T, T) => R, given erased ((T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T) => R, given erased ((T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T) => R, given erased ((T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T) => R, given erased ((T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + the[TupledFunction[given erased (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given erased ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] // error + } +} \ No newline at end of file diff --git a/tests/pos/tupled-function-instances.scala b/tests/pos/tupled-function-instances.scala new file mode 100644 index 000000000000..20fbe4c00356 --- /dev/null +++ b/tests/pos/tupled-function-instances.scala @@ -0,0 +1,67 @@ +object Test { + def main(args: Array[String]): Unit = { + type T + type R + + the[TupledFunction[() => R, Unit => R]] + the[TupledFunction[T => R, Tuple1[T] => R]] + the[TupledFunction[(T, T) => R, ((T, T)) => R]] + the[TupledFunction[(T, T, T) => R, ((T, T, T)) => R]] + the[TupledFunction[(T, T, T, T) => R, ((T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T) => R, ((T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T) => R, ((T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + + the[TupledFunction[given T => R, given Tuple1[T] => R]] + the[TupledFunction[given (T, T) => R, given ((T, T)) => R]] + the[TupledFunction[given (T, T, T) => R, given ((T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T) => R, given ((T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T) => R, given ((T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T) => R, given ((T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + the[TupledFunction[given (T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) => R, given ((T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T)) => R]] + + + type F2 = (T, T) => R + type TF2 = ((T, T)) => R + the[TupledFunction[F2, ((T, T)) => R]] + the[TupledFunction[(T, T) => R, TF2]] + the[TupledFunction[F2, TF2]] + + } +} \ No newline at end of file diff --git a/tests/run/tupled-function-andThen.check b/tests/run/tupled-function-andThen.check new file mode 100644 index 000000000000..12ff3f4e95fd --- /dev/null +++ b/tests/run/tupled-function-andThen.check @@ -0,0 +1,4 @@ +6 +(2,7) +18 +(6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96,102,108,114,120,126,132,138,144,150) diff --git a/tests/run/tupled-function-andThen.scala b/tests/run/tupled-function-andThen.scala new file mode 100644 index 000000000000..39c22262f2a7 --- /dev/null +++ b/tests/run/tupled-function-andThen.scala @@ -0,0 +1,39 @@ +object Test { + def main(args: Array[String]): Unit = { + + val f1 = (x1: Int, x2: Int) => (x1, x2, x1 + x2) + val g1 = (x1: Int, x2: Int, x3: Int) => x1 + x2 + x3 + val h1 = f1.andThen(g1) + println(h1(1, 2)) + + val f2 = (x1: Int, x2: Int) => (1, x1, x2, x1 + x2, x1 * x2) + val g2 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int) => (x1 + x2, x3 + x4 + x5) + val h2 = f2.andThen(g2) + println(h2(1, 2)) + + val h3 = h2.andThen(h1) + println(h3(1, 2)) + + val f25 = + (x0: Int, x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int) => + (2 * x0, 2 * x1, 2 * x2, 2 * x3, 2 * x4, 2 * x5, 2 * x6, 2 * x7, 2 * x8, 2 * x9, 2 * x10, 2 * x11, 2 * x12, 2 * x13, 2 * x14, 2 * x15, 2 * x16, 2 * x17, 2 * x18, 2 * x19, 2 * x20, 2 * x21, 2 * x22, 2 * x23, 2 * x24) + val g25 = + (x0: Int, x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int) => + (3 * x0, 3 * x1, 3 * x2, 3 * x3, 3 * x4, 3 * x5, 3 * x6, 3 * x7, 3 * x8, 3 * x9, 3 * x10, 3 * x11, 3 * x12, 3 * x13, 3 * x14, 3 * x15, 3 * x16, 3 * x17, 3 * x18, 3 * x19, 3 * x20, 3 * x21, 3 * x22, 3 * x23, 3 * x24) + val h25 = f25.andThen(g25) + println(h25(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)) + } + + /** Composes two instances of TupledFunctions in a new TupledFunctions, with this function applied first + * + * @tparam F a function type + * @tparam G a function type + * @tparam FArgs the tuple type with the same types as the function arguments of F + * @tparam GArgs the tuple type with the same types as the function arguments of G and return type of F + * @tparam R the return type of G + */ + def (f: F) andThen[F, G, FArgs <: Tuple, GArgs <: Tuple, R](g: G) given (tf: TupledFunction[F, FArgs => GArgs], tg: TupledFunction[G, GArgs => R]): FArgs => R = { + x => tg.tupled(g)(tf.tupled(f)(x)) + } + +} diff --git a/tests/run/tupled-function-apply.check b/tests/run/tupled-function-apply.check new file mode 100644 index 000000000000..f56944496b49 --- /dev/null +++ b/tests/run/tupled-function-apply.check @@ -0,0 +1,26 @@ +0 +1 +3 +6 +10 +15 +21 +28 +36 +45 +55 +66 +78 +91 +105 +120 +136 +153 +171 +190 +210 +231 +253 +276 +300 +325 diff --git a/tests/run/tupled-function-apply.scala b/tests/run/tupled-function-apply.scala new file mode 100644 index 000000000000..015d2bade219 --- /dev/null +++ b/tests/run/tupled-function-apply.scala @@ -0,0 +1,118 @@ +object Test { + def main(args: Array[String]): Unit = { + + val f0 = () => 0 + val t0 = () + println(f0(t0)) + + val f1 = (x: Int) => x + val t1 = Tuple1(1) + println(f1(t1)) + + val f2 = (x1: Int, x2: Int) => x1 + x2 + val t2 = (1, 2) + println(f2(t2)) + + val f3 = (x1: Int, x2: Int, x3: Int) => x1 + x2 + x3 + val t3 = (1, 2, 3) + println(f3(t3)) + + val f4 = (x1: Int, x2: Int, x3: Int, x4: Int) => x1 + x2 + x3 + x4 + val t4 = (1, 2, 3, 4) + println(f4(t4)) + + val f5 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int) => x1 + x2 + x3 + x4 + x5 + val t5 = (1, 2, 3, 4, 5) + println(f5(t5)) + + val f6 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int) => x1 + x2 + x3 + x4 + x5 + x6 + val t6 = (1, 2, 3, 4, 5, 6) + println(f6(t6)) + + val f7 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + val t7 = (1, 2, 3, 4, 5, 6, 7) + println(f7(t7)) + + val f8 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + val t8 = (1, 2, 3, 4, 5, 6, 7, 8) + println(f8(t8)) + + val f9 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + val t9 = (1, 2, 3, 4, 5, 6, 7, 8, 9) + println(f9(t9)) + + val f10 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + val t10 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + println(f10(t10)) + + val f11 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + val t11 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) + println(f11(t11)) + + val f12 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + val t12 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) + println(f12(t12)) + + val f13 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + val t13 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) + println(f13(t13)) + + val f14 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + val t14 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + println(f14(t14)) + + val f15 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + val t15 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) + println(f15(t15)) + + val f16 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + val t16 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + println(f16(t16)) + + val f17 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + val t17 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) + println(f17(t17)) + + val f18 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + val t18 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) + println(f18(t18)) + + val f19 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + val t19 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) + println(f19(t19)) + + val f20 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + val t20 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) + println(f20(t20)) + + val f21 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + val t21 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) + println(f21(t21)) + + val f22 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + val t22 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22) + println(f22(t22)) + + val f23 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + val t23 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23) + println(f23(t23)) + + val f24 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + val t24 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24) + println(f24(t24)) + + val f25 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + val t25 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25) + println(f25(t25)) + + } + + /** Apply this function to with each element of the tuple as a parameter + * + * @tparam F the function type + * @tparam Args the tuple type with the same types as the function arguments of F + * @tparam R the return type of F + */ + def (f: F) apply[F, Args <: Tuple, R](args: Args) given (tf: TupledFunction[F, Args => R]): R = + tf.tupled(f)(args) +} \ No newline at end of file diff --git a/tests/run/tupled-function-compose.check b/tests/run/tupled-function-compose.check new file mode 100644 index 000000000000..12ff3f4e95fd --- /dev/null +++ b/tests/run/tupled-function-compose.check @@ -0,0 +1,4 @@ +6 +(2,7) +18 +(6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96,102,108,114,120,126,132,138,144,150) diff --git a/tests/run/tupled-function-compose.scala b/tests/run/tupled-function-compose.scala new file mode 100644 index 000000000000..e077e4d439f0 --- /dev/null +++ b/tests/run/tupled-function-compose.scala @@ -0,0 +1,40 @@ +object Test { + def main(args: Array[String]): Unit = { + + val f1 = (x1: Int, x2: Int) => (x1, x2, x1 + x2) + val g1 = (x1: Int, x2: Int, x3: Int) => x1 + x2 + x3 + val h1 = g1.compose(f1) + println(h1(1, 2)) + + val f2 = (x1: Int, x2: Int) => (1, x1, x2, x1 + x2, x1 * x2) + val g2 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int) => (x1 + x2, x3 + x4 + x5) + val h2 = g2.compose(f2) + println(h2(1, 2)) + + val h3 = h1.compose(h2) + println(h3(1, 2)) + + val f25 = + (x0: Int, x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int) => + (2 * x0, 2 * x1, 2 * x2, 2 * x3, 2 * x4, 2 * x5, 2 * x6, 2 * x7, 2 * x8, 2 * x9, 2 * x10, 2 * x11, 2 * x12, 2 * x13, 2 * x14, 2 * x15, 2 * x16, 2 * x17, 2 * x18, 2 * x19, 2 * x20, 2 * x21, 2 * x22, 2 * x23, 2 * x24) + val g25 = + (x0: Int, x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int) => + (3 * x0, 3 * x1, 3 * x2, 3 * x3, 3 * x4, 3 * x5, 3 * x6, 3 * x7, 3 * x8, 3 * x9, 3 * x10, 3 * x11, 3 * x12, 3 * x13, 3 * x14, 3 * x15, 3 * x16, 3 * x17, 3 * x18, 3 * x19, 3 * x20, 3 * x21, 3 * x22, 3 * x23, 3 * x24) + val h25 = f25.compose(g25) + println(h25(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)) + + } + + /** Composes two instances of TupledFunctions in a new TupledFunctions, with this function applied last + * + * @tparam F a function type + * @tparam G a function type + * @tparam FArgs the tuple type with the same types as the function arguments of F and return type of G + * @tparam GArgs the tuple type with the same types as the function arguments of G + * @tparam R the return type of F + */ + def (f: F) compose[F, G, FArgs <: Tuple, GArgs <: Tuple, R](g: G) given (tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = { + x => tf.tupled(f)(tg.tupled(g)(x)) + } + +} diff --git a/tests/run/tupled-function-extension-method.check b/tests/run/tupled-function-extension-method.check new file mode 100644 index 000000000000..6f8d92537745 --- /dev/null +++ b/tests/run/tupled-function-extension-method.check @@ -0,0 +1,9 @@ +() +(1) +(1,3) +(1,3,6) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25) +(1) +(1,3) +(1,3,6) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25) diff --git a/tests/run/tupled-function-extension-method.scala b/tests/run/tupled-function-extension-method.scala new file mode 100644 index 000000000000..352f784771e2 --- /dev/null +++ b/tests/run/tupled-function-extension-method.scala @@ -0,0 +1,47 @@ +object Test { + def main(args: Array[String]): Unit = { + + val f0 = new Expr(() => ()) + val f1 = new Expr((i: Int) => Tuple1(i)) + val f2 = new Expr((i: Int, j: Int) => (i, i + j)) + val f3 = new Expr((i: Int, j: Int, k: Int) => (i, i + j, i + j + k)) + val f25 = new Expr( + (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int) => + (x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25) + ) + + println(f0()) + println(f1(1)) + println(f2(1, 2)) + println(f3(1, 2, 3)) + println(f25(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)) + + val if1 = new Expr(given (i: Int) => Tuple1(i)) + val if2 = new Expr(given (i: Int, j: Int) => (i, i + j)) + val if3 = new Expr(given (i: Int, j: Int, k: Int) => (i, i + j, i + j + k)) + val if25 = new Expr( + given (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int) => + (x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25) + ) + + println(if1.applyGiven(1)) + println(if2.applyGiven(1, 2)) + println(if3.applyGiven(1, 2, 3)) + println(if25.applyGiven(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)) + + } + + class Expr[T](val x: T) + + // Specialized only for arity 0 and one as auto tupling will not provide the disired effect + def (e: Expr[() => R]) apply[R](): R = e.x() + def (e: Expr[Arg => R]) apply[Arg, R](arg: Arg): R = e.x(arg) + def (e: Expr[given Arg => R]) applyGiven[Arg, R](arg: Arg): R = e.x given arg + + // Applied to all funtions of arity 2 or more (including more than 22 parameters) + def (e: Expr[F]) apply[F, Args <: Tuple, R](args: Args) given (tf: TupledFunction[F, Args => R]): R = + tf.tupled(e.x)(args) + def (e: Expr[F]) applyGiven[F, Args <: Tuple, R](args: Args) given (tf: TupledFunction[F, given Args => R]): R = + tf.tupled(e.x) given args + +} \ No newline at end of file diff --git a/tests/run/tupled-function-tupled.check b/tests/run/tupled-function-tupled.check new file mode 100644 index 000000000000..b4a487314d9c --- /dev/null +++ b/tests/run/tupled-function-tupled.check @@ -0,0 +1,3 @@ +276 +300 +325 diff --git a/tests/run/tupled-function-tupled.scala b/tests/run/tupled-function-tupled.scala new file mode 100644 index 000000000000..5aa71bb3b1d0 --- /dev/null +++ b/tests/run/tupled-function-tupled.scala @@ -0,0 +1,28 @@ +object Test { + def main(args: Array[String]): Unit = { + + val f23 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + val t23 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23) + println(f23.tupled(t23)) + + val f24 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + val t24 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24) + println(f24.tupled(t24)) + + val f25 = (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int) => x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + val t25 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25) + println(f25.tupled(t25)) + + } + + /** Creates a tupled version of this function: instead of N arguments, + * it accepts a single [[scala.Tuple]] argument. + * + * This is a generalization of [[scala.FunctionN.tupled]] that work on functions of any arity + * + * @tparam F the function type + * @tparam Args the tuple type with the same types as the function arguments of F + * @tparam R the return type of F + */ + def (f: F) tupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f) +} diff --git a/tests/run/tupled-function-untupled.scala b/tests/run/tupled-function-untupled.scala new file mode 100644 index 000000000000..dddffc88220a --- /dev/null +++ b/tests/run/tupled-function-untupled.scala @@ -0,0 +1,108 @@ +object Test { + def main(args: Array[String]): Unit = { + + val f0 = (args: Unit) => 0 + val g0: () => Int = f0.untupled + println(g0()) + + val f1 = (args: Tuple1[Int]) => 1 + val g1: (Int) => Int = f1.untupled + println(g1(1)) + + val f2 = (args: (Int, Int)) => 2 + val g2: (Int, Int) => Int = f2.untupled + println(g2(1, 2)) + + val f3 = (args: (Int, Int, Int)) => 3 + val g3: (Int, Int, Int) => Int = f3.untupled + println(g3(1, 2, 3)) + + val f4 = (args: (Int, Int, Int, Int)) => 4 + val g4: (Int, Int, Int, Int) => Int = f4.untupled + println(g4(1, 2, 3, 4)) + + val f5 = (args: (Int, Int, Int, Int, Int)) => 5 + val g5: (Int, Int, Int, Int, Int) => Int = f5.untupled + println(g5(1, 2, 3, 4, 5)) + + val f6 = (args: (Int, Int, Int, Int, Int, Int)) => 6 + val g6: (Int, Int, Int, Int, Int, Int) => Int = f6.untupled + println(g6(1, 2, 3, 4, 5, 6)) + + val f7 = (args: (Int, Int, Int, Int, Int, Int, Int)) => 7 + val g7: (Int, Int, Int, Int, Int, Int, Int) => Int = f7.untupled + println(g7(1, 2, 3, 4, 5, 6, 7)) + + val f8 = (args: (Int, Int, Int, Int, Int, Int, Int, Int)) => 8 + val g8: (Int, Int, Int, Int, Int, Int, Int, Int) => Int = f8.untupled + println(g8(1, 2, 3, 4, 5, 6, 7, 8)) + + val f9 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 9 + val g9: (Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f9.untupled + println(g9(1, 2, 3, 4, 5, 6, 7, 8, 9)) + + val f10 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 10 + val g10: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f10.untupled + println(g10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + + val f11 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 11 + val g11: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f11.untupled + println(g11(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)) + + val f12 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 12 + val g12: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f12.untupled + println(g12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + + val f13 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 13 + val g13: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f13.untupled + println(g13(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)) + + val f14 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 14 + val g14: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f14.untupled + println(g14(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)) + + val f15 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 15 + val g15: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f15.untupled + println(g15(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)) + + val f16 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 16 + val g16: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f16.untupled + println(g16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) + + val f17 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 17 + val g17: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f17.untupled + println(g17(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)) + + val f18 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 18 + val g18: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f18.untupled + println(g18(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)) + + val f19 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 19 + val g19: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f19.untupled + println(g19(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)) + + val f20 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 20 + val g20: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f20.untupled + println(g20(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)) + + val f21 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 21 + val g21: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f21.untupled + println(g21(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)) + + val f22 = (args: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => 22 + val g22: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = f22.untupled + println(g22(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)) + + } + + /** Creates an untupled version of this function: instead of single [[scala.Tuple]] argument, + * it accepts a N arguments. + * + * This is a generalization of [[scala.Function.untupled]] that work on functions of any arity + * + * @tparam F the function type + * @tparam Args the tuple type with the same types as the function arguments of F + * @tparam R the return type of F + */ + def (f: Args => R) untupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): F = tf.untupled(f) +}