Skip to content

Commit d2fdc7f

Browse files
Alexey AndreevAlexey Andreev
Alexey Andreev
authored and
Alexey Andreev
committed
JS: when both clauses of if become empty during optimization, remove if entirely. Make condition and then clause of JsIf non-nullable. Fix #KT-13912
1 parent b535812 commit d2fdc7f

File tree

11 files changed

+134
-24
lines changed

11 files changed

+134
-24
lines changed

js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsIf.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,55 @@
66

77
import com.google.dart.compiler.util.AstUtil;
88
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
910

1011
/**
1112
* Represents a JavaScript if statement.
1213
*/
1314
public final class JsIf extends SourceInfoAwareJsNode implements JsStatement {
15+
@NotNull
1416
private JsExpression ifExpression;
17+
18+
@NotNull
1519
private JsStatement thenStatement;
16-
private JsStatement elseStatement;
1720

18-
public JsIf() {
19-
}
21+
@Nullable
22+
private JsStatement elseStatement;
2023

21-
public JsIf(JsExpression ifExpression, JsStatement thenStatement, JsStatement elseStatement) {
24+
public JsIf(@NotNull JsExpression ifExpression, @NotNull JsStatement thenStatement, @Nullable JsStatement elseStatement) {
2225
this.ifExpression = ifExpression;
2326
this.thenStatement = thenStatement;
2427
this.elseStatement = elseStatement;
2528
}
2629

27-
public JsIf(JsExpression ifExpression, JsStatement thenStatement) {
28-
this.ifExpression = ifExpression;
29-
this.thenStatement = thenStatement;
30+
public JsIf(@NotNull JsExpression ifExpression, @NotNull JsStatement thenStatement) {
31+
this(ifExpression, thenStatement, null);
3032
}
3133

34+
@Nullable
3235
public JsStatement getElseStatement() {
3336
return elseStatement;
3437
}
3538

39+
@NotNull
3640
public JsExpression getIfExpression() {
3741
return ifExpression;
3842
}
3943

44+
@NotNull
4045
public JsStatement getThenStatement() {
4146
return thenStatement;
4247
}
4348

44-
public void setElseStatement(JsStatement elseStatement) {
49+
public void setElseStatement(@Nullable JsStatement elseStatement) {
4550
this.elseStatement = elseStatement;
4651
}
4752

48-
public void setIfExpression(JsExpression ifExpression) {
53+
public void setIfExpression(@NotNull JsExpression ifExpression) {
4954
this.ifExpression = ifExpression;
5055
}
5156

52-
public void setThenStatement(JsStatement thenStatement) {
57+
public void setThenStatement(@NotNull JsStatement thenStatement) {
5358
this.thenStatement = thenStatement;
5459
}
5560

js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/RedundantLabelRemoval.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,21 @@ internal class RedundantLabelRemoval(private val root: JsStatement) {
100100
}
101101
is JsIf -> {
102102
val thenRemoved = perform(statement.thenStatement, name) == null
103-
val elseRemoved = statement.elseStatement?.let { perform(it, name) == null } ?: false
103+
val elseStatement = statement.elseStatement
104+
val elseRemoved = elseStatement?.let { perform(it, name) == null } ?: false
104105
when {
105-
thenRemoved && elseRemoved -> null
106+
thenRemoved && (elseRemoved || elseStatement == null) -> {
107+
hasChanges = true
108+
JsAstUtils.asSyntheticStatement(statement.ifExpression)
109+
}
106110
elseRemoved -> {
107111
hasChanges = true
108112
statement.elseStatement = null
109113
statement
110114
}
111115
thenRemoved -> {
112116
hasChanges = true
113-
statement.thenStatement = statement.elseStatement
117+
statement.thenStatement = elseStatement ?: JsEmpty
114118
statement.elseStatement = null
115119
statement.ifExpression = JsAstUtils.not(statement.ifExpression)
116120
statement

js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -630,16 +630,7 @@ private JsIf mapIfStatement(Node ifNode) throws JsParserException {
630630

631631
// Create the "if" statement we're mapping to.
632632
//
633-
JsIf toIf = new JsIf();
634-
635-
// Map the test expression.
636-
//
637-
JsExpression toTestExpr = mapExpression(fromTestExpr);
638-
toIf.setIfExpression(toTestExpr);
639-
640-
// Map the "then" block.
641-
//
642-
toIf.setThenStatement(mapStatement(fromThenBlock));
633+
JsIf toIf = new JsIf(mapExpression(fromTestExpr), mapStatement(fromThenBlock));
643634

644635
// Map the "else" block.
645636
//

js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/BasicOptimizerTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ abstract class BasicOptimizerTest(private var basePath: String) {
108108
}
109109
super.visitIf(x)
110110
}
111+
112+
override fun visitLabel(x: JsLabel) {
113+
x.synthetic = isSyntheticId(x.name.ident)
114+
super.visitLabel(x)
115+
}
111116
}.accept(stmt)
112117
}
113118
}
@@ -119,7 +124,6 @@ abstract class BasicOptimizerTest(private var basePath: String) {
119124

120125
private fun isSyntheticId(id: String) = id.startsWith("$")
121126

122-
123127
private fun astToString(ast: List<JsStatement>): String {
124128
val output = TextOutputImpl()
125129
val visitor = JsSourceGenerationVisitor(output, null)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2010-2016 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jetbrains.kotlin.js.test.optimizer
18+
19+
import org.junit.Test
20+
21+
class RedundantLabelRemovalTest : BasicOptimizerTest("redundant-label-removal") {
22+
@Test fun emptyIfConditionPreserved() = box()
23+
24+
@Test fun ifWithEmptyThenAndNoElse() = box()
25+
}

js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ public JsNode visitIfExpression(@NotNull KtIfExpression expression, @NotNull Tra
285285
return new JsConditional(testExpression, jsThenExpression, jsElseExpression).source(expression);
286286
}
287287
}
288+
if (thenStatement == null) {
289+
thenStatement = JsEmpty.INSTANCE;
290+
}
288291
JsIf ifStatement = new JsIf(testExpression, thenStatement, elseStatement);
289292
return ifStatement.source(expression);
290293
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var global = "";
2+
3+
function id(value) {
4+
global += value + ";";
5+
return value;
6+
}
7+
8+
function test(x) {
9+
id(x);
10+
id(x + 1);
11+
}
12+
13+
function box() {
14+
test(23);
15+
if (global != "23;24;") return "fail";
16+
return "OK";
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
var global = "";
2+
3+
function id(value) {
4+
global += value + ";";
5+
return value;
6+
}
7+
8+
function test(x) {
9+
$outer: {
10+
if (id(x) + id(x + 1) > 0) {
11+
break $outer;
12+
}
13+
else {
14+
break $outer;
15+
}
16+
}
17+
}
18+
19+
function box() {
20+
test(23);
21+
if (global != "23;24;") return "fail";
22+
return "OK";
23+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function test(x) {
2+
return "OK";
3+
}
4+
5+
function box() {
6+
return test(23);
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
function test(x) {
2+
$outer: {
3+
if (x > 10) {
4+
break $outer;
5+
}
6+
}
7+
return "OK";
8+
}
9+
10+
function box() {
11+
return test(23);
12+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package foo
2+
3+
fun test1(): String {
4+
run {
5+
if (false) {
6+
}
7+
}
8+
return "O"
9+
}
10+
11+
fun test2(): String {
12+
1.let {
13+
if (false) {
14+
}
15+
}
16+
return "K"
17+
}
18+
19+
fun box() = test1() + test2()

0 commit comments

Comments
 (0)