Home | History | Annotate | Download | only in lambdadesugaring
      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 {
     13     String foo();
     14   }
     15 
     16   interface V {
     17     void foo();
     18   }
     19 
     20   interface VT<T> {
     21     void foo(T t);
     22   }
     23 
     24   interface P1<X> {
     25     X foo(int i);
     26   }
     27 
     28   interface I2 extends I {
     29   }
     30 
     31   interface I3 {
     32     String foo();
     33   }
     34 
     35   interface M1 {
     36   }
     37 
     38   interface M2 {
     39   }
     40 
     41   interface J {
     42     String foo(String a, int b, boolean c);
     43   }
     44 
     45   interface G {
     46     A foo();
     47   }
     48 
     49   interface H<T extends A> {
     50     T foo(T o);
     51   }
     52 
     53   interface K {
     54     Object foo(String a, String b, String c);
     55   }
     56 
     57   interface ObjectProvider {
     58     Object act();
     59   }
     60 
     61   interface S2Z {
     62     boolean foo(String a);
     63   }
     64 
     65   interface SS2Z {
     66     boolean foo(String a, String b);
     67   }
     68 
     69   interface ArrayTransformerA<T> {
     70     T[] transform(T[] a);
     71   }
     72 
     73   @SuppressWarnings("unchecked")
     74   interface ArrayTransformerB<T> {
     75     T[] transform(T... a);
     76   }
     77 
     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 
     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 
     99   static void atA(ArrayTransformerA<Integer> f) {
    100     print(f.transform(new Integer[] { 1, 2, 3 }));
    101   }
    102 
    103   static void atB(ArrayTransformerB<String> f) {
    104     print(f.transform("A", "B", "C"));
    105   }
    106 
    107   public static String staticUnused() {
    108     return "ReleaseTests::staticUnused";
    109   }
    110 
    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 
    120     A(String toString) {
    121       this.toString = toString;
    122     }
    123 
    124     @Override
    125     public String toString() {
    126       return toString;
    127     }
    128   }
    129 
    130   class B extends A {
    131     B(String toString) {
    132       super(toString);
    133     }
    134   }
    135 
    136   class C extends B {
    137     C(String toString) {
    138       super(toString);
    139     }
    140   }
    141 
    142   class D extends C {
    143     D(String toString) {
    144       super(toString);
    145     }
    146   }
    147 
    148   public static class Refs {
    149     public static String f(I i) {
    150       return i.foo();
    151     }
    152 
    153     public static void v(V v) {
    154       v.foo();
    155     }
    156 
    157     public static void vt(VT<String> v) {
    158       v.foo(null);
    159     }
    160 
    161     public static String p1(P1 p) {
    162       return p.foo(123).getClass().getCanonicalName();
    163     }
    164 
    165     public static String pSS2Z(SS2Z p) {
    166       return "" + p.foo("123", "321");
    167     }
    168 
    169     public static String pS2Z(S2Z p) {
    170       return "" + p.foo("123");
    171     }
    172 
    173     public static String p3(K k) {
    174       return k.foo("A", "B", "C").toString();
    175     }
    176 
    177     public static String g(ObjectProvider op) {
    178       return op.act().toString();
    179     }
    180 
    181     static class A extends OtherRefs {
    182       String fooInternal() {
    183         return "Refs::A::fooInternal()";
    184       }
    185 
    186       protected String fooProtected() {
    187         return "Refs::A::fooProtected()";
    188       }
    189 
    190       protected String fooProtectedOverridden() {
    191         return "Refs::A::fooProtectedOverridden()";
    192       }
    193 
    194       protected static String staticProtected() {
    195         return "Refs::A::staticProtected()";
    196       }
    197 
    198       static String staticInternal() {
    199         return "Refs::A::staticInternal()";
    200       }
    201     }
    202 
    203     public static class B extends A {
    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 
    251       private static String staticPrivate() {
    252         return "Refs::B::staticPrivate()";
    253       }
    254 
    255       private String fooPrivate() {
    256         return "Refs::B::fooPrivate()";
    257       }
    258 
    259       String fooInternal() {
    260         return "Refs::B::fooInternal()";
    261       }
    262 
    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
    274       protected String fooProtectedOverridden() {
    275         return "Refs::B::fooProtectedOverridden()";
    276       }
    277 
    278       public String fooPublic() {
    279         return "Refs::B::fooPublic()";
    280       }
    281 
    282       static int[] staticArray(int size) {
    283         return new int[size];
    284       }
    285     }
    286 
    287     static class D {
    288       D() {
    289         System.out.println("Refs::D::init()");
    290       }
    291     }
    292 
    293     public static class ProtectedInit extends OtherRefs.PublicInit {
    294       protected ProtectedInit() {
    295       }
    296 
    297       static String testProtected() {
    298         return g(ProtectedInit::new);
    299       }
    300 
    301       @Override
    302       public String toString() {
    303         return "OtherRefs::ProtectedInit::init()";
    304       }
    305     }
    306 
    307     static class InternalInit extends ProtectedInit {
    308       InternalInit() {
    309       }
    310 
    311       @Override
    312       public String toString() {
    313         return "Refs::InternalInit::init()";
    314       }
    315     }
    316 
    317     static class PrivateInit extends InternalInit {
    318       private PrivateInit() {
    319       }
    320 
    321       static String testPrivate() {
    322         return g(PrivateInit::new);
    323       }
    324 
    325       @Override
    326       public String toString() {
    327         return "Refs::PrivateInit::init()";
    328       }
    329     }
    330   }
    331 
    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 
    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 
    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 
    382   public void testInstanceLambdaMethods() {
    383     Integer i = 12345;
    384     System.out.println(h(() -> new A("{testInstanceLambdaMethods:" + i + "}")));
    385   }
    386 
    387   @SuppressWarnings("unchecked")
    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 
    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 
    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 
    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 
    430   public String f(I i) {
    431     return i.foo();
    432   }
    433 
    434   String g(J j, String a, int b, boolean c) {
    435     return j.foo(a, b, c);
    436   }
    437 
    438   String h(G g) {
    439     return g.foo().toString();
    440   }
    441 
    442   String i(H<B> h) {
    443     return h.foo(new B("i(H<B>)")).toString();
    444   }
    445 
    446   <T extends I2 & M1 & M2 & I3> String j(T l) {
    447     return ((I3) ((M2) ((M1) (((I2) l))))).foo();
    448   }
    449 
    450   static <T> void k(Legacy.BI<T> i, T v) {
    451     System.out.println(i.foo(v).toString());
    452   }
    453 
    454   static I statelessLambda() {
    455     return InstanceAndClassChecks::staticProvider;
    456   }
    457 
    458   static I statefulLambda() {
    459     return InstanceAndClassChecks.INSTANCE::instanceProvider;
    460   }
    461 
    462   static class InstanceAndClassChecks {
    463     static final InstanceAndClassChecks INSTANCE = new InstanceAndClassChecks();
    464 
    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 
    484     public static String staticProvider() {
    485       return "staticProvider";
    486     }
    487 
    488     public String instanceProvider() {
    489       return "instanceProvider";
    490     }
    491 
    492     static void assertSameInstance(I a, I b, String msg) {
    493       if (a != b) {
    494         throw new AssertionError(msg);
    495       }
    496     }
    497 
    498     static void assertDifferentInstance(I a, I b, String msg) {
    499       if (a == b) {
    500         throw new AssertionError(msg);
    501       }
    502     }
    503   }
    504 
    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 
    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