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:
@@ -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>]
|
||||||
|
=====================
|
||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user