Skip to content

Commit 98fc833

Browse files
Medowhillodersky
authored andcommitted
better warning, fix tests, & add comments
1 parent 251514b commit 98fc833

File tree

5 files changed

+34
-24
lines changed

5 files changed

+34
-24
lines changed

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
13641364
* Two trials: First, without implicits or SAM conversions enabled. Then,
13651365
* if the fist finds no eligible candidates, with implicits and SAM conversions enabled.
13661366
*/
1367-
def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
1367+
def resolveOverloaded(alts: List[TermRef], pt: Type, pos: Position = NoPosition)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
13681368

13691369
/** Is `alt` a method or polytype whose result type after the first value parameter
13701370
* section conforms to the expected type `resultType`? If `resultType`
@@ -1409,9 +1409,9 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14091409
case _ => chosen
14101410
}
14111411

1412-
var found = resolveOverloaded(alts, pt, Nil)(ctx.retractMode(Mode.ImplicitsEnabled))
1412+
var found = resolveOverloaded(alts, pt, Nil, pos)(ctx.retractMode(Mode.ImplicitsEnabled))
14131413
if (found.isEmpty && ctx.mode.is(Mode.ImplicitsEnabled))
1414-
found = resolveOverloaded(alts, pt, Nil)
1414+
found = resolveOverloaded(alts, pt, Nil, pos)
14151415
found match {
14161416
case alt :: Nil => adaptByResult(alt) :: Nil
14171417
case _ => found
@@ -1423,7 +1423,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14231423
* called twice from the public `resolveOverloaded` method, once with
14241424
* implicits and SAM conversions enabled, and once without.
14251425
*/
1426-
private def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type])(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
1426+
private def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type], pos: Position)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
14271427

14281428
def isDetermined(alts: List[TermRef]) = alts.isEmpty || alts.tail.isEmpty
14291429

@@ -1511,19 +1511,27 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15111511

15121512
case pt @ PolyProto(targs1, pt1) if targs.isEmpty =>
15131513
val alts1 = alts filter pt.isMatchedBy
1514-
resolveOverloaded(alts1, pt1, targs1.tpes)
1514+
resolveOverloaded(alts1, pt1, targs1.tpes, pos)
15151515

15161516
case defn.FunctionOf(args, resultType, _, _) =>
15171517
narrowByTypes(alts, args, resultType)
15181518

15191519
case pt =>
15201520
val noSam = alts filter (normalizedCompatible(_, pt))
15211521
if (noSam.isEmpty) {
1522+
/*
1523+
* the case should not be moved to the enclosing match
1524+
* since SAM type must be considered only if there are no candidates
1525+
* For example, the second f should be chosen for the following code:
1526+
* def f(x: String): Unit = ???
1527+
* def f: java.io.OutputStream = ???
1528+
* new java.io.ObjectOutputStream(f)
1529+
*/
15221530
pt match {
15231531
case SAMType(mtp) =>
15241532
val sam = narrowByTypes(alts, mtp.paramInfos, mtp.resultType)
15251533
if (sam.nonEmpty && !pt.classSymbol.hasAnnotation(defn.FunctionalInterfaceAnnot))
1526-
ctx.warning(ex"$pt does not have the @FunctionalInterface annotation.", ctx.tree.pos)
1534+
ctx.warning(ex"${sam.head.designator} is eta-expanded even though $pt does not have the @FunctionalInterface annotation.", pos)
15271535
sam
15281536
case _ => noSam
15291537
}
@@ -1536,7 +1544,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15361544
if (noDefaults.length == 1) noDefaults // return unique alternative without default parameters if it exists
15371545
else {
15381546
val deepPt = pt.deepenProto
1539-
if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs)
1547+
if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs, pos)
15401548
else alts
15411549
}
15421550
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2268,7 +2268,7 @@ class Typer extends Namer
22682268
val altDenots = ref.denot.alternatives
22692269
typr.println(i"adapt overloaded $ref with alternatives ${altDenots map (_.info)}%, %")
22702270
val alts = altDenots.map(TermRef(ref.prefix, ref.name, _))
2271-
resolveOverloaded(alts, pt) match {
2271+
resolveOverloaded(alts, pt, tree.pos) match {
22722272
case alt :: Nil =>
22732273
readaptSimplified(tree.withType(alt))
22742274
case Nil =>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Test {
2+
def foo(c: java.util.function.Consumer[String]) = c.accept("")
3+
4+
def f(x: String): Unit = ()
5+
def f(x: Int): Unit = ()
6+
7+
def main(args: Array[String]) = {
8+
foo(f) // Ok: Consumer is @FunctionalInterface
9+
10+
val oos = new java.io.ObjectOutputStream(f) // error: OutputStream is not @FunctionalInterface
11+
oos.write(0)
12+
oos.close()
13+
}
14+
}

tests/run/i4364a.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
object Test {
2-
var flag = false
3-
42
def f(): Unit = assert(false)
53
def f(x: Int): Unit = assert(false)
6-
def f(x: String): Unit = flag = true
4+
def f(x: String): Unit = ()
75

86
def foo(c: java.util.function.Consumer[String]) = c.accept("")
97

tests/run/i4364b.scala

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
11
object Test {
2-
var flag = false
3-
42
def f(x: Int): Unit = assert(false)
53
def f(x: String): Unit = assert(false)
64
def f: java.io.OutputStream = new java.io.OutputStream {
75
def write(x: Int) = ()
86
}
97

10-
def g(x: Int): Unit = flag = true
11-
def g(x: String): Unit = assert(false)
12-
138
def main(args: Array[String]) = {
14-
val oosF = new java.io.ObjectOutputStream(f)
15-
oosF.write(0)
16-
oosF.close()
17-
18-
val oosG = new java.io.ObjectOutputStream(g) // need warning
19-
oosG.write(0)
20-
oosG.close()
21-
assert(flag)
9+
val oos = new java.io.ObjectOutputStream(f)
10+
oos.write(0)
11+
oos.close()
2212
}
2313
}

0 commit comments

Comments
 (0)