Skip to content

Add overloading support for case-closures #2015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 23, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
def typeShape(tree: untpd.Tree): Type = tree match {
case untpd.Function(args, body) =>
defn.FunctionOf(args map Function.const(defn.AnyType), typeShape(body))
case Match(EmptyTree, _) =>
defn.PartialFunctionType.appliedTo(defn.AnyType :: defn.NothingType :: Nil)
case _ =>
defn.NothingType
}
Expand Down Expand Up @@ -1270,8 +1272,13 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
def narrowBySize(alts: List[TermRef]): List[TermRef] =
alts filter (alt => sizeFits(alt, alt.widen))

def isFunArg(arg: untpd.Tree) = arg match {
case untpd.Function(_, _) | Match(EmptyTree, _) => true
case _ => false
}

def narrowByShapes(alts: List[TermRef]): List[TermRef] = {
if (normArgs exists (_.isInstanceOf[untpd.Function]))
if (normArgs exists isFunArg)
if (hasNamedArg(args)) narrowByTrees(alts, args map treeShape, resultType)
else narrowByTypes(alts, normArgs map typeShape, resultType)
else
Expand Down
41 changes: 41 additions & 0 deletions tests/pos/inferOverloaded.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class MySeq[T] {
def map1[U](f: T => U): MySeq[U] = new MySeq[U]
def map2[U](f: T => U): MySeq[U] = new MySeq[U]
}

class MyMap[A, B] extends MySeq[(A, B)] {
def map1[C](f: (A, B) => C): MySeq[C] = new MySeq[C]
def map1[C, D](f: (A, B) => (C, D)): MyMap[C, D] = new MyMap[C, D]
def map1[C, D](f: ((A, B)) => (C, D)): MyMap[C, D] = new MyMap[C, D]

def foo(f: Function2[Int, Int, Int]): Unit = ()
def foo[R](pf: PartialFunction[(A, B), R]): MySeq[R] = new MySeq[R]
}

object Test {
val m = new MyMap[Int, String]

// This one already worked because it is not overloaded:
m.map2 { case (k, v) => k - 1 }

// These already worked because preSelectOverloaded eliminated the non-applicable overload:
m.map1(t => t._1)
m.map1((kInFunction, vInFunction) => kInFunction - 1)
val r1 = m.map1(t => (t._1, 42.0))
val r1t: MyMap[Int, Double] = r1

// These worked because the argument types are known for overload resolution:
m.map1({ case (k, v) => k - 1 }: PartialFunction[(Int, String), Int])
m.map2({ case (k, v) => k - 1 }: PartialFunction[(Int, String), Int])

// These ones did not work before, still don't work in dotty:
//m.map1 { case (k, v) => k }
//val r = m.map1 { case (k, v) => (k, k*10) }
//val rt: MyMap[Int, Int] = r
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the use case we are interested in for the collections. Do you have an idea why it fails?

//m.foo { case (k, v) => k - 1 }

// Used to be ambiguous but overload resolution now favors PartialFunction
def h[R](pf: Function2[Int, String, R]): Unit = ()
def h[R](pf: PartialFunction[(Double, Double), R]): Unit = ()
h { case (a: Double, b: Double) => 42: Int }
}