[PATCH] 8129740: Runtime exception when passing lambda in inner class constructor

bsrbnd bsrbnd at gmail.com
Mon Sep 14 13:11:36 UTC 2015


Hi,

As explained in issue 8129740, the following code produces a runtime
exception ("uninitialized this"):

public class Bug {
    Object vb=new Object();

    public class Inner {
        Object vi=new Object();

        public Inner(Runnable r) {r.run();}
        public Inner(Object o) {System.out.println(o);}
        public Inner() {
            this(()->System.out.println(vb)); // KO (bug 8129740
runtime exception)
        }
    }
    public static void main(String[] args) {
        new Bug().new Inner();
    }
}

class Other {
    public Object o=new Object();
}

With respect to JLS 8.8.7.1 (p. 264, l. 1-4), I think (if I've not
missed anything) that this example should probably run without
exception because "vb" is not within "Inner" class but in the
outer-class.

For example, all the following statements compile and run according to
jls 8.8.7.1:
 this(vb);
 this(()->System.out.println(new Other().o));
 this(new Runnable() {public void run() {System.out.println(vb);}});

And the following ones doesn't compile, according to jls:
 this(vi);
 this(()->System.out.println(vi));
 this(new Runnable() {public void run() {System.out.println(vi);}});

But, if the runtime exception is "right" (as said in issue 8129740),
we can detect in the attribute phase the special case of an outer
member access within a lambda expression in a this/super call as shown
in the following patch.
Method Attr.visitLambda() keeps a track in the AttrContext if we are
in a this/super call and method Attr.visitIdent() produces an error
message for that case (notice that "noOuterThisPath" on line 3209
never changes).

Regards,
bsrbnd

diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2327,6 +2327,7 @@
         }
         //create an environment for attribution of the lambda expression
         final Env<AttrContext> localEnv = lambdaEnv(that, env);
+        localEnv.info.isLambdaInSelfCall = localEnv.info.isSelfCall;
         boolean needsRecovery =
                 resultInfo.checkContext.deferredAttrContext().mode ==
DeferredAttr.AttrMode.CHECK;
         try {
@@ -3207,6 +3208,7 @@
         //     (`noOuterThisPath').
         Env<AttrContext> symEnv = env;
         boolean noOuterThisPath = false;
+        boolean isLambdaInSelfCall = symEnv.info.isLambdaInSelfCall;
         if (env.enclClass.sym.owner.kind != PCK && // we are in an inner class
             sym.kind.matches(KindSelector.VAL_MTH) &&
             sym.owner.kind == TYP &&
@@ -3238,7 +3240,7 @@
         // In a constructor body,
         // if symbol is a field or instance method, check that it is
         // not accessed before the supertype constructor is called.
-        if ((symEnv.info.isSelfCall || noOuterThisPath) &&
+        if ((symEnv.info.isSelfCall || isLambdaInSelfCall ||
noOuterThisPath) &&
             sym.kind.matches(KindSelector.VAL_MTH) &&
             sym.owner.kind == TYP &&
             (sym.flags() & STATIC) == 0) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java
@@ -72,6 +72,8 @@
      *  Is this an attribution environment for an instance creation expression?
      */
     boolean isNewClass = false;
+
+    boolean isLambdaInSelfCall = false;

     /** Are arguments to current function applications boxed into an
array for varargs?
      */
@@ -112,6 +114,7 @@
         info.isSpeculative = isSpeculative;
         info.isAnonymousDiamond = isAnonymousDiamond;
         info.isNewClass = isNewClass;
+        info.isLambdaInSelfCall = isLambdaInSelfCall;
         return info;
     }


More information about the compiler-dev mailing list