diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index a396fe13af7..0ab5093cfee 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -4513,11 +4513,12 @@ The "returned" value of try expression with no finally is either the last expres int subjectLocal; Type subjectType; + VariableDescriptor subjectVariableDescriptor = null; if (subjectVariable != null) { - VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, subjectVariable); - assert variableDescriptor != null : "Unresolved subject variable: " + subjectVariable.getName(); - subjectType = asmType(variableDescriptor.getType()); - subjectLocal = myFrameMap.enter(variableDescriptor, subjectType); + subjectVariableDescriptor = bindingContext.get(BindingContext.VARIABLE, subjectVariable); + assert subjectVariableDescriptor != null : "Unresolved subject variable: " + subjectVariable.getName(); + subjectType = asmType(subjectVariableDescriptor.getType()); + subjectLocal = myFrameMap.enter(subjectVariableDescriptor, subjectType); visitProperty(subjectVariable, null); tempVariables.put(subjectExpression, StackValue.local(subjectLocal, subjectType)); } @@ -4533,6 +4534,9 @@ The "returned" value of try expression with no finally is either the last expres subjectType = Type.VOID_TYPE; } + Label begin = new Label(); + v.mark(begin); + Label end = new Label(); boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression); @@ -4572,7 +4576,16 @@ The "returned" value of try expression with no finally is either the last expres markLineNumber(expression, isStatement); v.mark(end); - myFrameMap.leaveTemp(subjectType); + if (subjectVariableDescriptor != null) { + myFrameMap.leave(subjectVariableDescriptor); + v.visitLocalVariable( + subjectVariableDescriptor.getName().asString(), subjectType.getDescriptor(), null, + begin, end, subjectLocal + ); + } + else { + myFrameMap.leaveTemp(subjectType); + } tempVariables.remove(subjectExpression); return null; }); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.kt index 127011500d1..c3e0483ccd3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.kt @@ -8,6 +8,7 @@ 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.descriptors.VariableDescriptor import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.constants.ConstantValue @@ -69,6 +70,9 @@ abstract class SwitchCodegen( generateSubjectValue() generateSubjectValueToIndex() + val beginLabel = Label() + v.mark(beginLabel) + generateSwitchInstructionByTransitionsTable() generateEntries() @@ -81,6 +85,13 @@ abstract class SwitchCodegen( codegen.markLineNumber(expression, isStatement) v.mark(endLabel) + + subjectVariableDescriptor?.let { + v.visitLocalVariable( + it.name.asString(), subjectType.descriptor, null, + beginLabel, endLabel, subjectLocal + ) + } } /** @@ -115,19 +126,23 @@ abstract class SwitchCodegen( } } + private var subjectVariableDescriptor: VariableDescriptor? = null + /** * Generates subject value on top of the stack. * If the subject is a variable, it's stored and loaded. */ private fun generateSubjectValue() { if (subjectVariable != null) { - val variableDescriptor = bindingContext[BindingContext.VARIABLE, subjectVariable] + val mySubjectVariable = bindingContext[BindingContext.VARIABLE, subjectVariable] ?: throw AssertionError("Unresolved subject variable: $expression") - subjectLocal = codegen.frameMap.enter(variableDescriptor, subjectType) + subjectLocal = codegen.frameMap.enter(mySubjectVariable, subjectType) codegen.visitProperty(subjectVariable, null) StackValue.local(subjectLocal, subjectType).put(subjectType, codegen.v) + subjectVariableDescriptor = mySubjectVariable } else { codegen.gen(subjectExpression, subjectType) + subjectVariableDescriptor = null } } diff --git a/compiler/testData/codegen/bytecodeText/when/subjectValHasLocalVariableSlot.kt b/compiler/testData/codegen/bytecodeText/when/subjectValHasLocalVariableSlot.kt new file mode 100644 index 00000000000..ae5af7c4904 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/when/subjectValHasLocalVariableSlot.kt @@ -0,0 +1,10 @@ +// !LANGUAGE: +VariableDeclarationInWhenSubject + +fun test(a: Any) = + when (val subject = a) { + is Int -> "Int $subject" + is String -> "String ${subject.length}" + else -> "other" + } + +// 1 LOCALVARIABLE subject Ljava/lang/Object; \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/when/subjectValInEnumWhenHasLocalVariableSlot.kt b/compiler/testData/codegen/bytecodeText/when/subjectValInEnumWhenHasLocalVariableSlot.kt new file mode 100644 index 00000000000..92ac4dddb16 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/when/subjectValInEnumWhenHasLocalVariableSlot.kt @@ -0,0 +1,12 @@ +// !LANGUAGE: +VariableDeclarationInWhenSubject + +enum class X { A, B, C } + +fun test(a: X) = + when (val subject = a) { + X.A -> 0 + X.B -> 1 + X.C -> 2 + } + +// 1 LOCALVARIABLE subject \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/when/subjectValInIntWhenHasLocalVariableSlot.kt b/compiler/testData/codegen/bytecodeText/when/subjectValInIntWhenHasLocalVariableSlot.kt new file mode 100644 index 00000000000..ef48b2ba679 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/when/subjectValInIntWhenHasLocalVariableSlot.kt @@ -0,0 +1,11 @@ +// !LANGUAGE: +VariableDeclarationInWhenSubject + +fun test(a: Int) = + when (val subject = a) { + 1 -> 0 + 2 -> 1 + 3 -> 2 + else -> -1 + } + +// 1 LOCALVARIABLE subject \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/when/subjectValInStringWhenHasLocalVariableSlot.kt b/compiler/testData/codegen/bytecodeText/when/subjectValInStringWhenHasLocalVariableSlot.kt new file mode 100644 index 00000000000..5a772606690 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/when/subjectValInStringWhenHasLocalVariableSlot.kt @@ -0,0 +1,10 @@ +// !LANGUAGE: +VariableDeclarationInWhenSubject + +fun test(a: String) = + when (val subject = a) { + "" -> 0 + "a" -> 1 + else -> -1 + } + +// 1 LOCALVARIABLE subject \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 511fc528d25..c93fb61a2d8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -2811,6 +2811,26 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/when/simpleConstValsInsideWhen.kt"); } + @TestMetadata("subjectValHasLocalVariableSlot.kt") + public void testSubjectValHasLocalVariableSlot() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/when/subjectValHasLocalVariableSlot.kt"); + } + + @TestMetadata("subjectValInEnumWhenHasLocalVariableSlot.kt") + public void testSubjectValInEnumWhenHasLocalVariableSlot() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/when/subjectValInEnumWhenHasLocalVariableSlot.kt"); + } + + @TestMetadata("subjectValInIntWhenHasLocalVariableSlot.kt") + public void testSubjectValInIntWhenHasLocalVariableSlot() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/when/subjectValInIntWhenHasLocalVariableSlot.kt"); + } + + @TestMetadata("subjectValInStringWhenHasLocalVariableSlot.kt") + public void testSubjectValInStringWhenHasLocalVariableSlot() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/when/subjectValInStringWhenHasLocalVariableSlot.kt"); + } + @TestMetadata("whenNull.kt") public void testWhenNull() throws Exception { runTest("compiler/testData/codegen/bytecodeText/when/whenNull.kt");