1 /*
2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8035776
27  * @summary metafactory should fail if impl return does not match sam/bridge returns
28  */
29 import java.lang.invoke.*;
30 import java.util.Arrays;
31 import static java.lang.invoke.MethodType.methodType;
32 
33 public class MetafactorySamReturnTest {
34 
35     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
36 
37     public interface I {}
38 
39     public static class C {
m_void(String arg)40         public static void m_void(String arg) {}
m_boolean(String arg)41         public static boolean m_boolean(String arg) { return true; }
m_char(String arg)42         public static char m_char(String arg) { return 'x'; }
m_byte(String arg)43         public static byte m_byte(String arg) { return 12; }
m_short(String arg)44         public static short m_short(String arg) { return 12; }
m_int(String arg)45         public static int m_int(String arg) { return 12; }
m_long(String arg)46         public static long m_long(String arg) { return 12; }
m_float(String arg)47         public static float m_float(String arg) { return 12; }
m_double(String arg)48         public static double m_double(String arg) { return 12; }
m_String(String arg)49         public static String m_String(String arg) { return ""; }
m_Integer(String arg)50         public static Integer m_Integer(String arg) { return 23; }
m_Object(String arg)51         public static Object m_Object(String arg) { return new Object(); }
52 
getMH(Class<?> c)53         public static MethodHandle getMH(Class<?> c) {
54             try {
55                 return lookup.findStatic(C.class, "m_" + c.getSimpleName(), methodType(c, String.class));
56             }
57             catch (NoSuchMethodException | IllegalAccessException e) {
58                 throw new RuntimeException(e);
59             }
60         }
61     }
62 
main(String... args)63     public static void main(String... args) {
64         Class<?>[] t = { void.class, boolean.class, char.class,
65                          byte.class, short.class, int.class, long.class, float.class, double.class,
66                          String.class, Integer.class, Object.class };
67 
68         for (int i = 0; i < t.length; i++) {
69             MethodHandle mh = C.getMH(t[i]);
70             for (int j = 0; j < t.length; j++) {
71                 // TEMPORARY EXCEPTIONS
72                 if (t[j] == void.class) continue;
73                 if (t[i].isPrimitive() && t[j] == Object.class) continue;
74                 if (t[i] == char.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
75                 if (t[i] == byte.class && (t[j] == short.class || t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
76                 if (t[i] == short.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
77                 if (t[i] == int.class && (t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
78                 if (t[i] == long.class && (t[j] == float.class || t[j] == double.class)) continue;
79                 if (t[i] == float.class && t[j] == double.class) continue;
80                 if (t[i] == int.class && t[j] == Integer.class) continue;
81                 if (t[i] == Integer.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
82                 // END TEMPORARY EXCEPTIONS
83                 boolean correct = (t[i].isPrimitive() || t[j].isPrimitive())
84                                   ? t[i] == t[j]
85                                   : t[j].isAssignableFrom(t[i]);
86                 MethodType mti = methodType(t[i], String.class);
87                 MethodType mtiCS = methodType(t[i], CharSequence.class);
88                 MethodType mtj = methodType(t[j], String.class);
89                 MethodType mtjObj = methodType(t[j], Object.class);
90                 test(correct, mh, mti, mtj);
91                 testBridge(correct, mh, mti, mti, mtjObj);
92                 testBridge(correct, mh, mti, mti, mtiCS, mtjObj);
93             }
94         }
95     }
96 
test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT)97     static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
98         tryMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
99         tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
100     }
101 
testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)102     static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
103         tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT, bridgeMTs);
104     }
105 
tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT)106     static void tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
107                                MethodType instMT, MethodType samMT) {
108         try {
109             LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured),
110                                           samMT, mh, instMT);
111             if (!correct) {
112                 throw new AssertionError("Uncaught linkage error:" +
113                                          " impl=" + mh +
114                                          ", captured=" + Arrays.toString(captured) +
115                                          ", inst=" + instMT +
116                                          ", sam=" + samMT);
117             }
118         }
119         catch (LambdaConversionException e) {
120             if (correct) {
121                 throw new AssertionError("Unexpected linkage error:" +
122                                          " e=" + e +
123                                          ", impl=" + mh +
124                                          ", captured=" + Arrays.toString(captured) +
125                                          ", inst=" + instMT +
126                                          ", sam=" + samMT);
127             }
128         }
129     }
130 
tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)131     static void tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
132                                   MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
133         boolean bridge = bridgeMTs.length > 0;
134         Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
135         args[0] = samMT;
136         args[1] = mh;
137         args[2] = instMT;
138         args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
139         if (bridge) {
140             args[4] = bridgeMTs.length;
141             for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
142         }
143         try {
144             LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args);
145             if (!correct) {
146                 throw new AssertionError("Uncaught linkage error:" +
147                                          " impl=" + mh +
148                                          ", captured=" + Arrays.toString(captured) +
149                                          ", inst=" + instMT +
150                                          ", sam=" + samMT +
151                                          ", bridges=" + Arrays.toString(bridgeMTs));
152             }
153         }
154         catch (LambdaConversionException e) {
155             if (correct) {
156                 throw new AssertionError("Unexpected linkage error:" +
157                                          " e=" + e +
158                                          ", impl=" + mh +
159                                          ", captured=" + Arrays.toString(captured) +
160                                          ", inst=" + instMT +
161                                          ", sam=" + samMT +
162                                          ", bridges=" + Arrays.toString(bridgeMTs));
163             }
164         }
165     }
166 
167 }
168