From bae93b46fc15c4aa5a85d7714b20c9ae3d52635f Mon Sep 17 00:00:00 2001
From: Colin Alworth <colin@vertispan.com>
Date: Fri, 13 Dec 2024 10:04:03 -0600
Subject: [PATCH] Support JDT's implicit yield in switch statements

JDT generates a yield for arrow cases if the arrow points at a
expression, even though the expression cannot be returned. Synthesize a
block wrapping that expression as a statement, and add a break to the
end of it.

Fixes #10044
---
 .../gwt/dev/jjs/impl/GwtAstBuilder.java       | 14 ++++--
 .../google/gwt/dev/jjs/test/Java17Test.java   | 46 +++++++++++++++++++
 .../google/gwt/dev/jjs/test/Java17Test.java   |  3 ++
 3 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 354d9cdb65..30397d4368 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -545,9 +545,17 @@ public void endVisit(BreakStatement x, BlockScope scope) {
     @Override
     public void endVisit(YieldStatement x, BlockScope scope) {
       try {
-        SourceInfo info = makeSourceInfo(x);
-        JExpression expression = pop(x.expression);
-        push(new JYieldStatement(info, expression));
+        if (x.switchExpression == null) {
+          // This is an implicit 'yield' in a case with an arrow - synthesize a break instead and
+          // wrap with a block so that the child count in JDT and GWT matches.
+          SourceInfo info = makeSourceInfo(x);
+          JExpression pop = pop(x.expression);
+          push(new JBlock(info, pop.makeStatement(), new JBreakStatement(info, null)));
+        } else {
+          SourceInfo info = makeSourceInfo(x);
+          JExpression expression = pop(x.expression);
+          push(new JYieldStatement(info, expression));
+        }
       } catch (Throwable e) {
         throw translateException(x, e);
       }
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java
index fc238a981b..90960b0a11 100644
--- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java
@@ -494,4 +494,50 @@ public void testInlinedStringConstantsInCase() {
     };
     assertEquals(4, value);
   }
+
+  // https://github.com/gwtproject/gwt/issues/10044
+  public void testCaseArrowLabelsVoidExpression() {
+    // Each switch is extracted to its own method to avoid the early return bug.
+    assertEquals("success", arrowWithVoidExpr());
+
+    // Arrow with non-void expr
+    assertEquals("success", arrowWithStringExpr());
+    assertEquals("success", arrowWithIntExpr());
+
+    // Arrow with a statement - doesn't fail as part of this bug. This exists to verify
+    // that JDT won't give us a yield with a statement somehow.
+    assertEquals("success", arrowWithStatement());
+  }
+
+  private static String arrowWithVoidExpr() {
+    switch(0) {
+      case 0 -> assertTrue(true);
+    };
+    return "success";
+  }
+
+  private static String arrowWithStringExpr() {
+    switch(0) {
+      case 0 -> new Object().toString();
+    };
+    return "success";
+  }
+
+  private static String arrowWithIntExpr() {
+    switch(0) {
+      case 0 -> new Object().hashCode();
+    };
+    return "success";
+  }
+
+  private static String arrowWithStatement() {
+    switch(0) {
+      case 0 -> {
+        if (true) {
+          new Object().toString();
+        }
+      }
+    };
+    return "success";
+  }
 }
diff --git a/user/test/com/google/gwt/dev/jjs/test/Java17Test.java b/user/test/com/google/gwt/dev/jjs/test/Java17Test.java
index 39e0253397..844ff25c38 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java17Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java17Test.java
@@ -121,6 +121,9 @@ public void testSwitchExprInlining() {
   public void testInlinedStringConstantsInCase() {
     assertFalse(isGwtSourceLevel17());
   }
+  public void testCaseArrowLabelsVoidExpression() {
+    assertFalse(isGwtSourceLevel17());
+  }
 
   private boolean isGwtSourceLevel17() {
     return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA17) >= 0;