Skip to content

java interop: inherits unrelated defaults for $init$() from types #8599

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
ohze opened this issue Mar 24, 2020 · 4 comments · Fixed by #10509
Closed

java interop: inherits unrelated defaults for $init$() from types #8599

ohze opened this issue Mar 24, 2020 · 4 comments · Fixed by #10509
Assignees
Milestone

Comments

@ohze
Copy link

ohze commented Mar 24, 2020

minimized code

trait A { val a = 0 }
trait B { val b = 0 }
class Scala extends B with A
class Java extends Scala { }

Compilation output

[info] Compiling 1 Scala source and 1 Java source to /Users/thanhbv/ohze/dotty-example/target/scala-0.23/classes ...
[error] /Users/thanhbv/ohze/dotty-example/src/main/java/Java.java:1:1: types B and A are incompatible;
[error]   class Java inherits unrelated defaults for $init$() from types B and A
[error] (Compile / compileIncremental) javac returned non-zero exit code

expectation

compile successfully as in scala 2

@ohze ohze added the itype:bug label Mar 24, 2020
@ohze

This comment has been minimized.

@smarter

This comment has been minimized.

@smarter smarter closed this as completed Mar 24, 2020
@smarter smarter reopened this Mar 24, 2020
@ohze
Copy link
Author

ohze commented Mar 24, 2020

decompile using Procyon v0.5.36 to compare:

% curl -Lo pd.jar https://bitbucket.org/mstrobel/procyon/downloads/procyon-decompiler-0.5.36.jar

% java -jar pd.jar target/scala-0.23/classes/A.class target/scala-0.23/classes/Scala.class

public interface A {
    default void $init$() { }
    int a();
    default int initial$a() {
        return 0;
    }
}
public class Scala implements B, A {
    private final int b;
    private final int a;
    public Scala() {
        this.b = super.initial$b();
        super.$init$();
        this.a = super.initial$a();
        super.$init$();
    }
    @Override public int b() {
        return this.b;
    }
    @Override public int a() {
        return this.a;
    }
}

% java -jar pd.jar target/scala-2.13/classes/A.class target/scala-2.13/classes/Scala.class

@ScalaSignature(...)
public interface A {
    void A$_setter_$a_$eq(final int x$1);
    int a();
    default void $init$(final A $this) {
        $this.A$_setter_$a_$eq(0);
    }
}
@ScalaSignature(...)
public class Scala implements B, A {
    private int a;
    private int b;
    @Override public int a() {
        return this.a;
    }
    @Override public void A$_setter_$a_$eq(final int x$1) {
        this.a = x$1;
    }
    @Override public int b() {
        return this.b;
    }
    @Override public void B$_setter_$b_$eq(final int x$1) {
        this.b = x$1;
    }
    public Scala() {
        B.$init$();
        A.$init$();
        Statics.releaseFence();
    }
}

Note in dotty case (target/scala-0.23):

  • A.class has empty default void $init$() { }. And of course B.class also has that.
  • There are 2 calls to super.$init$() in Scala's constructor ??

@odersky
Copy link
Contributor

odersky commented Mar 26, 2020

This might go away once we switch to the old trait encoding scheme

giabao added a commit to ohze/akka that referenced this issue Mar 28, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 28, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 28, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 29, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 29, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 30, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 31, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 31, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 2, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 5, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 6, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 7, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 7, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 9, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 9, 2020
@sjrd sjrd added this to the 3.0.0-RC1 milestone Nov 26, 2020
sjrd added a commit to dotty-staging/dotty that referenced this issue Nov 26, 2020
Concrete trait methods are encoded as two methods in the back-end:

* a default method containing the real body, and
* a static forwarder, to use for super calls (due to JVM reasons).

Previously, we did that also for the trait initializer methods
`$init$`. However, that causes unrelated default methods to be
inherited by Scala classes that extend several traits. In turn,
that prevents Java classes from extending such classes.

Now, for the `$init$` methods, instead of creating a static
forwarder, we *move* the entire body to a static method. Therefore,
we only create a static method, and no default method.

This corresponds to what scalac does as well (both what we do and
how we do it), although the previous "discrepancy" was not causing
any incompatibility between Scala 2 and 3 per se.
@sjrd sjrd linked a pull request Nov 26, 2020 that will close this issue
sjrd added a commit to dotty-staging/dotty that referenced this issue Nov 27, 2020
Concrete trait methods are encoded as two methods in the back-end:

* a default method containing the real body, and
* a static forwarder, to use for super calls (due to JVM reasons).

Previously, we did that also for the trait initializer methods
`$init$`. However, that causes unrelated default methods to be
inherited by Scala classes that extend several traits. In turn,
that prevents Java classes from extending such classes.

Now, for the `$init$` methods, instead of creating a static
forwarder, we *move* the entire body to a static method. Therefore,
we only create a static method, and no default method.

This corresponds to what scalac does as well (both what we do and
how we do it), although the previous "discrepancy" was not causing
any incompatibility between Scala 2 and 3 per se.
sjrd added a commit that referenced this issue Nov 27, 2020
Fix #8599: Emit trait init methods only as static methods.
@Kordyjan Kordyjan removed this from the 3.0.0-M3 milestone Aug 2, 2023
@Kordyjan Kordyjan added this to the 3.0.0 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants