Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8328706

Disallow enclosing instances for local classes in constructor prologues

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 23
    • tools
    • None
    • source
    • minimal
    • Hide
      As described in the "Problem" section, affected code necessarily defines some local class inside a switch expression that is part of a superclass constructor parameter expression, and moreover the class is never instantiated. This is an unlikely scenario.
      Show
      As described in the "Problem" section, affected code necessarily defines some local class inside a switch expression that is part of a superclass constructor parameter expression, and moreover the class is never instantiated. This is an unlikely scenario.
    • Language construct
    • JDK

      Summary

      Prevent local classes declared in a constructor prologue from having an immediately enclosing instance.

      Problem

      JLS §15.9.2 specifies that a local class declared in a static context does not have an immediately enclosing instance.

      Superclass constructor invocation parameter expressions, which are evaluated prior to the actual super() or this() invocation, are considered to be in a static context (§8.1.3).

      The problem is that the compiler currently compiles local classes declared within superclass constructor invocation parameter expressions with an immediately enclosing instance, which is incorrect.

      This is an arcane bug, because currently the only way to define such local class is to shoehorn it into a switch expression, like this:

      import java.util.concurrent.atomic.*;
      public class Test extends AtomicReference<Object> {
          public Test() {
              super(switch (0) {
                default -> {
                    class Local { { Test.this.hashCode(); } }   // this should fail
                    yield null;
                  }
              });
          }
      }

      Moreover, any such class is completely useless, because it can never be instantiated (if you try, you'll get a compiler error). So this is a very contrived situation that likely never occurs in real code.

      However, with upcoming support for flexible constructors (JEP 447), which is already in preview, this bug will get more exposed to the real world because it will be much more natural to declare and use local classes in the "prologue" of a constructor.

      Solution

      The change proposed here is to fix the bug, i.e., change the compiler so that it no longer compiles local classes declared in a constructor prologue with an immediately enclosing instance.

      Specification

      Change the compiler to treat local classes the same as anonymous classes with respect to immediately enclosing instances. At it's heart, the change amounts to this patch:

      -            if (ctorProloguePrev && env.tree.hasTag(NEWCLASS)) {
      +            if (ctorProloguePrev) {
                       c.flags_field |= NOOUTERTHIS;
                   }

            acobbs Archie Cobbs
            acobbs Archie Cobbs
            Vicente Arturo Romero Zaldivar
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: