Skip to content

Commit 9018807

Browse files
authored
Merge pull request #2894 from dotty-staging/fix-#2367
Fix #2367: Allow SAM conversion for overloaded functions
2 parents 30dba8c + 5c7199b commit 9018807

File tree

3 files changed

+37
-21
lines changed

3 files changed

+37
-21
lines changed

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

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -474,21 +474,24 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
474474
type TypedArg = Arg
475475
type Result = Unit
476476

477+
protected def argOK(arg: TypedArg, formal: Type) = argType(arg, formal) match {
478+
case ref: TermRef if ref.denot.isOverloaded =>
479+
// in this case we could not resolve overloading because no alternative
480+
// matches expected type
481+
false
482+
case argtpe =>
483+
def SAMargOK = formal match {
484+
case SAMType(meth) => argtpe <:< meth.info.toFunctionType()
485+
case _ => false
486+
}
487+
isCompatible(argtpe, formal) || ctx.mode.is(Mode.ImplicitsEnabled) && SAMargOK
488+
}
489+
477490
/** The type of the given argument */
478491
protected def argType(arg: Arg, formal: Type): Type
479492

480493
def typedArg(arg: Arg, formal: Type): Arg = arg
481-
def addArg(arg: TypedArg, formal: Type) =
482-
ok = ok & {
483-
argType(arg, formal) match {
484-
case ref: TermRef if ref.denot.isOverloaded =>
485-
// in this case we could not resolve overloading because no alternative
486-
// matches expected type
487-
false
488-
case argtpe =>
489-
isCompatible(argtpe, formal)
490-
}
491-
}
494+
final def addArg(arg: TypedArg, formal: Type) = ok = ok & argOK(arg, formal)
492495
def makeVarArg(n: Int, elemFormal: Type) = {}
493496
def fail(msg: => Message, arg: Arg) =
494497
ok = false
@@ -512,11 +515,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
512515
}
513516

514517
/** Subclass of Application for applicability tests with type arguments and value
515-
* argument trees.
516-
*/
518+
* argument trees.
519+
*/
517520
class ApplicableToTreesDirectly(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context) extends ApplicableToTrees(methRef, targs, args, resultType)(ctx) {
518-
override def addArg(arg: TypedArg, formal: Type) =
519-
ok = ok & (argType(arg, formal) <:< formal)
521+
override def argOK(arg: TypedArg, formal: Type) = argType(arg, formal) <:< formal
520522
}
521523

522524
/** Subclass of Application for applicability tests with value argument types. */
@@ -1197,7 +1199,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11971199
/** Resolve overloaded alternative `alts`, given expected type `pt` and
11981200
* possibly also type argument `targs` that need to be applied to each alternative
11991201
* to form the method type.
1200-
* todo: use techniques like for implicits to pick candidates quickly?
1202+
* Two trials: First, without implicits or SAM conversions enabled. Then,
1203+
* if the fist finds no eligible candidates, with implicits and SAM conversions enabled.
12011204
*/
12021205
def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
12031206

@@ -1222,7 +1225,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12221225
* fallback to `chosen`.
12231226
*
12241227
* Note this order of events is done for speed. One might be tempted to
1225-
* preselect alternatives by result type. But is slower, because it discriminates
1228+
* preselect alternatives by result type. But this is slower, because it discriminates
12261229
* less. The idea is when searching for a best solution, as is the case in overloading
12271230
* resolution, we should first try criteria which are cheap and which have a high
12281231
* probability of pruning the search. result type comparisons are neither cheap nor
@@ -1258,7 +1261,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12581261
/** This private version of `resolveOverloaded` does the bulk of the work of
12591262
* overloading resolution, but does not do result adaptation. It might be
12601263
* called twice from the public `resolveOverloaded` method, once with
1261-
* implicits enabled, and once without.
1264+
* implicits and SAM conversions enabled, and once without.
12621265
*/
12631266
private def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type])(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
12641267

@@ -1338,7 +1341,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
13381341
if (isDetermined(alts1)) alts1
13391342
else {
13401343
val alts2 = narrowByShapes(alts1)
1341-
//ctx.log(i"narrowed by shape: ${alts1.map(_.symbol.showDcl)}%, %")
1344+
//ctx.log(i"narrowed by shape: ${alts2.map(_.symbol.showDcl)}%, %")
13421345
if (isDetermined(alts2)) alts2
13431346
else {
13441347
pretypeArgs(alts2, pt)

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
21612161
}
21622162
}
21632163

2164+
def toSAM(tree: Tree): Tree = tree match {
2165+
case tree: Block => tpd.cpy.Block(tree)(tree.stats, toSAM(tree.expr))
2166+
case tree: Closure => cpy.Closure(tree)(tpt = TypeTree(pt)).withType(pt)
2167+
}
2168+
21642169
def adaptToSubType(wtp: Type): Tree = {
21652170
// try converting a constant to the target type
21662171
val folded = ConstFold(tree, pt)
@@ -2172,7 +2177,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
21722177
return tpd.Block(adapt(tree, WildcardType) :: Nil, Literal(Constant(())))
21732178
// convert function literal to SAM closure
21742179
tree match {
2175-
case Closure(Nil, id @ Ident(nme.ANON_FUN), _)
2180+
case closure(Nil, id @ Ident(nme.ANON_FUN), _)
21762181
if defn.isFunctionType(wtp) && !defn.isFunctionType(pt) =>
21772182
pt match {
21782183
case SAMType(meth)
@@ -2181,7 +2186,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
21812186
// but this prevents case blocks from implementing polymorphic partial functions,
21822187
// since we do not know the result parameter a priori. Have to wait until the
21832188
// body is typechecked.
2184-
return cpy.Closure(tree)(Nil, id, TypeTree(pt)).withType(pt)
2189+
return toSAM(tree)
21852190
case _ =>
21862191
}
21872192
case _ =>

tests/pos/i2367.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Test {
2+
new Thread(() => println("hi"))
3+
4+
def foo(x: Int => Int, y: Int): Int = 1
5+
def foo(x: Int, y: Int): Int = 2
6+
foo(1, 2)
7+
foo(x => x, 2)
8+
}

0 commit comments

Comments
 (0)