summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2013-01-06 01:43:20 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-01-09 22:31:57 -0800
commitb1cea212f36b27636ef6aab76bf8992210a4426e (patch)
treef90697b53558394c3a1db7e30637e5236f89530d
parentf219ade08ed8174c7bded654e8070f4b61843513 (diff)
downloadscala-b1cea212f36b27636ef6aab76bf8992210a4426e.tar.gz
scala-b1cea212f36b27636ef6aab76bf8992210a4426e.tar.bz2
scala-b1cea212f36b27636ef6aab76bf8992210a4426e.zip
SI-6925 use concrete type in applyOrElse's match's selector
Fix a regression introduced in 28483739c3: 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] ```
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala11
-rw-r--r--test/files/pos/t6925.scala9
2 files changed, 19 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9d390476db..49c7181787 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/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)
diff --git a/test/files/pos/t6925.scala b/test/files/pos/t6925.scala
new file mode 100644
index 0000000000..862a6e9d0e
--- /dev/null
+++ b/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 })
+} \ No newline at end of file