scala/scala — pull request #4101 by adriaanm (2014-11-06 11:06:09+00:00)
Title: [sammy] eta-expansion, overloading, existentials

Review by @retronym, please.

While playing with Java 8 Streams from the repl,
I realized we weren't eta-expanding,
nor resolving overloading properly for SAMs.

Also, the way Java uses wildcards to represent use-site variance
stresses type inference (since it results in existentials).

Introduce `wildcardExtrapolation` to simplify the resulting types
(without losing precision): `wildcardExtrapolation(tp) =:= tp`.

For example, the `MethodType` given by `def bla(x: (_ >: String)): (_ <: Int)`
is both a subtype and a supertype of `def bla(x: String): Int`.

Translating http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ into Scala:

```
scala> import java.util.Arrays
scala> import java.util.stream.Stream
scala> import java.util.stream.IntStream
scala> val myList = Arrays.asList("a1", "a2", "b1", "c2", "c1")
myList: java.util.List[String] = [a1, a2, b1, c2, c1]

scala> myList.stream.filter(_.startsWith("c")).map(_.toUpperCase).sorted.forEach(println)
C1
C2

scala> myList.stream.filter(_.startsWith("c")).map(_.toUpperCase).sorted
res8: java.util.stream.Stream[?0] = java.util.stream.SortedOps$OfRef@133e7789

scala> Arrays.asList("a1", "a2", "a3").stream.findFirst.ifPresent(println)
a1

scala> Stream.of("a1", "a2", "a3").findFirst.ifPresent(println)
a1

scala> IntStream.range(1, 4).forEach(println)
:37: error: object creation impossible, since method accept in trait IntConsumer of type (x$1: Int)Unit is not defined
(Note that Int does not match Any: class Int in package scala is a subclass of class Any in package scala, but method parameter types must match exactly.)
IntStream.range(1, 4).forEach(println)
^

scala> IntStream.range(1, 4).forEach(println(_: Int)) // TODO: can we avoid this annotation?
1
2
3

scala> Arrays.stream(Array(1, 2, 3)).map(n => 2 * n + 1).average.ifPresent(println(_: Double))
5.0

scala> Stream.of("a1", "a2", "a3").map(_.substring(1)).mapToInt(_.parseInt).max.ifPresent(println(_: Int)) // whoops!
ReplGlobal.abort: Unknown type: , [class scala.reflect.internal.Types$ErrorType$, class scala.reflect.internal.Types$ErrorType$] TypeRef? false
error: Unknown type: , [class scala.reflect.internal.Types$ErrorType$, class scala.reflect.internal.Types$ErrorType$] TypeRef? false
scala.reflect.internal.FatalError: Unknown type: , [class scala.reflect.internal.Types$ErrorType$, class scala.reflect.internal.Types$ErrorType$] TypeRef? false
at scala.reflect.internal.Reporting$class.abort(Reporting.scala:59)

scala> IntStream.range(1, 4).mapToObj(i => "a" + i).forEach(println)
a1
a2
a3

```