I've been looking into SI-6146, a regression in the pattern matcher's exhaustiveness analysis.
scala> class C { sealed class S; object O { object T extends S} }
defined class C
scala> class D extends C {
| def foo(s: S) = s match {
| case O.T => // need to convert from <symbol T> to <type D.this.O.T>
| }
| }
<console>:9: warning: match may not be exhaustive.
It would fail on the following input: S()
def foo(s: S) = s match {
^
The challenge is to determine types for the sealed descendants which correspond to the type (including, importantly, the prefix) of the scrutinee; we need to get from `symbol T` to the type `D.this.O.T`.
`asSeenFrom` isn't enough, because that requires that we use a particular subtype / superclass symbol. In this case, it would seem the necessary ASF might involve any prefix of the scrutinee type and the descendent symbol's type.
But it brings me to a concrete question. I've found that we can refer to nested modules via either a ModuleTypeRef or via a SingleType. Calling .narrow.widen on the former yields the latter, which is an equivalent type. The latter seems more pliable; we can substitute the ThisType(C) with ThisType(D) with an appropriately targetted ASF to make the types line up.
==================================
scala> class C { object X { trait T } }
defined class C
scala> val T1 = u.typeOf[c.X.T forSome { val c: C}].typeSymbol.tpeHK
T1: u.Type = C.X.T
scala> showTp(T1)
res56: String =
TypeRef(
pre = ThisType(object X)
TypeSymbol(abstract trait T extends Object)
)
scala> val T2 = T1.map(t => if (t.typeSymbol.isModuleClass) t.widen.narrow else t)
T2: u.Type = C.this.X.T
scala> showTp(T2)
res57: String =
TypeRef(
pre = SingleType(pre = ThisType(class C), object X)
TypeSymbol(abstract trait T extends Object)
)
scala> T1 =:= T2
res58: Boolean = true
==================================
- Is `(if (t.typeSymbol.isModuleClass) t.widen.narrow else t) =:= t` always true?
- Why are there two representations here? Performance?
-jason
PS: here's the prelude for that session for power mode fans:
scala> :power
Already in power mode.
scala> val u = rootMirror.universe
u: $r.intp.global.type = scala.tools.nsc.interpreter.IMain$$anon$1@7563a93e
scala> import u._
import u._
scala> import intp.deconstruct.{show => showTp}
import intp.deconstruct.{show=>showTp}