ModuleTypeRef(object X) vs SingleType(pre, object X)

22 views
Skip to first unread message

Jason Zaugg

unread,
Feb 3, 2013, 1:20:26 PM2/3/13
to scala-i...@googlegroups.com
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.

Anyway, that's all background. Adriaan also did a little work on this https://github.com/adriaanm/scala/commit/1ec629fd

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}


Jason Zaugg

unread,
Feb 3, 2013, 1:26:02 PM2/3/13
to scala-i...@googlegroups.com
On Sun, Feb 3, 2013 at 7:20 PM, Jason Zaugg <jza...@gmail.com> wrote:
PS: here's the prelude for that session for power mode fans:

scala> :power
Already in power mode.

(I wonder if we could sneak in easter-egg to pop up: http://www.youtube.com/watch?v=-dJolYw8tnk)

-jason

Paul Phillips

unread,
Feb 3, 2013, 1:43:29 PM2/3/13
to scala-i...@googlegroups.com
On Sun, Feb 3, 2013 at 10:20 AM, Jason Zaugg <jza...@gmail.com> wrote:
 - Is `(if (t.typeSymbol.isModuleClass) t.widen.narrow else t) =:= t` always true?

Unless there are bugs, I believe so (but it hasn't always been thus.)
 
 - Why are there two representations here? Performance?

The history of this is long and I imagine there are different interpretations. It's one of those things I chased for years until one day I caught it.


After some followups to that commit, we have largely limited the appearance of "object X" instead of "X.type" at the language level - but not completely. Internally, it persists for hysterical raisins. I will be skeptical of any argument that both representations are necessary which is not accompanied by code which demonstrates that.

If you would like to see what may be the last frontier in terms of visible language-level distinction:


There are probably bits of the implementation which depend on both representations existing - for instance I'm pretty sure in at least one spot the difference is used to terminate recursion - but that's just how it is, not how it has to be.

Reply all
Reply to author
Forward
0 new messages