From 9c36a76171d497fe277030d2f682f927ae2657f4 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 6 Nov 2014 11:50:13 +0100 Subject: [sammy] eta-expansion, overloading (SI-8310) Playing with Java 8 Streams from the repl showed we weren't eta-expanding, nor resolving overloading for SAMs. Also, the way Java uses wildcards to represent use-site variance stresses type inference past its bendiness point (due to excessive existentials). I 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 shows most of this works, though we have some more work to do (see near the end). ``` 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 ``` --- test/files/pos/sammy_exist.scala | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/files/pos/sammy_exist.scala (limited to 'test/files/pos/sammy_exist.scala') diff --git a/test/files/pos/sammy_exist.scala b/test/files/pos/sammy_exist.scala new file mode 100644 index 0000000000..95c7c7b68e --- /dev/null +++ b/test/files/pos/sammy_exist.scala @@ -0,0 +1,24 @@ +// scala> typeOf[java.util.stream.Stream[_]].nonPrivateMember(TermName("map")).info +// [R](x$1: java.util.function.Function[_ >: T, _ <: R])java.util.stream.Stream[R] + +// java.util.function.Function +trait Fun[A, B] { def apply(x: A): B } + +// java.util.stream.Stream +class S[T](x: T) { def map[R](f: Fun[_ >: T, _ <: R]): R = f(x) } + +class Bla { def foo: Bla = this } + +object T { + val aBlaSAM = (new S(new Bla)).map(_.foo) // : Bla should be inferred, when running under -Xexperimental [TODO] + val fun: Fun[Bla, Bla] = (x: Bla) => x + val aBlaSAMX = (new S(new Bla)).map(fun) // : Bla should be inferred, when running under -Xexperimental [TODO] +} +// +// // or, maybe by variance-cast? +// import annotation.unchecked.{uncheckedVariance => uv} +// type SFun[-A, +B] = Fun[_ >: A, _ <: B @uv] +// +// def jf[T, R](f: T => R): SFun[T, R] = (x: T) => f(x): R +// +// val aBlaSAM = (new S(new Bla)).map(jf(_.foo)) // : Bla should be inferred [type checks, but existential inferred] \ No newline at end of file -- cgit v1.2.3