8051958: Cannot assign a value to final variable in lambda
authormcimadamore
Tue, 29 Jul 2014 15:31:57 -0700
changeset 25846 e7124d0dc984
parent 25845 14935053bb07
child 25847 90e43c49e318
8051958: Cannot assign a value to final variable in lambda Summary: Remove Attr.owner and refactor code for detecting forward field references Reviewed-by: vromero
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/test/tools/javac/lambda/8051958/T8051958.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Jul 24 15:12:48 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jul 29 15:31:57 2014 -0700
@@ -257,7 +257,7 @@
      *  @param env    The current environment.
      */
     boolean isAssignableAsBlankFinal(VarSymbol v, Env<AttrContext> env) {
-        Symbol owner = owner(env);
+        Symbol owner = env.info.scope.owner;
            // owner refers to the innermost variable, method or
            // initializer block declaration at this point.
         return
@@ -272,41 +272,6 @@
              ((v.flags() & STATIC) != 0) == Resolve.isStatic(env));
     }
 
-    /**
-     * Return the innermost enclosing owner symbol in a given attribution context
-     */
-    Symbol owner(Env<AttrContext> env) {
-        while (true) {
-            switch (env.tree.getTag()) {
-                case VARDEF:
-                    //a field can be owner
-                    VarSymbol vsym = ((JCVariableDecl)env.tree).sym;
-                    if (vsym.owner.kind == TYP) {
-                        return vsym;
-                    }
-                    break;
-                case METHODDEF:
-                    //method def is always an owner
-                    return ((JCMethodDecl)env.tree).sym;
-                case CLASSDEF:
-                    //class def is always an owner
-                    return ((JCClassDecl)env.tree).sym;
-                case BLOCK:
-                    //static/instance init blocks are owner
-                    Symbol blockSym = env.info.scope.owner;
-                    if ((blockSym.flags() & BLOCK) != 0) {
-                        return blockSym;
-                    }
-                    break;
-                case TOPLEVEL:
-                    //toplevel is always an owner (for pkge decls)
-                    return env.info.scope.owner;
-            }
-            Assert.checkNonNull(env.next);
-            env = env.next;
-        }
-    }
-
     /** Check that variable can be assigned to.
      *  @param pos    The current source code position.
      *  @param v      The assigned varaible
@@ -3820,7 +3785,7 @@
             // and are subject to definite assignment checking.
             if ((env.info.enclVar == v || v.pos > tree.pos) &&
                 v.owner.kind == TYP &&
-                canOwnInitializer(owner(env)) &&
+                enclosingInitEnv(env) != null &&
                 v.owner == env.info.scope.owner.enclClass() &&
                 ((v.flags() & STATIC) != 0) == Resolve.isStatic(env) &&
                 (!env.tree.hasTag(ASSIGN) ||
@@ -3840,6 +3805,36 @@
         }
 
         /**
+         * Returns the enclosing init environment associated with this env (if any). An init env
+         * can be either a field declaration env or a static/instance initializer env.
+         */
+        Env<AttrContext> enclosingInitEnv(Env<AttrContext> env) {
+            while (true) {
+                switch (env.tree.getTag()) {
+                    case VARDEF:
+                        JCVariableDecl vdecl = (JCVariableDecl)env.tree;
+                        if (vdecl.sym.owner.kind == TYP) {
+                            //field
+                            return env;
+                        }
+                        break;
+                    case BLOCK:
+                        if (env.next.tree.hasTag(CLASSDEF)) {
+                            //instance/static initializer
+                            return env;
+                        }
+                        break;
+                    case METHODDEF:
+                    case CLASSDEF:
+                    case TOPLEVEL:
+                        return null;
+                }
+                Assert.checkNonNull(env.next);
+                env = env.next;
+            }
+        }
+
+        /**
          * Check for illegal references to static members of enum.  In
          * an enum type, constructors and initializers may not
          * reference its static members unless they are constant.
@@ -3892,17 +3887,6 @@
                    v.name != names._class;
         }
 
-        /** Can the given symbol be the owner of code which forms part
-         *  if class initialization? This is the case if the symbol is
-         *  a type or field, or if the symbol is the synthetic method.
-         *  owning a block.
-         */
-        private boolean canOwnInitializer(Symbol sym) {
-            return
-                (sym.kind & (VAR | TYP)) != 0 ||
-                (sym.kind == MTH && (sym.flags() & BLOCK) != 0);
-        }
-
     Warner noteWarner = new Warner();
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8051958/T8051958.java	Tue Jul 29 15:31:57 2014 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8051958
+ * @summary Cannot assign a value to final variable in lambda
+ * @compile T8051958.java
+ */
+
+class T8051958 {
+    Runnable inst_r = ()-> {
+        final int x;
+        x = 1;
+    };
+
+    Runnable static_r = ()-> {
+        final int x;
+        x = 1;
+    };
+
+    {
+        Runnable inst_r = ()-> {
+            final int x;
+            x = 1;
+        };
+    }
+
+    static {
+        Runnable static_r = ()-> {
+            final int x;
+            x = 1;
+        };
+    }
+
+    void instTest() {
+        Runnable static_r = ()-> {
+            final int x;
+            x = 1;
+        };
+    }
+
+    static void staticTest() {
+        Runnable static_r = ()-> {
+            final int x;
+            x = 1;
+        };
+    }
+}