Support subject variable in specialized code generators for 'when'

This commit is contained in:
Dmitry Petrov
2018-06-09 17:00:25 +03:00
parent 3528405666
commit 34b76a3718
17 changed files with 427 additions and 20 deletions
@@ -39,10 +39,9 @@ public class EnumSwitchCodegen extends SwitchCodegen {
}
@Override
protected void generateSubject() {
protected void generateSubjectValueToIndex() {
codegen.getState().getMappingsClassesForWhenByEnum().generateMappingsClassForExpression(expression);
super.generateSubject();
generateNullCheckIfNeeded();
v.getstatic(
@@ -41,4 +41,9 @@ public class IntegralConstantsSwitchCodegen extends SwitchCodegen {
putTransitionOnce(value, entryLabel);
}
@Override
protected void generateSubjectValueToIndex() {
// Do nothing: subject is an int value
}
}
@@ -68,15 +68,13 @@ public class StringSwitchCodegen extends SwitchCodegen {
}
@Override
protected void generateSubject() {
tempVarIndex = codegen.myFrameMap.enterTemp(subjectType);
super.generateSubject();
v.store(tempVarIndex, subjectType);
v.load(tempVarIndex, subjectType);
protected void generateSubjectValueToIndex() {
generateNullCheckIfNeeded();
tempVarIndex = codegen.myFrameMap.enterTemp(subjectType);
v.store(tempVarIndex, subjectType);
v.load(tempVarIndex, subjectType);
v.invokevirtual(
subjectType.getInternalName(),
"hashCode", HASH_CODE_METHOD_DESC, false
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.codegen.`when`
import org.jetbrains.kotlin.cfg.WhenChecker
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.ConstantValue
@@ -27,8 +29,16 @@ abstract class SwitchCodegen(
) {
protected val bindingContext: BindingContext = codegen.bindingContext
protected val subjectVariable = expression.subjectVariable
protected val subjectExpression = expression.subjectExpression ?: throw AssertionError("No subject expression: ${expression.text}")
protected val subjectKotlinType = WhenChecker.whenSubjectTypeWithoutSmartCasts(expression, bindingContext)
?: throw AssertionError("No subject type: ${expression}")
@JvmField
protected val subjectType = subjectType ?: codegen.expressionType(expression.subjectExpression)
protected val subjectType = subjectType ?: codegen.asmType(subjectKotlinType)
protected var subjectLocal = -1
protected val resultType: Type = if (isStatement) Type.VOID_TYPE else codegen.expressionType(expression)
@@ -56,7 +66,8 @@ abstract class SwitchCodegen(
// if there is no else-entry and it's statement then default --- endLabel
defaultLabel = if (hasElse || !isStatement || isExhaustive) elseLabel else endLabel
generateSubject()
generateSubjectValue()
generateSubjectValueToIndex()
generateSwitchInstructionByTransitionsTable()
@@ -105,19 +116,29 @@ abstract class SwitchCodegen(
}
/**
* Should generate int subject on top of the stack
* Default implementation just run codegen for actual subject of expression
* May also gen nullability check if needed
* Generates subject value on top of the stack.
* If the subject is a variable, it's stored and loaded.
*/
protected open fun generateSubject() {
codegen.gen(expression.subjectExpression, subjectType)
private fun generateSubjectValue() {
if (subjectVariable != null) {
val variableDescriptor = bindingContext[BindingContext.VARIABLE, subjectVariable]
?: throw AssertionError("Unresolved subject variable: $expression")
subjectLocal = codegen.frameMap.enter(variableDescriptor, subjectType)
codegen.visitProperty(subjectVariable, null)
StackValue.local(subjectLocal, subjectType).put(subjectType, codegen.v)
} else {
codegen.gen(subjectExpression, subjectType)
}
}
protected fun generateNullCheckIfNeeded() {
assert(expression.subjectExpression != null) { "subject expression can't be null" }
val subjectJetType = bindingContext.getType(expression.subjectExpression!!) ?: error("subject type can't be null (i.e. void)")
/**
* Given a subject value on stack (after [generateSubjectValue]),
* produces int value to be used in switch.
*/
protected abstract fun generateSubjectValueToIndex()
if (TypeUtils.isNullableType(subjectJetType)) {
protected fun generateNullCheckIfNeeded() {
if (TypeUtils.isNullableType(subjectKotlinType)) {
val nullEntryIndex = findNullEntryIndex(expression)
val nullLabel = if (nullEntryIndex == -1) defaultLabel else entryLabels[nullEntryIndex]
val notNullLabel = Label()
@@ -293,6 +293,16 @@ object WhenChecker {
}
}
fun whenSubjectTypeWithoutSmartCasts(expression: KtWhenExpression, context: BindingContext): KotlinType? {
val subjectVariable = expression.subjectVariable
val subjectExpression = expression.subjectExpression
return when {
subjectVariable != null -> context.get(VARIABLE, subjectVariable)?.type
subjectExpression != null -> context.getType(subjectExpression)
else -> null
}
}
@JvmStatic
fun getEnumMissingCases(
expression: KtWhenExpression,
@@ -0,0 +1,22 @@
// WITH_RUNTIME
val String.name get() = this
fun List<String>.normalize(): List<String> {
val list = ArrayList<String>(this.size)
for (str in this) {
when (str.name) {
"." -> {}
".." -> if (!list.isEmpty() && list.last().name != "..") list.removeAt(list.size - 1) else list.add(str)
else -> list.add(str)
}
}
return list
}
fun box(): String {
val xs = listOf("a", "b", ".", "..").normalize()
if (xs != listOf("a")) return "Fail: $xs"
return "OK"
}
@@ -0,0 +1,26 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
// WITH_RUNTIME
// IGNORE_BACKEND: JS
fun dense(x: Int): Int {
return when (val xx = x) {
-4 -> 9
-1 -> 10
0 -> x + 11
1 -> 12
4 -> 13
5 -> 14
6 -> 15
7 -> 16
8 -> 17
9 -> x + 9
else -> 19
}
}
fun box(): String {
var result = (-5..10).map(::dense).joinToString()
if (result != "19, 9, 19, 19, 10, 11, 12, 19, 19, 13, 14, 15, 16, 17, 18, 19") return "dense:" + result
return "OK"
}
@@ -0,0 +1,19 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
// WITH_RUNTIME
// IGNORE_BACKEND: JS
fun sparse(x: Int): Int {
return when (val xx = (x % 4) * 100) {
100 -> 1
200 -> xx / 100
300 -> 3
else -> 4
}
}
fun box(): String {
var result = (0..3).map(::sparse).joinToString()
if (result != "4, 1, 2, 3") return "sparse:" + result
return "OK"
}
@@ -0,0 +1,41 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
// WITH_RUNTIME
// IGNORE_BACKEND: JS
import kotlin.test.assertEquals
enum class Season {
WINTER,
SPRING,
SUMMER,
AUTUMN
}
fun bar1(x : Season) : String {
return when (val xx = x) {
Season.WINTER, Season.SPRING -> "winter_spring $xx"
Season.SUMMER -> "summer"
else -> "autumn"
}
}
fun bar2(x : Season) : String {
return when (val xx = x) {
Season.WINTER, Season.SPRING -> "winter_spring $xx"
Season.SUMMER -> "summer"
Season.AUTUMN -> "autumn"
}
}
fun box() : String {
assertEquals("winter_spring WINTER", bar1(Season.WINTER))
assertEquals("winter_spring SPRING", bar1(Season.SPRING))
assertEquals("summer", bar1(Season.SUMMER))
assertEquals("autumn", bar1(Season.AUTUMN))
assertEquals("winter_spring WINTER", bar2(Season.WINTER))
assertEquals("winter_spring SPRING", bar2(Season.SPRING))
assertEquals("summer", bar2(Season.SUMMER))
assertEquals("autumn", bar2(Season.AUTUMN))
return "OK"
}
@@ -0,0 +1,44 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
// WITH_RUNTIME
// IGNORE_BACKEND: JS
import kotlin.test.assertEquals
enum class Season {
WINTER,
SPRING,
SUMMER,
AUTUMN
}
fun foo1(x : Season?) : String {
when(val xx = x) {
Season.AUTUMN, Season.SPRING -> return "autumn_or_spring $xx";
Season.SUMMER, null -> return "summer_or_null $xx"
}
return "other"
}
fun foo2(x : Season?) : String {
when(val xx = x) {
Season.AUTUMN, Season.SPRING -> return "autumn_or_spring $xx";
Season.SUMMER -> return "summer"
}
return "other"
}
fun box() : String {
assertEquals("autumn_or_spring AUTUMN", foo1(Season.AUTUMN))
assertEquals("autumn_or_spring SPRING", foo1(Season.SPRING))
assertEquals("summer_or_null SUMMER", foo1(Season.SUMMER))
assertEquals("summer_or_null null", foo1(null))
assertEquals("autumn_or_spring AUTUMN", foo2(Season.AUTUMN))
assertEquals("autumn_or_spring SPRING", foo2(Season.SPRING))
assertEquals("summer", foo2(Season.SUMMER))
assertEquals("other", foo2(null))
return "OK"
}
@@ -0,0 +1,24 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
// WITH_RUNTIME
// IGNORE_BACKEND: JS
import kotlin.test.assertEquals
fun foo(x : String) : String {
return when (val xx = x) {
"abc", "cde" -> "1 $xx"
"efg", "ghi" -> "2 $xx"
else -> "other $xx"
}
}
fun box() : String {
assertEquals("1 abc", foo("abc"))
assertEquals("1 cde", foo("cde"))
assertEquals("2 efg", foo("efg"))
assertEquals("2 ghi", foo("ghi"))
assertEquals("other xyz", foo("xyz"))
return "OK"
}
@@ -21649,6 +21649,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testStatement() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/statement.kt");
}
@TestMetadata("temporaryVarInWhenByStringIsDisposedProperly.kt")
public void testTemporaryVarInWhenByStringIsDisposedProperly() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/temporaryVarInWhenByStringIsDisposedProperly.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/when/whenSubjectVariable")
@@ -21668,6 +21673,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/captureSubjectVariable.kt");
}
@TestMetadata("denseIntSwitchWithSubjectVariable.kt")
public void testDenseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/denseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("equalityWithSubjectVariable.kt")
public void testEqualityWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/equalityWithSubjectVariable.kt");
@@ -21692,6 +21702,26 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testRangeCheckOnSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/rangeCheckOnSubjectVariable.kt");
}
@TestMetadata("sparseIntSwitchWithSubjectVariable.kt")
public void testSparseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/sparseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("whenByEnum.kt")
public void testWhenByEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByEnum.kt");
}
@TestMetadata("whenByNullableEnum.kt")
public void testWhenByNullableEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByNullableEnum.kt");
}
@TestMetadata("whenByString.kt")
public void testWhenByString() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByString.kt");
}
}
}
}
@@ -22520,6 +22520,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.kt");
}
@TestMetadata("smartcastToSealed.kt")
public void testSmartcastToSealed() throws Exception {
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.kt");
}
@TestMetadata("softModifierName.kt")
public void testSoftModifierName() throws Exception {
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/softModifierName.kt");
@@ -21649,6 +21649,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testStatement() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/statement.kt");
}
@TestMetadata("temporaryVarInWhenByStringIsDisposedProperly.kt")
public void testTemporaryVarInWhenByStringIsDisposedProperly() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/temporaryVarInWhenByStringIsDisposedProperly.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/when/whenSubjectVariable")
@@ -21668,6 +21673,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/captureSubjectVariable.kt");
}
@TestMetadata("denseIntSwitchWithSubjectVariable.kt")
public void testDenseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/denseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("equalityWithSubjectVariable.kt")
public void testEqualityWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/equalityWithSubjectVariable.kt");
@@ -21692,6 +21702,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testRangeCheckOnSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/rangeCheckOnSubjectVariable.kt");
}
@TestMetadata("sparseIntSwitchWithSubjectVariable.kt")
public void testSparseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/sparseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("whenByEnum.kt")
public void testWhenByEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByEnum.kt");
}
@TestMetadata("whenByNullableEnum.kt")
public void testWhenByNullableEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByNullableEnum.kt");
}
@TestMetadata("whenByString.kt")
public void testWhenByString() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByString.kt");
}
}
}
}
@@ -21649,6 +21649,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testStatement() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/statement.kt");
}
@TestMetadata("temporaryVarInWhenByStringIsDisposedProperly.kt")
public void testTemporaryVarInWhenByStringIsDisposedProperly() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/temporaryVarInWhenByStringIsDisposedProperly.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/when/whenSubjectVariable")
@@ -21668,6 +21673,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/captureSubjectVariable.kt");
}
@TestMetadata("denseIntSwitchWithSubjectVariable.kt")
public void testDenseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/denseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("equalityWithSubjectVariable.kt")
public void testEqualityWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/equalityWithSubjectVariable.kt");
@@ -21692,6 +21702,26 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testRangeCheckOnSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/rangeCheckOnSubjectVariable.kt");
}
@TestMetadata("sparseIntSwitchWithSubjectVariable.kt")
public void testSparseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/sparseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("whenByEnum.kt")
public void testWhenByEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByEnum.kt");
}
@TestMetadata("whenByNullableEnum.kt")
public void testWhenByNullableEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByNullableEnum.kt");
}
@TestMetadata("whenByString.kt")
public void testWhenByString() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByString.kt");
}
}
}
}
@@ -20664,6 +20664,79 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
public void testStatement() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/statement.kt");
}
@TestMetadata("temporaryVarInWhenByStringIsDisposedProperly.kt")
public void testTemporaryVarInWhenByStringIsDisposedProperly() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/temporaryVarInWhenByStringIsDisposedProperly.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/when/whenSubjectVariable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class WhenSubjectVariable extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInWhenSubjectVariable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/when/whenSubjectVariable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
}
@TestMetadata("captureSubjectVariable.kt")
public void testCaptureSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/captureSubjectVariable.kt");
}
@TestMetadata("denseIntSwitchWithSubjectVariable.kt")
public void testDenseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/denseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("equalityWithSubjectVariable.kt")
public void testEqualityWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/equalityWithSubjectVariable.kt");
}
@TestMetadata("ieee754Equality.kt")
public void testIeee754Equality() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/ieee754Equality.kt");
}
@TestMetadata("ieee754EqualityWithSmartCast.kt")
public void testIeee754EqualityWithSmartCast() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/ieee754EqualityWithSmartCast.kt");
}
@TestMetadata("isCheckOnSubjectVariable.kt")
public void testIsCheckOnSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/isCheckOnSubjectVariable.kt");
}
@TestMetadata("rangeCheckOnSubjectVariable.kt")
public void testRangeCheckOnSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/rangeCheckOnSubjectVariable.kt");
}
@TestMetadata("sparseIntSwitchWithSubjectVariable.kt")
public void testSparseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/sparseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("whenByEnum.kt")
public void testWhenByEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByEnum.kt");
}
@TestMetadata("whenByNullableEnum.kt")
public void testWhenByNullableEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByNullableEnum.kt");
}
@TestMetadata("whenByString.kt")
public void testWhenByString() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByString.kt");
}
}
}
}
@@ -19542,6 +19542,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testStatement() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/statement.kt");
}
@TestMetadata("temporaryVarInWhenByStringIsDisposedProperly.kt")
public void testTemporaryVarInWhenByStringIsDisposedProperly() throws Exception {
runTest("compiler/testData/codegen/box/when/stringOptimization/temporaryVarInWhenByStringIsDisposedProperly.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/when/whenSubjectVariable")
@@ -19561,6 +19566,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/captureSubjectVariable.kt");
}
@TestMetadata("denseIntSwitchWithSubjectVariable.kt")
public void testDenseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/denseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("equalityWithSubjectVariable.kt")
public void testEqualityWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/equalityWithSubjectVariable.kt");
@@ -19585,6 +19595,26 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testRangeCheckOnSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/rangeCheckOnSubjectVariable.kt");
}
@TestMetadata("sparseIntSwitchWithSubjectVariable.kt")
public void testSparseIntSwitchWithSubjectVariable() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/sparseIntSwitchWithSubjectVariable.kt");
}
@TestMetadata("whenByEnum.kt")
public void testWhenByEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByEnum.kt");
}
@TestMetadata("whenByNullableEnum.kt")
public void testWhenByNullableEnum() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByNullableEnum.kt");
}
@TestMetadata("whenByString.kt")
public void testWhenByString() throws Exception {
runTest("compiler/testData/codegen/box/when/whenSubjectVariable/whenByString.kt");
}
}
}
}