Skip to content

IncompatibleClassChangeError on inner class java.lang.Class #4192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nicolasstucki opened this issue Mar 26, 2018 · 7 comments
Closed

IncompatibleClassChangeError on inner class java.lang.Class #4192

nicolasstucki opened this issue Mar 26, 2018 · 7 comments

Comments

@nicolasstucki
Copy link
Contributor

object Test {
  def main(args: Array[String]): Unit = {
    class Foo
    classOf[Foo].getDeclaringClass
  }
}

fails with

Exception in thread "main" java.lang.IncompatibleClassChangeError: Test and Test$Foo$1 disagree on InnerClasses attribute
	at java.lang.Class.getDeclaringClass0(Native Method)
	at java.lang.Class.getDeclaringClass(Class.java:1235)
	at Test$.main(Foo.scala:4)
	at Test.main(Foo.scala)

It works on scalac.

@smarter
Copy link
Member

smarter commented Mar 27, 2018

This is probably related to all the changes to the InnerClass table generation done by @lrytz in the scalac backend since the dotty backend was forked (September 2014), good luck figuring it out: https://github.com/scala/scala/blob/2a88024236cdab266cabe11414120a6af796a56f/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala#L333-L588

@farquet
Copy link

farquet commented Nov 23, 2020

For reference, this issue is a blocker for generating GraalVM native images for code generated by the dotty compiler. GraalVM static analysis relies on those InnerClasses attributes to be correct to be able to work.

The scala compiler had a similar issue which got fixed in scala 2.12.7. scala/bug/issues/10487

@nicolasstucki nicolasstucki added this to the 3.0.0 milestone Nov 24, 2020
@prolativ prolativ self-assigned this Jan 28, 2021
@prolativ
Copy link
Contributor

Not sure if this should be treated as a separate issue or as a part of this one but while trying to construct a more complex test case for this I found out that there is a discrepancy between scala 2 and 3 about how class files are generated.
In this case

object Test {
  class Quux

  def main(args: Array[String]): Unit = {
    class Foo {
      class Bar

      println(classOf[Bar].getDeclaringClass)

      def test() = {
        class Baz
        println(classOf[Baz].getDeclaringClass)
      }
    }

    println(classOf[Foo].getDeclaringClass)
    val foo = new Foo
    foo.test()
  }
}

as the result of transformations done in lambdaLift and flatten phases Baz turns into Test$Foo$1$Baz$1 in scala 2 but into Test$Baz$1 in scala 3. Is this expected/acceptable? Is there a particular reason why this got changed? Taking into account that in both cases Quux becomes Test$Quux and Foo becomes Test$Foo$1, the scheme used in scala 2 seems more regular although it produces class files with longer names which might cause problems in some extreme cases (e.g. when one uses a Linux with an encrypted disk partition).
@smarter @nicolasstucki any ideas?

@smarter
Copy link
Member

smarter commented Jan 28, 2021

Is this expected/acceptable?

Yes, those are just implementation details.

it produces class files with longer names which might cause problems in some extreme cases (e.g. when one uses a Linux with an encrypted disk partition).

That won't be an issue once #5812 is fixed.

@propensive
Copy link
Contributor

In Scala 2, at least, I believe that very long names should have their "middle" replaced by a hash (MD5, I think), so they are never longer than a certain length. It's the "middle" so that the few characters at the start and end remain unencrypted and readable.

prolativ added a commit to dotty-staging/dotty that referenced this issue Mar 3, 2021
prolativ added a commit to dotty-staging/dotty that referenced this issue Mar 8, 2021
smarter added a commit that referenced this issue Mar 10, 2021
…neration

Fix #4192: Properly set InnerClasses end EnclosingMethod in class files
@farquet
Copy link

farquet commented Mar 10, 2021

Awesome!
Looking forward to test dotty native image compatibility once 3.0.0-RC2 is out

@smarter
Copy link
Member

smarter commented Mar 11, 2021

If you wish to try it out early, the fix should be part of the latest nightly: https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3.0.0-RC2/3.0.0-RC2-bin-20210310-4af1386-NIGHTLY/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants