changeset 745:4506d2ab97a0

Misc bug fixes: *) Fixed regression in flow analysis involving effectively-final variables *) Improved inference of lambda return type in case of cyclic type-inference
author mcimadamore
date Tue, 26 Oct 2010 17:50:10 +0100
parents e23ed3e167e8
children 76f6f9e8b0ec
files src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Flow.java test/tools/javac/lambda/BadAccess02.java test/tools/javac/lambda/BadAccess02.out test/tools/javac/lambda/DefiniteAssignment01.java test/tools/javac/lambda/TargetType01.out test/tools/javac/lambda/TargetType14.java test/tools/javac/lambda/TargetType14.out
diffstat 9 files changed, 143 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Oct 21 15:06:09 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Oct 26 17:50:10 2010 +0100
@@ -937,8 +937,12 @@
 
                 if (t.inst != null)
                     return isSubtypeNoCapture(t.inst, s); // TODO: ", warn"?
-
-                t.hibounds = t.hibounds.prepend(s);
+                else if ((s.isPrimitive() || s.tag == VOID) &&
+                    (t.qtype.tsym.flags() & LAMBDA) != 0) {
+                    t.inst = s;
+                } else {
+                    t.hibounds = t.hibounds.prepend(s);
+                }
                 return true;
             }
 
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 21 15:06:09 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Oct 26 17:50:10 2010 +0100
@@ -2203,9 +2203,23 @@
             }
         }
         Type ft = attribLambda(tempLambda);
