Turn off incorrect switch-optimization for when by enums

#KT-24708 Fixed
This commit is contained in:
Denis Zharkov
2018-08-09 16:34:32 +07:00
parent fc3c4ad883
commit c1cc722ac4
13 changed files with 181 additions and 11 deletions
@@ -959,11 +959,18 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
}
private boolean isWhenWithEnums(@NotNull KtWhenExpression expression) {
return WhenChecker.isWhenByEnum(expression, bindingContext) &&
switchCodegenProvider.checkAllItemsAreConstantsSatisfying(
expression,
constant -> constant instanceof EnumValue || constant instanceof NullValue
);
ClassId enumClassId = WhenChecker.getClassIdForEnumSubject(expression, bindingContext);
if (enumClassId == null) return false;
return switchCodegenProvider.checkAllItemsAreConstantsSatisfying(
expression,
constant -> isEnumEntryOrNull(enumClassId, constant)
);
}
private static boolean isEnumEntryOrNull(ClassId enumClassId, ConstantValue<?> constant) {
return (constant instanceof EnumValue && ((EnumValue) constant).getEnumClassId().equals(enumClassId)) ||
constant instanceof NullValue;
}
@NotNull
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import java.util.*
@@ -265,8 +266,12 @@ object WhenChecker {
)
@JvmStatic
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) =
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
fun getClassIdForEnumSubject(expression: KtWhenExpression, context: BindingContext) =
getClassIdForTypeIfEnum(whenSubjectType(expression, context))
@JvmStatic
fun getClassIdForTypeIfEnum(type: KotlinType?) =
getClassDescriptorOfTypeIfEnum(type)?.classId
@JvmStatic
fun getClassDescriptorOfTypeIfEnum(type: KotlinType?): ClassDescriptor? {
@@ -0,0 +1,27 @@
enum class A {
O, K
}
enum class B {
O, K
}
fun box(): String {
val a = A.O
val r1 = when (a) {
A.O -> "O"
A.K -> "K"
B.O -> "fail 1"
B.K -> "fail 2"
}
val b = B.K
val r2 = when (b) {
A.O -> "fail 3"
A.K -> "fail 4"
B.O -> "O"
B.K -> "K"
}
return r1 + r2
}
@@ -0,0 +1,16 @@
enum class A {
OK
}
enum class B {
FAIL
}
fun f() = A.OK
fun box(): String {
return when (f()) {
B.FAIL -> "fail"
A.OK -> "OK"
}
}
@@ -0,0 +1,30 @@
enum class A {
O, K
}
enum class B {
O, K
}
fun box(): String {
val a = A.O
val r1 = when (a) {
A.O -> "O"
A.K -> "K"
B.O -> "fail 1"
B.K -> "fail 2"
}
val b = B.K
val r2 = when (b) {
A.O -> "fail 3"
A.K -> "fail 4"
B.O -> "O"
B.K -> "K"
}
return r1 + r2
}
// 0 TABLESWITCH
// 0 LOOKUPSWITCH
@@ -0,0 +1,19 @@
enum class A {
OK
}
enum class B {
FAIL
}
fun f() = A.OK
fun box(): String {
return when (f()) {
B.FAIL -> "fail"
A.OK -> "OK"
}
}
// 0 TABLESWITCH
// 0 LOOKUPSWITCH
@@ -22739,6 +22739,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/when/enumOptimization/bigEnum.kt");
}
@TestMetadata("differentEnumClasses.kt")
public void testDifferentEnumClasses() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses.kt");
}
@TestMetadata("differentEnumClasses2.kt")
public void testDifferentEnumClasses2() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses2.kt");
}
@TestMetadata("duplicatingItems.kt")
public void testDuplicatingItems() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/duplicatingItems.kt");
@@ -2962,6 +2962,16 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/bigEnum.kt");
}
@TestMetadata("differentEnumClasses.kt")
public void testDifferentEnumClasses() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/differentEnumClasses.kt");
}
@TestMetadata("differentEnumClasses2.kt")
public void testDifferentEnumClasses2() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/differentEnumClasses2.kt");
}
@TestMetadata("duplicatingItems.kt")
public void testDuplicatingItems() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/duplicatingItems.kt");
@@ -22739,6 +22739,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/when/enumOptimization/bigEnum.kt");
}
@TestMetadata("differentEnumClasses.kt")
public void testDifferentEnumClasses() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses.kt");
}
@TestMetadata("differentEnumClasses2.kt")
public void testDifferentEnumClasses2() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses2.kt");
}
@TestMetadata("duplicatingItems.kt")
public void testDuplicatingItems() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/duplicatingItems.kt");
@@ -22739,6 +22739,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/when/enumOptimization/bigEnum.kt");
}
@TestMetadata("differentEnumClasses.kt")
public void testDifferentEnumClasses() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses.kt");
}
@TestMetadata("differentEnumClasses2.kt")
public void testDifferentEnumClasses2() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses2.kt");
}
@TestMetadata("duplicatingItems.kt")
public void testDuplicatingItems() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/duplicatingItems.kt");
@@ -20554,6 +20554,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/when/enumOptimization/bigEnum.kt");
}
@TestMetadata("differentEnumClasses.kt")
public void testDifferentEnumClasses() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses.kt");
}
@TestMetadata("differentEnumClasses2.kt")
public void testDifferentEnumClasses2() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses2.kt");
}
@TestMetadata("duplicatingItems.kt")
public void testDuplicatingItems() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/duplicatingItems.kt");
@@ -21619,6 +21619,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/when/enumOptimization/bigEnum.kt");
}
@TestMetadata("differentEnumClasses.kt")
public void testDifferentEnumClasses() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses.kt");
}
@TestMetadata("differentEnumClasses2.kt")
public void testDifferentEnumClasses2() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/differentEnumClasses2.kt");
}
@TestMetadata("duplicatingItems.kt")
public void testDuplicatingItems() throws Exception {
runTest("compiler/testData/codegen/box/when/enumOptimization/duplicatingItems.kt");
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.js.translate.expression
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.WhenChecker
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -208,11 +209,16 @@ private constructor(private val whenExpression: KtWhenExpression, context: Trans
entries: List<KtWhenEntry>,
expectedType: KotlinType
): Pair<List<EntryWithConstants>, Int> {
val classId = WhenChecker.getClassIdForTypeIfEnum(expectedType)
return collectConstantEntries(
fromIndex, entries,
{ (it.toConstantValue(expectedType) as? EnumValue)?.enumEntryName?.identifier },
{ uniqueEnumNames.add(it) },
{ JsStringLiteral(it) }
fromIndex, entries,
{
(it.toConstantValue(expectedType) as? EnumValue)
?.takeIf { enumEntry -> enumEntry.enumClassId == classId }
?.enumEntryName?.identifier
},
{ uniqueEnumNames.add(it) },
{ JsStringLiteral(it) }
)
}