Community
Participate
Working Groups
Created attachment 126617 [details] The example class to compile and run I originally discovered this bug on MacOS X Version: 3.3.2 Build id: M20080221-1800 I have also verified that it is a bug on Windows Vista Version: 3.4.1 Build id: M20080911-1700 Steps To Reproduce: 1. Create a new Java project. 2. Create a new package "test" 3. Create a new class HeldAsExample (see the attachment): package test; import test.HeldAsExample.Container.Middle1; import test.HeldAsExample.Container.Middle1.Middle2; public class HeldAsExample { public int t; public static void useArray(final int[] array) {} public class Container { public int c; public class Super { public int f; } public class Middle1 { public int m1; public class Middle2 { public int m2; public void stuff1(final Container other, final Container expected) { System.out.println("Inside stuff1, Middle2.this = " + Middle2.this + " == this? " + (Middle2.this == this)); System.out.println("Inside stuff1, Middle1.this = " + Middle1.this); System.out.println("Inside stuff1, Container.this = " + Container.this); System.out.println("Inside stuff1, HeldAsExample.this = " + HeldAsExample.this); /* The immediately enclosing instance of s6 is "this" (a Middle2 object) * The immediately enclosing instance with respect to Super is other. */ final Super s6 = other. new Super() { { System.out.println("Inside ACE, Middle2.this = " + Middle2.this); System.out.println("Inside ACE, Middle1.this = " + Middle1.this); System.out.println("Inside ACE, Container.this = " + Container.this); System.out.println("Inside ACE, HeldAsExample.this = " + HeldAsExample.this); System.out.println((Container.this == expected) ? "CORRECT" : "INCORRECT!"); } }; } } } } public static void main(String[] args) { final HeldAsExample h1 = new HeldAsExample(); System.out.println("h1 = " + h1); final Container c1 = h1. new Container(); System.out.println("c1 = " + c1); final Middle1 m1_1 = c1. new Middle1(); System.out.println("m1_1 = " + m1_1); final Middle2 m2_1 = m1_1. new Middle2(); System.out.println("m2_1 = " + m2_1); final HeldAsExample h2 = new HeldAsExample(); final Container c2 = h2. new Container(); System.out.println("h2 = " + h2); System.out.println("c2 = " + c2); m2_1.stuff1(c2, c1); } } Run the main method from HeldAsExample. The last line of the output will be "INCORRECT!". An example of what I get is h1 = test.HeldAsExample@6caf43 c1 = test.HeldAsExample$Container@2ac982 m1_1 = test.HeldAsExample$Container$Middle1@e89b94 m2_1 = test.HeldAsExample$Container$Middle1$Middle2@3a6727 h2 = test.HeldAsExample@4a65e0 c2 = test.HeldAsExample$Container@665753 Inside stuff1, Middle2.this = test.HeldAsExample$Container$Middle1$Middle2@3a6727 == this? true Inside stuff1, Middle1.this = test.HeldAsExample$Container$Middle1@e89b94 Inside stuff1, Container.this = test.HeldAsExample$Container@2ac982 Inside stuff1, HeldAsExample.this = test.HeldAsExample@6caf43 Inside ACE, Middle2.this = test.HeldAsExample$Container$Middle1$Middle2@3a6727 Inside ACE, Middle1.this = test.HeldAsExample$Container$Middle1@e89b94 Inside ACE, Container.this = test.HeldAsExample$Container@665753 Inside ACE, HeldAsExample.this = test.HeldAsExample@6caf43 INCORRECT! If you compile the same class with Sun's javac and execute it, you will see the last line of output will be "CORRECT". An example of what I get is h1 = test.HeldAsExample@6caf43 c1 = test.HeldAsExample$Container@2ac982 m1_1 = test.HeldAsExample$Container$Middle1@e89b94 m2_1 = test.HeldAsExample$Container$Middle1$Middle2@3a6727 h2 = test.HeldAsExample@4a65e0 c2 = test.HeldAsExample$Container@665753 Inside stuff1, Middle2.this = test.HeldAsExample$Container$Middle1$Middle2@3a6727 == this? true Inside stuff1, Middle1.this = test.HeldAsExample$Container$Middle1@e89b94 Inside stuff1, Container.this = test.HeldAsExample$Container@2ac982 Inside stuff1, HeldAsExample.this = test.HeldAsExample@6caf43 Inside ACE, Middle2.this = test.HeldAsExample$Container$Middle1$Middle2@3a6727 Inside ACE, Middle1.this = test.HeldAsExample$Container$Middle1@e89b94 Inside ACE, Container.this = test.HeldAsExample$Container@2ac982 Inside ACE, HeldAsExample.this = test.HeldAsExample@6caf43 CORRECT The difference is that when compiled with Eclipse, the 3rd line from the end, "Inside ACE, Container.this = ..." will print the same object id as the line "c2 = ...", and when compiled with Sun's javac, it will print the same object id as the line "c1 = ...". To the best of my understanding, the Eclipse compiler is incorrect. More information: Please see the Java Language Specification, 3rd Edition [JLS3], Sections 8.1.3, 15.8.4, and 15.9.2 for the definitions and algorithms used below. What this example is actually doing is showing the ids of the lexically enclosing instances of two different objects (1) An instance of test.HeldAsExample.Container.Super.Middle1.Middle2 (2) An instance of an anonymous class derived from test.heldAsExample.Container.Super that is created by a method executing on the first instance. In particular, within the main method, we have the following distinct objects: * h1, a HeldAsExample object * c1, a Container object whose immediately enclosing instance (and therefore first lexically enclosing instance) is the object referenced by h1 * m1_1, a Middle1 object whose immediately enclosing instance (and therefore first lexically enclosing instance) is the object referenced by c1, whose second lexically enclosing instance is the object referenced by h1 * m2_1, a Middle2 object whose immediately enclosing instance (and therefore first lexically enclosing instance) is the object referenced by m1_1, whose second lexically enclosing instance is the object referenced by c1, and whose third lexically enclosing instance is the object referenced by h1 * h2, a second HeldAsExample object * c2, a Container object whose immediately enclosing instance (and therefore first lexically enclosing instance) is the object referenced by h2 We then invoke "stuff1" on the object referenced by m2_1, and pass the two Container objects c2 to "other" and c1 to "expected". (The method operates on other, the argument expected is only there for error checking.) Method "stuff1" first prints the zeroth through third lexically enclosing instances of the receiver. Because the receiver is the object referenced by m2_1, we get the ids of the objects referenced by m2_1, m1_1, c1, and h1, respectively. So far, so good. Method "stuff1" then creates an instance of an anonymous class whose superclass is test.heldAsExample.Container.Super. This new expression is qualified by the a reference to the "other" parameter that is bound to same object as "c2" in main(). According to JLS3 Section 15.9.2, page 426, the immediately enclosing instance of this object should be object referenced by "this", which in this case is the object referenced by m2_1 in main(). So the 2nd through 4th lexically enclosing instances of this object should be the 1st through 3rd lexically enclosing instances of the object referenced by m2_1, namely the objects referenced by m1_1, c1, and h1, respectively. The instance initializer block of the anonymous class prints out the ids of the object's first through fourth lexically enclosing instances as referenced by the qualified this expressions Middle2.this, Middle1.this, Container.this, and HeldAsExample.this, respectively. Finally, it performs an explicit sanity check by comparing the object referenced by Container.this against the object passed to the parameter "expected". In this case, we had passed the object referenced by c1 to expected, which as described above references the third lexically enclosing object of the anonymous class instance, and ought to be the object referenced by Container.this. Sadly, what we see is that when compiled with the Eclipse compiler, Container.this within the anonymous class refers to object referenced by c2. This is wrong. What is interesting, however, is that the object referenced by c2 is the immediately enclosing instance with respect to class Super of the anonymous class instance. Java *does not* provide a syntax for identifying immediately enclosing instances with respect to a super class. Qualified this expression only refer to lexically enclosing instances as per JLS3 15.8.4. I suspect that a cross reference in an internal compiler model is incorrect in this case. This error means that programs compiled with Eclipse might behave differently than those compiled with javac. Not good.
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant. -- The automated Eclipse Genie.