• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package lambdadesugaring;
5 
6 import java.io.Serializable;
7 import java.util.ArrayList;
8 import lambdadesugaring.legacy.Legacy;
9 import lambdadesugaring.other.OtherRefs;
10 
11 public class LambdaDesugaring {
12   interface I {
foo()13     String foo();
14   }
15 
16   interface V {
foo()17     void foo();
18   }
19 
20   interface VT<T> {
foo(T t)21     void foo(T t);
22   }
23 
24   interface P1<X> {
foo(int i)25     X foo(int i);
26   }
27 
28   interface I2 extends I {
29   }
30 
31   interface I3 {
foo()32     String foo();
33   }
34 
35   interface M1 {
36   }
37 
38   interface M2 {
39   }
40 
41   interface J {
foo(String a, int b, boolean c)42     String foo(String a, int b, boolean c);
43   }
44 
45   interface G {
foo()46     A foo();
47   }
48 
49   interface H<T extends A> {
foo(T o)50     T foo(T o);
51   }
52 
53   interface K {
foo(String a, String b, String c)54     Object foo(String a, String b, String c);
55   }
56 
57   interface ObjectProvider {
act()58     Object act();
59   }
60 
61   interface S2Z {
foo(String a)62     boolean foo(String a);
63   }
64 
65   interface SS2Z {
foo(String a, String b)66     boolean foo(String a, String b);
67   }
68 
69   interface ArrayTransformerA<T> {
transform(T[] a)70     T[] transform(T[] a);
71   }
72 
73   @SuppressWarnings("unchecked")
74   interface ArrayTransformerB<T> {
transform(T... a)75     T[] transform(T... a);
76   }
77 
print(T[] a)78   static <T> void print(T[] a) {
79     StringBuilder builder = new StringBuilder("{");
80     String sep = "";
81     for (T s : a) {
82       builder.append(sep).append(s.toString());
83       sep = ", ";
84     }
85     builder.append("}");
86     System.out.println(builder.toString());
87   }
88 
reorder(T[] a)89   <T> T[] reorder(T[] a) {
90     int size = a.length;
91     for (int x = 0; x < size / 2; x++) {
92       T t = a[x];
93       a[x] = a[size - 1 - x];
94       a[size - 1 - x] = t;
95     }
96     return a;
97   }
98 
atA(ArrayTransformerA<Integer> f)99   static void atA(ArrayTransformerA<Integer> f) {
100     print(f.transform(new Integer[] { 1, 2, 3 }));
101   }
102 
atB(ArrayTransformerB<String> f)103   static void atB(ArrayTransformerB<String> f) {
104     print(f.transform("A", "B", "C"));
105   }
106 
staticUnused()107   public static String staticUnused() {
108     return "ReleaseTests::staticUnused";
109   }
110 
testUnusedLambdas()111   public static void testUnusedLambdas() {
112     System.out.print("Before unused ... ");
113     Object o = (I) LambdaDesugaring::staticUnused;
114     System.out.println("after unused.");
115   }
116 
117   class A {
118     final String toString;
119 
A(String toString)120     A(String toString) {
121       this.toString = toString;
122     }
123 
124     @Override
toString()125     public String toString() {
126       return toString;
127     }
128   }
129 
130   class B extends A {
B(String toString)131     B(String toString) {
132       super(toString);
133     }
134   }
135 
136   class C extends B {
C(String toString)137     C(String toString) {
138       super(toString);
139     }
140   }
141 
142   class D extends C {
D(String toString)143     D(String toString) {
144       super(toString);
145     }
146   }
147 
148   public static class Refs {
f(I i)149     public static String f(I i) {
150       return i.foo();
151     }
152 
v(V v)153     public static void v(V v) {
154       v.foo();
155     }
156 
vt(VT<String> v)157     public static void vt(VT<String> v) {
158       v.foo(null);
159     }
160 
p1(P1 p)161     public static String p1(P1 p) {
162       return p.foo(123).getClass().getCanonicalName();
163     }
164 
pSS2Z(SS2Z p)165     public static String pSS2Z(SS2Z p) {
166       return "" + p.foo("123", "321");
167     }
168 
pS2Z(S2Z p)169     public static String pS2Z(S2Z p) {
170       return "" + p.foo("123");
171     }
172 
p3(K k)173     public static String p3(K k) {
174       return k.foo("A", "B", "C").toString();
175     }
176 
g(ObjectProvider op)177     public static String g(ObjectProvider op) {
178       return op.act().toString();
179     }
180 
181     static class A extends OtherRefs {
fooInternal()182       String fooInternal() {
183         return "Refs::A::fooInternal()";
184       }
185 
fooProtected()186       protected String fooProtected() {
187         return "Refs::A::fooProtected()";
188       }
189 
fooProtectedOverridden()190       protected String fooProtectedOverridden() {
191         return "Refs::A::fooProtectedOverridden()";
192       }
193 
staticProtected()194       protected static String staticProtected() {
195         return "Refs::A::staticProtected()";
196       }
197 
staticInternal()198       static String staticInternal() {
199         return "Refs::A::staticInternal()";
200       }
201     }
202 
203     public static class B extends A {
test()204       public void test() {
205         System.out.println(f(new A()::fooInternal));
206         System.out.println(f(this::fooInternal));
207         System.out.println(f(this::fooProtected));
208         System.out.println(f(this::fooProtectedOverridden));
209         System.out.println(f(this::fooPublic));
210         System.out.println(f(this::fooInternal));
211 
212         System.out.println(f(super::fooProtectedOverridden));
213         System.out.println(f(this::fooOtherProtected));
214         System.out.println(f(this::fooOtherPublic));
215 
216         System.out.println(g(this::fooPrivate));
217         System.out.println(g(new Integer(123)::toString));
218         System.out.println(g(System::lineSeparator));
219 
220         System.out.println(f(A::staticInternal));
221         System.out.println(f(A::staticProtected));
222         System.out.println(f(B::staticPrivate));
223         System.out.println(f(OtherRefs::staticOtherPublic));
224         System.out.println(f(OtherRefs::staticOtherProtected));
225 
226         System.out.println(g(StringBuilder::new));
227         System.out.println(g(OtherRefs.PublicInit::new));
228         System.out.println(ProtectedInit.testProtected());
229         System.out.println(g(ProtectedInit::new));
230         System.out.println(g(InternalInit::new));
231         System.out.println(PrivateInit.testPrivate());
232         System.out.println(g(PrivateInit::new));
233 
234         System.out.println(p1(D[]::new));
235         System.out.println(p1(Integer::new));
236         System.out.println(p1(B::staticArray));
237 
238         System.out.println(pSS2Z(String::equalsIgnoreCase));
239         System.out.println(pS2Z("123321"::contains));
240         System.out.println(pS2Z(String::isEmpty));
241 
242         System.out.println(p3(B::fooConcat));
243 
244         v(D::new); // Discarding the return value
245         vt((new ArrayList<String>())::add);
246 
247         I3 i3 = this::fooPrivate;
248         System.out.println(f(i3::foo));
249       }
250 
staticPrivate()251       private static String staticPrivate() {
252         return "Refs::B::staticPrivate()";
253       }
254 
fooPrivate()255       private String fooPrivate() {
256         return "Refs::B::fooPrivate()";
257       }
258 
fooInternal()259       String fooInternal() {
260         return "Refs::B::fooInternal()";
261       }
262 
fooConcat(Object... objs)263       public static StringBuilder fooConcat(Object... objs) {
264         StringBuilder builder = new StringBuilder("Refs::B::fooConcat(");
265         String sep = "";
266         for (Object obj : objs) {
267           builder.append(sep).append(obj.toString());
268           sep = ", ";
269         }
270         return builder.append(")");
271       }
272 
273       @Override
fooProtectedOverridden()274       protected String fooProtectedOverridden() {
275         return "Refs::B::fooProtectedOverridden()";
276       }
277 
fooPublic()278       public String fooPublic() {
279         return "Refs::B::fooPublic()";
280       }
281 
staticArray(int size)282       static int[] staticArray(int size) {
283         return new int[size];
284       }
285     }
286 
287     static class D {
D()288       D() {
289         System.out.println("Refs::D::init()");
290       }
291     }
292 
293     public static class ProtectedInit extends OtherRefs.PublicInit {
ProtectedInit()294       protected ProtectedInit() {
295       }
296 
testProtected()297       static String testProtected() {
298         return g(ProtectedInit::new);
299       }
300 
301       @Override
toString()302       public String toString() {
303         return "OtherRefs::ProtectedInit::init()";
304       }
305     }
306 
307     static class InternalInit extends ProtectedInit {
InternalInit()308       InternalInit() {
309       }
310 
311       @Override
toString()312       public String toString() {
313         return "Refs::InternalInit::init()";
314       }
315     }
316 
317     static class PrivateInit extends InternalInit {
PrivateInit()318       private PrivateInit() {
319       }
320 
testPrivate()321       static String testPrivate() {
322         return g(PrivateInit::new);
323       }
324 
325       @Override
toString()326       public String toString() {
327         return "Refs::PrivateInit::init()";
328       }
329     }
330   }
331 
testLambdasSimple()332   public void testLambdasSimple() {
333     System.out.println(f(() -> "testLambdasSimple#1"));
334     System.out.println(
335         g((a, b, c) -> "{" + a + ":" + b + ":" + c + "}",
336             "testLambdasSimple#2", 123, true));
337   }
338 
testLambdasSimpleWithCaptures()339   public void testLambdasSimpleWithCaptures() {
340     String s = "<stirng>";
341     long l = 1234567890123456789L;
342     char c = '#';
343 
344     System.out.println(
345         g((x, y, z) -> "{" + s + ":" + l + ":" + c + ":" + x + ":" + y + ":" + z + "}",
346             "param1", 2, false));
347 
348     I i1 = () -> "i1";
349     I i2 = () -> i1.foo() + ":i2";
350     I i3 = () -> i2.foo() + ":i3";
351     System.out.println(f(() -> "{" + i3.foo() + ":anonymous}"));
352   }
353 
testInstructionPatchingWithCatchHandlers()354   public void testInstructionPatchingWithCatchHandlers() {
355     try {
356       int a = 1, b = 0;
357       System.out.println(f(() -> "testInstructionPatchingWithCatchHandlers:1"));
358       System.out.println(f(() -> ("does not matter " + (a / b))));
359     } catch (IndexOutOfBoundsException | ArithmeticException e) {
360       System.out.println("testInstructionPatchingWithCatchHandlers:Divide By Zero");
361     } catch (RuntimeException re) {
362       throw re;
363     } catch (Exception e) {
364       throw new RuntimeException(e);
365     }
366 
367     int changes = -1;
368     try {
369       if (f(() -> "").isEmpty()) {
370         changes = 32;
371         System.out.println(f(() -> "testInstructionPatchingWithCatchHandlers:lambda"));
372         throw new RuntimeException();
373       } else {
374         changes = 42;
375         throw new RuntimeException();
376       }
377     } catch (Throwable t) {
378       System.out.println("testInstructionPatchingWithCatchHandlers:changes=" + changes);
379     }
380   }
381 
testInstanceLambdaMethods()382   public void testInstanceLambdaMethods() {
383     Integer i = 12345;
384     System.out.println(h(() -> new A("{testInstanceLambdaMethods:" + i + "}")));
385   }
386 
387   @SuppressWarnings("unchecked")
testEnforcedSignatureHelper()388   private void testEnforcedSignatureHelper() {
389     H h = ((H<B>) x -> new B("{testEnforcedSignature:" + x + "}"));
390     System.out.println(h.foo(new A("A")).toString());
391   }
392 
testEnforcedSignature()393   public void testEnforcedSignature() {
394     String capture = "capture";
395     System.out.println(i(x -> new B("{testEnforcedSignature:" + x + "}")));
396     System.out.println(i(x -> new B("{testEnforcedSignature:" + capture + "}")));
397 
398     try {
399       testEnforcedSignatureHelper();
400     } catch (Exception e) {
401       System.out.println(e.getMessage());
402     }
403 
404     atA(t -> new LambdaDesugaring().reorder(t));
405     atB(t -> new LambdaDesugaring().reorder(t));
406   }
407 
testMultipleInterfaces()408   public void testMultipleInterfaces() {
409     System.out.println(j((I2 & M1 & I3 & M2) () -> "{testMultipleInterfaces:1}"));
410 
411     Object o = (I2 & M1 & I3 & M2) () -> "{testMultipleInterfaces:2}";
412     M1 m1 = (M1) o;
413     M2 m2 = (M2) m1;
414     I i = (I) m2;
415     System.out.println(((I3) i).foo());
416 
417     o = (I2 & Serializable & M2) () -> "{testMultipleInterfaces:3}";
418     m2 = (M2) o;
419     Serializable s = (Serializable) m2;
420     System.out.println(((I) s).foo());
421   }
422 
testBridges()423   public void testBridges() {
424     k((Legacy.BH) (x -> x), "{testBridges:1}");
425     k((Legacy.BK<Legacy.D> & Serializable) (x -> x), new Legacy.D("{testBridges:2}"));
426     // k((Legacy.BL) (x -> x), new Legacy.B("{testBridges:3}")); crashes javac
427     k((Legacy.BM) (x -> x), new Legacy.C("{testBridges:4}"));
428   }
429 
f(I i)430   public String f(I i) {
431     return i.foo();
432   }
433 
g(J j, String a, int b, boolean c)434   String g(J j, String a, int b, boolean c) {
435     return j.foo(a, b, c);
436   }
437 
h(G g)438   String h(G g) {
439     return g.foo().toString();
440   }
441 
i(H<B> h)442   String i(H<B> h) {
443     return h.foo(new B("i(H<B>)")).toString();
444   }
445 
j(T l)446   <T extends I2 & M1 & M2 & I3> String j(T l) {
447     return ((I3) ((M2) ((M1) (((I2) l))))).foo();
448   }
449 
k(Legacy.BI<T> i, T v)450   static <T> void k(Legacy.BI<T> i, T v) {
451     System.out.println(i.foo(v).toString());
452   }
453 
statelessLambda()454   static I statelessLambda() {
455     return InstanceAndClassChecks::staticProvider;
456   }
457 
statefulLambda()458   static I statefulLambda() {
459     return InstanceAndClassChecks.INSTANCE::instanceProvider;
460   }
461 
462   static class InstanceAndClassChecks {
463     static final InstanceAndClassChecks INSTANCE = new InstanceAndClassChecks();
464 
test()465     static void test() {
466       assertSameInstance(
467           InstanceAndClassChecks::staticProvider,
468           InstanceAndClassChecks::staticProvider,
469           "Instances must be same");
470       assertSameInstance(
471           InstanceAndClassChecks::staticProvider,
472           statelessLambda(),
473           "Instances must be same");
474 
475       assertDifferentInstance(
476           INSTANCE::instanceProvider,
477           INSTANCE::instanceProvider,
478           "Instances must be different");
479       assertDifferentInstance(
480           INSTANCE::instanceProvider,
481           statefulLambda(), "Instances must be different");
482     }
483 
staticProvider()484     public static String staticProvider() {
485       return "staticProvider";
486     }
487 
instanceProvider()488     public String instanceProvider() {
489       return "instanceProvider";
490     }
491 
assertSameInstance(I a, I b, String msg)492     static void assertSameInstance(I a, I b, String msg) {
493       if (a != b) {
494         throw new AssertionError(msg);
495       }
496     }
497 
assertDifferentInstance(I a, I b, String msg)498     static void assertDifferentInstance(I a, I b, String msg) {
499       if (a == b) {
500         throw new AssertionError(msg);
501       }
502     }
503   }
504 
main(String[] args)505   public static void main(String[] args) {
506     LambdaDesugaring tests = new LambdaDesugaring();
507     tests.testLambdasSimple();
508     LambdaDesugaring.testUnusedLambdas();
509     tests.testLambdasSimpleWithCaptures();
510     tests.testInstructionPatchingWithCatchHandlers();
511     tests.testInstanceLambdaMethods();
512     tests.testEnforcedSignature();
513     tests.testMultipleInterfaces();
514     tests.testBridges();
515     new Refs.B().test();
516     if (isAndroid()) {
517       InstanceAndClassChecks.test();
518     }
519   }
520 
isAndroid()521   static boolean isAndroid() {
522     try {
523       Class.forName("dalvik.system.VMRuntime");
524       return true;
525     } catch (Exception ignored) {
526     }
527     return false;
528   }
529 }
530