changeset 1131:397b7ba6e0b9

Fix: Non-compatible method references with explicit parameter types are erroneously accepted
author mcimadamore
date Wed, 13 Jul 2011 12:14:17 +0100
parents fff19d71854a
children cb09efd9e158
files src/share/classes/com/sun/tools/javac/comp/Attr.java test/tools/javac/lambda/MethodReference09.out test/tools/javac/lambda/MethodReference28.java test/tools/javac/lambda/MethodReference28.out
diffstat 4 files changed, 116 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Jul 11 13:39:22 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 13 12:14:17 2011 +0100
@@ -2715,6 +2715,29 @@
         Type mtype = types.memberType(tree.expr.type, tree.sym);
         Type returnType = tree.getMode() == ReferenceMode.INVOKE ?
                 mtype.getReturnType() : tree.expr.type;
+
+        if (tree.args != null) {
+            //if method ref has explict param types, perform an explicit
+            //applicability check; this amounts at checking that types in the
+            //SAM desctiptor are method-compatible with the resolved signature
+            List<Type> paramsToCheck = samDesc.getParameterTypes();
+            if (!refSym.isStatic() && !refSym.isConstructor() &&
+                    TreeInfo.isStaticSelector(tree.getQualifierExpression(), names)) {
+                //if this is an unbound reference, we need to drop the first parameter
+                //(which should be a subtype of the receiver expression)
+                if (paramsToCheck.isEmpty() ||
+                        !types.isSubtype(tree.getQualifierExpression().type, paramsToCheck.head)) {
+                    throw new Infer.InferenceException(diags).setMessage("infer.incompatible.arg.types.in.lambda");
+                }
+                paramsToCheck = paramsToCheck.tail;
+            }
+            if (!rs.argumentsAcceptable(localEnv, mtype, paramsToCheck, allowBoxing, (refSym.flags() & VARARGS) != 0, Warner.noWarnings)) {
+                throw new Infer.InferenceException(diags).setMessage("infer.incompatible.arg.types.in.lambda");
+            }
+        }
+
+        //go ahead with standard SAM compatibility check - note that param check
+        //is a no-op (as this has been taken care during method applicability)
         checkSAMCompatible(inferenceContext, to, List.of(returnType),
                 samDesc.getParameterTypes(), mtype.getThrownTypes(), allowBoxing, true);
         return to;
--- a/test/tools/javac/lambda/MethodReference09.out	Mon Jul 11 13:39:22 2011 -0700
+++ b/test/tools/javac/lambda/MethodReference09.out	Wed Jul 13 12:14:17 2011 +0100
@@ -1,3 +1,4 @@
 MethodReference09.java:42:23: compiler.err.non-static.cant.be.ref: kindname.method, getThis()
+MethodReference09.java:42:20: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference09.SAM
 MethodReference09.java:43:20: compiler.err.non-static.cant.be.ref: kindname.variable, this
-2 errors
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/MethodReference28.java	Wed Jul 13 12:14:17 2011 +0100
@@ -0,0 +1,77 @@
+/*
+ * 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 non-compatible method references with explicit args are rejected
+ * @compile/fail/ref=MethodReference28.out -XDrawDiagnostics MethodReference28.java
+ */
+
+class MethodReference28 {
+
+    interface SAM1 {
+        void m(int i);
+    }
+
+    interface SAM2 {
+        void m(MethodReference28 rec, int i);
+    }
+
+    static void m1(Integer i) { } //ok - boxing
+    static void m1(Integer i1, Integer i2) { } //wrong arity
+    static void m1(String s) { } //type mismatch
+    static void m1(String... ss) { } //type mismatch - varargs
+
+    void m2(Integer i) { } //ok - boxing
+    void m2(Integer i1, Integer i2) { } //wrong arity
+    void m2(String s) { } //type mismatch
+    void m2(String... ss) { } //type mismatch - varargs
+
+    static void testStatic() {
+        SAM1 s1 = MethodReference28#m1(Integer);
+        SAM1 s2 = MethodReference28#m1(Integer, Integer);
+        SAM1 s3 = MethodReference28#m1(String);
+        SAM1 s4 = MethodReference28#m1(String[]);
+    }
+
+    void testBadMember() {
+        SAM1 s1 = MethodReference28#m2(Integer);
+        SAM1 s2 = MethodReference28#m2(Integer, Integer);
+        SAM1 s3 = MethodReference28#m2(String);
+        SAM1 s4 = MethodReference28#m2(String[]);
+    }
+
+    void testMember() {
+        SAM1 s1 = this#m2(Integer);
+        SAM1 s2 = this#m2(Integer, Integer);
+        SAM1 s3 = this#m2(String);
+        SAM1 s4 = this#m2(String[]);
+    }
+
+    static void testUnbound() {
+        SAM2 s1 = MethodReference28#m2(Integer);
+        SAM2 s2 = MethodReference28#m2(Integer, Integer);
+        SAM2 s3 = MethodReference28#m2(String);
+        SAM2 s4 = MethodReference28#m2(String[]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/MethodReference28.out	Wed Jul 13 12:14:17 2011 +0100
@@ -0,0 +1,14 @@
+MethodReference28.java:52:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:53:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:54:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:58:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:59:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:60:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:61:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:66:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:67:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:68:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM1
+MethodReference28.java:73:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM2
+MethodReference28.java:74:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM2
+MethodReference28.java:75:19: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.incompatible.arg.types.in.lambda)), compiler.misc.type.mref, MethodReference28.SAM2
+13 errors