Skip to content

Commit b0f0926

Browse files
committed
Fix #5257: Support auto generic-tupling of parameters
1 parent 7087a6c commit b0f0926

File tree

6 files changed

+41
-6
lines changed

6 files changed

+41
-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: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,17 @@ 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+
if (sel.exists) sel :: tupleSelectors(n + 1, tp) else Nil
65+
}
66+
def genTupleSelectors(n: Int, tp: Type): List[Type] = tp match {
67+
case tp: AppliedType if !tp.derivesFrom(defn.ProductClass) && tp.derivesFrom(defn.PairClass) =>
68+
val List(head, tail) = tp.args
69+
head :: genTupleSelectors(n, tail)
70+
case _ => tupleSelectors(n, tp)
71+
}
72+
genTupleSelectors(0, tp)
6473
}
6574

6675
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

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)