From bae93b46fc15c4aa5a85d7714b20c9ae3d52635f Mon Sep 17 00:00:00 2001 From: Colin Alworth 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;