Skip to content

Commit cf60e58

Browse files
Merge pull request #5259 from dotty-staging/fix-#5257
Fix #5257: Support auto generic-tupling of parameters
2 parents 4075b97 + 1745af1 commit cf60e58

File tree

9 files changed

+56
-6
lines changed

9 files changed

+56
-6
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,10 +870,21 @@ object desugar {
870870
* def pn = x$1._n
871871
* body
872872
* }
873+
*
874+
* or if `isGenericTuple`
875+
*
876+
* x$1 => {
877+
* def p1 = x$1.apply(0)
878+
* ...
879+
* def pn = x$1.apply(n-1)
880+
* body
881+
* }
873882
*/
874-
def makeTupledFunction(params: List[ValDef], body: Tree)(implicit ctx: Context): Tree = {
883+
def makeTupledFunction(params: List[ValDef], body: Tree, isGenericTuple: Boolean)(implicit ctx: Context): Tree = {
875884
val param = makeSyntheticParameter()
876-
def selector(n: Int) = Select(refOfDef(param), nme.selectorName(n))
885+
def selector(n: Int) =
886+
if (isGenericTuple) Apply(Select(refOfDef(param), nme.apply), Literal(Constant(n)))
887+
else Select(refOfDef(param), nme.selectorName(n))
877888
val vdefs =
878889
params.zipWithIndex.map{
879890
case (param, idx) =>

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,19 @@ object Applications {
5959
extractorMemberType(tp, nme.get, errorPos).exists
6060

6161
def productSelectorTypes(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context): List[Type] = {
62-
val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos)
63-
sels.takeWhile(_.exists).toList
62+
def tupleSelectors(n: Int, tp: Type): List[Type] = {
63+
val sel = extractorMemberType(tp, nme.selectorName(n), errorPos)
64+
// extractorMemberType will return NoType if this is the tail of tuple with an unknown tail
65+
// such as `Int *: T` where `T <: Tuple`.
66+
if (sel.exists) sel :: tupleSelectors(n + 1, tp) else Nil
67+
}
68+
def genTupleSelectors(n: Int, tp: Type): List[Type] = tp match {
69+
case tp: AppliedType if !tp.derivesFrom(defn.ProductClass) && tp.derivesFrom(defn.PairClass) =>
70+
val List(head, tail) = tp.args
71+
head :: genTupleSelectors(n, tail)
72+
case _ => tupleSelectors(n, tp)
73+
}
74+
genTupleSelectors(0, tp)
6475
}
6576

6677
def productArity(tp: Type)(implicit ctx: Context): Int =

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ class Typer extends Namer
906906
/** Is `formal` a product type which is elementwise compatible with `params`? */
907907
def ptIsCorrectProduct(formal: Type) = {
908908
isFullyDefined(formal, ForceDegree.noBottom) &&
909-
defn.isProductSubType(formal) &&
909+
(defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) &&
910910
Applications.productSelectorTypes(formal).corresponds(params) {
911911
(argType, param) =>
912912
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe
@@ -915,7 +915,8 @@ class Typer extends Namer
915915

916916
val desugared =
917917
if (protoFormals.length == 1 && params.length != 1 && ptIsCorrectProduct(protoFormals.head)) {
918-
desugar.makeTupledFunction(params, fnBody)
918+
val isGenericTuple = !protoFormals.head.derivesFrom(defn.ProductClass)
919+
desugar.makeTupledFunction(params, fnBody, isGenericTuple)
919920
}
920921
else {
921922
val inferredParams: List[untpd.ValDef] =

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ i4947b
2323
i5119
2424
i5119b
2525
i5188a
26+
i5257.scala
2627
inline-varargs-1
2728
implicitShortcut
2829
inline-case-objects

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class CompilationTests extends ParallelTesting {
172172
implicit val testGroup: TestGroup = TestGroup("runAll")
173173
compileFilesInDir("tests/run-custom-args/Yretain-trees", defaultOptions and "-Yretain-trees") +
174174
compileFile("tests/run-custom-args/tuple-cons.scala", allowDeepSubtypes) +
175+
compileFile("tests/run-custom-args/i5256.scala", allowDeepSubtypes) +
175176
compileFilesInDir("tests/run", defaultOptions)
176177
}.checkRuns()
177178

tests/run-custom-args/i5256.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
276

tests/run-custom-args/i5256.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
object Test {
2+
3+
def main(args: Array[String]): Unit = {
4+
val f23: ((Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) => Int = {
5+
(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23) =>
6+
x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23
7+
}
8+
9+
println(f23((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)))
10+
}
11+
}

tests/run/i5257.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
3
2+
5

tests/run/i5257.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
object Test {
2+
3+
def main(args: Array[String]): Unit = {
4+
val f: Int *: Int *: Unit => Int = (x, y) => x + y
5+
val g: Int *: Tuple1[Int] => Int = (x, y) => x + y
6+
7+
println(f((1, 2)))
8+
println(g((2, 3)))
9+
}
10+
11+
}

0 commit comments

Comments
 (0)