Skip to content

Commit f37b2a1

Browse files
committed
Add overloading support for case-closures
case-closures (which are represented as Match nodes) have a known arity just like other function literals. So shape analysis for overloading resolution should apply to them as well.
1 parent 9f879c1 commit f37b2a1

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12271227
def typeShape(tree: untpd.Tree): Type = tree match {
12281228
case untpd.Function(args, body) =>
12291229
defn.FunctionOf(args map Function.const(defn.AnyType), typeShape(body))
1230+
case Match(EmptyTree, _) =>
1231+
defn.PartialFunctionType.appliedTo(defn.AnyType :: defn.NothingType :: Nil)
12301232
case _ =>
12311233
defn.NothingType
12321234
}
@@ -1270,8 +1272,13 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12701272
def narrowBySize(alts: List[TermRef]): List[TermRef] =
12711273
alts filter (alt => sizeFits(alt, alt.widen))
12721274

1275+
def isFunArg(arg: untpd.Tree) = arg match {
1276+
case untpd.Function(_, _) | Match(EmptyTree, _) => true
1277+
case _ => false
1278+
}
1279+
12731280
def narrowByShapes(alts: List[TermRef]): List[TermRef] = {
1274-
if (normArgs exists (_.isInstanceOf[untpd.Function]))
1281+
if (normArgs exists isFunArg)
12751282
if (hasNamedArg(args)) narrowByTrees(alts, args map treeShape, resultType)
12761283
else narrowByTypes(alts, normArgs map typeShape, resultType)
12771284
else

tests/pos/inferOverloaded.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
class MySeq[T] {
2+
def map1[U](f: T => U): MySeq[U] = new MySeq[U]
3+
def map2[U](f: T => U): MySeq[U] = new MySeq[U]
4+
}
5+
6+
class MyMap[A, B] extends MySeq[(A, B)] {
7+
def map1[C](f: (A, B) => C): MySeq[C] = new MySeq[C]
8+
def map1[C, D](f: (A, B) => (C, D)): MyMap[C, D] = new MyMap[C, D]
9+
def map1[C, D](f: ((A, B)) => (C, D)): MyMap[C, D] = new MyMap[C, D]
10+
11+
def foo(f: Function2[Int, Int, Int]): Unit = ()
12+
def foo[R](pf: PartialFunction[(A, B), R]): MySeq[R] = new MySeq[R]
13+
}
14+
15+
object Test {
16+
val m = new MyMap[Int, String]
17+
18+
// This one already worked because it is not overloaded:
19+
m.map2 { case (k, v) => k - 1 }
20+
21+
// These already worked because preSelectOverloaded eliminated the non-applicable overload:
22+
m.map1(t => t._1)
23+
m.map1((kInFunction, vInFunction) => kInFunction - 1)
24+
val r1 = m.map1(t => (t._1, 42.0))
25+
val r1t: MyMap[Int, Double] = r1
26+
27+
// These worked because the argument types are known for overload resolution:
28+
m.map1({ case (k, v) => k - 1 }: PartialFunction[(Int, String), Int])
29+
m.map2({ case (k, v) => k - 1 }: PartialFunction[(Int, String), Int])
30+
31+
// These ones did not work before, still don't work in dotty:
32+
//m.map1 { case (k, v) => k }
33+
//val r = m.map1 { case (k, v) => (k, k*10) }
34+
//val rt: MyMap[Int, Int] = r
35+
//m.foo { case (k, v) => k - 1 }
36+
37+
// Used to be ambiguous but overload resolution now favors PartialFunction
38+
def h[R](pf: Function2[Int, String, R]): Unit = ()
39+
def h[R](pf: PartialFunction[(Double, Double), R]): Unit = ()
40+
h { case (a: Double, b: Double) => 42: Int }
41+
}

0 commit comments

Comments
 (0)