scala3 icon indicating copy to clipboard operation
scala3 copied to clipboard

"asTerm called on not-a-Term" error when compiling against scala-js libraries.

Open scf37 opened this issue 1 year ago • 5 comments

Compiler version

3.4.1

Minimized code

I use scala-js artifacts to compile without sbt-scalajs plugin, it is intended. IDEA can't compile my scala-js project correctly so I included scala-js articacts as Provided to get code completion and validation working. However, compilation crashes.

lazy val test = project.in(file("."))
  .settings(
    scalaVersion := "3.4.1",
    libraryDependencies += "org.scala-js" % "scalajs-dom_sjs1_3" % "2.8.0" % Provided,
)
// ok
val f1: scalajs.js.Function0[Unit] = new scalajs.js.Function0[Unit]:
  override def apply(): Unit = ()

// causes crash
val f2: scalajs.js.Function0[Unit] = () => ()

Output (click arrow to expand)

sbt:test> compile
[info] compiling 1 Scala source to /tmp/1/target/scala-3.4.1/classes ...

  unhandled exception while running MegaPhase{crossVersionChecks, firstTransform, checkReentrant, elimPackagePrefixes, cookComments, checkLoopingImplicits, betaReduce, inlineVals, expandSAMs, elimRepeated, refchecks} on /tmp/1/Main.scala

  An unhandled exception was thrown in the compiler.
  Please file a crash report here:
  https://github.com/scala/scala3/issues/new/choose
  For non-enriched exceptions, compile with -Yno-enrich-error-messages.

     while compiling: /tmp/1/Main.scala
        during phase: MegaPhase{crossVersionChecks, firstTransform, checkReentrant, elimPackagePrefixes, cookComments, checkLoopingImplicits, betaReduce, inlineVals, expandSAMs, elimRepeated, refchecks}
                mode: Mode(ImplicitsEnabled)
     library version: version 2.13.12
    compiler version: version 3.4.1
            settings: -bootclasspath /home/asm/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.4.1/scala3-library_3-3.4.1.jar:/home/asm/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar -classpath /tmp/1/target/scala-3.4.1/classes:/home/asm/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-js/scalajs-dom_sjs1_3/2.8.0/scalajs-dom_sjs1_3-2.8.0.jar:/home/asm/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_sjs1_3/3.1.3/scala3-library_sjs1_3-3.1.3.jar:/home/asm/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-js/scalajs-library_2.13/1.7.1/scalajs-library_2.13-1.7.1.jar -d /tmp/1/target/scala-3.4.1/classes

