Skip to content

Commit

Permalink
Fix #5257: Support auto generic-tupling of parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Oct 31, 2018
1 parent 0fcbfdb commit e5ba40e
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 6 deletions.
15 changes: 13 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Expand Up @@ -870,10 +870,21 @@ object desugar {
* def pn = x$1._n
* body
* }
*
* or if `isGenericTuple`
*
* x$1 => {
* def p1 = x$1.apply(0)
* ...
* def pn = x$1.apply(n-1)
* body
* }
*/
def makeTupledFunction(params: List[ValDef], body: Tree)(implicit ctx: Context): Tree = {
def makeTupledFunction(params: List[ValDef], body: Tree, isGenericTuple: Boolean)(implicit ctx: Context): Tree = {
val param = makeSyntheticParameter()
def selector(n: Int) = Select(refOfDef(param), nme.selectorName(n))
def selector(n: Int) =
if (isGenericTuple) Apply(Select(refOfDef(param), nme.apply), Literal(Constant(n)))
else Select(refOfDef(param), nme.selectorName(n))
val vdefs =
params.zipWithIndex.map{
case (param, idx) =>
Expand Down
13 changes: 11 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Expand Up @@ -59,8 +59,17 @@ object Applications {
extractorMemberType(tp, nme.get, errorPos).exists

def productSelectorTypes(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context): List[Type] = {
val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos)
sels.takeWhile(_.exists).toList
def tupleSelectors(n: Int, tp: Type): List[Type] = {
val sel = extractorMemberType(tp, nme.selectorName(n), errorPos)
if (sel.exists) sel :: tupleSelectors(n + 1, tp) else Nil
}
def genTupleSelectors(n: Int, tp: Type): List[Type] = tp match {
case tp: AppliedType if !tp.derivesFrom(defn.ProductClass) && tp.derivesFrom(defn.PairClass) =>
val List(head, tail) = tp.args
head :: genTupleSelectors(n, tail)
case _ => tupleSelectors(n, tp)
}
genTupleSelectors(0, tp)
}

def productArity(tp: Type)(implicit ctx: Context): Int =
Expand Down
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Expand Up @@ -906,7 +906,7 @@ class Typer extends Namer
/** Is `formal` a product type which is elementwise compatible with `params`? */
def ptIsCorrectProduct(formal: Type) = {
isFullyDefined(formal, ForceDegree.noBottom) &&
defn.isProductSubType(formal) &&
(defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) &&
Applications.productSelectorTypes(formal).corresponds(params) {
(argType, param) =>
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe
Expand All @@ -915,7 +915,8 @@ class Typer extends Namer

val desugared =
if (protoFormals.length == 1 && params.length != 1 && ptIsCorrectProduct(protoFormals.head)) {
desugar.makeTupledFunction(params, fnBody)
val isGenericTuple = !protoFormals.head.derivesFrom(defn.ProductClass)
desugar.makeTupledFunction(params, fnBody, isGenericTuple)
}
else {
val inferredParams: List[untpd.ValDef] =
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotc/run-test-pickling.blacklist
Expand Up @@ -23,6 +23,7 @@ i4947b
i5119
i5119b
i5188a
i5257.scala
inline-varargs-1
implicitShortcut
inline-case-objects
Expand Down
2 changes: 2 additions & 0 deletions tests/run/i5257.check
@@ -0,0 +1,2 @@
3
5
11 changes: 11 additions & 0 deletions tests/run/i5257.scala
@@ -0,0 +1,11 @@
object Test {

def main(args: Array[String]): Unit = {
val f: Int *: Int *: Unit => Int = (x, y) => x + y
val g: Int *: Tuple1[Int] => Int = (x, y) => x + y

println(f((1, 2)))
println(g((2, 3)))
}

}

0 comments on commit e5ba40e

Please sign in to comment.