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 arities are mismatched
28  */
29 import java.lang.invoke.*;
30 import java.util.Arrays;
31 import static java.lang.invoke.MethodType.methodType;
32 
33 public class MetafactoryArityTest {
34 
35     public interface I {}
m(int arg)36     public static class C { public static String m(int arg) { return ""; } }
37 
38     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
39     static final Class<?>[] capInt = { int.class };
40     static final MethodHandle C_m;
41     static {
42         try { C_m = lookup.findStatic(C.class, "m", methodType(String.class, int.class)); }
43         catch (NoSuchMethodException | IllegalAccessException e) { throw new RuntimeException(e); }
44     }
45 
main(String... args)46     public static void main(String... args) {
47         MethodType unary = methodType(String.class, int.class);
48         MethodType nullary = methodType(String.class);
49         MethodType binary = methodType(String.class, int.class, int.class);
50         MethodType unaryCS = methodType(CharSequence.class, int.class);
51         MethodType nullaryCS = methodType(CharSequence.class);
52         MethodType binaryCS = methodType(CharSequence.class, int.class, int.class);
53         MethodType unaryObj = methodType(Object.class, int.class);
54         MethodType nullaryObj = methodType(Object.class);
55         MethodType binaryObj = methodType(Object.class, int.class, int.class);
56 
57         test(true, C_m, unary, unary);
58         test(false, C_m, unary, nullary);
59         test(false, C_m, nullary, unary);
60         test(false, C_m, unary, binary);
61         test(false, C_m, binary, unary);
62 
63         testBridge(true, C_m, unary, unary, unaryCS);
64         testBridge(false, C_m, unary, unary, nullaryCS);
65         testBridge(false, C_m, unary, unary, binaryCS);
66 
67         testBridge(true, C_m, unary, unary, unaryCS, unaryObj);
68         testBridge(false, C_m, unary, unary, unaryCS, nullaryObj);
69         testBridge(false, C_m, unary, unary, unaryCS, binaryObj);
70 
71         testCapture(true, C_m, capInt, nullary, nullary);
72         testCapture(false, C_m, capInt, binary, binary);
73         testCapture(false, C_m, capInt, nullary, unary);
74         testCapture(false, C_m, capInt, nullary, binary);
75         testCapture(false, C_m, capInt, unary, nullary);
76         testCapture(false, C_m, capInt, unary, binary);
77 
78         testCaptureBridge(true, C_m, capInt, nullary, nullary, nullaryCS);
79         testCaptureBridge(false, C_m, capInt, unary, unary, unaryCS);
80         testCaptureBridge(false, C_m, capInt, nullary, nullary, unaryCS);
81         testCaptureBridge(false, C_m, capInt, nullary, nullary, binaryCS);
82 
83         testCaptureBridge(true, C_m, capInt, nullary, nullary, nullaryCS, nullaryObj);
84         testCaptureBridge(false, C_m, capInt, unary, unary, unaryCS, unaryObj);
85         testCaptureBridge(false, C_m, capInt, nullary, nullary, nullaryCS, unaryObj);
86         testCaptureBridge(false, C_m, capInt, nullary, nullary, nullaryCS, binaryObj);
87     }
88 
test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT)89     static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
90         tryMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
91         tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
92     }
93 
testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)94     static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
95         tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT, bridgeMTs);
96     }
97 
testCapture(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT)98     static void testCapture(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT) {
99         tryMetafactory(correct, mh, captured, instMT, samMT);
100         tryAltMetafactory(correct, mh, captured, instMT, samMT);
101     }
102 
testCaptureBridge(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)103     static void testCaptureBridge(boolean correct, MethodHandle mh, Class<?>[] captured,
104                                   MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
105         tryAltMetafactory(correct, mh, captured, instMT, samMT, bridgeMTs);
106     }
107 
tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT)108     static void tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
109                                MethodType instMT, MethodType samMT) {
110         try {
111             LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured),
112                                           samMT, mh, instMT);
113             if (!correct) {
114                 throw new AssertionError("Uncaught linkage error:" +
115                                          " impl=" + mh +
116                                          ", captured=" + Arrays.toString(captured) +
117                                          ", inst=" + instMT +
118                                          ", sam=" + samMT);
119             }
120         }
121         catch (LambdaConversionException e) {
122             if (correct) {
123                 throw new AssertionError("Unexpected linkage error:" +
124                                          " e=" + e +
125                                          ", impl=" + mh +
126                                          ", captured=" + Arrays.toString(captured) +
127                                          ", inst=" + instMT +
128                                          ", sam=" + samMT);
129             }
130         }
131     }
132 
tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)133     static void tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
134                                   MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
135         boolean bridge = bridgeMTs.length > 0;
136         Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
137         args[0] = samMT;
138         args[1] = mh;
139         args[2] = instMT;
140         args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
141         if (bridge) {
142             args[4] = bridgeMTs.length;
143             for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
144         }
145         try {
146             LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args);
147             if (!correct) {
148                 throw new AssertionError("Uncaught linkage error:" +
149                                          " impl=" + mh +
150                                          ", captured=" + Arrays.toString(captured) +
151                                          ", inst=" + instMT +
152                                          ", sam=" + samMT +
153                                          ", bridges=" + Arrays.toString(bridgeMTs));
154             }
155         }
156         catch (LambdaConversionException e) {
157             if (correct) {
158                 throw new AssertionError("Unexpected linkage error:" +
159                                          " e=" + e +
160                                          ", impl=" + mh +
161                                          ", captured=" + Arrays.toString(captured) +
162                                          ", inst=" + instMT +
163                                          ", sam=" + samMT +
164                                          ", bridges=" + Arrays.toString(bridgeMTs));
165             }
166         }
167     }
168 
169 }
170