[error] ## Exception when compiling 1 sources to /tmp/1/target/scala-3.4.1/classes
[error] java.lang.AssertionError: assertion failed: asTerm called on not-a-Term val <none>
[error] scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error] dotty.tools.dotc.core.Symbols$Symbol.asTerm(Symbols.scala:171)
[error] dotty.tools.dotc.ast.tpd$.ClassDef(tpd.scala:326)
[error] dotty.tools.dotc.ast.tpd$.AnonClass(tpd.scala:390)
[error] dotty.tools.dotc.ast.tpd$.AnonClass(tpd.scala:372)
[error] dotty.tools.dotc.transform.ExpandSAMs.transformBlock(ExpandSAMs.scala:75)
[error] dotty.tools.dotc.transform.MegaPhase.goBlock(MegaPhase.scala:767)
[error] dotty.tools.dotc.transform.MegaPhase.goBlock(MegaPhase.scala:768)
[error] dotty.tools.dotc.transform.MegaPhase.transformBlock(MegaPhase.scala:473)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:311)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
[error] dotty.tools.dotc.transform.MegaPhase.mapValDef$1(MegaPhase.scala:247)
[error] dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:252)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:448)
[error] dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:461)
[error] dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:461)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:372)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
[error] dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:268)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:448)
[error] dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:461)
[error] dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:461)
[error] dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:392)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:395)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:477)
[error] dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:489)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:354)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:360)
[error] dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:315)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] dotty.tools.dotc.Run.runPhases$1(Run.scala:337)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:350)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:360)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:360)
[error] dotty.tools.dotc.Run.compileSources(Run.scala:261)
[error] dotty.tools.dotc.Run.compile(Run.scala:246)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:37)
[error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:141)
[error] dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:193)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:248)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:183)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:239)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:211)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:534)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:534)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5(Incremental.scala:180)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5$adapted(Incremental.scala:178)
[error] sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:464)
[error] sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:116)
[error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56)
[error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52)
[error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263)
[error] sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:419)
[error] sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:506)
[error] sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:406)
[error] sbt.internal.inc.Incremental$.apply(Incremental.scala:172)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:534)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:488)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:425)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137)
[error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:2371)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$2(Defaults.scala:2321)
[error] sbt.internal.server.BspCompileTask$.$anonfun$compute$1(BspCompileTask.scala:31)
[error] sbt.internal.io.Retry$.apply(Retry.scala:47)
[error] sbt.internal.io.Retry$.apply(Retry.scala:29)
[error] sbt.internal.io.Retry$.apply(Retry.scala:24)
[error] sbt.internal.server.BspCompileTask$.compute(BspCompileTask.scala:31)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:2319)
[error] scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:63)
[error] sbt.std.Transform$$anon$4.work(Transform.scala:69)
[error] sbt.Execute.$anonfun$submit$2(Execute.scala:283)
[error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:24)
[error] sbt.Execute.work(Execute.scala:292)
[error] sbt.Execute.$anonfun$submit$1(Execute.scala:283)
[error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] sbt.CompletionService$$anon$2.call(CompletionService.scala:65)
[error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[error] java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
[error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[error] java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[error] java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[error] java.base/java.lang.Thread.run(Thread.java:1583)
[error]            
[error] stack trace is suppressed; run last Compile / compileIncremental for the full output
[error] (Compile / compileIncremental) java.lang.AssertionError: assertion failed: asTerm called on not-a-Term val <none>
[error] Total time: 0 s, completed May 1, 2024, 9:54:47 PM

scf37 avatar May 01 '24 18:05 scf37

workaround:

val f0: Function0[Unit] = () => ()
val f: scalajs.js.Function0[Unit] = f0 // compiles just fine both under scalac and scala-js

scf37 avatar May 01 '24 19:05 scf37

You need the -scalajs option.

sjrd avatar May 01 '24 21:05 sjrd

There are more problems like that, for example, copy-pasted scala.scalajs.js.Promise to the project under different package does not compile. Adding -scalajs helped though.

I am not sure whether binary incompatibility between scalac and scala-js is intentional or should it be fixed so I leave this bug open.

scf37 avatar May 03 '24 18:05 scf37

The Scala/JVM world and the Scala.js world are distinct. You cannot hope to compile Scala.js libraries with compiler in Scala/JVM mode or conversely. I don't understand what you're trying to achieve here.

sjrd avatar May 03 '24 18:05 sjrd

It is all about IDE support. I have jvm, scalajs and shared .scala files under the same source root and manage them using unmanagedSources / includeFilter SBT setting.

Since nor IDEA nor Metals support includeFilter and I still want to have code completion and hit Ctrl+F9 in IDEA and see successful compilation (and even run JVM part of the application!), I'm exploring kind of "mixed" mode putting scala-jvm and scala-js .class/.tasty files on the same classpath for scalac.

Expectation: .class and .tasty files generated by scala-js are usable by scalac without -scalajs option. Resulting code will obviously won't run but all I need is typecheck.

Observation: scalac crashes or reports wrong errors when compiling scalajs.js.Function-related code without -scalajs scalac flag.

Therefore: Are those failures intentional? I assumed scala-js generates the same .class and .tasty files as scalac and only adds .sjsir files with additional metadata.

scf37 avatar May 03 '24 19:05 scf37

Therefore: Are those failures intentional? I assumed scala-js generates the same .class and .tasty files as scalac and only adds .sjsir files with additional metadata.

The failures are intentional, or at least they are not considered bugs. Contrary to popular belief, -scalajs does alter the regular compilation pipeline, and therefore does not produce the same class and TASTy files.

For a project structure with a cross JVM/JS project with shared sources and platform-specific sources, the recommended approach is to use https://github.com/portable-scala/sbt-crossproject

sjrd avatar May 03 '24 20:05 sjrd

I explore server-side HTML rendering using components containing cross-compiled scala css with frontend-only scala-js. like component/Component.scala (jvm) component/ComponentCss.scala (js and jvm) component/ComponentJs.scala (js)

Separating them under jvm/component/Component.scala js/component/ComponentJs.scala shared/component/ComponentCss.scala will be wildly inconvenient.

Therefore, should I create feature request in scalajs repo or this won't happen?

scf37 avatar May 04 '24 06:05 scf37

It won't happen, sorry.

sjrd avatar May 04 '24 08:05 sjrd

Closing this issue as it turned out to be a feature request unlikely to be implemented.

scf37 avatar May 04 '24 12:05 scf37