Strange error: bad superclass

I get a very strange error upon running Test/compile. Everything compiles completely fine if all the classes are located in src/main. However, if any reference (say instantiation) to the classes/traits are done within the src/test, the following errors are emitted:

[error] Error while emitting xxx/PluginSuite.scala
[error] assertion failed: Bad superClass for class StateDiagram: val <none>

Now, Plugin and PluginRouter depend mutually on each other. As stated above, if the client code is written in src/main, no problem arises. But when it is done in the src/test, the above error is emitted.

I have cleaned the cache and many other things, but the error persists.

Here, is the shortened code that reproduces the error:

trait StateDiagram {
  self: StateMachine =>
    ...
}

trait PluginStateDiagram extends StateDiagram {
  self: StateMachine =>
    ...
}

trait Plugin extends StateMachine with PluginStateDiagram {
  type S = PluginState
  val pluginRouter: PluginRouter

  from(any*).to(Initialized) { (x, y) =>
    pluginRouter.subscribe(this)
  }
}

class NetworkPlugin(val pluginRouter: PluginRouter) extends Plugin {}

class PluginSuite extends FunSuite {

  test("RequestManager should not error responses") {
    val pluginRouter = new PluginRouter()

    // This is where the error occurs.  If moved to src/main, it works fine.
    val networkPlugin = new NetworkPlugin(pluginRouter)
    }
}

build.sbt

lazy val root = (project in file(".")).settings(
  inThisBuild(List(organization := "org.naderica", scalaVersion := "3.6.3", name := "brix")),
  name := "brix",
  libraryDependencies ++= {
    val junitV = "4.13.2"
    val junitInterfaceV = "0.11"
    Seq(
      "junit" % "junit" % junitV % Test,
      "com.novocode" % "junit-interface" % junitInterfaceV % Test,
      "org.scalatest" %% "scalatest" % "latest.integration" % Test,
      "org.scalameta" %% "munit" % "latest.integration" % Test,
      "org.json" % "json" % "latest.integration",
      "io.cequence" %% "openai-scala-client" % "latest.integration",
      // "com.theokanning.openai-gpt3-java" % "service" % "latest.integration",
      "com.microsoft.playwright" % "playwright" % "latest.integration"
    )
  },
testOptions += Tests.Argument(TestFrameworks.JUnit, "-v")
)

A thought - I notice that you have a dependency on JUnit 4. Does this mean you have a mix of Java and Scala in the build? If so, does that include StateMachine?

I was thinking of Scala versus Java compilation order being a possibility…

1 Like

Thank you for your response.

Yes I have a mix of Java and Scala. The StateMachine and all its related classes/traits are written purely in Scala.

If I remove the mutual dependency between Plugin and PluginRouter, it works even if the code and the client code is in the src/test.

Inspired by your thought, I changed the ordering to the following, but the problem persisted to exist:

Seq(
  "org.scalatest" %% "scalatest" % "latest.integration" % Test,
  "org.scalameta" %% "munit" % "latest.integration" % Test,
  "junit" % "junit" % junitV % Test, "com.novocode" % "junit-interface" % junitInterfaceV % Test,
  "org.json" % "json" % "latest.integration","io.cequence" %% "openai-scala-client" % "latest.integration",
  // "com.theokanning.openai-gpt3-java" % "service" % "latest.integration",
  "com.microsoft.playwright" % "playwright" % "latest.integration"
)

I even removed the reference to Junit in build.sbt, but got the same problem.

cheers

Drat - the Java thing is probably a red herring, then. You never know, perhaps you have some residual coupling between the Java and Scala parts that is causing this, perhaps further reduction of the code will flush this out (or highlight something else).

If it is a Java / Scala thing after all, the order of dependencies doesn’t matter - instead, there is an SBT setting that controls how SBT orchestrates Java and Scala compilation, you need to look that up and try it.

Nevertheless, further reduction of the problem is the way to go. Good luck, hopefully someone else may chime in…

Thank you for sharing your thoughts. I actually reduced the original code to a minimum, and reproduced the same problem. I wonder if this is a SBT thing - but I am totally lost here.

I tried the various combinations of the following, but am still getting the same problem. So it seems that the problem is not related to Java/Scala ordering

Compile / compileOrder := CompileOrder.JavaThenScala
Compile / compileOrder := CompileOrder.ScalaThenJava
Test / compileOrder := CompileOrder.Mixed

OK. I’m really clutching at straws here, but did you try either Test / compileOrder := CompileOrder.JavaThenScala or Test / compileOrder := CompileOrder.ScalaThenJava?

Also, did your reduced example get rid of all the Java sources? If they are necessary for it, I guess there is some Java / Scala coupling in the failure, so that might still be a possibility.

Also, does this occur when doing a full compilation after a clean, or just for incremental recompilation?

I imagine now that the problem lies elsewhere, but I’d still want to eliminate that residual doubt.

Oh, one last thing - your code looks to be Scala 2.*, although perhaps you have a syntax compatibility flag set. If it is, say 2.13, have your tried using Scala 3.3?

My thinking being that this might not be an SBT issue after all, but something to to with the compiler. Scala 3 gives quite good error messages too, so if it’s a ā€˜genuine’ compilation error, it might give you a better idea. Worth a try on your reduced example…

Thank you indeed for your effort to help resolve this problem.

I have tried almost all the combinations of the following, i.e. Scala first, Java first, with only Compile / compileOrder, with only Test /compilerOrder, with only CompilerOrder.Mixed, with them together etc. The problem persists.

1. Compile / compileOrder := CompileOrder.ScalaThenJava,
2. Test / compileOrder := CompileOrder.ScalaThenJava,
3. Test / compileOrder := CompileOrder.JavaThenScala,
4. Compile / compileOrder := CompileOrder.JavaThenScala
5. Test / compileOrder := CompileOrder.Mixed,

I have consistently compiled in the following order, but get the same compilation error:
sbtn -> clean; compile; Test/compile
or
sbt clean; sbt compile; sbt test:compile

Note, I can see that StateMachine depends on
import java.util.concurrent.atomic.AtomicReference

I am using Scala 3.6.3 and Java 21.0.3. I still prefer the Scala 2 code style with {}. I believe I modified all the warnings of Scala 2 that Vscode Metal plugin reported. So theoretically, there should not be any Scala 2 specific code.

I will build a minimal version without AtomicReference. If it does help, I will try to use Scala 3 code style with ":" and tabs. Then I will post the results.

Best regards

I would ā€œassumeā€ it’s a class path problem.

That is distinct from a class loader problem.

My guess is that it’s not Java vs Scala but Compile vs Test.

With class loaders, usually it delegates to a parent and barring a deadlock it works.

With a class path, it may need to load a symbol that is missing from the class path. This is in the back end:

    assert(
      if (classSym == ObjectClass)
        superClassSym == NoSymbol
      else if (classSym.isInterface)
        superClassSym == ObjectClass
      else
        // A ClassBType for a primitive class (scala.Boolean et al) is only created when compiling these classes.
        ((superClassSym != NoSymbol) && !superClassSym.isInterface) || (isCompilingPrimitive && primitiveTypeToBType.contains(classSym)),
      s"Bad superClass for $classSym: $superClassSym"
    )

It’s the same code in Dotty, so I’m not sure how the example was compiled.

1 Like