user48956
user48956

Reputation: 15788

Why does scala treat locally defined classes differently to classes in outer scopes?

What does the compiler see differently in each class declaration below that causes typeOf to behave differently. (i.e. what's the property of the class declaration that causes it to fail).

import org.junit.Test
import scala.reflect.runtime.universe._


case class Person1(name: String)
class ReflectTest {

  case class Person2(name: String)

  @Test
  def constructorTest(): Unit = {

    case class Person3(name: String)

    typeOf[Person1]  // Yep
    typeOf[Person2]  // No problem
    typeOf[Person3]  // No typetag information available :(
  }
}

Upvotes: 2

Views: 144

Answers (1)

som-snytt
som-snytt

Reputation: 39577

It's a free type. And you can't refer to it with a prefix.

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> class C { class D }
defined class C

scala> val c = new C
c: C = C@29626d54

scala> val x = { final class X ; weakTypeTag[X] }
x: reflect.runtime.universe.WeakTypeTag[_ <: AnyRef] = WeakTypeTag[X]

scala> val t = typeTag[C]
t: reflect.runtime.universe.TypeTag[C] = TypeTag[C]

scala> val w = typeTag[c.D]
w: reflect.runtime.universe.TypeTag[c.D] = TypeTag[c.D]

scala> val v = typeTag[C#D]
v: reflect.runtime.universe.TypeTag[C#D] = TypeTag[C#D]

scala> (t.tpe.typeSymbol, t.tpe.typeSymbol.isStatic)
res1: (reflect.runtime.universe.Symbol, Boolean) = (class C,true)

scala> (x.tpe.typeSymbol, x.tpe.typeSymbol.isStatic)
res2: (reflect.runtime.universe.Symbol, Boolean) = (free type X,false)

scala> (w.tpe.typeSymbol, w.tpe.typeSymbol.isStatic)
res3: (reflect.runtime.universe.Symbol, Boolean) = (class D,false)

scala> (v.tpe.typeSymbol, v.tpe.typeSymbol.isStatic)
res4: (reflect.runtime.universe.Symbol, Boolean) = (class D,false)

scala> reflect.runtime.universe.internal.asFreeType(x.tpe.typeSymbol)
res5: reflect.runtime.universe.FreeTypeSymbol = free type X

Other things you can't do with local classes, as mentioned in the spec:

scala> val x = { private class X ; weakTypeTag[X] }
<console>:1: error: illegal start of statement (no modifiers allowed here)
val x = { private class X ; weakTypeTag[X] }
          ^

scala> import c.D
import c.D

I'd look more but it's late and my REPL broke...

scala> val y = { final class X { class Y } ; val x = new X ; import x.Y ; weakTypeTag[Y] } 
warning: there was one feature warning; re-run with -feature for details
java.lang.AssertionError: assertion failed: x.type
    at scala.reflect.internal.tpe.TypeMaps$adaptToNewRunMap$.adaptToNewRun(TypeMaps.scala:1106)
    at scala.reflect.internal.tpe.TypeMaps$adaptToNewRunMap$.apply(TypeMaps.scala:1150)
    at scala.reflect.internal.tpe.TypeMaps$adaptToNewRunMap$.apply(TypeMaps.scala:1079)
    at scala.reflect.internal.tpe.TypeMaps$adaptToNewRunMap$.apply(TypeMaps.scala:1148)
    at scala.reflect.internal.tpe.TypeMaps$TypeMap.mapOver(TypeMaps.scala:162)
    at scala.reflect.internal.tpe.TypeMaps$adaptToNewRunMap$.apply(TypeMaps.scala:1197)
    at scala.reflect.internal.tpe.TypeMaps$adaptToNewRunMap$.apply(TypeMaps.scala:1171)
    at scala.reflect.internal.Symbols$Symbol.adaptInfos(Symbols.scala:1629)
    at scala.reflect.internal.Symbols$Symbol.rawInfo(Symbols.scala:1581)
    at scala.tools.nsc.typechecker.Typers$Typer.isStale(Typers.scala:504)
    at scala.tools.nsc.typechecker.Typers$Typer.reallyExists(Typers.scala:496)
    at scala.tools.nsc.typechecker.Typers$Typer.typedSelectInternal$1(Typers.scala:4712)
    at scala.tools.nsc.typechecker.Typers$Typer.typedSelect$1(Typers.scala:4676)

Upvotes: 1

Related Questions