Skip to content

Commit 5626f25

Browse files
authored
Merge pull request #14651 from dotty-staging/14626
Adapt function arguments to n-ary prototype
2 parents 91d1122 + b945a1b commit 5626f25

File tree

3 files changed

+59
-26
lines changed

3 files changed

+59
-26
lines changed

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

+14
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,20 @@ object desugar {
14311431
Function(param :: Nil, Block(vdefs, body))
14321432
}
14331433

1434+
/** Convert a tuple pattern with given `elems` to a sequence of `ValDefs`,
1435+
* skipping elements that are not convertible.
1436+
*/
1437+
def patternsToParams(elems: List[Tree])(using Context): List[ValDef] =
1438+
def toParam(elem: Tree, tpt: Tree): Tree =
1439+
elem match
1440+
case Annotated(elem1, _) => toParam(elem1, tpt)
1441+
case Typed(elem1, tpt1) => toParam(elem1, tpt1)
1442+
case Ident(id: TermName) => ValDef(id, tpt, EmptyTree).withFlags(Param)
1443+
case _ => EmptyTree
1444+
elems.map(param => toParam(param, TypeTree()).withSpan(param.span)).collect {
1445+
case vd: ValDef => vd
1446+
}
1447+
14341448
def makeContextualFunction(formals: List[Tree], body: Tree, isErased: Boolean)(using Context): Function = {
14351449
val mods = if (isErased) Given | Erased else Given
14361450
val params = makeImplicitParameters(formals, mods)

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

+42-26
Original file line numberDiff line numberDiff line change
@@ -1424,33 +1424,49 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14241424
param.tpt.isEmpty || argType.widenExpr <:< typedAheadType(param.tpt).tpe
14251425
}
14261426

1427-
val desugared =
1428-
if (protoFormals.length == 1 && params.length != 1 && ptIsCorrectProduct(protoFormals.head)) {
1429-
val isGenericTuple =
1430-
protoFormals.head.derivesFrom(defn.TupleClass)
1431-
&& !defn.isTupleClass(protoFormals.head.typeSymbol)
1432-
desugar.makeTupledFunction(params, fnBody, isGenericTuple)
1433-
}
1434-
else {
1435-
val inferredParams: List[untpd.ValDef] =
1436-
for ((param, i) <- params.zipWithIndex) yield
1437-
if (!param.tpt.isEmpty) param
1438-
else
1439-
val formal = protoFormal(i)
1440-
val knownFormal = isFullyDefined(formal, ForceDegree.failBottom)
1441-
val paramType =
1442-
if knownFormal then formal
1443-
else inferredFromTarget(param, formal, calleeType, paramIndex)
1444-
.orElse(errorType(AnonymousFunctionMissingParamType(param, tree, formal), param.srcPos))
1445-
val paramTpt = untpd.TypedSplice(
1446-
(if knownFormal then InferredTypeTree() else untpd.TypeTree())
1447-
.withType(paramType.translateFromRepeated(toArray = false))
1448-
.withSpan(param.span.endPos)
1449-
)
1450-
cpy.ValDef(param)(tpt = paramTpt)
1451-
desugar.makeClosure(inferredParams, fnBody, resultTpt, isContextual, tree.span)
1452-
}
1427+
var desugared: untpd.Tree = EmptyTree
1428+
if protoFormals.length == 1 && params.length != 1 && ptIsCorrectProduct(protoFormals.head) then
1429+
val isGenericTuple =
1430+
protoFormals.head.derivesFrom(defn.TupleClass)
1431+
&& !defn.isTupleClass(protoFormals.head.typeSymbol)
1432+
desugared = desugar.makeTupledFunction(params, fnBody, isGenericTuple)
1433+
else if protoFormals.length > 1 && params.length == 1 then
1434+
def isParamRef(scrut: untpd.Tree): Boolean = scrut match
1435+
case untpd.Annotated(scrut1, _) => isParamRef(scrut1)
1436+
case untpd.Ident(id) => id == params.head.name
1437+
fnBody match
1438+
case untpd.Match(scrut, untpd.CaseDef(untpd.Tuple(elems), untpd.EmptyTree, rhs) :: Nil)
1439+
if scrut.span.isSynthetic && isParamRef(scrut) && elems.hasSameLengthAs(protoFormals) =>
1440+
// If `pt` is N-ary function type, convert synthetic lambda
1441+
// x$1 => x$1 match case (a1, ..., aN) => e
1442+
// to
1443+
// (a1, ..., aN) => e
1444+
val params1 = desugar.patternsToParams(elems)
1445+
if params1.hasSameLengthAs(elems) then
1446+
desugared = cpy.Function(tree)(params1, rhs)
1447+
case _ =>
1448+
1449+
if desugared.isEmpty then
1450+
val inferredParams: List[untpd.ValDef] =
1451+
for ((param, i) <- params.zipWithIndex) yield
1452+
if (!param.tpt.isEmpty) param
1453+
else
1454+
val formal = protoFormal(i)
1455+
val knownFormal = isFullyDefined(formal, ForceDegree.failBottom)
1456+
val paramType =
1457+
if knownFormal then formal
1458+
else inferredFromTarget(param, formal, calleeType, paramIndex)
1459+
.orElse(errorType(AnonymousFunctionMissingParamType(param, tree, formal), param.srcPos))
1460+
val paramTpt = untpd.TypedSplice(
1461+
(if knownFormal then InferredTypeTree() else untpd.TypeTree())
1462+
.withType(paramType.translateFromRepeated(toArray = false))
1463+
.withSpan(param.span.endPos)
1464+
)
1465+
cpy.ValDef(param)(tpt = paramTpt)
1466+
desugared = desugar.makeClosure(inferredParams, fnBody, resultTpt, isContextual, tree.span)
1467+
14531468
typed(desugared, pt)
1469+
.showing(i"desugared fun $tree --> $desugared with pt = $pt", typr)
14541470
}
14551471

14561472
def typedClosure(tree: untpd.Closure, pt: Type)(using Context): Tree = {

tests/pos/i14626.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import language.`future`
2+
def Test =
3+
for (a, b) <- List("a","b","c").lazyZip(List(1,2,3)) do println(s"$a$b")

0 commit comments

Comments
 (0)