Help understanding local class definitions

I can’t comment this at the language spec/compiler implementation level, but to my understanding, barring specific compiler tricks, there will be one class at the bytecode level per class declaration at the source code level. However, at the source code level the compiler will enforce the perception that for inner class declarations, there will be one class per outer instance.

class Foo {
  class Bar // only one Foo$Bar.class

  def accept(b: Bar): Unit = ()

  def acceptAny(o: AnyRef): Unit =
    o match {
      case _: Bar => println("Bar")
      case _ => println("other")
    }
}

val f1 = new Foo
val f2 = new Foo

f1.accept(new f1.Bar) // ok
//f1.accept(new f2.Bar) // doesn't compile

f1.acceptAny(new f1.Bar) // "Bar"
f1.acceptAny(new f2.Bar) // "other"

[EDIT: I guess that the synthetic $outer reference is used to distinguish cases in the #acceptAny() dispatch, but I’m not sure.]

With method-local classes in recursive functions, there’s no “anchor” the compiler can use to tie a class reference to a specific recursion level, and pattern matching boils down to reflection in disguise, anyway, so method-local classes basically behave just like inner classes.

def rabbitHole(count: Int): Unit = {
  class FooExc extends RuntimeException
  try {
    if(count <= 0) throw new FooExc else rabbitHole(count - 1)
  }
  catch {
    case e: FooExc =>
      println(e.getClass)
      throw e
  }
}

rabbitHole(2)

Output:

class de.sangamon.scalausers.MemberClassId$FooExc$1
class de.sangamon.scalausers.MemberClassId$FooExc$1
class de.sangamon.scalausers.MemberClassId$FooExc$1
Exception in thread "main" de.sangamon.scalausers.MemberClassId$FooExc$1