Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5b68b92
quick wip
niloc132 Nov 25, 2025
262b13b
Vaguely functional implementation, except for switches
niloc132 Nov 26, 2025
95174ed
A little more clean up, all samples build cleanly
niloc132 Nov 26, 2025
6b603e7
Don't try to move {}s, better java gen, fix a js bug
niloc132 Nov 27, 2025
2938c74
Checkpoint, user tests pass but compiler fails
niloc132 Nov 27, 2025
de87228
More consistent output, still have a small size regression (inlining?)
niloc132 Nov 30, 2025
3f3c0f2
Try to restore ExpandBlocks, more problems found
niloc132 Nov 30, 2025
4a64133
Nearly correct impl of ExpandBlocks
niloc132 Dec 1, 2025
2786f4b
Cleanup dead code
niloc132 Jan 4, 2026
fdc0352
Remove the 'expand blocks' experiment
niloc132 Jan 28, 2026
bd9638b
break long line
niloc132 Jan 28, 2026
d3b0503
Update tests to drop extra braces when unnecessary
niloc132 Jan 29, 2026
b4cb9d5
Defensively add {}s to JS ifs
niloc132 Jan 30, 2026
c0fa094
Improved version of adding necessary braces
niloc132 Jan 30, 2026
48e32a9
checkstyle
niloc132 Jan 30, 2026
446049a
Drop Java 11 support
niloc132 Jan 30, 2026
8a8cf18
Compute total size of samples correctly
zbynek Jan 31, 2026
cb19126
Include deferred size in compilation report
zbynek Jan 31, 2026
0beeb84
Merge remote-tracking branch 'pr/10263' into 10239-if-child-blocks-test
niloc132 Feb 1, 2026
021fed8
Merge branch 'main' into 10239-if-child-blocks-test
niloc132 Feb 14, 2026
459f301
fix java ast dump to avoid dangling else
niloc132 Feb 15, 2026
6f26726
do/for/while support
niloc132 Feb 15, 2026
cb302b2
if's else can never be null, fixed other tests
niloc132 Feb 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/full-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java-version: [ '11', '17', '21', '22' ]
java-version: [ '17', '21', '22' ]
steps:
- name: Checkout GWT itself into one directory
uses: actions/checkout@v6
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/quick-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
fail-fast: false
matrix:
java-version: ['11', '17', '21', '22']
java-version: ['17', '21', '22']
steps:
- name: Checkout GWT itself into one directory
uses: actions/checkout@v6
Expand Down
2 changes: 1 addition & 1 deletion dev/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<target name="compile.tests" depends="build, compile.emma.if.enabled, build.alldeps.jar"
description="Compiles the test code for this project">
<gwt.javac srcdir="" destdir="${javac.junit.out}">
<gwt.javac srcdir="" destdir="${javac.junit.out}" release="17">
<src path="core/src"/>
<src path="core/test"/>
<classpath>
Expand Down
25 changes: 25 additions & 0 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ public JBlock(SourceInfo info, JStatement... statements) {
this.statements.addAll(Arrays.asList(statements));
}

public static JBlock ensureBlock(SourceInfo info, JStatement statement) {
if (statement == null) {
return new JBlock(info);
}
if (statement instanceof JBlock) {
return (JBlock) statement;
}

return new JBlock(statement.getSourceInfo(), statement);
}

/**
* Insert a statement into this block.
*/
Expand Down Expand Up @@ -105,4 +116,18 @@ public boolean unconditionalControlBreak() {
}
return false;
}

