scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.87k stars 1.06k forks source link

`Bad symbolic reference` when a java classfile refers to an annotation inner class not on the classpath #13523

Closed n3f4s closed 2 years ago

n3f4s commented 3 years ago

Compiler version

Compiler version: 3.1.0-RC1

Minimized code

object Bot extends App {
  val token = sys.env("DISCORD_TEST_BOT")
  val gid = sys.env("GUILD_ID")
  val client: GatewayDiscordClient = (DiscordClient.create(token).login().block())
  val pingCmd = (ApplicationCommandRequest.builder()
                   .name ("ping")
                   .description ("Test ping command")
                   .build)

  val restClient = client.getRestClient
  val appId = restClient.getApplicationId.block

  (restClient
     .getApplicationService
     .createGuildApplicationCommand (appId, Snowflake.asLong(gid), pingCmd)
     .doOnError (err ⇒ println(s"Can't create command: ${err}"))
     .onErrorResume (e ⇒ Mono.empty())
     .block)

  (client
     on new ReactiveEventAdapter() {
       val cooldown_table = Map[Long, ZonedDateTime]()

       override def onSlashCommand(evt: SlashCommandEvent) = {
         if(evt.getCommandName() == "ping") {
         val reply = evt
           .getInteraction()
           .getMember()
           .toScala
           .map(mem ⇒ { "pong" })
           .getOrElse("Error: no member")
           evt.reply(reply)
         } else {
           Mono.empty()
         }
       }
     }
     blockLast)
}

Output

[error] Bad symbolic reference. A signature
[error] refers to Value/T in package org.immutables.value which is not available.
[error] It may be completely missing from the current classpath, or the version on
[error] the classpath might be incompatible with the version used when compiling the signature.
[warn] Caught: java.lang.AssertionError: assertion failed: failure to resolve inner class:
[warn] externalName = org.immutables.value.Value$Immutable,
[warn] outerName = org.immutables.value.Value,
[warn] innerName = Immutable
[warn] owner.fullName = org.immutables.value.Value
[warn] while parsing ~/.cache/coursier/v1/https/oss.sonatype.org/content/repositories/snapshots/com/discord4j/discord4j-core/3.2.0-SNAPSHOT/discord4j-core-3.2.0-20210908.030540-190.jar(discord4j/core/spec/InteractionApplicationCommandCallbackReplyMonoGenerator.class) while parsing annotations in ~/.cache/coursier/v1/https/oss.sonatype.org/content/repositories/snapshots/com/discord4j/discord4j-core/3.2.0-SNAPSHOT/discord4j-core-3.2.0-20210908.030540-190.jar(discord4j/core/spec/InteractionApplicationCommandCallbackReplyMonoGenerator.class)
[warn] 5 warnings found

Expectation

The code compiles (and run as expected) with the Scala 2 compiler but give me this error message when compiling with the Scala 3 compiler.

The full code and sbt build file can be found here: https://github.com/n3f4s/scala3D4j3.2ErrorMWE

smarter commented 3 years ago

Workaround: add a dependency on immutables:

diff --git build.sbt build.sbt
index 0fddd4b..0c3ad48 100644
--- build.sbt
+++ build.sbt
@@ -11,6 +11,7 @@ lazy val app = project
     resolvers += "d4j-snapshot" at "https://oss.sonatype.org/content/repositories/snapshots",
     libraryDependencies ++= Seq(
       "com.discord4j" % "discord4j-core" % "3.2.0-SNAPSHOT",
+      "org.immutables" % "value" % "2.8.2"

       ),
     name := "Test bot",

The ClassfileParser should ignore annotations without classfiles instead of crashing, just like scala 2 and java do.

smarter commented 3 years ago

https://github.com/lampepfl/dotty/commit/6f32b6299833fd23868fca9c00ee14ed6cb1158c should have fixed this but wasn't enough to deal with inner classes apparently.

griggt commented 2 years ago

A self-contained example:

Value.java

public @interface Value {
    @interface Immutable {}
}

@Value.Immutable
abstract class Baz {}

Test.scala

object Test {
  def baz: Baz = ???
}
$ javac Value.java
$ rm Value*.class
$ scalac -3.head Test.scala
Bad symbolic reference. A signature
refers to Value/T in package <empty> which is not available.
It may be completely missing from the current classpath, or the version on
the classpath might be incompatible with the version used when compiling the signature.
Caught: java.lang.AssertionError: assertion failed: failure to resolve inner class:
externalName = Value$Immutable,
outerName = Value,
innerName = Immutable
owner.fullName = Value
while parsing ./Baz.class while parsing annotations in ./Baz.class
1 warning found
1 error found

$ scalac -213 Test.scala    // succeeds
anatoliykmetyuk commented 2 years ago

This issue was picked for the Issue Spree 15 of May 3rd which takes place a week from now. @SethTisue, @griggt and @jodersky will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here.