Generate debug information for 'when' subject variable
NB debugger tests currently don't support language version or individual language feature settings.
This commit is contained in:
@@ -4513,11 +4513,12 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
|
|
||||||
int subjectLocal;
|
int subjectLocal;
|
||||||
Type subjectType;
|
Type subjectType;
|
||||||
|
VariableDescriptor subjectVariableDescriptor = null;
|
||||||
if (subjectVariable != null) {
|
if (subjectVariable != null) {
|
||||||
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, subjectVariable);
|
subjectVariableDescriptor = bindingContext.get(BindingContext.VARIABLE, subjectVariable);
|
||||||
assert variableDescriptor != null : "Unresolved subject variable: " + subjectVariable.getName();
|
assert subjectVariableDescriptor != null : "Unresolved subject variable: " + subjectVariable.getName();
|
||||||
subjectType = asmType(variableDescriptor.getType());
|
subjectType = asmType(subjectVariableDescriptor.getType());
|
||||||
subjectLocal = myFrameMap.enter(variableDescriptor, subjectType);
|
subjectLocal = myFrameMap.enter(subjectVariableDescriptor, subjectType);
|
||||||
visitProperty(subjectVariable, null);
|
visitProperty(subjectVariable, null);
|
||||||
tempVariables.put(subjectExpression, StackValue.local(subjectLocal, subjectType));
|
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;
|
subjectType = Type.VOID_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label begin = new Label();
|
||||||
|
v.mark(begin);
|
||||||
|
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression);
|
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);
|
markLineNumber(expression, isStatement);
|
||||||
v.mark(end);
|
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);
|
tempVariables.remove(subjectExpression);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen.`when`
|
|||||||
import org.jetbrains.kotlin.cfg.WhenChecker
|
import org.jetbrains.kotlin.cfg.WhenChecker
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
import org.jetbrains.kotlin.psi.KtWhenExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
@@ -69,6 +70,9 @@ abstract class SwitchCodegen(
|
|||||||
generateSubjectValue()
|
generateSubjectValue()
|
||||||
generateSubjectValueToIndex()
|
generateSubjectValueToIndex()
|
||||||
|
|
||||||
|
val beginLabel = Label()
|
||||||
|
v.mark(beginLabel)
|
||||||
|
|
||||||
generateSwitchInstructionByTransitionsTable()
|
generateSwitchInstructionByTransitionsTable()
|
||||||
|
|
||||||
generateEntries()
|
generateEntries()
|
||||||
@@ -81,6 +85,13 @@ abstract class SwitchCodegen(
|
|||||||
|
|
||||||
codegen.markLineNumber(expression, isStatement)
|
codegen.markLineNumber(expression, isStatement)
|
||||||
v.mark(endLabel)
|
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.
|
* Generates subject value on top of the stack.
|
||||||
* If the subject is a variable, it's stored and loaded.
|
* If the subject is a variable, it's stored and loaded.
|
||||||
*/
|
*/
|
||||||
private fun generateSubjectValue() {
|
private fun generateSubjectValue() {
|
||||||
if (subjectVariable != null) {
|
if (subjectVariable != null) {
|
||||||
val variableDescriptor = bindingContext[BindingContext.VARIABLE, subjectVariable]
|
val mySubjectVariable = bindingContext[BindingContext.VARIABLE, subjectVariable]
|
||||||
?: throw AssertionError("Unresolved subject variable: $expression")
|
?: throw AssertionError("Unresolved subject variable: $expression")
|
||||||
subjectLocal = codegen.frameMap.enter(variableDescriptor, subjectType)
|
subjectLocal = codegen.frameMap.enter(mySubjectVariable, subjectType)
|
||||||
codegen.visitProperty(subjectVariable, null)
|
codegen.visitProperty(subjectVariable, null)
|
||||||
StackValue.local(subjectLocal, subjectType).put(subjectType, codegen.v)
|
StackValue.local(subjectLocal, subjectType).put(subjectType, codegen.v)
|
||||||
|
subjectVariableDescriptor = mySubjectVariable
|
||||||
} else {
|
} else {
|
||||||
codegen.gen(subjectExpression, subjectType)
|
codegen.gen(subjectExpression, subjectType)
|
||||||
|
subjectVariableDescriptor = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
@@ -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;
|
||||||
+12
@@ -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
|
||||||
+11
@@ -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
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// !LANGUAGE: +VariableDeclarationInWhenSubject
|
||||||
|
|
||||||
|
fun test(a: String) =
|
||||||
|
when (val subject = a) {
|
||||||
|
"" -> 0
|
||||||
|
"a" -> 1
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 LOCALVARIABLE subject
|
||||||
@@ -2811,6 +2811,26 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/when/simpleConstValsInsideWhen.kt");
|
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")
|
@TestMetadata("whenNull.kt")
|
||||||
public void testWhenNull() throws Exception {
|
public void testWhenNull() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/when/whenNull.kt");
|
runTest("compiler/testData/codegen/bytecodeText/when/whenNull.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user