public JStatement singleStatement() {
if (statements.isEmpty()) {
return null;
}
if (statements.size() == 1) {
JStatement jStatement = statements.get(0);
if (jStatement instanceof JBlock) {
return ((JBlock) jStatement).singleStatement();
}
return jStatement;
}
return this;
}
}
10 changes: 4 additions & 6 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JDoStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@
*/
public class JDoStatement extends JStatement {

private JStatement body;
private JBlock body;
private JExpression testExpr;

public JDoStatement(SourceInfo info, JExpression testExpr, JStatement body) {
super(info);
this.testExpr = testExpr;
this.body = body;
this.body = JBlock.ensureBlock(info, body);
}

public JStatement getBody() {
public JBlock getBody() {
return body;
}

Expand All @@ -43,9 +43,7 @@ public JExpression getTestExpr() {
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
testExpr = visitor.accept(testExpr);
if (body != null) {
body = visitor.accept(body, true);
}
body = JBlock.ensureBlock(getSourceInfo(), visitor.accept(body, false));
}
visitor.endVisit(this, ctx);
}
Expand Down
10 changes: 4 additions & 6 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/
public class JForStatement extends JStatement {

private JStatement body;
private JBlock body;
private List<JStatement> initializers;
private JExpression condition;
private JExpression increments;
Expand All @@ -40,13 +40,13 @@
this.initializers = Lists.newArrayList(initializers);
this.condition = condition;
this.increments = increments;
this.body = body;
this.body = JBlock.ensureBlock(info, body);
}

/**
* Returns the {@code for} statement body.
*/
public JStatement getBody() {
public JBlock getBody() {
return body;
}

Expand Down Expand Up @@ -81,9 +81,7 @@
if (increments != null) {
increments = visitor.accept(increments);
}
if (body != null) {
body = visitor.accept(body, true);
}
body = JBlock.ensureBlock(getSourceInfo(), visitor.accept(body, false));//TODO no tests fail without this change...

Check warning on line 84 in dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java

View workflow job for this annotation

GitHub Actions / build (21)

[checkstyle] reported by reviewdog 🐶 Line is longer than 100 characters (found 121). Raw Output: /home/runner/work/gwt/gwt/gwt/dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java:84:0: warning: Line is longer than 100 characters (found 121). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
}
visitor.endVisit(this, ctx);
}
Expand Down
20 changes: 8 additions & 12 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JIfStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,35 @@
*/
public class JIfStatement extends JStatement {

private JStatement elseStmt;
private JBlock elseStmt;
private JExpression ifExpr;
private JStatement thenStmt;
private JBlock thenStmt;

public JIfStatement(SourceInfo info, JExpression ifExpr, JStatement thenStmt, JStatement elseStmt) {

Check warning on line 29 in dev/core/src/com/google/gwt/dev/jjs/ast/JIfStatement.java

View workflow job for this annotation

GitHub Actions / build (21)

[checkstyle] reported by reviewdog 🐶 Line is longer than 100 characters (found 102). Raw Output: /home/runner/work/gwt/gwt/gwt/dev/core/src/com/google/gwt/dev/jjs/ast/JIfStatement.java:29:0: warning: Line is longer than 100 characters (found 102). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
super(info);
this.ifExpr = ifExpr;
this.thenStmt = thenStmt;
this.elseStmt = elseStmt;
this.thenStmt = JBlock.ensureBlock(info, thenStmt);
this.elseStmt = JBlock.ensureBlock(info, elseStmt);
}

public JStatement getElseStmt() {
public JBlock getElseStmt() {
return elseStmt;
}

public JExpression getIfExpr() {
return ifExpr;
}

public JStatement getThenStmt() {
public JBlock getThenStmt() {
return thenStmt;
}

@Override
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
ifExpr = visitor.accept(ifExpr);
if (thenStmt != null) {
thenStmt = visitor.accept(thenStmt, true);
}
if (elseStmt != null) {
elseStmt = visitor.accept(elseStmt, true);
}
thenStmt = JBlock.ensureBlock(getSourceInfo(), visitor.accept(thenStmt, false));
elseStmt = JBlock.ensureBlock(getSourceInfo(), visitor.accept(elseStmt, false));
}
visitor.endVisit(this, ctx);
}
Expand Down
10 changes: 4 additions & 6 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JWhileStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@
*/
public class JWhileStatement extends JStatement {

private JStatement body;
private JBlock body;
private JExpression testExpr;

public JWhileStatement(SourceInfo info, JExpression testExpr, JStatement body) {
super(info);
this.testExpr = testExpr;
this.body = body;
this.body = JBlock.ensureBlock(info, body);
}

public JStatement getBody() {
public JBlock getBody() {
return body;
}

Expand All @@ -43,9 +43,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
testExpr = visitor.accept(testExpr);
if (body != null) {
body = visitor.accept(body, true);
}
body = JBlock.ensureBlock(getSourceInfo(), visitor.accept(body, false));//TODO no tests fail without this change...

Check warning on line 46 in dev/core/src/com/google/gwt/dev/jjs/ast/JWhileStatement.java

View workflow job for this annotation

GitHub Actions / build (21)

[checkstyle] reported by reviewdog 🐶 Line is longer than 100 characters (found 121). Raw Output: /home/runner/work/gwt/gwt/gwt/dev/core/src/com/google/gwt/dev/jjs/ast/JWhileStatement.java:46:0: warning: Line is longer than 100 characters (found 121). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
}
visitor.endVisit(this, ctx);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,17 +328,17 @@ public void endVisit(JDeclarationStatement x, Context ctx) {
}

/**
* Convert do { } while (false); into a block.
* Convert do { } while (false); into a block, or do { } while (true); into while(true) { }.
*/
@Override
public void endVisit(JDoStatement x, Context ctx) {
JExpression expression = x.getTestExpr();
if (expression instanceof JBooleanLiteral) {
JBooleanLiteral booleanLiteral = (JBooleanLiteral) expression;

// If false, replace do with do's body
if (!booleanLiteral.getValue()) {
if (JjsUtils.isEmptyBlock(x.getBody())) {
// If false, replace do with do's body
if (x.getBody().isEmpty()) {
ctx.removeMe();
} else { // Unless it contains break/continue statements
FindBreakContinueStatementsVisitor visitor = new FindBreakContinueStatementsVisitor();
Expand All @@ -347,6 +347,11 @@ public void endVisit(JDoStatement x, Context ctx) {
ctx.replaceMe(x.getBody());
}
}
// } else {
// // If true, replace with while(true) { body }
// JWhileStatement whileStatement = new JWhileStatement(x.getSourceInfo(), expression,
// x.getBody());
// ctx.replaceMe(whileStatement);
}
}
}
Expand Down Expand Up @@ -1964,10 +1969,8 @@ private void tryRemoveSwitch(JSwitchStatement x, Context ctx) {
} else {
// Create an if statement equivalent to the single-case switch.
JBinaryOperation compareOperation = caseStatement.convertToCompareExpression(x.getExpr());
JBlock block = new JBlock(x.getSourceInfo());
block.addStmt(statement);
JIfStatement ifStatement =
new JIfStatement(x.getSourceInfo(), compareOperation, block, null);
new JIfStatement(x.getSourceInfo(), compareOperation, statement, null);
replaceMe(ifStatement, ctx);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@
}

@Override
public JsStatement transformBlock(JBlock block) {
public JsBlock transformBlock(JBlock block) {
JsBlock jsBlock = new JsBlock(block.getSourceInfo());
List<JsStatement> stmts = jsBlock.getStatements();

Expand Down Expand Up @@ -692,7 +692,7 @@
public JsNode transformDoStatement(JDoStatement doStatement) {
JsDoWhile stmt = new JsDoWhile(doStatement.getSourceInfo());
stmt.setCondition(transform(doStatement.getTestExpr()));
stmt.setBody(jsEmptyIfNull(doStatement.getSourceInfo(), transform(doStatement.getBody())));
stmt.setBody(jsEmptyIfNull(doStatement.getSourceInfo(), transform(doStatement.getBody().singleStatement())));

Check warning on line 695 in dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java

View workflow job for this annotation

GitHub Actions / build (21)

[checkstyle] reported by reviewdog 🐶 Line is longer than 100 characters (found 115). Raw Output: /home/runner/work/gwt/gwt/gwt/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java:695:0: warning: Line is longer than 100 characters (found 115). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
return stmt;
}

Expand Down Expand Up @@ -742,7 +742,7 @@
result.setInitExpr(initExpr);
result.setCondition(transform(forStatement.getCondition()));
result.setIncrExpr(transform(forStatement.getIncrements()));
result.setBody(jsEmptyIfNull(forStatement.getSourceInfo(), transform(forStatement.getBody())));
result.setBody(jsEmptyIfNull(forStatement.getSourceInfo(), transform(forStatement.getBody().singleStatement())));

Check warning on line 745 in dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java

View workflow job for this annotation

GitHub Actions / build (21)

[checkstyle] reported by reviewdog 🐶 Line is longer than 100 characters (found 119). Raw Output: /home/runner/work/gwt/gwt/gwt/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java:745:0: warning: Line is longer than 100 characters (found 119). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)

return result;
}
Expand All @@ -753,8 +753,8 @@

result.setIfExpr(transform(ifStatement.getIfExpr()));
result.setThenStmt(jsEmptyIfNull(ifStatement.getSourceInfo(),
transform(ifStatement.getThenStmt())));
result.setElseStmt(transform(ifStatement.getElseStmt()));
transform(ifStatement.getThenStmt().singleStatement())));
result.setElseStmt(transform(ifStatement.getElseStmt().singleStatement()));

return result;
}
Expand Down Expand Up @@ -1168,7 +1168,7 @@
SourceInfo info = whileStatement.getSourceInfo();
JsWhile stmt = new JsWhile(info);
stmt.setCondition(transform(whileStatement.getTestExpr()));
stmt.setBody(jsEmptyIfNull(info, transform(whileStatement.getBody())));
stmt.setBody(jsEmptyIfNull(info, transform(whileStatement.getBody().singleStatement())));
return stmt;
}

Expand Down
4 changes: 2 additions & 2 deletions dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,8 @@ public JExpression apply(JStatement statement) {
public void endVisit(IfStatement x, BlockScope scope) {
try {
SourceInfo info = makeSourceInfo(x);
JStatement elseStatement = pop(x.elseStatement);
JStatement thenStatement = pop(x.thenStatement);
JBlock elseStatement = popBlock(info, x.elseStatement);
JBlock thenStatement = popBlock(info, x.thenStatement);
JExpression condition = pop(x.condition);
push(new JIfStatement(info, condition, thenStatement, elseStatement));
} catch (Throwable e) {
Expand Down
33 changes: 9 additions & 24 deletions dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ public static JExpression simplifyConditional(JConditional expression) {
public static JStatement simplifyIfStatement(JIfStatement ifStatement, JType methodReturnType) {
SourceInfo info = ifStatement.getSourceInfo();
JExpression conditionExpression = ifStatement.getIfExpr();
JStatement thenStmt = ifStatement.getThenStmt();
JStatement elseStmt = ifStatement.getElseStmt();
final JBlock thenStmt = ifStatement.getThenStmt();
final JBlock elseStmt = ifStatement.getElseStmt();
if (conditionExpression instanceof JMultiExpression) {
// if(a,b,c) d else e -> {a; b; if(c) d else e; }
JMultiExpression condMulti = (JMultiExpression) conditionExpression;
Expand All @@ -258,10 +258,10 @@ public static JStatement simplifyIfStatement(JIfStatement ifStatement, JType met

if (conditionExpression instanceof JBooleanLiteral) {
boolean conditionValue = ((JBooleanLiteral) conditionExpression).getValue();
if (conditionValue && !JjsUtils.isEmptyBlock(thenStmt)) {
if (conditionValue && !thenStmt.isEmpty()) {
// If true, replace myself with then statement
return thenStmt;
} else if (!conditionValue && !JjsUtils.isEmptyBlock(elseStmt)) {
} else if (!conditionValue && !elseStmt.isEmpty()) {
// If false, replace myself with else statement
return elseStmt;
} else {
Expand All @@ -270,19 +270,15 @@ public static JStatement simplifyIfStatement(JIfStatement ifStatement, JType met
}
}

if (JjsUtils.isEmptyBlock(thenStmt) && JjsUtils.isEmptyBlock(elseStmt)) {
if (thenStmt.isEmpty() && elseStmt.isEmpty()) {
return conditionExpression.makeStatement();
}

if (!JjsUtils.isEmptyBlock(elseStmt)) {
if (!elseStmt.isEmpty()) {
// if (!cond) foo else bar -> if (cond) bar else foo
JExpression negationArugment =
Simplifier.maybeGetNegatedExpressionArgument(conditionExpression);
if (negationArugment != null) {
// Force sub-parts to blocks, otherwise we break else-if chains.
// TODO: this goes away when we normalize the Java AST properly.
thenStmt = ensureBlock(thenStmt);
elseStmt = ensureBlock(elseStmt);
return simplifyIfStatement(
new JIfStatement(info, negationArugment, elseStmt, thenStmt), methodReturnType);
}
Expand Down Expand Up @@ -513,22 +509,11 @@ private static JExpression extractExpression(JStatement statement) {
return null;
}

private static JStatement extractSingleStatement(JStatement statement) {
if (statement instanceof JBlock) {
JBlock block = (JBlock) statement;
if (block.getStatements().size() == 1) {
return extractSingleStatement(block.getStatements().get(0));
}
}

return statement;
}

private static JStatement rewriteIfStatementAsExpression(SourceInfo sourceInfo,
JExpression conditionExpression, JStatement thenStmt, JStatement elseStmt,
JExpression conditionExpression, JBlock thenBlock, JBlock elseBlock,
JType methodReturnType) {
thenStmt = extractSingleStatement(thenStmt);
elseStmt = extractSingleStatement(elseStmt);
JStatement thenStmt = thenBlock.singleStatement();
JStatement elseStmt = elseBlock.singleStatement();

if (thenStmt instanceof JReturnStatement && elseStmt instanceof JReturnStatement
&& methodReturnType != null) {
Expand Down
Loading