Skip to content

Dotty does not generate accessors for protected calls from inner classes, resulting in IllegalAccessError #2780

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
bbarker opened this issue Jun 18, 2017 · 4 comments

Comments

@bbarker
Copy link
Contributor

bbarker commented Jun 18, 2017

I hazard a guess this is an issue with handling multiple classloaders. This small project demonstrates the issue.

The problem seems to occur when an anonymous or inner class is created that accesses a protected or private member in the outer class. However, I've only been able to reproduce the error when my outer class extends a class implemented in some (java) library - this is the HelloInput.scala example in the repo (and the protected variable in question is speed). The example in Main.scala uses the same approach with a minimal example implemented completely in the project, and seems to work fine.

Stack trace in dotty:

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,run-main-group-0]
java.lang.IllegalAccessError: tried to access field com.jme3.app.LegacyApplication.speed from class HelloInput$$anon$1
        at HelloInput$$anon$1.onAnalog(HelloInput.scala:47)
        at com.jme3.input.InputManager.invokeAnalogs(InputManager.java:245)
        at com.jme3.input.InputManager.invokeUpdateActions(InputManager.java:215)
        at com.jme3.input.InputManager.update(InputManager.java:908)
        at com.jme3.app.LegacyApplication.update(LegacyApplication.java:725)
        at com.jme3.app.SimpleApplication.update(SimpleApplication.java:227)
        at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
        at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
        at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
        at java.lang.Thread.run(Thread.java:748)

To reproduce:

  1. sbt runHelloInput
  2. Press 'j' or 'k' to trigger the method that will calles the IAE.

To compare to scalac, just change the scalaVersion := in build.sbt.

@bbarker bbarker changed the title Regression from scalac 2.11.11 with IllegalAccessError Regression from scalac 2.11.11 (IllegalAccessError) Jun 18, 2017
@smarter
Copy link
Member

smarter commented Jun 18, 2017

Thanks for providing a simple example demonstrating the problem! Here's a minmized test case showing the issue:
Base.java:

package bla;

public class Base {
  protected String foo = "";
}

i2780.scala:

class Foo extends bla.Base {
  class Inner {
    println(foo)
  }
}

object Test {
  def main(args: Array[String]): Unit = {
    val f = new Foo
    new f.Inner
  }
}
% javac try/Base.java -d .
% scalac try/i2780.scala
% scala Test

% dotc try/i2780.scala
% dotr Test
Exception in thread "main" java.lang.IllegalAccessError: tried to access field bla.Base.foo from class Foo$Inner
        at Foo$Inner.<init>(i2780.scala:3)
        at Test$.main(i2780.scala:10)
        at Test.main(i2780.scala)

This is easily explained by comparing the decompiled Foo.class:
scalac 2.12.2:

public class Foo
extends Base {
    public /* synthetic */ String protected$foo(Foo x$1) {
        return x$1.foo;
    }

    public Foo() {
    }

    public class Inner {
        public final /* synthetic */ Foo $outer;

        public /* synthetic */ Foo Foo$Inner$$$outer() {
            return this.$outer;
        }

        public Inner(Foo $outer) {
            if ($outer == null) {
                throw null;
            }
            this.$outer = $outer;
            Predef..MODULE$.println((Object)$outer.protected$foo($outer));
        }
    }

}

dotc:

public class Foo
extends Base {
    public Foo() {
    }

    public static class Inner {
        private final Foo $outer;

        public Inner(Foo $outer) {
            if ($outer == null) {
                throw new NullPointerException();
            }
            this.$outer = $outer;
            Predef..MODULE$.println((Object)this.Foo$Inner$$$outer().foo);
        }

        private Foo $outer() {
            return this.$outer;
        }

        public final Foo Foo$Inner$$$outer() {
            return this.$outer();
        }
    }

}

We failed to generate an accessor for the protected field foo accessed from the inner class Inner.

@smarter smarter changed the title Regression from scalac 2.11.11 (IllegalAccessError) Dotty does not generate accessors for protected calls from inner classes, resulting in IllegalAccessError Jun 18, 2017
@smarter
Copy link
Member

smarter commented Jun 18, 2017

There's at least one issue in SuperAccesors#needsProtectedAccessor, selfType is the host self-type but is used to do a subtype check instead of the current class self-type, compare https://github.com/lampepfl/dotty/blob/21b314992439203345154bf417cc503c007d7f1b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala#L305 with https://github.com/scala/scala/blob/d1ec01aa1cf65c3f9b161b2f0c0025ad0c9ade97/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala#L550. However, fixing this results in an error in SuperAccessors#protectedAccessorCall (variable foo in class Base does not take parameters) which I haven't managed to fix.

@smarter
Copy link
Member

smarter commented Jun 18, 2017

Here's a WIP branch with the fix I suggested above if anyone wants to try to finish this, I don't think I'll have time to do it myself in the near future: https://github.com/dotty-staging/dotty/commits/fix-i2780

smarter added a commit to dotty-staging/dotty that referenced this issue Jun 18, 2017
odersky pushed a commit to dotty-staging/dotty that referenced this issue Jun 20, 2017
@smarter
Copy link
Member

smarter commented Jun 21, 2017

@bbarker This should be fixed in the latest nightly, you can try it out by setting scalaVersion := 0.2.0-bin-20170620-1d05796-NIGHTLY in your build (make sure to also use the latest version of the sbt-dotty plugin: 0.1.3)

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

2 participants