diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-11-06 11:50:13 +0100 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-11-06 14:17:45 +0100 |
commit | 9c36a76171d497fe277030d2f682f927ae2657f4 (patch) | |
tree | a548b30aea610dcec56057fd99c25f7cfb6ab715 /src/reflect | |
parent | ae70f020cdd22d155882191ca60d40542615b606 (diff) | |
download | scala-9c36a76171d497fe277030d2f682f927ae2657f4.tar.gz scala-9c36a76171d497fe277030d2f682f927ae2657f4.tar.bz2 scala-9c36a76171d497fe277030d2f682f927ae2657f4.zip |
[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)
<console>: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: <error>, <error> [class scala.reflect.internal.Types$ErrorType$, class scala.reflect.internal.Types$ErrorType$] TypeRef? false
error: Unknown type: <error>, <error> [class scala.reflect.internal.Types$ErrorType$, class scala.reflect.internal.Types$ErrorType$] TypeRef? false
scala.reflect.internal.FatalError: Unknown type: <error>, <error> [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
```
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/tpe/TypeMaps.scala | 16 | ||||
-rw-r--r-- | src/reflect/scala/reflect/runtime/JavaUniverseForce.scala | 1 |
3 files changed, 18 insertions, 1 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index e2ee6a9076..85b080f29b 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -790,7 +790,7 @@ trait Definitions extends api.StandardDefinitions { * The class defining the method is a supertype of `tp` that * has a public no-arg primary constructor. */ - def samOf(tp: Type): Symbol = { + def samOf(tp: Type): Symbol = if (!settings.Xexperimental) NoSymbol else { // if tp has a constructor, it must be public and must not take any arguments // (not even an implicit argument list -- to keep it simple for now) val tpSym = tp.typeSymbol diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index f06420de96..662306d5ab 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -422,6 +422,22 @@ private[internal] trait TypeMaps { } } + /** + * Get rid of BoundedWildcardType where variance allows us to do so. + * Invariant: `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`. + */ + object wildcardExtrapolation extends TypeMap(trackVariance = true) { + def apply(tp: Type): Type = + tp match { + case BoundedWildcardType(TypeBounds(lo, AnyTpe)) if variance.isContravariant =>lo + case BoundedWildcardType(TypeBounds(NothingTpe, hi)) if variance.isCovariant => hi + case tp => mapOver(tp) + } + } + /** Might the given symbol be important when calculating the prefix * of a type? When tp.asSeenFrom(pre, clazz) is called on `tp`, * the result will be `tp` unchanged if `pre` is trivial and `clazz` diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 18a3c5d63f..c87b810bdd 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -170,6 +170,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.dropSingletonType this.abstractTypesToBounds this.dropIllegalStarTypes + this.wildcardExtrapolation this.IsDependentCollector this.ApproximateDependentMap this.wildcardToTypeVarMap |