@@ -3,7 +3,7 @@ package dotc
3
3
package typer
4
4
5
5
import core ._
6
- import ast .{Trees , tpd , untpd }
6
+ import ast .{Trees , tpd , untpd , desugar }
7
7
import util .Spans ._
8
8
import util .Stats .record
9
9
import util .{SourcePosition , NoSourcePosition , SourceFile }
@@ -864,7 +864,7 @@ trait Applications extends Compatibility {
864
864
case funRef : TermRef =>
865
865
val app =
866
866
if (proto.allArgTypesAreCurrent())
867
- new ApplyToTyped (tree, fun1, funRef, proto.unforcedTypedArgs , pt)
867
+ new ApplyToTyped (tree, fun1, funRef, proto.typedArgs() , pt)
868
868
else
869
869
new ApplyToUntyped (tree, fun1, funRef, proto, pt)(
870
870
given fun1 .nullableInArgContext(given argCtx (tree)))
@@ -891,7 +891,7 @@ trait Applications extends Compatibility {
891
891
}
892
892
893
893
fun1.tpe match {
894
- case err : ErrorType => cpy.Apply (tree)(fun1, proto.unforcedTypedArgs ).withType(err)
894
+ case err : ErrorType => cpy.Apply (tree)(fun1, proto.typedArgs() ).withType(err)
895
895
case TryDynamicCallType => typedDynamicApply(tree, pt)
896
896
case _ =>
897
897
if (originalProto.isDropped) fun1
@@ -1635,14 +1635,46 @@ trait Applications extends Compatibility {
1635
1635
def narrowByTypes (alts : List [TermRef ], argTypes : List [Type ], resultType : Type ): List [TermRef ] =
1636
1636
alts filter (isApplicableMethodRef(_, argTypes, resultType))
1637
1637
1638
+ /** Normalization steps before checking arguments:
1639
+ *
1640
+ * { expr } --> expr
1641
+ * (x1, ..., xn) => expr --> ((x1, ..., xn)) => expr
1642
+ * if n != 1, no alternative has a corresponding formal parameter that
1643
+ * is an n-ary function, and at least one alternative has a corresponding
1644
+ * formal parameter that is a unary function.
1645
+ */
1646
+ def normArg (alts : List [TermRef ], arg : untpd.Tree , idx : Int ): untpd.Tree = arg match
1647
+ case Block (Nil , expr) => normArg(alts, expr, idx)
1648
+ case untpd.Function (args : List [untpd.ValDef ] @ unchecked, body) =>
1649
+
1650
+ // If ref refers to a method whose parameter at index `idx` is a function type,
1651
+ // the arity of that function, otherise -1.
1652
+ def paramCount (ref : TermRef ) =
1653
+ val formals = ref.widen.firstParamTypes
1654
+ if formals.length > idx then
1655
+ formals(idx) match
1656
+ case defn.FunctionOf (args, _, _, _) => args.length
1657
+ case _ => - 1
1658
+ else - 1
1659
+
1660
+ val numArgs = args.length
1661
+ if numArgs != 1
1662
+ && ! alts.exists(paramCount(_) == numArgs)
1663
+ && alts.exists(paramCount(_) == 1 )
1664
+ then
1665
+ desugar.makeTupledFunction(args, body, isGenericTuple = true )
1666
+ // `isGenericTuple = true` is the safe choice here. It means the i'th tuple
1667
+ // element is selected with `(i)` instead of `_i`, which gives the same code
1668
+ // in the end, but the compilation time and the ascribed type are more involved.
1669
+ // It also means that -Ytest-pickler -Xprint-types fails for sources exercising
1670
+ // the idiom since after pickling the target is known, so _i is used directly.
1671
+ else arg
1672
+ case _ => arg
1673
+ end normArg
1674
+
1638
1675
val candidates = pt match {
1639
1676
case pt @ FunProto (args, resultType) =>
1640
1677
val numArgs = args.length
1641
- val normArgs = args.mapConserve {
1642
- case Block (Nil , expr) => expr
1643
- case x => x
1644
- }
1645
-
1646
1678
def sizeFits (alt : TermRef ): Boolean = alt.widen.stripPoly match {
1647
1679
case tp : MethodType =>
1648
1680
val ptypes = tp.paramInfos
@@ -1661,9 +1693,10 @@ trait Applications extends Compatibility {
1661
1693
alts.filter(sizeFits(_))
1662
1694
1663
1695
def narrowByShapes (alts : List [TermRef ]): List [TermRef ] =
1664
- if (normArgs exists untpd.isFunctionWithUnknownParamType)
1665
- if (hasNamedArg(args)) narrowByTrees(alts, args map treeShape, resultType)
1666
- else narrowByTypes(alts, normArgs map typeShape, resultType)
1696
+ val normArgs = args.mapWithIndexConserve(normArg(alts, _, _))
1697
+ if normArgs.exists(untpd.isFunctionWithUnknownParamType) then
1698
+ if hasNamedArg(args) then narrowByTrees(alts, normArgs.map(treeShape), resultType)
1699
+ else narrowByTypes(alts, normArgs.map(typeShape), resultType)
1667
1700
else
1668
1701
alts
1669
1702
@@ -1681,16 +1714,14 @@ trait Applications extends Compatibility {
1681
1714
1682
1715
val alts1 = narrowBySize(alts)
1683
1716
// ctx.log(i"narrowed by size: ${alts1.map(_.symbol.showDcl)}%, %")
1684
- if ( isDetermined(alts1)) alts1
1685
- else {
1717
+ if isDetermined(alts1) then alts1
1718
+ else
1686
1719
val alts2 = narrowByShapes(alts1)
1687
1720
// ctx.log(i"narrowed by shape: ${alts2.map(_.symbol.showDcl)}%, %")
1688
- if ( isDetermined(alts2)) alts2
1689
- else {
1721
+ if isDetermined(alts2) then alts2
1722
+ else
1690
1723
pretypeArgs(alts2, pt)
1691
- narrowByTrees(alts2, pt.unforcedTypedArgs, resultType)
1692
- }
1693
- }
1724
+ narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
1694
1725
1695
1726
case pt @ PolyProto (targs1, pt1) if targs.isEmpty =>
1696
1727
val alts1 = alts.filter(pt.isMatchedBy(_))
@@ -1749,7 +1780,7 @@ trait Applications extends Compatibility {
1749
1780
else pt match {
1750
1781
case pt @ FunProto (_, resType : FunProto ) =>
1751
1782
// try to narrow further with snd argument list
1752
- val advanced = advanceCandidates(pt.unforcedTypedArgs .tpes)
1783
+ val advanced = advanceCandidates(pt.typedArgs() .tpes)
1753
1784
resolveOverloaded(advanced.map(_._1), resType, Nil ) // resolve with candidates where first params are stripped
1754
1785
.map(advanced.toMap) // map surviving result(s) back to original candidates
1755
1786
case _ =>
0 commit comments