Skip to content

dotc, scalac and javac lead to java.lang.VerifyError #8101

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
anatoliykmetyuk opened this issue Jan 27, 2020 · 4 comments
Closed

dotc, scalac and javac lead to java.lang.VerifyError #8101

anatoliykmetyuk opened this issue Jan 27, 2020 · 4 comments
Assignees

Comments

@anatoliykmetyuk
Copy link
Contributor

minimized code

Foo.scala:

trait Foo {
  def f: String = ???
}

JavaFoo.java:

public abstract class JavaFoo {
    public abstract int read();
}

iss1.scala:

class Bar extends JavaFoo with Foo {
  def read(): Int = ???
}

@main def Test =
  val stdout = new Bar

Compile the first two files with scalac and javac respectively:

javac JavaFoo.java; scalac Foo.scala

Then compile and run the third file with the *.class files from the scalac and javac invocation on the classpath. From SBT:

;dotty-bootstrapped/dotc  -classpath /path/to/classfiles/  /path/to/iss1.scala ;dotty-bootstrapped/dotr  -classpath /path/to/classfiles/  Test
Runtime output
Exception in thread "main" java.lang.VerifyError: Bad operand type when invoking <init>
Exception Details:
  Location:
    Bar.<init>()V @5: invokespecial
  Reason:
    Invalid type: 'Bar' (current frame, stack[0])
  Current Frame:
    bci: @5
    flags: { }
    locals: { 'Bar' }
    stack: { 'Bar' }
  Bytecode:
    0x0000000: 2ab7 000b 2ab7 000c b1

	at iss1$package$.Test(iss1.scala:6)
	at Test.main(iss1.scala:5)

If you debug with -Xprint, at some point Bar has a bad constructor which calls super twice:

  ) class Bar extends JavaFoo, Foo {
    def <init>(): Unit =
      {
        super()
        super[Foo]()
        ()
      }

expectation

Should run correctly.

@anatoliykmetyuk anatoliykmetyuk self-assigned this Jan 27, 2020
@smarter smarter self-assigned this Jan 27, 2020
@smarter
Copy link
Member

smarter commented Jan 27, 2020

I have an immediate fix, but to be complete it seems like we'll need to replace all usages of setFlag/resetFlag/flags_= in the compiler by something which takes all future denotations into account, see smarter@d975d53 /cc @odersky

@smarter
Copy link
Member

smarter commented Jan 27, 2020

Oops, the previous commit didn't work since it didn't set the flag on the current denotation, smarter@410adde should work.

@odersky
Copy link
Contributor

odersky commented Jan 29, 2020

After having looked at all setFlags and resetFlags in transform it seems to me that Scala2PartiallyAugmented flag is the only problematic one. Problematic means:

The flag is changed more than once on the same symbol, and the symbol survives a compilation run.

The Scala2PartiallyAugmented is essentially a signal between two phases that work has to be done. I believe it's better not use a flag for that.

odersky added a commit to dotty-staging/dotty that referenced this issue Jan 29, 2020
Flags can't be used as non-monotonic signals between phases
since denotations are phase-versioned and later denotations
might exist already when the flag of an earlier denotation is
set. Use a set of mixins instead.
odersky added a commit to dotty-staging/dotty that referenced this issue Jan 29, 2020
Flags can't be used as non-monotonic signals between phases
since denotations are phase-versioned and later denotations
might exist already when the flag of an earlier denotation is
set. Use another flag _Scala2xFullyAugmented_ to make changes monotonic.
@smarter
Copy link
Member

smarter commented Jan 29, 2020

I agree that not resetting a flag is better, but Scala2PartiallyAugmented is not the only problematic flag in general. For example, in Memoize we do:

field.setFlag(Mutable) // Necessary for vals mixed in from Scala2 traits

if for some reason at this point a later denotation already exists for field (this does not require multiple compilation runs, only the use of ctx.atPhase/withPhase), then this denotation will not have the Mutable flag set, I assume that would then lead to broken bytecode.

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

3 participants