+        final boolean needsReturnTypeInferred = ft.getReturnType() == Type.noType;
+        if (needsReturnTypeInferred) {
+            TypeSymbol tvSym = new TypeSymbol(LAMBDA,
+                        names.fromString("R"),
+                        null,
+                        env.info.scope.owner);
+            TypeVar resType = new TypeVar(tvSym, Type.noType, null);
+            tvars.prepend(resType);
+            ft = new FunctionType(ft.getParameterTypes(),
+                    resType, ft.getThrownTypes(), ft.tsym);
+        }
         return that.type = new ForAll(tvars.toList(), ft) {
             @Override
             public Type inst(List<Type> actuals, Type to, Types types) {
+                if (needsReturnTypeInferred) {
+                    actuals = actuals.tail;
+                }
                 if (that.type.tag == FORALL) {
                     //now that we have a target type 'to' and a set of instantiated types
                     //for each of the unknown lambda parameter types, we can proceed
@@ -2303,6 +2317,7 @@
                 log.warning(that.pos(), warnKey, uninferredTypeNames);
             }
             thrownTypes = Type.noTypes;
+            resType = Type.noType;
         }
 
         that.type = new FunctionType(argtypes.toList(),
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Oct 21 15:06:09 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Oct 26 17:50:10 2010 +0100
@@ -194,7 +194,7 @@
     private       Lint lint;
     private final boolean allowRethrowAnalysis;
     boolean daEnabled = true;
-    boolean inLambda = false;
+    Symbol currentLambda = null;
 
     public static Flow instance(Context context) {
         Flow instance = context.get(flowKey);
@@ -439,8 +439,9 @@
     }
 
     void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
-        if (inLambda &&
+        if (currentLambda != null &&
                 sym.owner.kind == MTH &&
+                sym.owner != currentLambda &&
                 (sym.flags() & EFFECTIVELY_FINAL) == 0) {
             log.error(pos, "cant.ref.non.effectively.final.var",
                     sym);
@@ -612,7 +613,7 @@
         int nextadrPrev = nextadr;
         ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
         Lint lintPrev = lint;
-        boolean prevInLambda = inLambda;
+        Symbol prevLambda = currentLambda;
 
         pendingExits = new ListBuffer<PendingExit>();
         if (tree.name != names.empty) {
@@ -624,7 +625,7 @@
         lint = lint.augment(tree.sym.attributes_field);
 
         try {
-            inLambda = false;
+            currentLambda = null;
             // define all the static fields
             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                 if (l.head.getTag() == JCTree.VARDEF) {
@@ -716,7 +717,7 @@
             caught = caughtPrev;
             classDef = classDefPrev;
             lint = lintPrev;
-            inLambda = prevInLambda;
+            currentLambda = prevLambda;
         }
     }
 
@@ -1316,9 +1317,9 @@
         Bits prevInits = inits;
         ListBuffer<PendingExit> prevPending = pendingExits;
         boolean prevAlive = alive;
-        boolean prevInLambda = inLambda;
+        Symbol prevLambda = currentLambda;
         try {
-            inLambda = true;
+            currentLambda = tree.sym;
             caught = List.of(syms.throwableType); //inhibit exception checking
             thrown = List.nil();            
             inits = inits.orSet(uninits);
@@ -1358,7 +1359,7 @@
             inits = prevInits;
             alive = prevAlive;
             pendingExits = prevPending;
-            inLambda = prevInLambda;
+            currentLambda = prevLambda;
         }        
     }
 
--- a/test/tools/javac/lambda/BadAccess02.java	Thu Oct 21 15:06:09 2010 +0100
+++ b/test/tools/javac/lambda/BadAccess02.java	Tue Oct 26 17:50:10 2010 +0100
@@ -31,7 +31,7 @@
 public class BadAccess02 {
 
     interface SAM {
-        int m();
+        int m(int h);
     }
 
     static void test1() {
@@ -39,7 +39,7 @@
         int j = 0; //non-effectively final
         j = 2;
         final int L = 0;
-        SAM s = #{ j + l + L };
+        SAM s = #{ int h -> int k = 0; return h + j + l + L; };
     }
 
     void test2() {
@@ -47,6 +47,6 @@
         int j = 0; //non-effectively final
         j = 2;
         final int L = 0;
-        SAM s = #{ j + l + L };
+        SAM s = #{ int h -> int k = 0; return h + k + j + l + L; };
     }
 }
--- a/test/tools/javac/lambda/BadAccess02.out	Thu Oct 21 15:06:09 2010 +0100
+++ b/test/tools/javac/lambda/BadAccess02.out	Tue Oct 26 17:50:10 2010 +0100
@@ -1,3 +1,3 @@
-BadAccess02.java:42:20: compiler.err.cant.ref.non.effectively.final.var: j
-BadAccess02.java:50:20: compiler.err.cant.ref.non.effectively.final.var: j
+BadAccess02.java:42:51: compiler.err.cant.ref.non.effectively.final.var: j
+BadAccess02.java:50:55: compiler.err.cant.ref.non.effectively.final.var: j
 2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/DefiniteAssignment01.java	Tue Oct 26 17:50:10 2010 +0100
@@ -0,0 +1,52 @@
+/*
+ * 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 DA/DU rules are implemented correctly when SAM constructor refers to target method
+ * @author  Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles DefiniteAssignment01
+ */
+
+public class DefiniteAssignment01 {
+
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    static abstract class SAM {
+        SAM() {
+            m(0);
+        }
+        abstract void m(Integer x);
+    }
+
+    public static void main(String[] args) {
+        final SAM s = # { i -> assertTrue(i == 0); };
+        assert(assertionCount == 1);
+    }
+}
--- a/test/tools/javac/lambda/TargetType01.out	Thu Oct 21 15:06:09 2010 +0100
+++ b/test/tools/javac/lambda/TargetType01.out	Tue Oct 26 17:50:10 2010 +0100
@@ -1,2 +1,4 @@
 TargetType01.java:45:33: compiler.err.ref.ambiguous: M, kindname.method, M(TargetType01.F_I_I), TargetType01, kindname.method, M(TargetType01.F_S_S), TargetType01
-1 error
+TargetType01.java:45:34: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Integer, java.lang.String
+TargetType01.java:45:9: compiler.err.ref.ambiguous: M, kindname.method, M(TargetType01.F_I_I), TargetType01, kindname.method, M(TargetType01.F_S_S), TargetType01
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/TargetType14.java	Tue Oct 26 17:50:10 2010 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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 type is inferred from target type when cyclic inference found
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=TargetType14.out -XDrawDiagnostics TargetType14.java
+ */
+
+class TargetType14 {
+
+    interface SAM<X> {
+        X m(int i, int j);
+    }
+
+    static void test() {
+        SAM<Integer> s1 = #{ i, j -> i + j };
+        m(#{ i, j -> i + j });
+        SAM<Integer> s2 = m2(#{ i, j -> i + j }); //ok
+        SAM<Integer> s3 = m2(#{ i, j -> "" + i + j }); //no
+    }
+
+    static void m(SAM<Integer> s) { }
+    static <X> SAM<X> m2(SAM<X> s) { return null; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/TargetType14.out	Tue Oct 26 17:50:10 2010 +0100
@@ -0,0 +1,7 @@
+TargetType14.java:38:27: compiler.warn.cyclic.lambda.inference.throws.1: i,j
+TargetType14.java:39:11: compiler.warn.cyclic.lambda.inference.throws.1: i,j
+TargetType14.java:40:30: compiler.warn.cyclic.lambda.inference.throws.1: i,j
+TargetType14.java:41:30: compiler.warn.cyclic.lambda.inference.throws.1: i,j
+TargetType14.java:41:48: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.String, java.lang.Integer
+1 error
+4 warnings