JDK-6708938 : Synthetic super-constructor call should never use 'this' as a qualifier
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2008-05-30
  • Updated: 2016-05-26
  • Resolved: 2011-07-21
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 rcFixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
The following program doesn't compile (excerpt from Java Puzzlers - Puzzle 90 - 'it's absurd, it's pain, it's a superclass'):

public class Outer {
    class Inner1 extends Outer {}
    class Inner2 extends Inner1 {}
}

The program doesn't compile as the synthetic super call generated by javac inside Inner2's default constructor is:

this.super();

As a consequence the program is rejected with the following error:

Test.java:3: cannot reference this before supertype constructor has been called
    class Inner2 extends Inner1 {}
    ^

This program would have compiled if javac were able to generate the following code:

Outer.this.super()

It's quite sensible not to consider the unqualified this as a suitable qualifier for a qualified super constructor call that has to be generated automatically by javac. Such a choice will always result in reference of 'this' before the superclass constructor has been called. However, this behaviour seems to be mandated by the JLS, section 8.8.7.1:

"Let C be the class being instantiated, let S be the direct superclass of C, and let i be the instance being created. The evaluation of an explicit constructor invocation proceeds as follows:

    * First, if the constructor invocation statement is a superclass constructor invocation, then the immediately enclosing instance of i with respect to S (if any) must be determined. Whether or not i has an immediately enclosing instance with respect to S is determined by the superclass constructor invocation as follows:
          o If S is not an inner class, or if the declaration of S occurs in a static context, no immediately enclosing instance of i with respect to S exists. A compile-time error occurs if the superclass constructor invocation is a qualified superclass constructor invocation.
          o Otherwise:
                + If the superclass constructor invocation is qualified, then the Primary expression p immediately preceding ".super" is evaluated. If the primary expression evaluates to null, a NullPointerException is raised, and the superclass constructor invocation completes abruptly. Otherwise, the result of this evaluation is the immediately enclosing instance of i with respect to S. Let O be the immediately lexically enclosing class of S; it is a compile-time error if the type of p is not O or a subclass of O.
                + Otherwise:
                      # If S is a local class (��14.3), then let O be the innermost lexically enclosing class of S. 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.
                      # Otherwise, S is an inner member class (��8.5). It is a compile-time error if S is not a member of a lexically enclosing class, or of a superclass or superinterface thereof. 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
[...] "

The last bullet explicitely states that, in this particular cases, javac should exploit the 0th-this as a qualifier for the super expression (this is because Inner2 is a subtype of Outer which encloses Inner1). I think that the lookup should start from the innermost lexically enclosing class of Inner2 (Outer) - thus skipping Inner2 completely. The change in the compiler to do so is quite trivial, and I think it would make the use of inner class more intuitive for the end-user.

This change seems also the only way for fixing a compiler regression bug (6541876) without restricting the space of the programs accepted by javac (e.g. fix for 4903103 should be invalidated if no JLS change is in sight).

Comments
EVALUATION You're right. Strictly speaking, 'this' is a good immediately enclosing instance w.r.t. the superclass UNLESS (as Puzzle 90 puts it) the superclass of the inner class is itself an inner class, and of the same lexically enclosing class to boot. Consider the rule as per JLS3: "Let C be the class being instantiated, let S be the direct superclass of C, and let i be the instance being created...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." Inheritance permits S to be a member of C, resulting in n=0, but it is inappropriate to consider the implicit membership due to inheritance when looking for an explicit enclosing class. Thus for 8.8.7.1, we should say "Let O be the innermost lexically enclosing class ***in which S is declared as a member***". Or equivalently, "Let O be the innermost lexically enclosing class of S".
09-09-2008

EVALUATION I don't agree. C is Inner2. S is Inner1. O is Inner2 itself as Inner2 indirectly inherits from Outer so that Inner1 become also one of the member of Inner2. It follows that, in this case n=0, and that the qualifier of the super call must be this.
01-08-2008

EVALUATION I'm not sure I agree that the JLS is mandating 'this.super()' in Inner2's implicit constructor. Consider: "# Otherwise, S is an inner member class (��8.5). It is a compile-time error if S is not a member of a lexically enclosing class, or of a superclass or superinterface thereof. 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" C is Inner2. S is Inner1. O is Outer. n is 1 because Outer is the 1-th lexically enclosing class of Inner2. For the instance i of Inner2 being created, the immediately enclosing instance with respect to Inner1 is the 1-th lexically enclosing instance of 'this', i.e. Outer.this.
28-07-2008