You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Eric Milles (JIRA)" <ji...@apache.org> on 2019/05/27 12:48:00 UTC

[jira] [Comment Edited] (GROOVY-9106) @CompileStatic and @PackageScope support for inner classes and package peers

    [ https://issues.apache.org/jira/browse/GROOVY-9106?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16848905#comment-16848905 ] 

Eric Milles edited comment on GROOVY-9106 at 5/27/19 12:47 PM:
---------------------------------------------------------------

Re: {{IllegalAccessError }} discussion at end of GROOVY-9043: If I do this in Java, it works:
{code:java}
package p;

public class One {
    String value = "value";
    static final String CONST = "const";
}
{code}

{code:java}
package p;

public class Two extends One {
    public int valueLength() {
        return value.length();
    }
    public static void main(String[] args) {
        System.out.println(new Two().valueLength());
    }
}
{code}

The bytecode for {{valueLength}} is:
{code}
  // Method descriptor #15 ()I
  // Stack: 1, Locals: 1
  public int valueLength();
    0  aload_0 [this]
    1  getfield p.Two.value : java.lang.String [16]
    4  invokevirtual java.lang.String.length() : int [20]
    7  ireturn
      Line numbers:
        [pc: 0, line: 5]
      Local variable table:
        [pc: 0, pc: 8] local: this index: 0 type: p.Two
{code}

I will update with the bytecode generated for the Groovy @CS version of Two that is failing.
{code}
 // Method descriptor #27 ()I
  // Stack: 1, Locals: 1
  public int valueSize();
     0  aload_0 [this]
     1  getfield p.One.value : java.lang.String [31]
     4  invokestatic org.codehaus.groovy.runtime.StringGroovyMethods.size(java.lang.String) : int [37]
     7  ireturn
     8  nop
     9  nop
    10  athrow
      Line numbers:
        [pc: 0, line: 8]
        [pc: 8, line: 9]
      Local variable table:
        [pc: 0, pc: 8] local: this index: 0 type: p.GroovyTwo
      Stack map table: number of frames 1
        [pc: 8, full, stack: {java.lang.Throwable}, locals: {}]
{code}
Groovy loads field {{p.One.value}} and Java loads {{p.Two.value}} in the case of subclass access.


was (Author: emilles):
Re: {{IllegalAccessError }} discussion at end of GROOVY-9043: If I do this in Java, it works:
{code:java}
package p;

public class One {
    String value = "value";
    static final String CONST = "const";
}
{code}

{code:java}
package p;

public class Two extends One {
    public int valueLength() {
        return value.length();
    }
    public static void main(String[] args) {
        System.out.println(new Two().valueLength());
    }
}
{code}

The bytecode for {{valueLength}} is:
{code}
  // Method descriptor #15 ()I
  // Stack: 1, Locals: 1
  public int valueLength();
    0  aload_0 [this]
    1  getfield p.Two.value : java.lang.String [16]
    4  invokevirtual java.lang.String.length() : int [20]
    7  ireturn
      Line numbers:
        [pc: 0, line: 5]
      Local variable table:
        [pc: 0, pc: 8] local: this index: 0 type: p.Two
{code}

I will update with the bytecode generated for the Groovy @CS version of Two that is failing.

> @CompileStatic and @PackageScope support for inner classes and package peers
> ----------------------------------------------------------------------------
>
>                 Key: GROOVY-9106
>                 URL: https://issues.apache.org/jira/browse/GROOVY-9106
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 3.0.0-alpha-4, 2.5.6
>            Reporter: Eric Milles
>            Priority: Minor
>
> Follow up to GROOVY-9043.  A combination of {{@CompileStatic}} and {{@PackageScope}} has a number of variants.  Not all work as expected at the moment:
> A package-private static class member should be accessible to:
> - declaring class
> - static inner classes
> - non-static inner classes
> - anonymous inner classes
> - any other class within the same package
> - closures and lambdas enclosed by any of the above
> This should include direct references as well as indirect references.  Some class {{C}} declared outside the package may extend and should not have access, but package members should retain access to the package-private member through {{C}} references. See "indirect static access" below.
> A package-private static class member should *not* be accessible to -- should be a STC error:
> - any class in another package; this includes extends and implements, static and non-static scopes, direct and indirect references.  Although if declaring class is a trait...
> TODO: Are the rules any different for non-static package-private members?  Except for the fact that they must be accessed from non-static scopes.
> Should print "value" when compiled and executed:
> {code:groovy}
> import groovy.transform.*
> @CompileStatic class Main {
>   @PackageScope static final String VALUE = 'value'
>   static main(args) {
>     print VALUE
>   }
> }
> {code}
> Should print "value" when compiled and executed:
> {code:groovy}
> import groovy.transform.*
> @CompileStatic class Main {
>   @PackageScope static final String VALUE = 'value'
>   class Inner {
>     void meth() { print VALUE }
>   }
>   static main(args) {
>     new Inner(new Main()).meth()
>   }
> }
> {code}
> Should print "value" when compiled and executed:
> {code:groovy}
> import groovy.transform.*
> @CompileStatic class Main {
>   @PackageScope static final String VALUE = 'value'
>   static class Inner { // Inner is static in this case
>     void meth() { print VALUE }
>   }
>   static main(args) {
>     new Inner(new Main()).meth()
>   }
> }
> {code}
> Should print "value" when compiled and executed:
> {code:groovy}
> import groovy.transform.*
> @CompileStatic class Main {
>   @PackageScope static final String VALUE = 'value'
>   static main(args) {
>     new Peer().meth()
>   }
> }
> @CompileStatic class Peer {
>   void meth() {
>     print Main.VALUE
>   }
> }
> {code}
> Should print "value" when compiled and executed:
> {code:groovy}
> package p
> import groovy.transform.*
> class Main {
>   @PackageScope static final String VALUE = 'value'
>   static main(args) {
>     new Peer().meth()
>   }
> }
> package q
> class More extends p.Main {}
> package p
> import groovy.transform.*
> @CompileStatic class Peer {
>   void meth() {
>     print q.More.VALUE // indirect static access
>   }
> }
> {code}
> TODO: add cases for closures/lambdas
> Other should have STC error at compile time:
> {code:groovy}
> package p
> class Main {
>   @groovy.transform.PackageScope static final String VALUE = 'value'
> }
> package q
> @groovy.transform.CompileStatic
> class Other extends p.Main {
>   static void meth() {
>     print VALUE
>   }
> }
> {code}
> Other should have STC error at compile time (see GROOVY-9093):
> {code:groovy}
> package p
> class Main {
>   @groovy.transform.PackageScope static final String VALUE = 'value'
> }
> package q
> @groovy.transform.CompileStatic
> class Other extends p.Main {
>   void meth() { // non-static
>     print VALUE
>   }
> }
> {code}
> Test should have STC error at compile time:
> {code:groovy}
> package p
> class Main {
>   @groovy.transform.PackageScope static final String VALUE = 'value'
> }
> package p
> class Other extends Main {}
> package q
> @groovy.transform.CompileStatic
> class Test {
>   void meth() {
>     p.Other.VALUE // Main and Other are in same package, Test is not
>   }
> }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)