Skip to content

Commit fe33616

Browse files
committed
Merge pull request scala#4822 from retronym/ticket/9178
SI-9178 Don't eta expand to an Function0-like SAM expected type
2 parents 15ef839 + 9da23ec commit fe33616

File tree

11 files changed

+63
-1
lines changed

11 files changed

+63
-1
lines changed

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
862862
case Block(_, tree1) => tree1.symbol
863863
case _ => tree.symbol
864864
}
865-
if (!meth.isConstructor && (isFunctionType(pt) || samOf(pt).exists)) { // (4.2)
865+
def shouldEtaExpandToSam: Boolean = {
866+
// SI-9536 don't adapt parameterless method types to a to SAM's, fall through to empty application
867+
// instead for backwards compatiblity with 2.11. See comments of that ticket and SI-7187
868+
// for analogous trouble with non-SAM eta expansion. Suggestions there are: a) deprecate eta expansion to Function0,
869+
// or b) switch the order of eta-expansion and empty application in this adaptation.
870+
!mt.params.isEmpty && samOf(pt).exists
871+
}
872+
if (!meth.isConstructor && (isFunctionType(pt) || shouldEtaExpandToSam)) { // (4.2)
866873
debuglog(s"eta-expanding $tree: ${tree.tpe} to $pt")
867874
checkParamsConvertible(tree, tree.tpe)
868875
val tree0 = etaExpand(context.unit, tree, this)

test/files/pos/t9178.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xfatal-warnings -deprecation

test/files/pos/t9178.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// eta expansion to Function0 is problematic (as shown here).
2+
// Perhaps we should we deprecate it? See discussion in the comments of
3+
// on SI-9178.
4+
//
5+
// This test encodes the status quo: no deprecation.
6+
object Test {
7+
def foo(): () => String = () => ""
8+
val f: () => Any = foo
9+
10+
def main(args: Array[String]): Unit = {
11+
println(f()) // <function0>
12+
}
13+
}

test/files/pos/t9178b.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xexperimental

test/files/pos/t9178b.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
abstract class Test{
2+
val writeInput: java.io.OutputStream => Unit
3+
def getOutputStream(): java.io.OutputStream
4+
5+
writeInput(getOutputStream)
6+
}
7+

test/files/run/t9178a.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xexperimental

test/files/run/t9178a.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait Sam { def apply(): Unit }
2+
abstract class Test {
3+
def foo(): Sam
4+
// no parens, instantiateToMethodType would wrap in a `new Sam { def apply = foo }`
5+
// rather than applying to an empty param list() */
6+
val f: Sam = foo
7+
}
8+
9+
object Test extends Test {
10+
lazy val samIAm = new Sam { def apply() {} }
11+
def foo() = samIAm
12+
def main(args: Array[String]): Unit = {
13+
assert(f eq samIAm, f)
14+
}
15+
}

test/files/run/t9489.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xexperimental

test/files/run/t9489/A.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public class A {
2+
public B b() { return null; }
3+
}

test/files/run/t9489/B.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public abstract class B {
2+
public abstract int m();
3+
}

test/files/run/t9489/test.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class T {
2+
def f(a: A) = g(a.b) // was: "found Int, required B"
3+
def g(b: => B) = null
4+
}
5+
6+
object Test extends T {
7+
def main(args: Array[String]): Unit = {
8+
f(new A)
9+
}
10+
}

0 commit comments

Comments
 (0)