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 c95b286a2cb..d9f95ee1b29 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -120,24 +120,41 @@ public class JetControlFlowProcessor { private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() { + private JetExpression getSubjectExpression(JetWhenCondition condition) { + JetWhenExpression whenExpression = PsiTreeUtil.getParentOfType(condition, JetWhenExpression.class); + return whenExpression != null ? whenExpression.getSubjectExpression() : null; + } + @Override public void visitWhenConditionInRange(@NotNull JetWhenConditionInRange condition) { - generateInstructions(condition.getRangeExpression()); - generateInstructions(condition.getOperationReference()); - - // TODO : read the call to contains()... - createNonSyntheticValue(condition, condition.getRangeExpression(), condition.getOperationReference()); + if (!generateCall(condition.getOperationReference())) { + JetExpression rangeExpression = condition.getRangeExpression(); + generateInstructions(rangeExpression); + createNonSyntheticValue(condition, rangeExpression); + } } @Override public void visitWhenConditionIsPattern(@NotNull JetWhenConditionIsPattern condition) { - // TODO: types in CF? + mark(condition); + createNonSyntheticValue(condition, getSubjectExpression(condition)); } @Override public void visitWhenConditionWithExpression(@NotNull JetWhenConditionWithExpression condition) { - generateInstructions(condition.getExpression()); - copyValue(condition.getExpression(), condition); + mark(condition); + + JetExpression expression = condition.getExpression(); + generateInstructions(expression); + + JetExpression subjectExpression = getSubjectExpression(condition); + if (subjectExpression != null) { + // todo: this can be replaced by equals() invocation (when corresponding resolved call is recorded) + createNonSyntheticValue(condition, subjectExpression, expression); + } + else { + copyValue(expression, condition); + } } @Override @@ -1254,19 +1271,14 @@ public class JetControlFlowProcessor { JetWhenCondition condition = conditions[i]; condition.accept(conditionVisitor); if (i + 1 < conditions.length) { - PseudoValue conditionValue = createSyntheticValue(condition, subjectExpression, condition); - builder.nondeterministicJump(bodyLabel, expression, conditionValue); + builder.nondeterministicJump(bodyLabel, expression, builder.getBoundValue(condition)); } } if (!isElse) { nextLabel = builder.createUnboundLabel(); - PseudoValue conditionValue = null; JetWhenCondition lastCondition = KotlinPackage.lastOrNull(conditions); - if (lastCondition != null) { - conditionValue = createSyntheticValue(lastCondition, subjectExpression, lastCondition); - } - builder.nondeterministicJump(nextLabel, expression, conditionValue); + builder.nondeterministicJump(nextLabel, expression, builder.getBoundValue(lastCondition)); } builder.bindLabel(bodyLabel); @@ -1515,7 +1527,9 @@ public class JetControlFlowProcessor { SmartFMap parameterValues) { JetExpression expression = valueArgument.getArgumentExpression(); if (expression != null) { - generateInstructions(expression); + if (!valueArgument.isExternal()) { + generateInstructions(expression); + } PseudoValue argValue = builder.getBoundValue(expression); if (argValue != null) { diff --git a/compiler/testData/cfg/controlStructures/returnsInWhen.instructions b/compiler/testData/cfg/controlStructures/returnsInWhen.instructions index 49d8226374a..1d7e70b7bff 100644 --- a/compiler/testData/cfg/controlStructures/returnsInWhen.instructions +++ b/compiler/testData/cfg/controlStructures/returnsInWhen.instructions @@ -14,6 +14,7 @@ L0: mark(when(a) { is Int -> return a }) r(a) -> mark(is Int -> return a) + mark(is Int) magic(is Int|) -> jmp?(L4|) NEXT:[, r(a) -> ] L3: diff --git a/compiler/testData/cfg/controlStructures/returnsInWhen.values b/compiler/testData/cfg/controlStructures/returnsInWhen.values index edef58283ef..8c6fb2241ec 100644 --- a/compiler/testData/cfg/controlStructures/returnsInWhen.values +++ b/compiler/testData/cfg/controlStructures/returnsInWhen.values @@ -5,8 +5,8 @@ fun illegalWhenBlock(a: Any): Any { } } --------------------- - : {<: Any} NEW: magic(a: Any) -> - : * NEW: magic(is Int|) -> -a : * NEW: r(a) -> -a : {<: Any} NEW: r(a) -> + : {<: Any} NEW: magic(a: Any) -> +a : * NEW: r(a) -> +is Int : * NEW: magic(is Int|) -> +a : {<: Any} NEW: r(a) -> ===================== diff --git a/compiler/testData/cfg/controlStructures/whenConditions.instructions b/compiler/testData/cfg/controlStructures/whenConditions.instructions new file mode 100644 index 00000000000..6cf42f7c0b0 --- /dev/null +++ b/compiler/testData/cfg/controlStructures/whenConditions.instructions @@ -0,0 +1,89 @@ +== foo == +fun foo(a: Number) { + val t = when (a) { + 1 -> "1" + in Collections.singleton(2) -> "2" + is Int -> "Int" + !in Collections.singleton(3) -> "!3" + !is Number -> "!Number" + else -> null + } +} +--------------------- +L0: + 1 + v(a: Number) + magic(a: Number) -> + w(a|) + 2 mark({ val t = when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null } }) + v(val t = when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }) + mark(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }) + r(a) -> + mark(1 -> "1") + mark(1) + r(1) -> + magic(1|, ) -> + jmp?(L4|) NEXT:[mark(in Collections.singleton(2) -> "2"), mark("1")] +L3: + mark("1") + r("1") -> + jmp(L2) NEXT:[merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> ] +L4: + mark(in Collections.singleton(2) -> "2") PREV:[jmp?(L4|)] + mark(Collections.singleton(2)) + r(2) -> + mark(singleton(2)) + call(singleton(2), singleton|) -> + mark(in Collections.singleton(2)) + call(in Collections.singleton(2), contains|, ) -> + jmp?(L6|) NEXT:[mark(is Int -> "Int"), mark("2")] +L5: + mark("2") + r("2") -> + jmp(L2) NEXT:[merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> ] +L6: + mark(is Int -> "Int") PREV:[jmp?(L6|)] + mark(is Int) + magic(is Int|) -> + jmp?(L8|) NEXT:[mark(!in Collections.singleton(3) -> "!3"), mark("Int")] +L7: + mark("Int") + r("Int") -> + jmp(L2) NEXT:[merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> ] +L8: + mark(!in Collections.singleton(3) -> "!3") PREV:[jmp?(L8|)] + mark(Collections.singleton(3)) + r(3) -> + mark(singleton(3)) + call(singleton(3), singleton|) -> + mark(!in Collections.singleton(3)) + call(!in Collections.singleton(3), contains|, ) -> + jmp?(L10|) NEXT:[mark(!is Number -> "!Number"), mark("!3")] +L9: + mark("!3") + r("!3") -> + jmp(L2) NEXT:[merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> ] +L10: + mark(!is Number -> "!Number") PREV:[jmp?(L10|)] + mark(!is Number) + magic(!is Number|) -> + jmp?(L12|) NEXT:[mark(else -> null), mark("!Number")] +L11: + mark("!Number") + r("!Number") -> + jmp(L2) NEXT:[merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> ] +L12: + mark(else -> null) PREV:[jmp?(L12|)] +L13: + r(null) -> + jmp(L2) +L2: + merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> PREV:[jmp(L2), jmp(L2), jmp(L2), jmp(L2), jmp(L2), jmp(L2)] + w(t|) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/controlStructures/whenConditions.kt b/compiler/testData/cfg/controlStructures/whenConditions.kt new file mode 100644 index 00000000000..6e499f92f84 --- /dev/null +++ b/compiler/testData/cfg/controlStructures/whenConditions.kt @@ -0,0 +1,12 @@ +import java.util.Collections + +fun foo(a: Number) { + val t = when (a) { + 1 -> "1" + in Collections.singleton(2) -> "2" + is Int -> "Int" + !in Collections.singleton(3) -> "!3" + !is Number -> "!Number" + else -> null + } +} \ No newline at end of file diff --git a/compiler/testData/cfg/controlStructures/whenConditions.values b/compiler/testData/cfg/controlStructures/whenConditions.values new file mode 100644 index 00000000000..f8498191f25 --- /dev/null +++ b/compiler/testData/cfg/controlStructures/whenConditions.values @@ -0,0 +1,34 @@ +== foo == +fun foo(a: Number) { + val t = when (a) { + 1 -> "1" + in Collections.singleton(2) -> "2" + is Int -> "Int" + !in Collections.singleton(3) -> "!3" + !is Number -> "!Number" + else -> null + } +} +--------------------- + : {<: Number} NEW: magic(a: Number) -> +a : AND{{<: Any?}, *} NEW: r(a) -> +1 : * NEW: r(1) -> +1 : * NEW: magic(1|, ) -> +"1" : {<: String?} NEW: r("1") -> +2 : {<: Int?} NEW: r(2) -> +singleton(2) : OR{{<: Collection}, {<: Collection}} NEW: call(singleton(2), singleton|) -> +Collections.singleton(2) : OR{{<: Collection}, {<: Collection}} COPY +in Collections.singleton(2) : * NEW: call(in Collections.singleton(2), contains|, ) -> +"2" : {<: String?} NEW: r("2") -> +is Int : * NEW: magic(is Int|) -> +"Int" : {<: String?} NEW: r("Int") -> +3 : {<: Int?} NEW: r(3) -> +singleton(3) : OR{{<: Collection}, {<: Collection}} NEW: call(singleton(3), singleton|) -> +Collections.singleton(3) : OR{{<: Collection}, {<: Collection}} COPY +!in Collections.singleton(3) : * NEW: call(!in Collections.singleton(3), contains|, ) -> +"!3" : {<: String?} NEW: r("!3") -> +!is Number : * NEW: magic(!is Number|) -> +"!Number" : {<: String?} NEW: r("!Number") -> +null : {<: String?} NEW: r(null) -> +when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null } : {<: String?} NEW: merge(when (a) { 1 -> "1" in Collections.singleton(2) -> "2" is Int -> "Int" !in Collections.singleton(3) -> "!3" !is Number -> "!Number" else -> null }|, , , , , ) -> +===================== diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index f9b2a86710b..8ec6caec2cd 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -147,6 +147,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { doTest("compiler/testData/cfg/controlStructures/returnsInWhen.kt"); } + @TestMetadata("whenConditions.kt") + public void testWhenConditions() throws Exception { + doTest("compiler/testData/cfg/controlStructures/whenConditions.kt"); + } + } @TestMetadata("compiler/testData/cfg/conventions") diff --git a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java index 3eb26661bab..3940cd4cce4 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java @@ -149,6 +149,11 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { doTest("compiler/testData/cfg/controlStructures/returnsInWhen.kt"); } + @TestMetadata("whenConditions.kt") + public void testWhenConditions() throws Exception { + doTest("compiler/testData/cfg/controlStructures/whenConditions.kt"); + } + } @TestMetadata("compiler/testData/cfg/conventions")