Tue, 14 May 2013 11:11:09 -0700
8012556: Implement lambda methods on interfaces as static
8006140: Javac NPE compiling Lambda expression on initialization expression of static field in interface
Summary: Lambdas occurring in static contexts or those not needing instance information should be generated into static methods. This has long been the case for classes. However, as a work-around to the lack of support for statics on interfaces, interface lambda methods have been generated into default methods. For lambdas in interface static contexts (fields and static methods) this causes an NPE in javac because there is no 'this'. MethodHandles now support static methods on interfaces. This changeset allows lambda methods to be generated as static interface methods. An existing bug in Hotspot (8013875) is exposed in a test when the "-esa" flag is used. This test and another test that already exposed this bug have been marked with @ignore.
Reviewed-by: mcimadamore
1 /*
2 * Copyright (c) 2012, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 /**
27 * @test
28 * @bug 8003639
29 * @summary convert lambda testng tests to jtreg and add them
30 * @run testng LambdaTranslationTest2
31 */
33 import org.testng.annotations.Test;
35 import java.util.ArrayList;
36 import java.util.List;
38 import static org.testng.Assert.assertEquals;
39 import static org.testng.Assert.assertTrue;
41 /**
42 * LambdaTranslationTest2 -- end-to-end smoke tests for lambda evaluation
43 */
45 @Test
46 public class LambdaTranslationTest2 {
48 final String dummy = "dummy";
50 public void testLambdas() {
51 TPredicate<String> isEmpty = s -> s.isEmpty();
52 assertTrue(isEmpty.test(""));
53 assertTrue(!isEmpty.test("foo"));
55 TPredicate<Object> oIsEmpty = s -> ((String) s).isEmpty();
56 assertTrue(oIsEmpty.test(""));
57 assertTrue(!oIsEmpty.test("foo"));
59 TPredicate<Object> alwaysTrue = o -> true;
60 assertTrue(alwaysTrue.test(""));
61 assertTrue(alwaysTrue.test(null));
63 TPredicate<Object> alwaysFalse = o -> false;
64 assertTrue(!alwaysFalse.test(""));
65 assertTrue(!alwaysFalse.test(null));
67 // tests local capture
68 String foo = "foo";
69 TPredicate<String> equalsFoo = s -> s.equals(foo);
70 assertTrue(!equalsFoo.test(""));
71 assertTrue(equalsFoo.test("foo"));
73 // tests instance capture
74 TPredicate<String> equalsDummy = s -> s.equals(dummy);
75 assertTrue(!equalsDummy.test(""));
76 assertTrue(equalsDummy.test("dummy"));
78 TMapper<Object, Object> ident = s -> s;
80 assertEquals("blarf", ident.map("blarf"));
81 assertEquals("wooga", ident.map("wooga"));
82 assertTrue("wooga" == ident.map("wooga"));
84 // constant capture
85 TMapper<Object, Object> prefixer = s -> "p" + s;
86 assertEquals("pblarf", prefixer.map("blarf"));
87 assertEquals("pwooga", prefixer.map("wooga"));
89 // instance capture
90 TMapper<Object, Object> prefixer2 = s -> dummy + s;
91 assertEquals("dummyblarf", prefixer2.map("blarf"));
92 assertEquals("dummywooga", prefixer2.map("wooga"));
93 }
95 interface Factory<T> {
96 T make();
97 }
99 interface StringFactory extends Factory<String> { }
101 interface StringFactory2 extends Factory<String> {
102 String make();
103 }
105 public void testBridges() {
106 Factory<String> of = () -> "y";
107 Factory<?> ef = () -> "z";
109 assertEquals("y", of.make());
110 assertEquals("y", ((Factory<?>) of).make());
111 assertEquals("y", ((Factory) of).make());
113 assertEquals("z", ef.make());
114 assertEquals("z", ((Factory) ef).make());
115 }
117 public void testBridgesImplicitSpecialization() {
118 StringFactory sf = () -> "x";
120 assertEquals("x", sf.make());
121 assertEquals("x", ((Factory<String>) sf).make());
122 assertEquals("x", ((Factory<?>) sf).make());
123 assertEquals("x", ((Factory) sf).make());
124 }
126 public void testBridgesExplicitSpecialization() {
127 StringFactory2 sf = () -> "x";
129 assertEquals("x", sf.make());
130 assertEquals("x", ((Factory<String>) sf).make());
131 assertEquals("x", ((Factory<?>) sf).make());
132 assertEquals("x", ((Factory) sf).make());
133 }
135 public void testSuperCapture() {
136 class A {
137 String make() { return "x"; }
138 }
140 class B extends A {
141 void testSuperCapture() {
142 StringFactory sf = () -> super.make();
143 assertEquals("x", sf.make());
144 }
145 }
147 new B().testSuperCapture();
148 }
150 interface WidenD {
151 public String m(float a0, double a1);
152 }
154 interface WidenS {
155 public String m(byte a0, short a1);
156 }
158 interface WidenI {
159 public String m(byte a0, short a1, char a2, int a3);
160 }
162 interface WidenL {
163 public String m(byte a0, short a1, char a2, int a3, long a4);
164 }
166 interface Box {
167 public String m(byte a0, short a1, char a2, int a3, long a4, boolean a5, float a6, double a7);
168 }
170 static String pb(Byte a0, Short a1, Character a2, Integer a3, Long a4, Boolean a5, Float a6, Double a7) {
171 return String.format("b%d s%d c%c i%d j%d z%b f%f d%f", a0, a1, a2, a3, a4, a5, a6, a7);
172 }
174 static String pwI1(int a0, int a1, int a2, int a3) {
175 return String.format("b%d s%d c%d i%d", a0, a1, a2, a3);
176 }
178 static String pwI2(Integer a0, Integer a1, Integer a2, Integer a3) {
179 return String.format("b%d s%d c%d i%d", a0, a1, a2, a3);
180 }
182 static String pwL1(long a0, long a1, long a2, long a3, long a4) {
183 return String.format("b%d s%d c%d i%d j%d", a0, a1, a2, a3, a4);
184 }
186 static String pwL2(Long a0, Long a1, Long a2, Long a3, Long a4) {
187 return String.format("b%d s%d c%d i%d j%d", a0, a1, a2, a3, a4);
188 }
190 static String pwS1(short a0, short a1) {
191 return String.format("b%d s%d", a0, a1);
192 }
194 static String pwS2(Short a0, Short a1) {
195 return String.format("b%d s%d", a0, a1);
196 }
198 static String pwD1(double a0, double a1) {
199 return String.format("f%f d%f", a0, a1);
200 }
202 static String pwD2(Double a0, Double a1) {
203 return String.format("f%f d%f", a0, a1);
204 }
206 public void testPrimitiveWidening() {
207 WidenS ws1 = LambdaTranslationTest2::pwS1;
208 assertEquals("b1 s2", ws1.m((byte) 1, (short) 2));
210 WidenD wd1 = LambdaTranslationTest2::pwD1;
211 assertEquals("f1.000000 d2.000000", wd1.m(1.0f, 2.0));
213 WidenI wi1 = LambdaTranslationTest2::pwI1;
214 assertEquals("b1 s2 c3 i4", wi1.m((byte) 1, (short) 2, (char) 3, 4));
216 WidenL wl1 = LambdaTranslationTest2::pwL1;
217 assertEquals("b1 s2 c3 i4 j5", wl1.m((byte) 1, (short) 2, (char) 3, 4, 5L));
219 // @@@ TODO: clarify spec on widen+box conversion
220 }
222 interface Unbox {
223 public String m(Byte a0, Short a1, Character a2, Integer a3, Long a4, Boolean a5, Float a6, Double a7);
224 }
226 static String pu(byte a0, short a1, char a2, int a3, long a4, boolean a5, float a6, double a7) {
227 return String.format("b%d s%d c%c i%d j%d z%b f%f d%f", a0, a1, a2, a3, a4, a5, a6, a7);
228 }
230 public void testUnboxing() {
231 Unbox u = LambdaTranslationTest2::pu;
232 assertEquals("b1 s2 cA i4 j5 ztrue f6.000000 d7.000000", u.m((byte)1, (short) 2, 'A', 4, 5L, true, 6.0f, 7.0));
233 }
235 public void testBoxing() {
236 Box b = LambdaTranslationTest2::pb;
237 assertEquals("b1 s2 cA i4 j5 ztrue f6.000000 d7.000000", b.m((byte) 1, (short) 2, 'A', 4, 5L, true, 6.0f, 7.0));
238 }
240 static boolean cc(Object o) {
241 return ((String) o).equals("foo");
242 }
244 public void testArgCastingAdaptation() {
245 TPredicate<String> p = LambdaTranslationTest2::cc;
246 assertTrue(p.test("foo"));
247 assertTrue(!p.test("bar"));
248 }
250 interface SonOfPredicate<T> extends TPredicate<T> { }
252 public void testExtendsSAM() {
253 SonOfPredicate<String> p = s -> s.isEmpty();
254 assertTrue(p.test(""));
255 assertTrue(!p.test("foo"));
256 }
258 public void testConstructorRef() {
259 Factory<List<String>> lf = ArrayList<String>::new;
260 List<String> list = lf.make();
261 assertTrue(list instanceof ArrayList);
262 assertTrue(list != lf.make());
263 list.add("a");
264 assertEquals("[a]", list.toString());
265 }
267 private static String privateMethod() {
268 return "private";
269 }
271 public void testPrivateMethodRef() {
272 Factory<String> sf = LambdaTranslationTest2::privateMethod;
273 assertEquals("private", sf.make());
274 }
276 private interface PrivateIntf {
277 String make();
278 }
280 public void testPrivateIntf() {
281 PrivateIntf p = () -> "foo";
282 assertEquals("foo", p.make());
283 }
285 interface Op<T> {
286 public T op(T a, T b);
287 }
289 public void testBoxToObject() {
290 Op<Integer> maxer = Math::max;
291 for (int i=-100000; i < 100000; i += 100)
292 for (int j=-100000; j < 100000; j += 99) {
293 assertEquals((int) maxer.op(i,j), Math.max(i,j));
294 }
295 }
297 protected static String protectedMethod() {
298 return "protected";
299 }
301 public void testProtectedMethodRef() {
302 Factory<String> sf = LambdaTranslationTest2::protectedMethod;
303 assertEquals("protected", sf.make());
304 }
306 class Inner1 {
307 String m1() {
308 return "Inner1.m1()";
309 }
311 class Inner2 {
312 public String m1() {
313 return "Inner1.Inner2.m1()";
314 }
316 protected String m2() {
317 return "Inner1.Inner2.m2()";
318 }
320 String m3() {
321 return "Inner1.Inner2.m3()";
322 }
324 class Inner3<T> {
325 T t = null;
326 Inner3(T t) {
327 this.t = t;
328 }
329 T m1() {
330 return t;
331 }
332 }
333 }
334 }
336 public void testInnerClassMethodRef() {
337 Factory<String> fs = new Inner1()::m1;
338 assertEquals("Inner1.m1()", fs.make());
340 fs = new Inner1().new Inner2()::m1;
341 assertEquals("Inner1.Inner2.m1()", fs.make());
343 fs = new Inner1().new Inner2()::m2;
344 assertEquals("Inner1.Inner2.m2()", fs.make());
346 fs = new Inner1().new Inner2()::m3;
347 assertEquals("Inner1.Inner2.m3()", fs.make());
349 fs = new Inner1().new Inner2().new Inner3<String>("Inner1.Inner2.Inner3")::m1;
350 assertEquals("Inner1.Inner2.Inner3", fs.make());
352 Factory<Integer> fsi = new Inner1().new Inner2().new Inner3<Integer>(100)::m1;
353 assertEquals(100, (int)fsi.make());
354 }
355 }