Proper instructions for elvis operator

We should not mark elvis operator unused, for the rhs may have desired side-effects
This commit is contained in:
Andrey Breslav
2013-12-05 12:51:18 +04:00
parent 3629a539e4
commit 4ca90e9c68
8 changed files with 50 additions and 2 deletions
@@ -101,6 +101,7 @@ public interface JetControlFlowBuilder {
enum PredefinedOperation { enum PredefinedOperation {
AND, AND,
OR, OR,
ELVIS,
NOT_NULL_ASSERTION NOT_NULL_ASSERTION
} }
void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation); void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation);
@@ -250,7 +250,7 @@ public class JetControlFlowProcessor {
public void visitBinaryExpression(@NotNull JetBinaryExpression expression) { public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
JetSimpleNameExpression operationReference = expression.getOperationReference(); JetSimpleNameExpression operationReference = expression.getOperationReference();
IElementType operationType = operationReference.getReferencedNameElementType(); IElementType operationType = operationReference.getReferencedNameElementType();
if (!ImmutableSet.of(ANDAND, OROR, EQ, ELVIS).contains(operationType)) { if (!ImmutableSet.of(ANDAND, OROR, EQ, JetTokens.ELVIS).contains(operationType)) {
mark(expression); mark(expression);
} }
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
@@ -296,13 +296,14 @@ public class JetControlFlowProcessor {
generateBothArguments(expression); generateBothArguments(expression);
} }
} }
else if (operationType == ELVIS) { else if (operationType == JetTokens.ELVIS) {
generateInstructions(expression.getLeft(), false); generateInstructions(expression.getLeft(), false);
Label afterElvis = builder.createUnboundLabel(); Label afterElvis = builder.createUnboundLabel();
builder.jumpOnTrue(afterElvis); builder.jumpOnTrue(afterElvis);
if (right != null) { if (right != null) {
generateInstructions(right, false); generateInstructions(right, false);
} }
builder.predefinedOperation(expression, JetControlFlowBuilder.PredefinedOperation.ELVIS);
builder.bindLabel(afterElvis); builder.bindLabel(afterElvis);
} }
else if (operationType == JetTokens.EQEQ || operationType == JetTokens.EXCLEQ) { else if (operationType == JetTokens.EQEQ || operationType == JetTokens.EXCLEQ) {
@@ -9,6 +9,7 @@ L0:
ret L1 NEXT:[<END>] ret L1 NEXT:[<END>]
- jt(L2) NEXT:[r(null), <END>] PREV:[] - jt(L2) NEXT:[r(null), <END>] PREV:[]
- r(null) PREV:[] - r(null) PREV:[]
- r(return ?: null) PREV:[]
L1: L1:
L2: L2:
<END> NEXT:[<SINK>] PREV:[ret L1] <END> NEXT:[<SINK>] PREV:[ret L1]
@@ -0,0 +1,23 @@
== test ==
fun test(a: Any?) {
a ?: ""
}
---------------------
L0:
<START>
v(a: Any?)
w(a)
mark({ a ?: "" })
r(a)
jt(L2) NEXT:[mark(""), <END>]
mark("")
r("")
r(a ?: "")
L1:
L2:
<END> NEXT:[<SINK>] PREV:[jt(L2), r(a ?: "")]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
+3
View File
@@ -0,0 +1,3 @@
fun test(a: Any?) {
a ?: ""
}
@@ -0,0 +1,9 @@
fun foo(a: Any?) {
a ?: ""
}
fun foo1(a: Any?) {
a ?: sideEffect()
}
fun sideEffect() {}
@@ -142,6 +142,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
doTest("compiler/testData/cfg/invoke.kt"); doTest("compiler/testData/cfg/invoke.kt");
} }
@TestMetadata("lastElvis.kt")
public void testLastElvis() throws Exception {
doTest("compiler/testData/cfg/lastElvis.kt");
}
@TestMetadata("LazyBooleans.kt") @TestMetadata("LazyBooleans.kt")
public void testLazyBooleans() throws Exception { public void testLazyBooleans() throws Exception {
doTest("compiler/testData/cfg/LazyBooleans.kt"); doTest("compiler/testData/cfg/LazyBooleans.kt");
@@ -1572,6 +1572,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt"); doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt");
} }
@TestMetadata("unusedElvis.kt")
public void testUnusedElvis() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/unusedElvis.kt");
}
} }
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures") @TestMetadata("compiler/testData/diagnostics/tests/controlStructures")