changeset 559:3e219523bf43

Fixed two bugs: *) return statement inside lambda cannot appear in non-method context; *) need a better way to disable definite assignment analysis during lambda attribution
author mcimadamore
date Tue, 15 Jun 2010 12:56:14 +0100
parents 1f2a6005435d
children 535313e3087e
files src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Flow.java src/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/share/classes/com/sun/tools/javac/util/Bits.java test/tools/javac/lambda/BadReturn02.java test/tools/javac/lambda/BadReturn02.out test/tools/javac/lambda/LambdaConv06.java test/tools/javac/lambda/LambdaExpr02.java
diffstat 8 files changed, 185 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jun 15 11:22:08 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jun 15 12:56:14 2010 +0100
@@ -768,7 +768,9 @@
             chk.checkDeprecatedAnnotation(tree.pos(), v);
 
             if (tree.init != null) {
-                if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) {
+                if ((v.flags_field & FINAL) != 0 &&
+                        tree.init.getTag() != JCTree.NEWCLASS &&
+                        tree.init.getTag() != JCTree.LAMBDA) {
                     // In this case, `v' is final.  Ensure that it's initializer is
                     // evaluated.
                     v.getConstValue(); // ensure initializer is evaluated
@@ -1213,16 +1215,16 @@
     public void visitReturn(JCReturn tree) {
         // Check that there is an enclosing method which is
         // nested within than the enclosing class.
+        boolean isLambda = env.enclMethod != null &&
+                (env.enclMethod.sym.flags() & LAMBDA) != 0;
         if (env.enclMethod == null ||
-            (env.enclMethod.sym.owner != env.enclClass.sym &&
-            !env.enclMethod.sym.name.equals(names.lambda))) {
+            env.enclMethod.sym.owner != env.enclClass.sym ||
+            (isLambda && env.next.enclMethod == null)) {
             log.error(tree.pos(), "ret.outside.meth");
-
         } else {
             // Attribute return expression, if it exists, and check that
             // it conforms to result type of enclosing method.
             Symbol m = env.enclMethod.sym;
-            boolean isLambda = (env.enclMethod.sym.flags() & LAMBDA) != 0;
             if (m.type.getReturnType().tag == VOID) {
                 if (tree.expr != null)
                     log.error(tree.expr.pos(),
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Jun 15 11:22:08 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Jun 15 12:56:14 2010 +0100
@@ -344,8 +344,7 @@
      *  I.e. is symbol either a local or a blank final variable?
      */
     boolean trackable(VarSymbol sym) {
-        return daEnabled &&
-            (sym.owner.kind == MTH ||
+        return (sym.owner.kind == MTH ||
              ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
               classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
     }
@@ -1251,10 +1250,8 @@
             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
                 JCVariableDecl def = l.head;
                 scan(def);
-                if (daEnabled) {
-                    inits.incl(def.sym.adr);
-                    uninits.excl(def.sym.adr);
-                }
+                inits.incl(def.sym.adr);
+                uninits.excl(def.sym.adr);
             }
             alive = true;
             scanStat(tree.body);
@@ -1402,9 +1399,9 @@
     public void analyzeTree(JCTree tree, TreeMaker make) {
         try {
             this.make = make;
-            inits = new Bits();
-            uninits = new Bits();
-            uninitsTry = new Bits();
+            inits = daEnabled ? new Bits() : Bits.emptyBits;
+            uninits = daEnabled ? new Bits() : Bits.emptyBits;
+            uninitsTry = daEnabled ? new Bits() : Bits.emptyBits;
             initsWhenTrue = initsWhenFalse =
                 uninitsWhenTrue = uninitsWhenFalse = null;
             if (vars == null)
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Jun 15 11:22:08 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Jun 15 12:56:14 2010 +0100
@@ -627,7 +627,9 @@
         tree.sym = v;
         if (tree.init != null) {
             v.flags_field |= HASINIT;
-            if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) {
+            if ((v.flags_field & FINAL) != 0 &&
+                    tree.init.getTag() != JCTree.NEWCLASS &&
+                    tree.init.getTag() != JCTree.LAMBDA) {
                 Env<AttrContext> initEnv = getInitEnv(tree, env);
                 initEnv.info.enclVar = v;
                 v.setLazyConstValue(initEnv(tree, initEnv), log, attr, tree.init);
--- a/src/share/classes/com/sun/tools/javac/util/Bits.java	Tue Jun 15 11:22:08 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/util/Bits.java	Tue Jun 15 12:56:14 2010 +0100
@@ -219,4 +219,69 @@
         }
         if (count != 125) throw new Error();
     }
+
+    /**
+     * The following class is used in order to perform flow analysis without
+     * definite assignment --- this way we can keep the original flow code
+     * without wasting memory on definite assignment analysis and risking
+     * NPEs (e.g. because variable addresses have not been computed yet when
+     * flow is called for lambda expression --- during Attr).
+     */
+    public static Bits emptyBits = new Bits() {
+
+        @Override
+        public Bits andSet(Bits xs) {
+            return this;
+        }
+
+        @Override
+        public void clear() {
+            //do nothing
+        }
+
+        @Override
+        public Bits diffSet(Bits xs) {
+            return this;
+        }
+
+        @Override
+        public Bits dup() {
+            return this;
+        }
+
+        @Override
+        public void excl(int x) {
+            //do nothing
+        }
+
+        @Override
+        public void incl(int x) {
+            //do nothing
+        }
+
+        @Override
+        public void inclRange(int start, int limit) {
+            //do nothing
+        }
+
+        @Override
+        public boolean isMember(int x) {
+            return true;
+        }
+
+        @Override
+        public int nextBit(int x) {
+            return -1;
+        }
+
+        @Override
+        public Bits orSet(Bits xs) {
+            return this;
+        }
+
+        @Override
+        public Bits xorSet(Bits xs) {
+            return this;
+        }
+    };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadReturn02.java	Tue Jun 15 12:56:14 2010 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, 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.
+ *
+ * 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
+ * @summary check that return statement outside method context are flagged with errors
+ * @author Jan Lahoda
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=BadReturn02.out -XDrawDiagnostics BadReturn02.java
+ */
+
+class BadReturn02 {
+    static Object lambda_01 = #(int pos) {
+        return;
+    };
+
+    static final Object lambda_02 = #(int pos) {
+        return;
+    };
+
+    Object lambda_03 = #(int pos) {
+        return;
+    };
+
+    final Object lambda_04 = #(int pos) {
+        return;
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadReturn02.out	Tue Jun 15 12:56:14 2010 +0100
@@ -0,0 +1,5 @@
+BadReturn02.java:34:9: compiler.err.ret.outside.meth
+BadReturn02.java:38:9: compiler.err.ret.outside.meth
+BadReturn02.java:42:9: compiler.err.ret.outside.meth
+BadReturn02.java:46:9: compiler.err.ret.outside.meth
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv06.java	Tue Jun 15 12:56:14 2010 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 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.
+ *
+ * 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
+ * @summary ensure that definite assignment analysis doesn't mess up with lambda attribution
+ * @author Jan Lahoda
+ * @author  Maurizio Cimadamore
+ * @compile LambdaConv06.java
+ */
+
+class LambdaConv06 {
+
+    private int t() {
+        return a(#(final Object indexed) {
+            return b(new R() {
+                public String build(final Object index) {
+                    return "";
+                }
+            });
+        });
+    }
+
+    private int a(R r) {return 0;}
+    private String b(R r) {return null;}
+
+    public static interface R {
+        public String build(Object o);
+    }
+}
--- a/test/tools/javac/lambda/LambdaExpr02.java	Tue Jun 15 11:22:08 2010 +0100
+++ b/test/tools/javac/lambda/LambdaExpr02.java	Tue Jun 15 12:56:14 2010 +0100
@@ -39,32 +39,6 @@
             throw new AssertionError();
     }
 
-    static {
-        int i1 = #(){ return 3; }.();
-        assertTrue(3 == i1);
-        Integer i2 = #(){ return 3; }.();
-        assertTrue(3 == i2);
-        int i3 = #(int x){ return x + 1; }.(3);
-        assertTrue(4 == i3);
-        int i4 = #(Number x){ return x.intValue(); }.(new Float(3.0f));
-        assertTrue(3 == i4);
-        Object o = #(){ return 3; };
-        assertTrue(o != null);
-    }
-
-    {
-        int i1 = #(){ return 3; }.();
-        assertTrue(3 == i1);
-        Integer i2 = #(){ return 3; }.();
-        assertTrue(3 == i2);
-        int i3 = #(int x){ return x + 1; }.(3);
-        assertTrue(4 == i3);
-        int i4 = #(Number x){ return x.intValue(); }.(new Float(3.0f));
-        assertTrue(3 == i4);
-        Object o = #(){ return 3; };
-        assertTrue(o != null);
-    }
-
     static void test1() {
         int i1 = #(){ return 3; }.();
         assertTrue(3 == i1);
@@ -94,6 +68,6 @@
     public static void main(String[] args) {
         test1();
         new LambdaExpr02().test2();
-        assertTrue(assertionCount == 20);
+        assertTrue(assertionCount == 10);
     }
 }