Skip to content

Traits do not have static forwarders in bytecode #7328

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
bishabosha opened this issue Sep 27, 2019 · 3 comments
Closed

Traits do not have static forwarders in bytecode #7328

bishabosha opened this issue Sep 27, 2019 · 3 comments

Comments

@bishabosha
Copy link
Member

bishabosha commented Sep 27, 2019

minimized code

compile with dotc 19.0-RC1

trait Foo { def foo: String = "foo" }

compile with scalacenter/scala@a8f11ef

object TestFoo {
  def main(args: Array[String]): Unit = {
    assert(new Foo {}.foo == "foo")
  }
}

runtime error:

Exception in thread "main" java.lang.NoSuchMethodError: Foo.foo$(LFoo;)Ljava/lang/String;
	at TestFoo$$anon$1.foo(TestFoo.scala:5)
	at TestFoo$.main(TestFoo.scala:5)
	at TestFoo.main(TestFoo.scala)
        ...

expectation

Anonymous subclasses of traits generated by Scala 2.13.x implement methods by calling a static forwarder on the generated Interface.

@smarter
Copy link
Member

smarter commented Sep 27, 2019

Dotty and Scala 2 use a some what different trait encoding. For differences in forwarders see #5928, for differences in initialization see scala/scala-dev#642. It's likely that we'll end up changing both scalac and dotty to converge to a single representation, but until that happens feel free to make a PR adding static forwarders to Dotty if that makes your work easier.

@bishabosha
Copy link
Member Author

bishabosha commented Dec 10, 2019

So I believe this should be closed in favour of an issue to move the whole scala 2 scheme over, as seen here field initialisation and access just isn't compatible

The following trait is compiled with Dotty

trait TraitWithSideEffects {
  val map: mutable.AnyRefMap[String, Boolean] = mutable.AnyRefMap.empty

  map += "True"  -> true
  map += "False" -> false
}

an anonymous subclass for TraitWithSideEffects looks like this in scalac with tasty reader: (using CFR 0.146)

public final class TraitWithSideEffects$.anon.1
implements TraitWithSideEffects {

    // default ctor does nothing

    @Override
    public AnyRefMap<String, Object> map() {
        return TraitWithSideEffects.map$((TraitWithSideEffects)this);
    }
}

and the correct implementation produced by dotty:

private static final class TraitWithSideEffects$.anon.1
implements TraitWithSideEffects {
    private final AnyRefMap map = TraitWithSideEffects.super.initial$map();

    // default ctor also calls $init$

    public AnyRefMap map() {
        return this.map;
    }
}

@sjrd
Copy link
Member

sjrd commented Jul 22, 2020

Fixed in #8652.

@sjrd sjrd closed this as completed Jul 22, 2020
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