changeset 1140:6a38e7ad078f

Bug fixes: *) Bad test in LambdaToMethod leads to infinite loop *) Regression in lambda candidate checker *) Updated void-copatibility definition so that semantics is influenced by loose vs. strict conversion context *) Removed redundant cast warnings when lambda/method reference is explicitly converted to target type
author mcimadamore
date Thu, 25 Aug 2011 14:42:31 +0100
parents b9e08af836ed
children ec50962638d3
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/LambdaToMethod.java test/tools/javac/lambda/LambdaConv18.java test/tools/javac/lambda/LambdaConv18.out test/tools/javac/lambda/LambdaConv19.java test/tools/javac/lambda/TargetType16.java test/tools/javac/lambda/TargetType16.out
diffstat 8 files changed, 132 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Aug 10 17:48:09 2011 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Aug 25 14:42:31 2011 +0100
@@ -1840,7 +1840,7 @@
                     identifyLambdaCandidate &&
                     clazztype.tag == CLASS &&
                     lambdaOrReferenceAllowed(tree) &&
-                    !types.isSam(clazztype.tsym)) {
+                    types.isSam(clazztype.tsym)) {
                 MethodSymbol samDescriptor = types.findDescriptor(clazztype.tsym);
                 int count = 0;
                 boolean found = false;
@@ -2732,7 +2732,7 @@
 
         if (completesNormally &&
                 resultTypes.length() == 0 &&
-                !isVoidCompatible(samDescriptor.getReturnType())) {
+                !isVoidCompatible(samDescriptor.getReturnType(), allowBoxing)) {
            throw new Infer.InvalidInstanceException(diags).setMessage("infer.incompatible.ret.types.in.lambda", syms.voidType);
         } else {
             for (Type resType : resultTypes) {
@@ -2761,18 +2761,19 @@
      */
     public boolean isReturnCompatible(Env<AttrContext> env, Type t, Type s, boolean allowBoxing) {
         return t.tag == NONE || //can't complete normally
-                t.tag == VOID && isVoidCompatible(s) ||
-                s.tag == VOID && isVoidCompatible(t) ||
+                t.tag == VOID && isVoidCompatible(s, allowBoxing) ||
+                s.tag == VOID && isVoidCompatible(t, allowBoxing) ||
                 (allowBoxing ? types.isConvertible(t, s) : types.isSubtypeUnchecked(t, s));
     }
 
     /**
      * A return type in a lambda expression is said to be void-compatible
-     * if it's either 'void' or 'java.lang.Void'
+     * if it's either 'void' or 'java.lang.Void' (the latter only valid if we are
+     * in a loose conversion context).
      */
-    public boolean isVoidCompatible(Type t) {
+    public boolean isVoidCompatible(Type t, boolean allowBoxing) {
         return t.tag == VOID ||
-                types.isSameType(t, types.boxedClass(syms.voidType).type);
+                (allowBoxing && types.isSameType(t, types.boxedClass(syms.voidType).type));
     }
 
     abstract class SAMDeferredAttribution<T extends JCTree> extends ForAll {
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Aug 10 17:48:09 2011 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Aug 25 14:42:31 2011 +0100
@@ -1528,7 +1528,8 @@
         if (!tree.type.isErroneous()
             && lint.isEnabled(Lint.LintCategory.CAST)
             && types.isSameType(tree.expr.type, tree.clazz.type)
-            && !is292targetTypeCast(tree)) {
+            && !is292targetTypeCast(tree)
+            && !isLambdaOrMethodReference(tree.expr)) {
             log.warning(Lint.LintCategory.CAST,
                     tree.pos(), "redundant.cast", tree.expr.type);
         }
@@ -1546,6 +1547,12 @@
             }
             return is292targetTypeCast;
         }
+        
+        private boolean isLambdaOrMethodReference(JCExpression tree) {
+            JCExpression expr = TreeInfo.skipParens(tree);
+            return expr.getTag() == JCTree.LAMBDA ||
+                    expr.getTag() == JCTree.REFERENCE;
+        }
 
     public void visitTopLevel(JCCompilationUnit tree) {
         // Do nothing for TopLevel since each class is visited individually
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Aug 10 17:48:09 2011 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Aug 25 14:42:31 2011 +0100
@@ -569,19 +569,21 @@
                         tree.type.constValue() == null) {
                     TranslationContext localContext = context;
                     while (localContext != null) {
-                        if (localContext.tree.getTag() != JCTree.LAMBDA) continue;
-                        JCTree block = capturedDecl(localContext.depth, tree.sym);
-                        if (block == null) break;
-                        ((LambdaTranslationContext)localContext).addCapturedVarIfNeeded(tree.sym);
+                        if (localContext.tree.getTag() == JCTree.LAMBDA) {
+                            JCTree block = capturedDecl(localContext.depth, tree.sym);
+                            if (block == null) break;
+                            ((LambdaTranslationContext)localContext).addCapturedVarIfNeeded(tree.sym);
+                        }
                         localContext = localContext.prev;
                     }
                 } else if (tree.sym.owner.kind == TYP) {
                     TranslationContext localContext = context;
                     while (localContext != null) {
-                        if (localContext.tree.getTag() != JCTree.LAMBDA) continue;
-                        JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
-                        if (clazz == null) break;
-                        ((LambdaTranslationContext)localContext).addEnclosingRefIfNeeded(clazz.sym);
+                        if (localContext.tree.getTag() == JCTree.LAMBDA) {
+                            JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
+                            if (clazz == null) break;
+                            ((LambdaTranslationContext)localContext).addEnclosingRefIfNeeded(clazz.sym);
+                        }
                         localContext = localContext.prev;
                     }
                 }
@@ -593,10 +595,11 @@
             if (context != null && lambdaSymbolFilter.accepts(tree.sym) && tree.name == names._this) {
                 TranslationContext localContext = context;
                 while (localContext != null) {
-                    if (localContext.tree.getTag() != JCTree.LAMBDA) continue;
-                    JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
-                    if (clazz == null) break;
-                    ((LambdaTranslationContext)localContext).addEnclosingRefIfNeeded(clazz.sym);
+                    if (localContext.tree.getTag() == JCTree.LAMBDA) {
+                        JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
+                        if (clazz == null) break;
+                        ((LambdaTranslationContext)localContext).addEnclosingRefIfNeeded(clazz.sym);
+                    }
                     localContext = localContext.prev;
                 }
                 scan(tree.selected);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv18.java	Thu Aug 25 14:42:31 2011 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011, 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 simple test for lambda candidate check
+ * @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDidentifyLambdaCandidate=true LambdaConv18.java
+ */
+
+class LambdaConv18 {
+
+    interface SAM {
+        void m();
+    }
+
+    interface NonSAM {
+        void m1();
+        void m2();
+    }
+
+    SAM s1 = new SAM() { public void m() {} };
+    NonSAM s2 = new NonSAM() { public void m1() {}
+                              public void m2() {} };
+    NonExistent s3 = new NonExistent() { public void m() {} };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv18.out	Thu Aug 25 14:42:31 2011 +0100
@@ -0,0 +1,4 @@
+LambdaConv18.java:44:5: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
+LambdaConv18.java:41:24: compiler.note.potential.lambda.found
+LambdaConv18.java:44:26: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv19.java	Thu Aug 25 14:42:31 2011 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, 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 redundant cast warnings are not generated for SAM conversions
+ * @compile -Xlint:cast -Werror LambdaConv19.java
+ */
+
+class LambdaConv19 {
+
+    interface SAM {
+        void m();
+    }
+
+    SAM s = (SAM)#{ };
+}
--- a/test/tools/javac/lambda/TargetType16.java	Wed Aug 10 17:48:09 2011 +0100
+++ b/test/tools/javac/lambda/TargetType16.java	Thu Aug 25 14:42:31 2011 +0100
@@ -23,14 +23,20 @@
 
 /*
  * @test
- * @summary Bad recovery from ambiguous overload resolution
+ * @summary Check void-compatibility in strict vs. loose conversion contexts
  * @author  Maurizio Cimadamore
- * @compile/fail/ref=TargetType16.out -XDrawDiagnostics TargetType16.java
  */
 
-class TargetType16 {
+public class TargetType16 {
+    
+    static int assertionCount = 0;
 
-
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+    
     interface SAM1 {
         void m1();
     }
@@ -39,10 +45,11 @@
         X m2();
     }
 
-    void m(SAM1 s1) { }
-    <T> void m(SAM2<T> s2) { }
+    static void m(SAM1 s1) { assertTrue(true); }
+    static <T> void m(SAM2<T> s2) { assertTrue(false); }
 
-    {
-        m(#{ System.out.println("Hello!") }); //ambiguity here
+    public static void main(String[] args) {
+        m(#{ System.out.println("Hello!") }); //'void' has precedence
+        assertTrue(assertionCount == 1);
     }
 }
--- a/test/tools/javac/lambda/TargetType16.out	Wed Aug 10 17:48:09 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-TargetType16.java:46:9: compiler.err.ref.ambiguous: m, kindname.method, m(TargetType16.SAM1), TargetType16, kindname.method, <T>m(TargetType16.SAM2<T>), TargetType16
-1 error