Permalink
Browse files

SI-6925 use concrete type in applyOrElse's match's selector

Fix a regression introduced in 2848373:

PartialFunction synthesis was broken so that we'd get:
```
scala> def f[T](xs: Set[T]) = xs collect { case x => x }
f: [T](xs: Set[T])scala.collection.immutable.Set[_ <: T]
```

rather than
```
scala> def f[T](xs: Set[T]) = xs collect { case x => x }
f: [T](xs: Set[T])scala.collection.immutable.Set[T]
```
  • Loading branch information...
1 parent f219ade commit b1cea212f36b27636ef6aab76bf8992210a4426e @adriaanm adriaanm committed Jan 6, 2013
Showing with 19 additions and 1 deletion.
  1. +10 −1 src/compiler/scala/tools/nsc/typechecker/Typers.scala
  2. +9 −0 test/files/pos/t6925.scala
View
11 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -996,6 +996,7 @@ trait Typers extends Modes with Adaptations with Tags {
object variantToSkolem extends VariantTypeMap {
def apply(tp: Type) = mapOver(tp) match {
case TypeRef(NoPrefix, tpSym, Nil) if variance != 0 && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm =>
+ tpSym.initialize // must initialize or tpSym.tpe might see random type params!! TODO: why is that??
val bounds = if (variance == 1) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe)
// origin must be the type param so we can deskolemize
val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds)
@@ -2683,7 +2684,15 @@ trait Typers extends Modes with Adaptations with Tags {
val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
paramSyms foreach (methodBodyTyper.context.scope enter _)
- val match_ = methodBodyTyper.typedMatch(gen.mkUnchecked(selector), cases, mode, ptRes)
+ // SI-6925: subsume type of the selector to `argTp`
+ // we don't want/need the match to see the `A1` type that we must use for variance reasons in the method signature
+ // the cast is safe: it's an upcast -- the cast is needed because `(x: A1): A` doesn't always type check, even though `A1 <: A`
+ // specifically, it's needed when dealing with singleton types due to limitations/bugs? with SingletonClass
+ // (I first tried to use singletonBounds for A1's info when argTp.iStable -- didn't work)
+ // I decided to always do the cast, as posterasure will detect it's redundant and remove it
+ val selectorSubsumed =
+ Typed(gen.mkAsInstanceOf(selector, argTp.withoutAnnotations, true, false), TypeTree(argTp)) // TODO: factor this out -- mkCastTyped?
+ val match_ = methodBodyTyper.typedMatch(gen.mkUnchecked(selectorSubsumed), cases, mode, ptRes)
val resTp = match_.tpe
anonClass setInfo ClassInfoType(parentsPartial(List(argTp, resTp)), newScope, anonClass)
View
9 test/files/pos/t6925.scala
@@ -0,0 +1,9 @@
+class Test {
+ def f[T](xs: Set[T]) /* no expected type to trigger inference */ =
+ xs collect { case x => x }
+
+ def g[T](xs: Set[T]): Set[T] = f[T](xs) // check that f's inferred type is Set[T]
+
+ // check that this type checks:
+ List(1).flatMap(n => Set(1).collect { case w => w })
+}

0 comments on commit b1cea21

Please sign in to comment.