From 4ca90e9c68d11ee88a48d348fbef1b726e4d9061 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 5 Dec 2013 12:51:18 +0400 Subject: [PATCH] Proper instructions for elvis operator We should not mark elvis operator unused, for the rhs may have desired side-effects --- .../jet/lang/cfg/JetControlFlowBuilder.java | 1 + .../jet/lang/cfg/JetControlFlowProcessor.java | 5 ++-- .../cfg/deadCode/returnInElvis.instructions | 1 + compiler/testData/cfg/lastElvis.instructions | 23 +++++++++++++++++++ compiler/testData/cfg/lastElvis.kt | 3 +++ .../tests/controlFlowAnalysis/unusedElvis.kt | 9 ++++++++ .../jet/cfg/ControlFlowTestGenerated.java | 5 ++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++++ 8 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/cfg/lastElvis.instructions create mode 100644 compiler/testData/cfg/lastElvis.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/unusedElvis.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 00ca48cc64a..c745046792c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -101,6 +101,7 @@ public interface JetControlFlowBuilder { enum PredefinedOperation { AND, OR, + ELVIS, NOT_NULL_ASSERTION } void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 630f6704bc5..653a7931992 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -250,7 +250,7 @@ public class JetControlFlowProcessor { public void visitBinaryExpression(@NotNull JetBinaryExpression expression) { JetSimpleNameExpression operationReference = expression.getOperationReference(); 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); } JetExpression right = expression.getRight(); @@ -296,13 +296,14 @@ public class JetControlFlowProcessor { generateBothArguments(expression); } } - else if (operationType == ELVIS) { + else if (operationType == JetTokens.ELVIS) { generateInstructions(expression.getLeft(), false); Label afterElvis = builder.createUnboundLabel(); builder.jumpOnTrue(afterElvis); if (right != null) { generateInstructions(right, false); } + builder.predefinedOperation(expression, JetControlFlowBuilder.PredefinedOperation.ELVIS); builder.bindLabel(afterElvis); } else if (operationType == JetTokens.EQEQ || operationType == JetTokens.EXCLEQ) { diff --git a/compiler/testData/cfg/deadCode/returnInElvis.instructions b/compiler/testData/cfg/deadCode/returnInElvis.instructions index 2c55d538e82..0dd426eef03 100644 --- a/compiler/testData/cfg/deadCode/returnInElvis.instructions +++ b/compiler/testData/cfg/deadCode/returnInElvis.instructions @@ -9,6 +9,7 @@ L0: ret L1 NEXT:[] - jt(L2) NEXT:[r(null), ] PREV:[] - r(null) PREV:[] +- r(return ?: null) PREV:[] L1: L2: NEXT:[] PREV:[ret L1] diff --git a/compiler/testData/cfg/lastElvis.instructions b/compiler/testData/cfg/lastElvis.instructions new file mode 100644 index 00000000000..6391da3c1bc --- /dev/null +++ b/compiler/testData/cfg/lastElvis.instructions @@ -0,0 +1,23 @@ +== test == +fun test(a: Any?) { + a ?: "" +} +--------------------- +L0: + + v(a: Any?) + w(a) + mark({ a ?: "" }) + r(a) + jt(L2) NEXT:[mark(""), ] + mark("") + r("") + r(a ?: "") +L1: +L2: + NEXT:[] PREV:[jt(L2), r(a ?: "")] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/lastElvis.kt b/compiler/testData/cfg/lastElvis.kt new file mode 100644 index 00000000000..a9ef878c05c --- /dev/null +++ b/compiler/testData/cfg/lastElvis.kt @@ -0,0 +1,3 @@ +fun test(a: Any?) { + a ?: "" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unusedElvis.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unusedElvis.kt new file mode 100644 index 00000000000..bd95cc90596 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unusedElvis.kt @@ -0,0 +1,9 @@ +fun foo(a: Any?) { + a ?: "" +} + +fun foo1(a: Any?) { + a ?: sideEffect() +} + +fun sideEffect() {} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index 7d1c4ea9293..3e26e1d106e 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -142,6 +142,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { doTest("compiler/testData/cfg/invoke.kt"); } + @TestMetadata("lastElvis.kt") + public void testLastElvis() throws Exception { + doTest("compiler/testData/cfg/lastElvis.kt"); + } + @TestMetadata("LazyBooleans.kt") public void testLazyBooleans() throws Exception { doTest("compiler/testData/cfg/LazyBooleans.kt"); diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 9445d48dba8..4e2e2c71912 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1572,6 +1572,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage 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")