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