8044546: Crash on faulty reduce/lambda
authorvromero
Fri, 20 Jun 2014 20:36:54 +0100
changeset 25279 a665d5cbb8c3
parent 25278 8a326edaf411
child 25280 687ed8b6d77b
8044546: Crash on faulty reduce/lambda Reviewed-by: mcimadamore, dlsmith Contributed-by: maurizio.cimadamore@oracle.com, vicente.romero@oracle.com
langtools/src/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/test/tools/javac/generics/inference/T8044546/CrashImplicitLambdaTest.java
langtools/test/tools/javac/generics/inference/T8044546/NestedInvocationsTest.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Jun 20 10:56:47 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Jun 20 20:36:54 2014 +0100
@@ -2968,6 +2968,12 @@
         }
 
         @Override
+        public Type visitUndetVar(UndetVar t, Void ignored) {
+            //do nothing - we should not replace inside undet variables
+            return t;
+        }
+
+        @Override
         public Type visitClassType(ClassType t, Void ignored) {
             if (!t.isCompound()) {
                 List<Type> typarams = t.getTypeArguments();
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 20 10:56:47 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 20 20:36:54 2014 +0100
@@ -249,36 +249,30 @@
      */
     Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
         InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
-        Type owntype = found;
-        if (!owntype.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
-            if (allowPoly && inferenceContext.free(found)) {
-                if ((ownkind & ~resultInfo.pkind) == 0) {
-                    owntype = resultInfo.check(tree, inferenceContext.asUndetVar(owntype));
-                } else {
-                    log.error(tree.pos(), "unexpected.type",
-                            kindNames(resultInfo.pkind),
-                            kindName(ownkind));
-                    owntype = types.createErrorType(owntype);
-                }
+        Type owntype;
+        if (!found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
+            if ((ownkind & ~resultInfo.pkind) != 0) {
+                log.error(tree.pos(), "unexpected.type",
+                        kindNames(resultInfo.pkind),
+                        kindName(ownkind));
+                owntype = types.createErrorType(found);
+            } else if (allowPoly && inferenceContext.free(found)) {
+                //delay the check if there are inference variables in the found type
+                //this means we are dealing with a partially inferred poly expression
+                owntype = resultInfo.pt;
                 inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
                     @Override
                     public void typesInferred(InferenceContext inferenceContext) {
                         ResultInfo pendingResult =
-                                    resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
+                                resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
                         check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
                     }
                 });
-                return tree.type = resultInfo.pt;
             } else {
-                if ((ownkind & ~resultInfo.pkind) == 0) {
-                    owntype = resultInfo.check(tree, owntype);
-                } else {
-                    log.error(tree.pos(), "unexpected.type",
-                            kindNames(resultInfo.pkind),
-                            kindName(ownkind));
-                    owntype = types.createErrorType(owntype);
-                }
+                owntype = resultInfo.check(tree, found);
             }
+        } else {
+            owntype = found;
         }
         tree.type = owntype;
         return owntype;
@@ -2472,6 +2466,7 @@
                     currentTarget = infer.instantiateFunctionalInterface(that,
                             currentTarget, explicitParamTypes, resultInfo.checkContext);
                 }
+                currentTarget = types.removeWildcards(currentTarget);
                 lambdaType = types.findDescriptorType(currentTarget);
             } else {
                 currentTarget = Type.recoveryType;
@@ -2894,7 +2889,7 @@
                     resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
                     isSerializable(currentTarget);
             if (currentTarget != Type.recoveryType) {
-                currentTarget = targetChecker.visit(currentTarget, that);
+                currentTarget = types.removeWildcards(targetChecker.visit(currentTarget, that));
                 desc = types.findDescriptorType(currentTarget);
             } else {
                 currentTarget = Type.recoveryType;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Jun 20 10:56:47 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Jun 20 20:36:54 2014 +0100
@@ -534,8 +534,8 @@
 
     Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) {
         final Infer.InferenceContext inferenceContext = checkContext.inferenceContext();
-        if (inferenceContext.free(req)) {
-            inferenceContext.addFreeTypeListener(List.of(req), new FreeTypeListener() {
+        if (inferenceContext.free(req) || inferenceContext.free(found)) {
+            inferenceContext.addFreeTypeListener(List.of(req, found), new FreeTypeListener() {
                 @Override
                 public void typesInferred(InferenceContext inferenceContext) {
                     checkType(pos, inferenceContext.asInstType(found), inferenceContext.asInstType(req), checkContext);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Jun 20 10:56:47 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Jun 20 20:36:54 2014 +0100
@@ -354,6 +354,7 @@
             Type to, Attr.ResultInfo resultInfo,
             InferenceContext inferenceContext) {
         inferenceContext.solve(List.of(from.qtype), new Warner());
+        inferenceContext.notifyChange();
         Type capturedType = resultInfo.checkContext.inferenceContext()
                 .cachedCapture(tree, from.inst, false);
         if (types.isConvertible(capturedType,
@@ -450,7 +451,7 @@
         class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
 
             public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
-                rs.deferredAttr.super(AttrMode.SPECULATIVE, msym, phase);
+                (rs.deferredAttr).super(AttrMode.SPECULATIVE, msym, phase);
             }
 
             public Type apply(Type t) {
@@ -518,6 +519,8 @@
                 //or if it's not a subtype of the original target, issue an error
                 checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
             }
+            //propagate constraints as per JLS 18.2.1
+            checkContext.compatible(owntype, funcInterface, types.noWarnings);
             return owntype;
         }
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Jun 20 10:56:47 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Jun 20 20:36:54 2014 +0100
@@ -958,9 +958,10 @@
         }
 
         public boolean compatible(Type found, Type req, Warner warn) {
+            InferenceContext inferenceContext = deferredAttrContext.inferenceContext;
             return strict ?
-                    types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asUndetVar(req), warn) :
-                    types.isConvertible(found, deferredAttrContext.inferenceContext.asUndetVar(req), warn);
+                    types.isSubtypeUnchecked(inferenceContext.asUndetVar(found), inferenceContext.asUndetVar(req), warn) :
+                    types.isConvertible(inferenceContext.asUndetVar(found), inferenceContext.asUndetVar(req), warn);
         }
 
         public void report(DiagnosticPosition pos, JCDiagnostic details) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/inference/T8044546/CrashImplicitLambdaTest.java	Fri Jun 20 20:36:54 2014 +0100
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ * 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 8044546
+ * @summary Crash on faulty reduce/lambda
+ * @compile CrashImplicitLambdaTest.java
+ */
+
+abstract class CrashImplicitLambdaTest {
+    boolean foo() {
+        return bar(true, a -> {});
+    }
+
+    abstract <T1> T1 bar(T1 t1, S<T1> s);
+
+    interface S<S1> {
+        void baz(S1 s1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/inference/T8044546/NestedInvocationsTest.java	Fri Jun 20 20:36:54 2014 +0100
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * 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 8044546
+ * @summary Crash on faulty reduce/lambda
+ * @compile NestedInvocationsTest.java
+ */
+
+class NestedInvocationsTest<T> {
+    boolean foo(I<T> i) {
+        return baz(zas(i));
+    }
+
+    <U> J<U, Boolean> zas(I<U> i) {
+        return null;
+    }
+
+    <R> R baz(J<T, R> j) {
+        return null;
+    }
+
+    interface I<I1> {}
+
+    interface J<J1, J2> {}
+}