JDK-6541876 : "Enclosing Instance" error new in 1.6
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-04-03
  • Updated: 2017-05-16
  • Resolved: 2011-04-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b134Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
javac 1.6.0_01

ADDITIONAL OS VERSION INFORMATION :
Win XP (SP2)

A DESCRIPTION OF THE PROBLEM :
This worked in 1.5

public class Test {
    
    private abstract interface X {
        static abstract class Y {
            private abstract class Z {}
        }
    }
    
    private static abstract class A {
        private static class B extends Test.X.Y {
            private class C extends Test.X.Y.Z {}
        }
    }
    
    /** Creates a new instance of Test */
    public Test() {
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
    }
    
}


but not in 1.6 anymore:

Test.java:24: an enclosing instance that contains Test.X.Y.Z is required
private class C extends Test.X.Y.Z {}
1 error



REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
not update to 1.6?

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL: http://hg.openjdk.java.net/jdk7/tl/langtools/rev/02b699d97a55
02-03-2011

EVALUATION I think that, after all the discussions, the example described in this CR should be rejected by javac because of membership. public class Test { private abstract interface X { static abstract class Y { private abstract class Z {} } } private static abstract class A { private static class B extends Test.X.Y { private class C extends Test.X.Y.Z {} } } } Look at "C extends Test.X.Y.Z"... this class is 'translated' into: private class C extends Test.X.Y.Z {} C() { super(); } } Then look at JLS 8.8.7.1 (the usual paragraph :-) ) "Let O be the innermost lexically enclosing class of which S is a member, and let n be an integer such that O is the nth lexically enclosing class of C. The immediately enclosing instance of i with respect to S is the nth lexically enclosing instance of this." In this case *) O is Test.X.Y *) S is Test.X.Y.Z *) C is Test.A.B.C As it can be seen, there's no lexically enclosing class T of Test.A.B.C, for which either (i) T == Test.X.Y or (ii) Test.X.Y.Z is a member of T. This because Test.X.Y.Z has been declared as private; if you put a 'protected' instead of a 'private' the program is accepted (in that case Test.X.Y.Z is a member of both Test.X.Y *and* Test.A.B). I see no way for this which example should compile (reading the JLS). The fact that, perhaps, the example shouldn't compile also with X.Y.Z being declared as protected, that's an entirely different story, that deserves another CR (but, see above, making the compiler 100% compatible with the JLS on these issues will cause a lot of complaints I'm afraid).
20-08-2008

EVALUATION I've filed the spec bug 6708938. If that issue get addressed properly we should be able to fix this without breaking any existing regression test. Moreover fixing this would also enable to accept the aforementioned regression test (currently this is a negative regression test). tools/javac/implicitThis/NewBeforeOuterConstructed3.java This change should positively expand the space of compilable programs.
30-05-2008

EVALUATION This bug is a regression of 4903103. The biggest problem ofthis bug is that it can't bo solved without requiring a slightly incompatible change to the compiler. Here is a set of closely related CRs: 1) 6541876 (this CR) 2) 4903103 3) 4787017 Each of these CR show a small program that the submitter expected to compile. The programs look quite similar one to each other; all of them define inner classes subclassing other inner classes. Moreover the problem reported in all the above CR has to do with some problem with a super-constructor invocation that is being silently generated by javac inside the default constructor. What I can see now is that (after 6 years!!): a) 4787017 introduced a difference between the compiler and the spec, in particular, in the way in which inner classes should be selected: the difference is in that (I'm quoting from 4689050) "The current wording is in 15.9.2 selects the nearest enclosing instance of which the class being created is a member. Existing compilers, on the other hand, select the nearest enclosing class that is a subtype of the type containing the class being created". It seems that Neal made an attempt to adhere to the spec, but without success, as he got some regression failures. It seems also that (but this is not documented) that he decided to keep the compiler that way (since we have today some regression tests that mandate a different behaviour wrt the one described in JLS 15.9.2). b) 4903103 attempted to partially solve the discrepancy between the compiler and the JLS. It also introduced a discrepancy between javac and other compilers, that are still rejecting the code submitted in that CR. This fix is morally legal, since it added the missing accessibility check that was missing in the compiler. However the fix is only partial. Currently we have that Resolve.java "thinks" accordingly to the JLS, while inside Lower.java, we still have the "old", not-JLS-compliant behavior. Btw, this is why if you try to actually run the example in 4903103 you get a VerifyError. Which seems to be a problem related to 4689058. This mishap is due to the javac dicotomy when dealing with inner classes and enclosing instance resolution: attribution gets it right, code generation gets it wrong (in this case it seems more like schizophrenia). Obviously if you make code-generation to adhere to the spec (and to attribution) the aformentioned regression test (see a) bullet) will start to fail - since that was a deliberately "wanted" incompatibily... this problem seems also to be the same reported in other CRs 4704371 and 6313120. Actually it's quite funny that we have two regression tests, namely: 1) tools/javac/implicitThis/NewBeforeOuterConstructed3.java 2) tools/javac/nested/4903103/T4903103.java Those two regression tests are almost identical, exception for the fact that in 2) inner classes are declared with a private modifier. This bit is enough for javac for accepting 2) while rejepting 1) even if the two test cases are indeed identical - the main point here is that the outer class should be used as enclosing instance in the synthetic superclass constructor while the compiler erroneously emits an uninited this. By specifying 'private', the compler starts rejecting the uninited 'this' as the nested superclass is not a member of the subclass and the subclass cannot be used as enclosing instance thereof. c) We still have (after 6 years) a JLS bug (4689050) in the "accepted" state regarding this issue. It seemed that Gilad was keen to preserve the spec as they were. But in this case we all have to make a decision once for all whether to support this entirely (and, as such, rejecting programs such as the one in this CR or the one in 4787017). I hope this helps in gettig this mess sorted out. Said that, as per JLS 15.9.2, the program submitted in this CR should *not* compile: "Otherwise, C is an inner member class (��8.5). * If the class instance creation expression is an unqualified class instance creation expression, then: o If the class instance creation expression occurs in a static context, then a compile-time error occurs. o Otherwise, if C is a member of an enclosing class then let O be the innermost lexically enclosing class of which C is a member, and let n be an integer such that O is the nth lexically enclosing class of the class in which the class instance creation expression appears. The immediately enclosing instance of i is the nth lexically enclosing instance of this. o Otherwise, a compile-time error occurs." Here we have that no superconstructor call can be generated for class C, since C's superclass is the inner Test.X.Y.Z which is not accessible from (i) C's 1st lexically enclosing class B (since B does not inherit Z which is private in X.Y), (ii) C's 2nd lexically enclosing class A (since Z is not a member of A), (iii) C's 3rd lexically enclosing instance Test (since Z is not a member of Test). The compiler is right here, but what do we do with all the stuff above? Btw the example in this CR is accepted by other java compilers (e.g. Eclipse) - it seems like most compilers have decided not to support programs as the one in 4903103, but to support programs like the one in this CR and like the one in 4787017.
24-04-2008