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