[IR] Improve stepping/LVT behavior around destructuring
This commit is contained in:
committed by
Alexander Udalov
parent
c3dbb44e5f
commit
7f531d8426
+6
@@ -313,6 +313,12 @@ public class FirSteppingTestGenerated extends AbstractFirSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
|
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("localProperty.kt")
|
||||||
|
public void testLocalProperty() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/localProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("multilineExpression.kt")
|
@TestMetadata("multilineExpression.kt")
|
||||||
public void testMultilineExpression() throws Exception {
|
public void testMultilineExpression() throws Exception {
|
||||||
|
|||||||
+4
-1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.config.languageVersionSettings
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
|
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
|
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||||
@@ -24,7 +25,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||||
@@ -252,4 +252,7 @@ open class JvmGeneratorExtensionsImpl(
|
|||||||
|
|
||||||
override val parametersAreAssignable: Boolean
|
override val parametersAreAssignable: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
|
override val debugInfoOnlyOnVariablesInDestructuringDeclarations: Boolean
|
||||||
|
get() = true
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -722,10 +722,10 @@ private class TypeOperatorLowering(private val backendContext: JvmBackendContext
|
|||||||
val source = if (owner is IrFunction && owner.isDelegated()) {
|
val source = if (owner is IrFunction && owner.isDelegated()) {
|
||||||
"${owner.name.asString()}(...)"
|
"${owner.name.asString()}(...)"
|
||||||
} else {
|
} else {
|
||||||
val (startOffset, endOffset) = expression.extents()
|
|
||||||
val declarationParent = parent as? IrDeclaration
|
val declarationParent = parent as? IrDeclaration
|
||||||
val sourceView = declarationParent?.let(::sourceViewFor)
|
val sourceView = declarationParent?.let(::sourceViewFor)
|
||||||
if (sourceView != null && startOffset >= 0 && endOffset < sourceView.length) {
|
val (startOffset, endOffset) = expression.extents()
|
||||||
|
if (sourceView?.validSourcePosition(startOffset, endOffset) == true) {
|
||||||
sourceView.subSequence(startOffset, endOffset).toString()
|
sourceView.subSequence(startOffset, endOffset).toString()
|
||||||
} else {
|
} else {
|
||||||
// Fallback for inconsistent line numbers
|
// Fallback for inconsistent line numbers
|
||||||
@@ -757,6 +757,9 @@ private class TypeOperatorLowering(private val backendContext: JvmBackendContext
|
|||||||
origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR ||
|
origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR ||
|
||||||
origin == IrDeclarationOrigin.DELEGATED_MEMBER
|
origin == IrDeclarationOrigin.DELEGATED_MEMBER
|
||||||
|
|
||||||
|
private fun CharSequence.validSourcePosition(startOffset: Int, endOffset: Int): Boolean =
|
||||||
|
startOffset in 0 until endOffset && endOffset < length
|
||||||
|
|
||||||
private fun IrElement.extents(): Pair<Int, Int> {
|
private fun IrElement.extents(): Pair<Int, Int> {
|
||||||
var startOffset = Int.MAX_VALUE
|
var startOffset = Int.MAX_VALUE
|
||||||
var endOffset = 0
|
var endOffset = 0
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class BodyGenerator(
|
|||||||
valueParameter.type.toIrType(),
|
valueParameter.type.toIrType(),
|
||||||
IrStatementOrigin.DESTRUCTURING_DECLARATION
|
IrStatementOrigin.DESTRUCTURING_DECLARATION
|
||||||
)
|
)
|
||||||
statementGenerator.declareComponentVariablesInBlock(ktDestructuringDeclaration, irBlockBody, parameterValue)
|
statementGenerator.declareComponentVariablesInBlock(ktDestructuringDeclaration, irBlockBody, parameterValue, parameterValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
val ktBodyStatements = ktBody.statements
|
val ktBodyStatements = ktBody.statements
|
||||||
|
|||||||
@@ -463,8 +463,14 @@ fun IrExpression.isUnchanging() =
|
|||||||
|
|
||||||
fun IrExpression.hasNoSideEffects() = isUnchanging() || this is IrGetValue
|
fun IrExpression.hasNoSideEffects() = isUnchanging() || this is IrGetValue
|
||||||
|
|
||||||
fun CallGenerator.generateCall(ktElement: KtElement, call: CallBuilder, origin: IrStatementOrigin? = null) =
|
fun CallGenerator.generateCall(
|
||||||
generateCall(ktElement.startOffsetSkippingComments, ktElement.endOffset, call, origin)
|
ktElement: KtElement,
|
||||||
|
call: CallBuilder,
|
||||||
|
origin: IrStatementOrigin? = null,
|
||||||
|
startOffset: Int = ktElement.startOffsetSkippingComments,
|
||||||
|
endOffset: Int = ktElement.endOffset,
|
||||||
|
) =
|
||||||
|
generateCall(startOffset, endOffset, call, origin)
|
||||||
|
|
||||||
fun CallGenerator.generateCall(irExpression: IrExpression, call: CallBuilder, origin: IrStatementOrigin? = null) =
|
fun CallGenerator.generateCall(irExpression: IrExpression, call: CallBuilder, origin: IrStatementOrigin? = null) =
|
||||||
generateCall(irExpression.startOffset, irExpression.endOffset, call, origin)
|
generateCall(irExpression.startOffset, irExpression.endOffset, call, origin)
|
||||||
|
|||||||
+31
@@ -48,4 +48,35 @@ open class GeneratorExtensions : StubGeneratorExtensions() {
|
|||||||
|
|
||||||
open val parametersAreAssignable: Boolean
|
open val parametersAreAssignable: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables improved source offsets for the desugared IR generated for
|
||||||
|
* destructuring declarations.
|
||||||
|
*
|
||||||
|
* Local variables defined by destructuring, e.g.
|
||||||
|
*
|
||||||
|
* val (x, y) = destructee()
|
||||||
|
*
|
||||||
|
* is represented in IR by
|
||||||
|
*
|
||||||
|
* block {
|
||||||
|
* val containerTmp = destructee()
|
||||||
|
* val x = containerTmp.component1()
|
||||||
|
* val y = containerTmp.component2()
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* When [debugInfoOnlyOnVariablesInDestructuringDeclarations] is `false`, the
|
||||||
|
* access to `containerTmp` in the calls to `component` calls are given source
|
||||||
|
* positions corresponding to `destructee()` which causes multi-line
|
||||||
|
* destructuring declarations to step back and forth between the variables being
|
||||||
|
* declared and the right-hand side, implying the repeated evaluation of the
|
||||||
|
* right-hand side.
|
||||||
|
*
|
||||||
|
* When `true`, only the stores to `x` and `y` in the generated code are are
|
||||||
|
* given source offsets, the source offsets of `x` and `y` in the original
|
||||||
|
* declaration, giving fewer, more accurate steps, that are closer to the JVM
|
||||||
|
* backend in behavior.
|
||||||
|
*/
|
||||||
|
open val debugInfoOnlyOnVariablesInDestructuringDeclarations: Boolean
|
||||||
|
get() = false
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
@@ -202,10 +203,16 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
|
|||||||
irInnerBody.statements.add(irLoopParameter)
|
irInnerBody.statements.add(irLoopParameter)
|
||||||
|
|
||||||
if (ktLoopDestructuringDeclaration != null) {
|
if (ktLoopDestructuringDeclaration != null) {
|
||||||
|
val firstContainerValue = VariableLValue(context, irLoopParameter)
|
||||||
statementGenerator.declareComponentVariablesInBlock(
|
statementGenerator.declareComponentVariablesInBlock(
|
||||||
ktLoopDestructuringDeclaration,
|
ktLoopDestructuringDeclaration,
|
||||||
irInnerBody,
|
irInnerBody,
|
||||||
VariableLValue(context, irLoopParameter)
|
firstContainerValue,
|
||||||
|
if (context.extensions.debugInfoOnlyOnVariablesInDestructuringDeclarations) {
|
||||||
|
VariableLValue(context, irLoopParameter, startOffset = SYNTHETIC_OFFSET, endOffset = SYNTHETIC_OFFSET)
|
||||||
|
} else {
|
||||||
|
firstContainerValue
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+60
-13
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.backend.common.BackendException
|
import org.jetbrains.kotlin.backend.common.BackendException
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.util.referenceFunction
|
import org.jetbrains.kotlin.ir.util.referenceFunction
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -32,7 +34,8 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
||||||
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue
|
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.createTemporaryVariableInBlock
|
import org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue
|
||||||
|
import org.jetbrains.kotlin.psi2ir.intermediate.declareTemporaryVariableInBlock
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST
|
import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST
|
||||||
@@ -110,8 +113,14 @@ class StatementGenerator(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val sourceElement =
|
||||||
|
if (context.extensions.debugInfoOnlyOnVariablesInDestructuringDeclarations) {
|
||||||
|
property.nameIdentifier ?: property
|
||||||
|
} else {
|
||||||
|
property
|
||||||
|
}
|
||||||
return context.symbolTable.declareVariable(
|
return context.symbolTable.declareVariable(
|
||||||
property.startOffsetSkippingComments, property.endOffset, IrDeclarationOrigin.DEFINED,
|
sourceElement.startOffsetSkippingComments, sourceElement.endOffset, IrDeclarationOrigin.DEFINED,
|
||||||
variableDescriptor,
|
variableDescriptor,
|
||||||
variableDescriptor.type.toIrType(),
|
variableDescriptor.type.toIrType(),
|
||||||
property.initializer?.let { generateExpression(it) }
|
property.initializer?.let { generateExpression(it) }
|
||||||
@@ -128,14 +137,31 @@ class StatementGenerator(
|
|||||||
.generateLocalDelegatedProperty(ktProperty, ktDelegate, variableDescriptor, scopeOwnerSymbol)
|
.generateLocalDelegatedProperty(ktProperty, ktDelegate, variableDescriptor, scopeOwnerSymbol)
|
||||||
|
|
||||||
override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Nothing?): IrStatement {
|
override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Nothing?): IrStatement {
|
||||||
|
val (blockStartOffset, blockEndOffset) = if (context.extensions.debugInfoOnlyOnVariablesInDestructuringDeclarations) {
|
||||||
|
SYNTHETIC_OFFSET to SYNTHETIC_OFFSET
|
||||||
|
} else {
|
||||||
|
multiDeclaration.startOffsetSkippingComments to multiDeclaration.endOffset
|
||||||
|
}
|
||||||
val irBlock = IrCompositeImpl(
|
val irBlock = IrCompositeImpl(
|
||||||
multiDeclaration.startOffsetSkippingComments, multiDeclaration.endOffset,
|
blockStartOffset, blockEndOffset,
|
||||||
context.irBuiltIns.unitType, IrStatementOrigin.DESTRUCTURING_DECLARATION
|
context.irBuiltIns.unitType, IrStatementOrigin.DESTRUCTURING_DECLARATION
|
||||||
)
|
)
|
||||||
val ktInitializer = multiDeclaration.initializer!!
|
val ktInitializer = multiDeclaration.initializer!!
|
||||||
val containerValue = scope.createTemporaryVariableInBlock(context, generateExpression(ktInitializer), irBlock, "container")
|
val irInitializer = generateExpression(ktInitializer)
|
||||||
|
|
||||||
declareComponentVariablesInBlock(multiDeclaration, irBlock, containerValue)
|
val containerVariable = scope.declareTemporaryVariableInBlock(irInitializer, irBlock, nameHint = "container")
|
||||||
|
|
||||||
|
val firstContainerValue = VariableLValue(context, containerVariable)
|
||||||
|
declareComponentVariablesInBlock(
|
||||||
|
multiDeclaration,
|
||||||
|
irBlock,
|
||||||
|
firstContainerValue,
|
||||||
|
if (context.extensions.debugInfoOnlyOnVariablesInDestructuringDeclarations) {
|
||||||
|
VariableLValue(context, containerVariable, startOffset = SYNTHETIC_OFFSET, endOffset = SYNTHETIC_OFFSET)
|
||||||
|
} else {
|
||||||
|
firstContainerValue
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
@@ -143,26 +169,47 @@ class StatementGenerator(
|
|||||||
fun declareComponentVariablesInBlock(
|
fun declareComponentVariablesInBlock(
|
||||||
multiDeclaration: KtDestructuringDeclaration,
|
multiDeclaration: KtDestructuringDeclaration,
|
||||||
irBlock: IrStatementContainer,
|
irBlock: IrStatementContainer,
|
||||||
containerValue: IntermediateValue
|
firstContainerValue: IntermediateValue,
|
||||||
|
restContainerValue: IntermediateValue
|
||||||
) {
|
) {
|
||||||
val callGenerator = CallGenerator(this)
|
val callGenerator = CallGenerator(this)
|
||||||
|
|
||||||
|
// TODO: Every access to the container value causes a null check even though subsequent checks after the first can be assumed to pass.
|
||||||
|
var containerValue = firstContainerValue
|
||||||
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
|
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
|
||||||
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
|
|
||||||
|
|
||||||
val componentSubstitutedCall = pregenerateCall(componentResolvedCall)
|
|
||||||
componentSubstitutedCall.setExplicitReceiverValue(containerValue)
|
|
||||||
|
|
||||||
val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry)
|
val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry)
|
||||||
|
|
||||||
// componentN for '_' SHOULD NOT be evaluated
|
// componentN for '_' SHOULD NOT be evaluated
|
||||||
if (componentVariable.name.isSpecial) continue
|
if (componentVariable.name.isSpecial) continue
|
||||||
|
|
||||||
|
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
|
||||||
|
val componentSubstitutedCall = pregenerateCall(componentResolvedCall)
|
||||||
|
|
||||||
|
componentSubstitutedCall.setExplicitReceiverValue(containerValue)
|
||||||
|
|
||||||
|
containerValue = restContainerValue
|
||||||
|
|
||||||
|
val (componentCallStartOffset, componentCallEndOffset) =
|
||||||
|
if (context.extensions.debugInfoOnlyOnVariablesInDestructuringDeclarations) {
|
||||||
|
SYNTHETIC_OFFSET to SYNTHETIC_OFFSET
|
||||||
|
} else {
|
||||||
|
ktEntry.startOffsetSkippingComments to ktEntry.endOffset
|
||||||
|
}
|
||||||
val irComponentCall = callGenerator.generateCall(
|
val irComponentCall = callGenerator.generateCall(
|
||||||
ktEntry.startOffsetSkippingComments, ktEntry.endOffset, componentSubstitutedCall,
|
componentCallStartOffset, componentCallEndOffset,
|
||||||
|
componentSubstitutedCall,
|
||||||
IrStatementOrigin.COMPONENT_N.withIndex(index + 1)
|
IrStatementOrigin.COMPONENT_N.withIndex(index + 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val componentVarOffsetSource: PsiElement =
|
||||||
|
if (context.extensions.debugInfoOnlyOnVariablesInDestructuringDeclarations) {
|
||||||
|
ktEntry.nameIdentifier ?: ktEntry
|
||||||
|
} else {
|
||||||
|
ktEntry
|
||||||
|
}
|
||||||
val irComponentVar = context.symbolTable.declareVariable(
|
val irComponentVar = context.symbolTable.declareVariable(
|
||||||
ktEntry.startOffsetSkippingComments, ktEntry.endOffset, IrDeclarationOrigin.DEFINED,
|
componentVarOffsetSource.startOffsetSkippingComments, componentVarOffsetSource.endOffset,
|
||||||
|
IrDeclarationOrigin.DEFINED,
|
||||||
componentVariable, componentVariable.type.toIrType(), irComponentCall
|
componentVariable, componentVariable.type.toIrType(), irComponentCall
|
||||||
)
|
)
|
||||||
irBlock.statements.add(irComponentVar)
|
irBlock.statements.add(irComponentVar)
|
||||||
|
|||||||
+22
-4
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.builders.IrGeneratorContext
|
import org.jetbrains.kotlin.ir.builders.IrGeneratorContext
|
||||||
import org.jetbrains.kotlin.ir.builders.Scope
|
import org.jetbrains.kotlin.ir.builders.Scope
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementContainer
|
import org.jetbrains.kotlin.ir.expressions.IrStatementContainer
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
@@ -31,9 +32,26 @@ fun Scope.createTemporaryVariableInBlock(
|
|||||||
context: IrGeneratorContext,
|
context: IrGeneratorContext,
|
||||||
irExpression: IrExpression,
|
irExpression: IrExpression,
|
||||||
block: IrStatementContainer,
|
block: IrStatementContainer,
|
||||||
nameHint: String? = null
|
nameHint: String? = null,
|
||||||
|
startOffset: Int = irExpression.startOffset,
|
||||||
|
endOffset: Int = irExpression.endOffset
|
||||||
): IntermediateValue {
|
): IntermediateValue {
|
||||||
val temporaryVariable = createTemporaryVariable(irExpression, nameHint)
|
return VariableLValue(
|
||||||
block.statements.add(temporaryVariable)
|
context,
|
||||||
return VariableLValue(context, temporaryVariable)
|
declareTemporaryVariableInBlock(irExpression, block, nameHint, startOffset, endOffset)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Scope.declareTemporaryVariableInBlock(
|
||||||
|
irExpression: IrExpression,
|
||||||
|
block: IrStatementContainer,
|
||||||
|
nameHint: String? = null,
|
||||||
|
startOffset: Int = irExpression.startOffset,
|
||||||
|
endOffset: Int = irExpression.endOffset
|
||||||
|
): IrVariable {
|
||||||
|
val temporaryVariable = createTemporaryVariable(irExpression, nameHint, startOffset = startOffset, endOffset = endOffset)
|
||||||
|
block.statements.add(temporaryVariable)
|
||||||
|
return temporaryVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -38,8 +38,14 @@ class VariableLValue(
|
|||||||
LValue,
|
LValue,
|
||||||
AssignmentReceiver {
|
AssignmentReceiver {
|
||||||
|
|
||||||
constructor(context: IrGeneratorContext, irVariable: IrVariable, origin: IrStatementOrigin? = null) :
|
constructor(
|
||||||
this(context, irVariable.startOffset, irVariable.endOffset, irVariable.symbol, irVariable.type, origin)
|
context: IrGeneratorContext,
|
||||||
|
irVariable: IrVariable,
|
||||||
|
origin: IrStatementOrigin? = null,
|
||||||
|
startOffset: Int = irVariable.startOffset,
|
||||||
|
endOffset: Int = irVariable.endOffset
|
||||||
|
) :
|
||||||
|
this(context, startOffset, endOffset, irVariable.symbol, irVariable.type, origin)
|
||||||
|
|
||||||
override fun load(): IrExpression =
|
override fun load(): IrExpression =
|
||||||
IrGetValueImpl(startOffset, endOffset, type, symbol, origin)
|
IrGetValueImpl(startOffset, endOffset, type, symbol, origin)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.builders
|
package org.jetbrains.kotlin.ir.builders
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||||
@@ -71,12 +70,14 @@ class Scope(val scopeOwnerSymbol: IrSymbol) {
|
|||||||
nameHint: String? = null,
|
nameHint: String? = null,
|
||||||
isMutable: Boolean = false,
|
isMutable: Boolean = false,
|
||||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
||||||
irType: IrType? = null
|
irType: IrType? = null,
|
||||||
|
startOffset: Int = irExpression.startOffset,
|
||||||
|
endOffset: Int = irExpression.endOffset
|
||||||
): IrVariable {
|
): IrVariable {
|
||||||
return createTemporaryVariableDeclaration(
|
return createTemporaryVariableDeclaration(
|
||||||
irType ?: irExpression.type,
|
irType ?: irExpression.type,
|
||||||
nameHint, isMutable,
|
nameHint, isMutable,
|
||||||
origin, irExpression.startOffset, irExpression.endOffset
|
origin, startOffset, endOffset
|
||||||
).apply {
|
).apply {
|
||||||
initializer = irExpression
|
initializer = irExpression
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val
|
val
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
class MyPair(val x: String, val y: String) {
|
class MyPair(val x: String, val y: String) {
|
||||||
operator fun component1(): String {
|
operator fun component1(): String {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val p = "O" to "K"
|
val p = "O" to "K"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val p = Triple("X","O","K")
|
val p = Triple("X","O","K")
|
||||||
|
|||||||
-2
@@ -49,11 +49,9 @@ fun box() {
|
|||||||
// test.kt:17 box:
|
// test.kt:17 box:
|
||||||
// test.kt:14 foo: a:MyPair=MyPair, block:kotlin.jvm.functions.Function1=TestKt$box$1
|
// test.kt:14 foo: a:MyPair=MyPair, block:kotlin.jvm.functions.Function1=TestKt$box$1
|
||||||
// test.kt:19 invoke:
|
// test.kt:19 invoke:
|
||||||
// test.kt:20 invoke:
|
|
||||||
// test.kt:6 component1:
|
// test.kt:6 component1:
|
||||||
// test.kt:20 invoke:
|
// test.kt:20 invoke:
|
||||||
// test.kt:19 invoke: x:java.lang.String="O":java.lang.String
|
// test.kt:19 invoke: x:java.lang.String="O":java.lang.String
|
||||||
// test.kt:22 invoke: x:java.lang.String="O":java.lang.String
|
|
||||||
// test.kt:10 component2:
|
// test.kt:10 component2:
|
||||||
// test.kt:22 invoke: x:java.lang.String="O":java.lang.String
|
// test.kt:22 invoke: x:java.lang.String="O":java.lang.String
|
||||||
// test.kt:25 invoke: x:java.lang.String="O":java.lang.String, y:java.lang.String="K":java.lang.String
|
// test.kt:25 invoke: x:java.lang.String="O":java.lang.String, y:java.lang.String="K":java.lang.String
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
fun box(): String {
|
||||||
|
val
|
||||||
|
o
|
||||||
|
=
|
||||||
|
"O"
|
||||||
|
|
||||||
|
|
||||||
|
val k = "K"
|
||||||
|
|
||||||
|
return o + k
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECTATIONS
|
||||||
|
|
||||||
|
// test.kt:8 box
|
||||||
|
// test.kt:6 box
|
||||||
|
// test.kt:11 box
|
||||||
|
// test.kt:13 box
|
||||||
+1
-1
@@ -18,5 +18,5 @@
|
|||||||
@3:27..53 PROPERTY_REFERENCE 'public final lazyNullString: kotlin.String [delegated,val]' field=null getter='public final fun <get-lazyNullString> (): kotlin.String declared in <root>' setter=null type=kotlin.reflect.KProperty0<kotlin.String> origin=PROPERTY_REFERENCE_FOR_DELEGATE
|
@3:27..53 PROPERTY_REFERENCE 'public final lazyNullString: kotlin.String [delegated,val]' field=null getter='public final fun <get-lazyNullString> (): kotlin.String declared in <root>' setter=null type=kotlin.reflect.KProperty0<kotlin.String> origin=PROPERTY_REFERENCE_FOR_DELEGATE
|
||||||
@5:0..7:1 FUN name:testLazyNullString visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
@5:0..7:1 FUN name:testLazyNullString visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||||
@5:25..7:1 BLOCK_BODY
|
@5:25..7:1 BLOCK_BODY
|
||||||
@6:4..34 VAR name:s type:kotlin.String [val]
|
@6:8..9 VAR name:s type:kotlin.String [val]
|
||||||
@6:20..34 CALL 'public final fun <get-lazyNullString> (): kotlin.String declared in <root>' type=kotlin.String origin=GET_PROPERTY
|
@6:20..34 CALL 'public final fun <get-lazyNullString> (): kotlin.String declared in <root>' type=kotlin.String origin=GET_PROPERTY
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
@0:0..6:0 FILE fqName:<root> fileName:/postfixIncrementDecrement.kt
|
@0:0..6:0 FILE fqName:<root> fileName:/postfixIncrementDecrement.kt
|
||||||
@0:0..5:1 FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
@0:0..5:1 FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||||
@0:11..5:1 BLOCK_BODY
|
@0:11..5:1 BLOCK_BODY
|
||||||
@1:4..13 VAR name:x type:kotlin.Int [var]
|
@1:8..9 VAR name:x type:kotlin.Int [var]
|
||||||
@1:12..13 CONST Int type=kotlin.Int value=0
|
@1:12..13 CONST Int type=kotlin.Int value=0
|
||||||
@2:4..13 VAR name:y type:kotlin.Int [var]
|
@2:8..9 VAR name:y type:kotlin.Int [var]
|
||||||
@2:12..13 CONST Int type=kotlin.Int value=0
|
@2:12..13 CONST Int type=kotlin.Int value=0
|
||||||
@3:4..5 SET_VAR 'var y: kotlin.Int [var] declared in <root>.test' type=kotlin.Unit origin=EQ
|
@3:4..5 SET_VAR 'var y: kotlin.Int [var] declared in <root>.test' type=kotlin.Unit origin=EQ
|
||||||
@3:8..11 BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
@3:8..11 BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||||
|
|||||||
+6
@@ -313,6 +313,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
|
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("localProperty.kt")
|
||||||
|
public void testLocalProperty() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/localProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("multilineExpression.kt")
|
@TestMetadata("multilineExpression.kt")
|
||||||
public void testMultilineExpression() throws Exception {
|
public void testMultilineExpression() throws Exception {
|
||||||
|
|||||||
+6
@@ -313,6 +313,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
|
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("localProperty.kt")
|
||||||
|
public void testLocalProperty() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/localProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("multilineExpression.kt")
|
@TestMetadata("multilineExpression.kt")
|
||||||
public void testMultilineExpression() throws Exception {
|
public void testMultilineExpression() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user