Skip to content

10786 setting privateWithin for java protected inner classes#7323

Merged
adriaanm merged 1 commit intoscala:2.12.xfrom
psilospore:10786
Oct 18, 2018
Merged

10786 setting privateWithin for java protected inner classes#7323
adriaanm merged 1 commit intoscala:2.12.xfrom
psilospore:10786

Conversation

@psilospore
Copy link
Contributor

@psilospore psilospore commented Oct 6, 2018

First PR to scala hopefully it's right. This fixes scala/bug#10786

@scala-jenkins scala-jenkins added this to the 2.12.8 milestone Oct 6, 2018
@psilospore
Copy link
Contributor Author

psilospore commented Oct 6, 2018

Here's how I tested it locally:

~/Developer/scala/scala/sandbox 10786*
❯ cat Test.java
package pkg;

public class Test { protected static class Inner {} }

~/Developer/scala/scala/sandbox 10786*
❯ cat Use.scala
package pkg

import scala.tools.nsc._
import scala.reflect.runtime.universe._

object Use extends Test.Inner with App {
        println("hi")
        println(typeOf[_root_.pkg.Test].companion.decl(TypeName("Inner")).privateWithin)

}


~/Developer/scala/scala/sandbox 10786*
❯ javac -d . Test.java

~/Developer/scala/scala/sandbox 10786*
❯ ../build/pack/bin/scalac -cp . Use.scala
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512m; support was removed in 8.0

~/Developer/scala/scala/sandbox 10786*
❯ ../build/pack/bin/scala pkg.Use
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512m; support was removed in 8.0
hi
package pkg

~/Developer/scala/scala/sandbox 10786*

I see that in the scala hacker guide it mentions: "Code which should compile successfully, but doesn’t need to be executed, needs to go into the “pos” directory."

Would I just place those files in pos then (minus the print statements)?

@hrhino

This comment has been minimized.

@SethTisue SethTisue added the welcome hello new contributor! label Oct 9, 2018
(newStub(name.toTypeName), newStub(name.toTermName))
} else {
val cls = owner.newClass(name.toTypeName, NoPosition, sflags)
if (cls.isProtected) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the right spot to me. The other cases seem to use propagatePackageBoundary. I'm not super familiar with this part. Assigning lrytz for review :-)

@adriaanm adriaanm requested a review from lrytz October 10, 2018 10:11
@adriaanm
Copy link
Contributor

Welcome, @psilospore, and congrats already on your first scalac bug fix 👏 🍰

Copy link
Member

@lrytz lrytz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a looong while to understand what's going on here, but in the end your change seems to be the correct fix.

Here's my test case:

A.java

package a.b;

public class A {
  static class N1 {
    public int x = 1;
    public static int y = 1;
  }
  static protected class N2 {
    public int x = 1;
    public static int y = 1;
  }
}

Test.sclaa

package a.b {
  class C {
    class T1 extends A.N1
    class T2 extends A.N2
    def test(): Unit = {
      val n1 = new A.N1
      n1.x
      A.N1.y
      val n2 = new A.N2
      n2.x
      A.N2.y
    }

    class I extends A {
      class T1 extends A.N1
      class T2 extends A.N2
      def test(): Unit = {
        val n1 = new A.N1
        n1.x
        A.N1.y
        val n2 = new A.N2
        n2.x
        A.N2.y
      }
    }
  }
}

I was wondering why the bug only affects N2, but not N1. What's going on:

  • The classfile parser for A creates symbols for all nested classes (enterOwnInnerClasses)
  • When those inner symbols complete, the classfile parser runs on A$N1 / A$N2 etc
    • There is an invocation of propagatePackageBoundary, which sets the privateWithin for N1, because the classfile A$N1 has no access modifier
    • However, this does not happen for A$N2, because that classfile is marked public in bytecode (!). The JVM access rules require making the class public (this will probably change on Java 11 with nestmates?)

Could you

  • Add a comment to your fix? Something like "need to set privateWithin here because the classfile of a nested protected class is public in bytecode, so propagatePackageBoundary will not set it when the symbols are completed"
  • Extend the test case to test access to a static member within the nested class

Copy link
Member

@lrytz lrytz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thank you! This looks good now. Could you squash all commits into a single one and write a summary for the commit message?

modules loaded by classpath, and created tests.
@psilospore
Copy link
Contributor Author

No problem!

Thanks, @lrytz, @adriaanm, and @hrhino I appreciate all the help!

@adriaanm adriaanm merged commit 2b48ca6 into scala:2.12.x Oct 18, 2018
@adriaanm
Copy link
Contributor

Thanks, @psilospore!

@hrhino
Copy link
Contributor

hrhino commented Oct 18, 2018

congrats on your first PR, @psilospore!

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

Labels

welcome hello new contributor!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants