Community
Participate
Working Groups
It may not be the biggest problem in the world, but given code such as this: public class InnerLocalClassTest { void test() { class Local { } new Local() { }; } } ECJ generates the following constructor for the anonymous new Foo() {} Compiled from "InnerLocalClassTest.java" class InnerLocalClassTest$1 extends InnerLocalClassTest$1Local { final InnerLocalClassTest this$0; descriptor: LInnerLocalClassTest; InnerLocalClassTest$1(InnerLocalClassTest, InnerLocalClassTest); descriptor: (LInnerLocalClassTest;LInnerLocalClassTest;)V Code: 0: aload_0 1: aload_2 2: putfield #10 // Field this$0:LInnerLocalClassTest; 5: aload_0 6: aload_1 7: invokespecial #12 // Method InnerLocalClassTest$1Local."<init>":(LInnerLocalClassTest;)V 10: return } Note how there are two arguments for the constructor, one for the reference, one for using in the constructor. javac only does this more elegantly: Compiled from "InnerLocalClassTest.java" class InnerLocalClassTest$1 extends InnerLocalClassTest$1Local { final InnerLocalClassTest this$0; descriptor: LInnerLocalClassTest; InnerLocalClassTest$1(InnerLocalClassTest); descriptor: (LInnerLocalClassTest;)V Code: 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:LInnerLocalClassTest; 5: aload_0 6: aload_1 7: invokespecial #2 // Method InnerLocalClassTest$1Local."<init>":(LInnerLocalClassTest;)V 10: return } I can't tell if this could be an issue in other inner/anonymous cases.
Jesper, is this a non-issue ? "2) In a class instance creation expression for a local class or anonymous class, §15.9.2 specifies the immediately enclosing instance of the local/anonymous class. The local/anonymous class is necessarily emitted by the same compiler as the class instance creation expression. That compiler can represent the immediately enclosing instance how ever it wishes. There is no need for the Java programming language to implicitly declare a parameter in the local/anonymous class's constructor."
Non-issue perhaps, but figuring out with argument is the mandated and which one is synthetic, is guesswork...
(In reply to comment #2) > Non-issue perhaps, but figuring out with argument is the mandated and which > one is synthetic, is guesswork... Actually, it directly follows from the last two sentences of the quoted text that none of the synthetic parameters in this case are mandated. Doesn't it ? BTW, Are we skipping the parameter attributes for lambda methods ? javac seems to do so. See also: https://bugs.eclipse.org/bugs/show_bug.cgi?id=101512
(In reply to comment #3) > Actually, it directly follows from the last two sentences of the quoted text > that none of the synthetic parameters in this case are mandated. Doesn't it ? I guess so. Will add test about this to JEP118 work. > BTW, Are we skipping the parameter attributes for lambda methods ? javac > seems to > do so. Will check. > See also: https://bugs.eclipse.org/bugs/show_bug.cgi?id=101512 Possible dupe, but this bug covers the arguments, not the fields.
(In reply to comment #2) > Non-issue perhaps, but figuring out with argument is the mandated and which > one is synthetic, is guesswork... (1) OK, I think I know what needs to be done *according to the present spec* We need to look at the super class of the anonynmous class and if that is a local class, it could not have been compiled by a different compiler and so ECJ is at liberty to "represent the immediately enclosing instance how ever it wishes" On the other hand, if the super class happens to be an inner class it could have been compiled by a different compiler and so the enclosing reference to the super class parameter must be received as a mandated implicit parameter. HOWEVER, 8.8.9, point 3) reads --- In a class instance creation expression for an anonymous class, and where the anonymous class's superclass is inner, §15.9.2 specifies the immediately enclosing instance with respect to the superclass. Similar to (1), the superclass may have been emitted by a compiler which is different than the compiler of the class instance creation expression. Therefore, there must be a standard way for the compiler of the creation expression to pass a reference (representing the immediately enclosing instance with respect to the superclass) to the superclass's constructor. Consequently, the Java programming language deems that an anonymous class's constructor implicitly declares an initial parameter for the immediately enclosing instance with respect to the superclass. --- but 8b100's behavior is confusing on the following code: // -- public class X { void foo() { new Y().new Z() { }; } } class Y { class Z {} } // -- final X this$0; descriptor: LX; flags: ACC_FINAL, ACC_SYNTHETIC X$1(X, Y); descriptor: (LX;LY;)V flags: Code: stack=3, locals=3, args_size=3 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:LX; 5: aload_0 6: aload_2 7: dup 8: invokevirtual #2 // Method java/lang/Object.getClas s:()Ljava/lang/Class; 11: pop 12: invokespecial #3 // Method Y$Z."<init>":(LY;)V 15: return LineNumberTable: line 3: 0 MethodParameters: Name Flags this$0 final mandated x0 Why would the anonymous class's own enclosing instances be mandated while "x0" which I presume is the super classes enclosing instance be flag less ? (2) Here is a bug: // -- public class X { class Y {} private class Z {} } For the private constructor of Z(), we emit "final mandated this$0", it should be "final synthetic this$0" ("The constructor of a non-private inner member class implicitly declares, as its first formal parameter, a variable representing the immediately enclosing instance") (3) I believe javac 8b100 is in error when it emits a mandated this$0 parameter for // -- public class X { void foo() { class Local { } } } this should be covered by "The local/anonymous class is necessarily emitted by the same compiler as the class instance creation expression. That compiler can represent the immediately enclosing instance how ever it wishes. There is no need for the Java programming language to implicitly declare a parameter in the local/anonymous class's constructor." I'll ask in the mailing this about this.
(In reply to comment #0) > It may not be the biggest problem in the world, but given code such as this: > > public class InnerLocalClassTest { > void test() { > class Local { } > new Local() { }; > } > } We have confirmation from the spec committee that this is covered by the text quoted by comment#1. So please add a test to make sure that we emit the two parameters as synthetic and we can close this one. Also for the record: (In reply to comment #5) > but 8b100's behavior is confusing on the following code: > > // -- > public class X { > void foo() { > new Y().new Z() { > }; > } > } > class Y { > class Z {} > } > // -- > > final X this$0; > descriptor: LX; > flags: ACC_FINAL, ACC_SYNTHETIC > > X$1(X, Y); > descriptor: (LX;LY;)V > flags: > Code: > stack=3, locals=3, args_size=3 > 0: aload_0 > 1: aload_1 > 2: putfield #1 // Field this$0:LX; > 5: aload_0 > 6: aload_2 > 7: dup > 8: invokevirtual #2 // Method > java/lang/Object.getClas > s:()Ljava/lang/Class; > 11: pop > 12: invokespecial #3 // Method Y$Z."<init>":(LY;)V > 15: return > LineNumberTable: > line 3: 0 > MethodParameters: > Name Flags > this$0 final mandated > x0 > > Why would the anonymous class's own enclosing instances be mandated > while "x0" which I presume is the super classes enclosing instance > be flag less ? This is acknowledged to be a pair of bugs in javac. this$0 should be synthetic and x0 should be mandated. > (3) I believe javac 8b100 is in error when it emits a mandated this$0 > parameter > for > > // -- > public class X { > void foo() { > class Local { > } > } > } > > this should be covered by > > "The local/anonymous class is necessarily emitted by the same compiler as > the class instance creation expression. That compiler can represent the > immediately enclosing instance how ever it wishes. There is no need for > the Java programming language to implicitly declare a parameter in the > local/anonymous class's constructor." > > I'll ask in the mailing this about this. This is acknowledged as a bug in javac too. This is covered by the same compiler and its discretion bullet. Please close if present behavior is correct after adding suitable tests if not already there, Thanks!
(In reply to comment #6) > (In reply to comment #5) > > > but 8b100's behavior is confusing on the following code: > > > > // -- > > public class X { > > void foo() { > > new Y().new Z() { > > }; > > } > > } > > class Y { > > class Z {} > > } > > // -- > > > > final X this$0; > > descriptor: LX; > > flags: ACC_FINAL, ACC_SYNTHETIC > > > > X$1(X, Y); > > descriptor: (LX;LY;)V > > flags: > > Code: > > stack=3, locals=3, args_size=3 > > 0: aload_0 > > 1: aload_1 > > 2: putfield #1 // Field this$0:LX; > > 5: aload_0 > > 6: aload_2 > > 7: dup > > 8: invokevirtual #2 // Method > > java/lang/Object.getClas > > s:()Ljava/lang/Class; > > 11: pop > > 12: invokespecial #3 // Method Y$Z."<init>":(LY;)V > > 15: return > > LineNumberTable: > > line 3: 0 > > MethodParameters: > > Name Flags > > this$0 final mandated > > x0 > > > > Why would the anonymous class's own enclosing instances be mandated > > while "x0" which I presume is the super classes enclosing instance > > be flag less ? > > This is acknowledged to be a pair of bugs in javac. this$0 should be > synthetic and x0 should be mandated. This does not make sense, since it is a constructor for an anonymous class, and so by nature up to the compiler's discretion. It is true that x0 will then be used as an implicit argument to Y$Z(Y) as per §15.9.2, but it's place in the parameter list is still something the emitting compile may choose, and indeed it isn't even the initial argument. I can take this to the list if you want.
(In reply to comment #7) > > This is acknowledged to be a pair of bugs in javac. this$0 should be > > synthetic and x0 should be mandated. > > This does not make sense, since it is a constructor for an anonymous class, > and so by nature up to the compiler's discretion. > > It is true that x0 will then be used as an implicit argument to Y$Z(Y) as > per §15.9.2, but it's place in the parameter list is still something the > emitting compile may choose, and indeed it isn't even the initial argument. > > I can take this to the list if you want. Please do. Thanks for catching this. I am inclined to agree with you. If you concur, it may not be a bad idea to challenge the whole notion of ACC_MANDATED flag: or at least question who is supposed to be consumer and what is the expected/typical use case scenario for it is.
The tests for the correct generation of the synthetic constructor arguments is added as part of bug 406982. The quirk about passing one extra argument is really not worth fixing, so i'm closing as such.