[EE-IR] Support Local Functions
This commit introduces support for calling and referencing local functions and objects in evaluate expression on the IR backend. The primary incision is a lowering inserted after Local Declaration Lowering, that uses the intermediate data structures recorded by LDL to rewrite calls to local functions to the appropriate function in the binary, instead of predicting the compilation strategy. The required changes to the rest of the pipeline facilitate piping the required data around. The key to this transformation is that _captures by the local function_ must be introduced as _captures by the fragment function_, such that the evaluator infrastructure can find the appropriate values at run-time. This is necessary due to the strategy of compiling local functions to static functions instead of closures. Additional test coverage of stepping behavior support the corresponding changes in the Evaluator, part of the Kotlin Debugger plug-in.
This commit is contained in:
committed by
Nikita Nazarov
parent
5af9303a16
commit
4f8ef8c315
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory
|
|||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
||||||
import org.jetbrains.kotlin.config.*
|
import org.jetbrains.kotlin.config.*
|
||||||
import org.jetbrains.kotlin.config.LanguageVersion.*
|
import org.jetbrains.kotlin.config.LanguageVersion.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||||
@@ -423,6 +421,11 @@ class GenerationState private constructor(
|
|||||||
private fun shouldOnlyCollectSignatures(origin: JvmDeclarationOrigin) =
|
private fun shouldOnlyCollectSignatures(origin: JvmDeclarationOrigin) =
|
||||||
classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode
|
classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode
|
||||||
|
|
||||||
|
val newFragmentCaptureParameters: MutableList<Triple<String, KotlinType, DeclarationDescriptor>> = mutableListOf()
|
||||||
|
fun recordNewFragmentCaptureParameter(string: String, type: KotlinType, descriptor: DeclarationDescriptor) {
|
||||||
|
newFragmentCaptureParameters.add(Triple(string, type, descriptor))
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val LANGUAGE_TO_METADATA_VERSION = EnumMap<LanguageVersion, JvmMetadataVersion>(LanguageVersion::class.java).apply {
|
val LANGUAGE_TO_METADATA_VERSION = EnumMap<LanguageVersion, JvmMetadataVersion>(LanguageVersion::class.java).apply {
|
||||||
val oldMetadataVersion = JvmMetadataVersion(1, 1, 18)
|
val oldMetadataVersion = JvmMetadataVersion(1, 1, 18)
|
||||||
|
|||||||
+22
@@ -193,6 +193,28 @@ public class FirLocalVariableTestGenerated extends AbstractFirLocalVariableTest
|
|||||||
runTest("compiler/testData/debug/localVariables/underscoreNames.kt");
|
runTest("compiler/testData/debug/localVariables/underscoreNames.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/testData/debug/localVariables/constructors")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Constructors {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInConstructors() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/debug/localVariables/constructors"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleConstructors.kt")
|
||||||
|
public void testMultipleConstructors() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/localVariables/constructors/multipleConstructors.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("property.kt")
|
||||||
|
public void testProperty() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/localVariables/constructors/property.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/debug/localVariables/receiverMangling")
|
@TestMetadata("compiler/testData/debug/localVariables/receiverMangling")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+18
@@ -247,6 +247,18 @@ public class FirSteppingTestGenerated extends AbstractFirSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/inlineSimpleCall.kt");
|
runTest("compiler/testData/debug/stepping/inlineSimpleCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt15259.kt")
|
||||||
|
public void testKt15259() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/kt15259.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt29179.kt")
|
||||||
|
public void testKt29179() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/kt29179.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt42208.kt")
|
@TestMetadata("kt42208.kt")
|
||||||
public void testKt42208() throws Exception {
|
public void testKt42208() throws Exception {
|
||||||
@@ -337,6 +349,12 @@ public class FirSteppingTestGenerated extends AbstractFirSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/noParametersArgumentCallInExpression.kt");
|
runTest("compiler/testData/debug/stepping/noParametersArgumentCallInExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nullcheck.kt")
|
||||||
|
public void testNullcheck() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/nullcheck.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("primitiveNullChecks.kt")
|
@TestMetadata("primitiveNullChecks.kt")
|
||||||
public void testPrimitiveNullChecks() throws Exception {
|
public void testPrimitiveNullChecks() throws Exception {
|
||||||
|
|||||||
+16
-5
@@ -11,9 +11,9 @@ import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.*
|
import org.jetbrains.kotlin.backend.common.ir.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.inline.isInlineParameter
|
import org.jetbrains.kotlin.backend.common.lower.inline.isInlineParameter
|
||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.*
|
import org.jetbrains.kotlin.ir.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
@@ -71,7 +71,8 @@ class LocalDeclarationsLowering(
|
|||||||
val localNameSanitizer: (String) -> String = { it },
|
val localNameSanitizer: (String) -> String = { it },
|
||||||
val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT,
|
val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT,
|
||||||
val suggestUniqueNames: Boolean = true, // When `true` appends a `-#index` suffix to lifted declaration names
|
val suggestUniqueNames: Boolean = true, // When `true` appends a `-#index` suffix to lifted declaration names
|
||||||
val forceFieldsForInlineCaptures: Boolean = false // See `LocalClassContext`
|
val forceFieldsForInlineCaptures: Boolean = false, // See `LocalClassContext`
|
||||||
|
private val postLocalDeclarationLoweringCallback: ((IntermediateDatastructures) -> Unit)? = null
|
||||||
) :
|
) :
|
||||||
BodyLoweringPass {
|
BodyLoweringPass {
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ class LocalDeclarationsLowering(
|
|||||||
ScopeWithCounter(this)
|
ScopeWithCounter(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class LocalContext {
|
abstract class LocalContext {
|
||||||
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
|
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
|
||||||
|
|
||||||
// By the time typeRemapper is used, the map will be already filled
|
// By the time typeRemapper is used, the map will be already filled
|
||||||
@@ -121,7 +122,7 @@ class LocalDeclarationsLowering(
|
|||||||
abstract fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression?
|
abstract fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression?
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class LocalContextWithClosureAsParameters : LocalContext() {
|
abstract class LocalContextWithClosureAsParameters : LocalContext() {
|
||||||
|
|
||||||
abstract val declaration: IrFunction
|
abstract val declaration: IrFunction
|
||||||
abstract val transformedDeclaration: IrFunction
|
abstract val transformedDeclaration: IrFunction
|
||||||
@@ -135,7 +136,7 @@ class LocalDeclarationsLowering(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LocalFunctionContext(
|
class LocalFunctionContext(
|
||||||
override val declaration: IrSimpleFunction,
|
override val declaration: IrSimpleFunction,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
val ownerForLoweredDeclaration: IrDeclarationContainer
|
val ownerForLoweredDeclaration: IrDeclarationContainer
|
||||||
@@ -246,6 +247,10 @@ class LocalDeclarationsLowering(
|
|||||||
rewriteDeclarations()
|
rewriteDeclarations()
|
||||||
|
|
||||||
insertLoweredDeclarationForLocalFunctions()
|
insertLoweredDeclarationForLocalFunctions()
|
||||||
|
|
||||||
|
postLocalDeclarationLoweringCallback?.invoke(
|
||||||
|
IntermediateDatastructures(localFunctions, newParameterToOld, newParameterToCaptured)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertLoweredDeclarationForLocalFunctions() {
|
private fun insertLoweredDeclarationForLocalFunctions() {
|
||||||
@@ -967,6 +972,12 @@ class LocalDeclarationsLowering(
|
|||||||
}, Data(null, false))
|
}, Data(null, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class IntermediateDatastructures(
|
||||||
|
val localFunctions: Map<IrFunction, LocalFunctionContext>,
|
||||||
|
val newParameterToOld: Map<IrValueParameter, IrValueParameter>,
|
||||||
|
val newParameterToCaptured: Map<IrValueParameter, IrValueSymbol>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local inner classes capture anything through outer
|
// Local inner classes capture anything through outer
|
||||||
|
|||||||
+4
-2
@@ -56,7 +56,6 @@ open class JvmIrCodegenFactory(
|
|||||||
private val externalMangler: JvmDescriptorMangler? = null,
|
private val externalMangler: JvmDescriptorMangler? = null,
|
||||||
private val externalSymbolTable: SymbolTable? = null,
|
private val externalSymbolTable: SymbolTable? = null,
|
||||||
private val jvmGeneratorExtensions: JvmGeneratorExtensionsImpl = JvmGeneratorExtensionsImpl(configuration),
|
private val jvmGeneratorExtensions: JvmGeneratorExtensionsImpl = JvmGeneratorExtensionsImpl(configuration),
|
||||||
private val prefixPhases: CompilerPhase<JvmBackendContext, IrModuleFragment, IrModuleFragment>? = null,
|
|
||||||
private val evaluatorFragmentInfoForPsi2Ir: EvaluatorFragmentInfo? = null,
|
private val evaluatorFragmentInfoForPsi2Ir: EvaluatorFragmentInfo? = null,
|
||||||
private val shouldStubAndNotLinkUnboundSymbols: Boolean = false,
|
private val shouldStubAndNotLinkUnboundSymbols: Boolean = false,
|
||||||
) : CodegenFactory {
|
) : CodegenFactory {
|
||||||
@@ -258,11 +257,14 @@ open class JvmIrCodegenFactory(
|
|||||||
)
|
)
|
||||||
JvmIrSerializerImpl(state.configuration)
|
JvmIrSerializerImpl(state.configuration)
|
||||||
else null
|
else null
|
||||||
val phases = prefixPhases?.then(jvmLoweringPhases) ?: jvmLoweringPhases
|
val phases = if (evaluatorFragmentInfoForPsi2Ir != null) jvmFragmentLoweringPhases else jvmLoweringPhases
|
||||||
val phaseConfig = customPhaseConfig ?: PhaseConfig(phases)
|
val phaseConfig = customPhaseConfig ?: PhaseConfig(phases)
|
||||||
val context = JvmBackendContext(
|
val context = JvmBackendContext(
|
||||||
state, irModuleFragment.irBuiltins, irModuleFragment, symbolTable, phaseConfig, extensions, backendExtension, irSerializer,
|
state, irModuleFragment.irBuiltins, irModuleFragment, symbolTable, phaseConfig, extensions, backendExtension, irSerializer,
|
||||||
)
|
)
|
||||||
|
if (evaluatorFragmentInfoForPsi2Ir != null) {
|
||||||
|
context.localDeclarationsLoweringData = mutableMapOf()
|
||||||
|
}
|
||||||
val intrinsics by lazy { IrIntrinsicMethods(irModuleFragment.irBuiltins, context.ir.symbols) }
|
val intrinsics by lazy { IrIntrinsicMethods(irModuleFragment.irBuiltins, context.ir.symbols) }
|
||||||
context.getIntrinsic = { symbol: IrFunctionSymbol -> intrinsics.getIntrinsic(symbol) }
|
context.getIntrinsic = { symbol: IrFunctionSymbol -> intrinsics.getIntrinsic(symbol) }
|
||||||
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ private val arrayConstructorPhase = makeIrFilePhase(
|
|||||||
description = "Transform `Array(size) { index -> value }` into a loop"
|
description = "Transform `Array(size) { index -> value }` into a loop"
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val expectDeclarationsRemovingPhase = makeIrModulePhase<CommonBackendContext>(
|
internal val expectDeclarationsRemovingPhase = makeIrModulePhase(
|
||||||
::ExpectDeclarationRemover,
|
::ExpectDeclarationRemover,
|
||||||
name = "ExpectDeclarationsRemoving",
|
name = "ExpectDeclarationsRemoving",
|
||||||
description = "Remove expect declaration from module fragment"
|
description = "Remove expect declaration from module fragment"
|
||||||
@@ -139,7 +139,15 @@ internal val localDeclarationsPhase = makeIrFilePhase(
|
|||||||
private fun scopedVisibility(inInlineFunctionScope: Boolean): DescriptorVisibility =
|
private fun scopedVisibility(inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||||
if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||||
},
|
},
|
||||||
forceFieldsForInlineCaptures = true
|
forceFieldsForInlineCaptures = true,
|
||||||
|
postLocalDeclarationLoweringCallback = context.localDeclarationsLoweringData?.let {
|
||||||
|
{ data ->
|
||||||
|
data.localFunctions.forEach { (localFunction, localContext) ->
|
||||||
|
it[localFunction] =
|
||||||
|
JvmBackendContext.LocalFunctionData(localContext, data.newParameterToOld, data.newParameterToCaptured)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
name = "JvmLocalDeclarations",
|
name = "JvmLocalDeclarations",
|
||||||
@@ -383,12 +391,20 @@ private val jvmFilePhases = listOf(
|
|||||||
// makePatchParentsPhase()
|
// makePatchParentsPhase()
|
||||||
)
|
)
|
||||||
|
|
||||||
val jvmLoweringPhases = NamedCompilerPhase(
|
val jvmLoweringPhases = buildJvmLoweringPhases("IrLowering", listOf("PerformByIrFile" to jvmFilePhases))
|
||||||
name = "IrLowering",
|
|
||||||
|
private fun buildJvmLoweringPhases(
|
||||||
|
name: String,
|
||||||
|
phases: List<Pair<String, List<NamedCompilerPhase<JvmBackendContext, IrFile>>>>
|
||||||
|
): NamedCompilerPhase<JvmBackendContext, IrModuleFragment> {
|
||||||
|
return NamedCompilerPhase(
|
||||||
|
name = name,
|
||||||
description = "IR lowering",
|
description = "IR lowering",
|
||||||
nlevels = 1,
|
nlevels = 1,
|
||||||
actions = setOf(defaultDumper, validationAction),
|
actions = setOf(defaultDumper, validationAction),
|
||||||
lower = validateIrBeforeLowering then
|
lower =
|
||||||
|
fragmentSharedVariablesLowering then
|
||||||
|
validateIrBeforeLowering then
|
||||||
processOptionalAnnotationsPhase then
|
processOptionalAnnotationsPhase then
|
||||||
expectDeclarationsRemovingPhase then
|
expectDeclarationsRemovingPhase then
|
||||||
serializeIrPhase then
|
serializeIrPhase then
|
||||||
@@ -396,10 +412,40 @@ val jvmLoweringPhases = NamedCompilerPhase(
|
|||||||
fileClassPhase then
|
fileClassPhase then
|
||||||
jvmStaticInObjectPhase then
|
jvmStaticInObjectPhase then
|
||||||
repeatedAnnotationPhase then
|
repeatedAnnotationPhase then
|
||||||
performByIrFile(lower = jvmFilePhases) then
|
buildLoweringsPhase(phases) then
|
||||||
generateMultifileFacadesPhase then
|
generateMultifileFacadesPhase then
|
||||||
resolveInlineCallsPhase then
|
resolveInlineCallsPhase then
|
||||||
// should be last transformation
|
// should be last transformation
|
||||||
prepareForBytecodeInlining then
|
prepareForBytecodeInlining then
|
||||||
validateIrAfterLowering
|
validateIrAfterLowering
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a compiler phase from a list of lowering sequences: each subsequence is run
|
||||||
|
// in parallel per file, and each parallel composition is run in sequence.
|
||||||
|
private fun buildLoweringsPhase(
|
||||||
|
perModuleLowerings: List<Pair<String, List<NamedCompilerPhase<JvmBackendContext, IrFile>>>>,
|
||||||
|
): CompilerPhase<JvmBackendContext, IrModuleFragment, IrModuleFragment> =
|
||||||
|
perModuleLowerings.map { (name, lowerings) -> performByIrFile(name, lower = lowerings) }
|
||||||
|
.reduce<
|
||||||
|
CompilerPhase<JvmBackendContext, IrModuleFragment, IrModuleFragment>,
|
||||||
|
CompilerPhase<JvmBackendContext, IrModuleFragment, IrModuleFragment>
|
||||||
|
> { result, phase -> result then phase }
|
||||||
|
|
||||||
|
|
||||||
|
val jvmFragmentLoweringPhases = run {
|
||||||
|
val localDeclarationsIndex = jvmFilePhases.indexOf(localDeclarationsPhase)
|
||||||
|
val loweringsUpToLocalDeclarations = jvmFilePhases.subList(0, localDeclarationsIndex + 1)
|
||||||
|
val remainingLowerings = jvmFilePhases.subList(localDeclarationsIndex + 1, jvmFilePhases.size)
|
||||||
|
buildJvmLoweringPhases(
|
||||||
|
"IrFragmentLowering",
|
||||||
|
listOf(
|
||||||
|
"PrefixOfIRPhases" to loweringsUpToLocalDeclarations,
|
||||||
|
"FragmentLowerings" to listOf(
|
||||||
|
fragmentLocalFunctionPatchLowering,
|
||||||
|
reflectiveAccessLowering,
|
||||||
|
),
|
||||||
|
"SuffixOfIRPhases" to remainingLowerings
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.localDeclarationsPhase
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.lower.FragmentSharedVariablesLowering.Companion.GENERATED_FUNCTION_NAME
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
|
||||||
|
// Used from CodeFragmentCompiler for IDE Debugger Plug-In
|
||||||
|
@Suppress("unused")
|
||||||
|
val fragmentLocalFunctionPatchLowering = makeIrFilePhase(
|
||||||
|
::FragmentLocalFunctionPatchLowering,
|
||||||
|
name = "FragmentLocalFunctionPatching",
|
||||||
|
description = "Rewrite calls to local functions to the appropriate, lifted function created by local declarations lowering.",
|
||||||
|
prerequisite = setOf(localDeclarationsPhase)
|
||||||
|
)
|
||||||
|
|
||||||
|
// This lowering rewrites local function calls in code fragments to the
|
||||||
|
// corresponding lifted declaration. In the process, the lowering determines
|
||||||
|
// whether the captures of the local function are a subset of the captures of
|
||||||
|
// the fragment, and if not, introduces additional captures to the fragment
|
||||||
|
// wrapper. The captures are then supplied to the fragment wrapper as
|
||||||
|
// parameters supplied at evaluation time.
|
||||||
|
internal class FragmentLocalFunctionPatchLowering(
|
||||||
|
val context: JvmBackendContext
|
||||||
|
) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||||
|
|
||||||
|
lateinit var localDeclarationsData: Map<IrFunction, JvmBackendContext.LocalFunctionData>
|
||||||
|
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
context.localDeclarationsLoweringData?.let {
|
||||||
|
localDeclarationsData = it
|
||||||
|
} ?: return
|
||||||
|
irFile.transformChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement {
|
||||||
|
if (declaration.name.asString() != GENERATED_FUNCTION_NAME) return declaration
|
||||||
|
|
||||||
|
declaration.body!!.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
val localsData = localDeclarationsData[expression.symbol.owner] ?: return super.visitCall(expression)
|
||||||
|
val remappedTarget: LocalDeclarationsLowering.LocalFunctionContext = localsData.localContext
|
||||||
|
|
||||||
|
val irBuilder = context.createJvmIrBuilder(declaration.symbol)
|
||||||
|
return irBuilder.irCall(remappedTarget.transformedDeclaration).apply {
|
||||||
|
this.copyTypeArgumentsFrom(expression)
|
||||||
|
extensionReceiver = expression.extensionReceiver
|
||||||
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
|
|
||||||
|
remappedTarget.transformedDeclaration.valueParameters.map { newValueParameterDeclaration ->
|
||||||
|
val oldParameter = localsData.newParameterToOld[newValueParameterDeclaration]
|
||||||
|
|
||||||
|
val getValue = if (oldParameter != null) {
|
||||||
|
// the parameter is an actual parameter to the local
|
||||||
|
// function, not a parameter corresponding to a
|
||||||
|
// capture introduced by a lowering: fetch
|
||||||
|
// the corresponding argument from the existing
|
||||||
|
// call and place at the appropriate slot in the
|
||||||
|
// call to the lowered function
|
||||||
|
expression.getValueArgument(oldParameter.index)!!
|
||||||
|
} else {
|
||||||
|
// The parameter is introduced by the lowering to
|
||||||
|
// private static function, so corresponds to a _capture_ by the local function
|
||||||
|
val capturedValueSymbol =
|
||||||
|
localsData.newParameterToCaptured[newValueParameterDeclaration]
|
||||||
|
?: error("Non-mapped parameter $newValueParameterDeclaration")
|
||||||
|
|
||||||
|
// We introduce a new parameter to the _fragment function_ surrounding the call to the
|
||||||
|
// lowered local function, and supply _that_ parameter to the corresponding _argument_ slot
|
||||||
|
// in the call to the lowered function.
|
||||||
|
val newParameter = declaration.addValueParameter {
|
||||||
|
type = capturedValueSymbol.owner.type
|
||||||
|
name = capturedValueSymbol.owner.name
|
||||||
|
}
|
||||||
|
|
||||||
|
context.state.recordNewFragmentCaptureParameter(
|
||||||
|
newParameter.name.asString(),
|
||||||
|
capturedValueSymbol.owner.type.toIrBasedKotlinType(),
|
||||||
|
capturedValueSymbol.owner.toIrBasedDescriptor()
|
||||||
|
)
|
||||||
|
|
||||||
|
irBuilder.irGet(newParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
putValueArgument(newValueParameterDeclaration.index, getValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return declaration
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
-14
@@ -5,32 +5,35 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.jvm.lower
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineScopeResolver
|
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.findInlineCallSites
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isJvmInterface
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.SyntheticAccessorLowering.Companion.isAccessible
|
import org.jetbrains.kotlin.backend.jvm.lower.SyntheticAccessorLowering.Companion.isAccessible
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.defaultType
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.starProjectedType
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
// Used from CodeFragmentCompiler for IDE Debugger Plug-In
|
// Used from CodeFragmentCompiler for IDE Debugger Plug-In
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val reflectiveAccessLowering = makeIrModulePhase(
|
val reflectiveAccessLowering = makeIrFilePhase(
|
||||||
::ReflectiveAccessLowering,
|
::ReflectiveAccessLowering,
|
||||||
name = "ReflectiveCalls",
|
name = "ReflectiveCalls",
|
||||||
description = "Avoid the need for accessors by replacing direct access to inaccessible members with accesses via reflection",
|
description = "Avoid the need for accessors by replacing direct access to inaccessible members with accesses via reflection",
|
||||||
@@ -85,9 +88,13 @@ internal class ReflectiveAccessLowering(
|
|||||||
// `fieldLocationAndReceiver`.
|
// `fieldLocationAndReceiver`.
|
||||||
val callsOnCompanionObjects: MutableMap<IrCall, IrClassSymbol> = mutableMapOf()
|
val callsOnCompanionObjects: MutableMap<IrCall, IrClassSymbol> = mutableMapOf()
|
||||||
|
|
||||||
|
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||||
private fun recordCompanionObjectAsDispatchReceiver(expression: IrCall) {
|
private fun recordCompanionObjectAsDispatchReceiver(expression: IrCall) {
|
||||||
if ((expression.dispatchReceiver as? IrGetObjectValue)?.symbol?.owner?.isCompanion == true) {
|
val dispatchReceiver = expression.dispatchReceiver as? IrGetField ?: return
|
||||||
callsOnCompanionObjects[expression] = (expression.dispatchReceiver!! as IrGetObjectValue).symbol
|
val dispatchReceiverType = dispatchReceiver.symbol.owner.type as? IrSimpleType ?: return
|
||||||
|
val klass = dispatchReceiverType.classOrNull
|
||||||
|
if (klass != null && klass.owner.isCompanion) {
|
||||||
|
callsOnCompanionObjects[expression] = klass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +214,20 @@ internal class ReflectiveAccessLowering(
|
|||||||
putValueArgument(0, receiver)
|
putValueArgument(0, receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createBuilder(startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET) =
|
||||||
|
context.createJvmIrBuilder(currentScope!!, startOffset, endOffset)
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.irVararg(
|
||||||
|
elementType: IrType,
|
||||||
|
values: List<IrExpression>
|
||||||
|
): IrExpression {
|
||||||
|
return IrArrayBuilder(createBuilder(), context.irBuiltIns.arrayClass.typeWith(elementType)).apply {
|
||||||
|
for (value in values) {
|
||||||
|
+value
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.getDeclaredMethod(
|
private fun IrBuilderWithScope.getDeclaredMethod(
|
||||||
declaringClass: IrExpression,
|
declaringClass: IrExpression,
|
||||||
methodName: String,
|
methodName: String,
|
||||||
@@ -293,13 +314,13 @@ internal class ReflectiveAccessLowering(
|
|||||||
|
|
||||||
private fun generateReflectiveMethodInvocation(call: IrCall): IrExpression =
|
private fun generateReflectiveMethodInvocation(call: IrCall): IrExpression =
|
||||||
generateReflectiveMethodInvocation(
|
generateReflectiveMethodInvocation(
|
||||||
call.superQualifierSymbol?.defaultType ?: call.dispatchReceiver!!.type,
|
call.superQualifierSymbol?.defaultType ?: call.dispatchReceiver?.type ?: call.symbol.owner.parentAsClass.defaultType,
|
||||||
call.symbol.owner.name.asString(),
|
call.symbol.owner.name.asString(),
|
||||||
mutableListOf<IrType>().apply {
|
mutableListOf<IrType>().apply {
|
||||||
call.symbol.owner.extensionReceiverParameter?.let { add(it.type) }
|
call.symbol.owner.extensionReceiverParameter?.let { add(it.type) }
|
||||||
addAll(call.valueParameterTypes())
|
addAll(call.valueParameterTypes())
|
||||||
},
|
},
|
||||||
call.dispatchReceiver!!,
|
call.dispatchReceiver,
|
||||||
mutableListOf<IrExpression>().apply {
|
mutableListOf<IrExpression>().apply {
|
||||||
call.extensionReceiver?.let { add(it) }
|
call.extensionReceiver?.let { add(it) }
|
||||||
addAll(call.getValueArguments())
|
addAll(call.getValueArguments())
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
|||||||
import org.jetbrains.kotlin.backend.common.DefaultMapping
|
import org.jetbrains.kotlin.backend.common.DefaultMapping
|
||||||
import org.jetbrains.kotlin.backend.common.Mapping
|
import org.jetbrains.kotlin.backend.common.Mapping
|
||||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||||
import org.jetbrains.kotlin.backend.jvm.caches.BridgeLoweringCache
|
import org.jetbrains.kotlin.backend.jvm.caches.BridgeLoweringCache
|
||||||
import org.jetbrains.kotlin.backend.jvm.caches.CollectionStubComputer
|
import org.jetbrains.kotlin.backend.jvm.caches.CollectionStubComputer
|
||||||
@@ -47,6 +48,18 @@ class JvmBackendContext(
|
|||||||
val backendExtension: JvmBackendExtension,
|
val backendExtension: JvmBackendExtension,
|
||||||
val irSerializer: JvmIrSerializer?,
|
val irSerializer: JvmIrSerializer?,
|
||||||
) : CommonBackendContext {
|
) : CommonBackendContext {
|
||||||
|
|
||||||
|
data class LocalFunctionData(
|
||||||
|
val localContext: LocalDeclarationsLowering.LocalFunctionContext,
|
||||||
|
val newParameterToOld: Map<IrValueParameter, IrValueParameter>,
|
||||||
|
val newParameterToCaptured: Map<IrValueParameter, IrValueSymbol>
|
||||||
|
)
|
||||||
|
|
||||||
|
// If not-null, this is populated by LocalDeclarationsLowering with the intermediate data
|
||||||
|
// allowing mapping from local function captures to parameters and accurate transformation
|
||||||
|
// of calls to local functions from code fragments (i.e. the expression evaluator).
|
||||||
|
var localDeclarationsLoweringData: MutableMap<IrFunction, LocalFunctionData>? = null
|
||||||
|
|
||||||
// If the JVM fqname of a class differs from what is implied by its parent, e.g. if it's a file class
|
// If the JVM fqname of a class differs from what is implied by its parent, e.g. if it's a file class
|
||||||
// annotated with @JvmPackageName, the correct name is recorded here.
|
// annotated with @JvmPackageName, the correct name is recorded here.
|
||||||
val classNameOverride: MutableMap<IrClass, JvmClassName>
|
val classNameOverride: MutableMap<IrClass, JvmClassName>
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ class GeneratorContext private constructor(
|
|||||||
val typeTranslator: TypeTranslator,
|
val typeTranslator: TypeTranslator,
|
||||||
override val irBuiltIns: IrBuiltIns,
|
override val irBuiltIns: IrBuiltIns,
|
||||||
internal val callToSubstitutedDescriptorMap: MutableMap<IrDeclarationReference, CallableDescriptor>,
|
internal val callToSubstitutedDescriptorMap: MutableMap<IrDeclarationReference, CallableDescriptor>,
|
||||||
internal val fragmentContext: FragmentContext?,
|
internal var fragmentContext: FragmentContext?,
|
||||||
) : IrGeneratorContext {
|
) : IrGeneratorContext {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
+9
-6
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir.generators.fragments
|
package org.jetbrains.kotlin.psi2ir.generators.fragments
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
||||||
@@ -23,11 +22,13 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver
|
|||||||
class FragmentCompilerSymbolTableDecorator(
|
class FragmentCompilerSymbolTableDecorator(
|
||||||
signatureComposer: IdSignatureComposer,
|
signatureComposer: IdSignatureComposer,
|
||||||
irFactory: IrFactory,
|
irFactory: IrFactory,
|
||||||
private val fragmentInfo: EvaluatorFragmentInfo,
|
var fragmentInfo: EvaluatorFragmentInfo?,
|
||||||
nameProvider: NameProvider = NameProvider.DEFAULT,
|
nameProvider: NameProvider = NameProvider.DEFAULT,
|
||||||
) : SymbolTable(signatureComposer, irFactory, nameProvider) {
|
) : SymbolTable(signatureComposer, irFactory, nameProvider) {
|
||||||
|
|
||||||
override fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol {
|
override fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol {
|
||||||
|
val fi = fragmentInfo ?: return super.referenceValueParameter(descriptor)
|
||||||
|
|
||||||
if (descriptor !is ReceiverParameterDescriptor) return super.referenceValueParameter(descriptor)
|
if (descriptor !is ReceiverParameterDescriptor) return super.referenceValueParameter(descriptor)
|
||||||
|
|
||||||
val finderPredicate = when (val receiverValue = descriptor.value) {
|
val finderPredicate = when (val receiverValue = descriptor.value) {
|
||||||
@@ -41,18 +42,20 @@ class FragmentCompilerSymbolTableDecorator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val parameterPosition =
|
val parameterPosition =
|
||||||
fragmentInfo.parameters.indexOfFirst(finderPredicate)
|
fi.parameters.indexOfFirst(finderPredicate)
|
||||||
if (parameterPosition > -1) {
|
if (parameterPosition > -1) {
|
||||||
return super.referenceValueParameter(fragmentInfo.methodDescriptor.valueParameters[parameterPosition])
|
return super.referenceValueParameter(fi.methodDescriptor.valueParameters[parameterPosition])
|
||||||
}
|
}
|
||||||
return super.referenceValueParameter(descriptor)
|
return super.referenceValueParameter(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun referenceValue(value: ValueDescriptor): IrValueSymbol {
|
override fun referenceValue(value: ValueDescriptor): IrValueSymbol {
|
||||||
|
val fi = fragmentInfo ?: return super.referenceValue(value)
|
||||||
|
|
||||||
val parameterPosition =
|
val parameterPosition =
|
||||||
fragmentInfo.parameters.indexOfFirst { it.descriptor == value }
|
fi.parameters.indexOfFirst { it.descriptor == value }
|
||||||
if (parameterPosition > -1) {
|
if (parameterPosition > -1) {
|
||||||
return super.referenceValueParameter(fragmentInfo.methodDescriptor.valueParameters[parameterPosition])
|
return super.referenceValueParameter(fi.methodDescriptor.valueParameters[parameterPosition])
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.referenceValue(value)
|
return super.referenceValue(value)
|
||||||
|
|||||||
+16
-2
@@ -38,14 +38,28 @@ class FragmentModuleGenerator(
|
|||||||
patchDeclarationParents()
|
patchDeclarationParents()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val fileContext = context.createFileScopeContext(ktFile)
|
generateInContextWithoutFragmentInfo(ktFile) {
|
||||||
generateSingleFile(DeclarationGenerator(fileContext), ktFile, irModule)
|
generateSingleFile(DeclarationGenerator(it), ktFile, irModule)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T> generateInContextWithoutFragmentInfo(ktFile: KtFile, block: (GeneratorContext) -> T): T {
|
||||||
|
val symbolTableDecorator = context.symbolTable as FragmentCompilerSymbolTableDecorator
|
||||||
|
val fragmentInfo = symbolTableDecorator.fragmentInfo
|
||||||
|
symbolTableDecorator.fragmentInfo = null
|
||||||
|
|
||||||
|
val fileContext = context.createFileScopeContext(ktFile)
|
||||||
|
fileContext.fragmentContext = null
|
||||||
|
|
||||||
|
return block(fileContext).also {
|
||||||
|
symbolTableDecorator.fragmentInfo = fragmentInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createEmptyIrFile(ktFile: KtFile): IrFileImpl {
|
private fun createEmptyIrFile(ktFile: KtFile): IrFileImpl {
|
||||||
val fileEntry = PsiIrFileEntry(ktFile)
|
val fileEntry = PsiIrFileEntry(ktFile)
|
||||||
val packageFragmentDescriptor = context.moduleDescriptor.findPackageFragmentForFile(ktFile)!!
|
val packageFragmentDescriptor = context.moduleDescriptor.findPackageFragmentForFile(ktFile)!!
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
open class Base(i: Int)
|
||||||
|
|
||||||
|
class Derived(): Base(1) {
|
||||||
|
constructor(p: Int): this() {
|
||||||
|
val a = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(p1: Int, p2: Int): this()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() {
|
||||||
|
Derived(3)
|
||||||
|
Derived(4, 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECTATIONS
|
||||||
|
// test.kt:15 box:
|
||||||
|
// test.kt:7 <init>: p:int=3:int
|
||||||
|
// test.kt:6 <init>:
|
||||||
|
// test.kt:4 <init>: i:int=1:int
|
||||||
|
// test.kt:6 <init>:
|
||||||
|
// test.kt:8 <init>: p:int=3:int
|
||||||
|
// EXPECTATIONS JVM_IR
|
||||||
|
// test.kt:9 <init>: p:int=3:int, a:int=2:int
|
||||||
|
// EXPECTATIONS
|
||||||
|
// test.kt:15 box:
|
||||||
|
|
||||||
|
// test.kt:16 box:
|
||||||
|
// test.kt:11 <init>: p1:int=4:int, p2:int=5:int
|
||||||
|
// test.kt:6 <init>:
|
||||||
|
// test.kt:4 <init>: i:int=1:int
|
||||||
|
// test.kt:6 <init>:
|
||||||
|
// test.kt:11 <init>: p1:int=4:int, p2:int=5:int
|
||||||
|
// test.kt:16 box:
|
||||||
|
// test.kt:17 box:
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
class F(val a: String)
|
||||||
|
|
||||||
|
fun box() {
|
||||||
|
F("foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECTATIONS
|
||||||
|
// test.kt:7 box:
|
||||||
|
// test.kt:4 <init>: a:java.lang.String="foo":java.lang.String
|
||||||
|
// test.kt:7 box:
|
||||||
|
// test.kt:8 box:
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// FILE: test.kt
|
||||||
|
interface ObjectFace
|
||||||
|
|
||||||
|
private fun makeFace() = object : ObjectFace {
|
||||||
|
|
||||||
|
init { 5 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() {
|
||||||
|
makeFace()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IR backend has additional steps on the way _out_ of the init block.
|
||||||
|
|
||||||
|
// EXPECTATIONS
|
||||||
|
// test.kt:12 box
|
||||||
|
// test.kt:6 makeFace
|
||||||
|
// test.kt:6 <init>
|
||||||
|
// test.kt:8 <init>
|
||||||
|
// test.kt:9 makeFace
|
||||||
|
// test.kt:12 box
|
||||||
|
// test.kt:13 box
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// FILE: test.kt
|
||||||
|
class A {
|
||||||
|
val a = 1
|
||||||
|
fun bar() = 2
|
||||||
|
fun foo() {
|
||||||
|
3
|
||||||
|
//Breakpoint! from the Evaluate Expression test suite.
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() {
|
||||||
|
A().foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECTATIONS
|
||||||
|
// test.kt:15 box
|
||||||
|
// test.kt:4 <init>
|
||||||
|
// test.kt:5 <init>
|
||||||
|
// test.kt:15 box
|
||||||
|
// test.kt:8 foo
|
||||||
|
// test.kt:10 foo
|
||||||
|
// test.kt:11 foo
|
||||||
|
// test.kt:16 box
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
fun box() {
|
||||||
|
test("OK")
|
||||||
|
test(null)
|
||||||
|
testExpressionBody("OK")
|
||||||
|
testExpressionBody(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(nullable: String?): Boolean {
|
||||||
|
return nullable != null &&
|
||||||
|
// Some comment
|
||||||
|
nullable.length == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testExpressionBody(nullable: String?) =
|
||||||
|
nullable != null &&
|
||||||
|
// Some comment
|
||||||
|
nullable.length == 2
|
||||||
|
|
||||||
|
// EXPECTATIONS
|
||||||
|
// EXPECTATIONS JVM
|
||||||
|
// test.kt:6 box
|
||||||
|
// test.kt:15 test
|
||||||
|
// test.kt:13 test
|
||||||
|
// test.kt:6 box
|
||||||
|
|
||||||
|
// test.kt:7 box
|
||||||
|
// test.kt:15 test
|
||||||
|
// test.kt:13 test
|
||||||
|
// test.kt:7 box
|
||||||
|
|
||||||
|
// test.kt:8 box
|
||||||
|
// test.kt:21 testExpressionBody
|
||||||
|
// test.kt:8 box
|
||||||
|
|
||||||
|
// test.kt:9 box
|
||||||
|
// test.kt:21 testExpressionBody
|
||||||
|
// test.kt:9 box
|
||||||
|
|
||||||
|
// test.kt:10 box
|
||||||
|
|
||||||
|
// EXPECTATIONS JVM_IR
|
||||||
|
// test.kt:6 box
|
||||||
|
// test.kt:13 test
|
||||||
|
// test.kt:15 test
|
||||||
|
// test.kt:13 test
|
||||||
|
// test.kt:6 box
|
||||||
|
|
||||||
|
// test.kt:7 box
|
||||||
|
// test.kt:13 test
|
||||||
|
// test.kt:15 test
|
||||||
|
// test.kt:13 test
|
||||||
|
// test.kt:7 box
|
||||||
|
|
||||||
|
// test.kt:8 box
|
||||||
|
// test.kt:19 testExpressionBody
|
||||||
|
// test.kt:21 testExpressionBody
|
||||||
|
// test.kt:8 box
|
||||||
|
|
||||||
|
// test.kt:9 box
|
||||||
|
// test.kt:19 testExpressionBody
|
||||||
|
// test.kt:21 testExpressionBody
|
||||||
|
// test.kt:9 box
|
||||||
|
|
||||||
|
// test.kt:10 box
|
||||||
+22
@@ -193,6 +193,28 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest {
|
|||||||
runTest("compiler/testData/debug/localVariables/underscoreNames.kt");
|
runTest("compiler/testData/debug/localVariables/underscoreNames.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/testData/debug/localVariables/constructors")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Constructors {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInConstructors() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/debug/localVariables/constructors"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleConstructors.kt")
|
||||||
|
public void testMultipleConstructors() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/localVariables/constructors/multipleConstructors.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("property.kt")
|
||||||
|
public void testProperty() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/localVariables/constructors/property.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/debug/localVariables/receiverMangling")
|
@TestMetadata("compiler/testData/debug/localVariables/receiverMangling")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+18
@@ -247,6 +247,18 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/inlineSimpleCall.kt");
|
runTest("compiler/testData/debug/stepping/inlineSimpleCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt15259.kt")
|
||||||
|
public void testKt15259() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/kt15259.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt29179.kt")
|
||||||
|
public void testKt29179() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/kt29179.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt42208.kt")
|
@TestMetadata("kt42208.kt")
|
||||||
public void testKt42208() throws Exception {
|
public void testKt42208() throws Exception {
|
||||||
@@ -337,6 +349,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/noParametersArgumentCallInExpression.kt");
|
runTest("compiler/testData/debug/stepping/noParametersArgumentCallInExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nullcheck.kt")
|
||||||
|
public void testNullcheck() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/nullcheck.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("primitiveNullChecks.kt")
|
@TestMetadata("primitiveNullChecks.kt")
|
||||||
public void testPrimitiveNullChecks() throws Exception {
|
public void testPrimitiveNullChecks() throws Exception {
|
||||||
|
|||||||
+22
@@ -193,6 +193,28 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest {
|
|||||||
runTest("compiler/testData/debug/localVariables/underscoreNames.kt");
|
runTest("compiler/testData/debug/localVariables/underscoreNames.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/testData/debug/localVariables/constructors")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Constructors {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInConstructors() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/debug/localVariables/constructors"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleConstructors.kt")
|
||||||
|
public void testMultipleConstructors() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/localVariables/constructors/multipleConstructors.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("property.kt")
|
||||||
|
public void testProperty() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/localVariables/constructors/property.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/debug/localVariables/receiverMangling")
|
@TestMetadata("compiler/testData/debug/localVariables/receiverMangling")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+18
@@ -247,6 +247,18 @@ public class SteppingTestGenerated extends AbstractSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/inlineSimpleCall.kt");
|
runTest("compiler/testData/debug/stepping/inlineSimpleCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt15259.kt")
|
||||||
|
public void testKt15259() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/kt15259.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt29179.kt")
|
||||||
|
public void testKt29179() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/kt29179.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt42208.kt")
|
@TestMetadata("kt42208.kt")
|
||||||
public void testKt42208() throws Exception {
|
public void testKt42208() throws Exception {
|
||||||
@@ -337,6 +349,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/noParametersArgumentCallInExpression.kt");
|
runTest("compiler/testData/debug/stepping/noParametersArgumentCallInExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nullcheck.kt")
|
||||||
|
public void testNullcheck() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/nullcheck.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("primitiveNullChecks.kt")
|
@TestMetadata("primitiveNullChecks.kt")
|
||||||
public void testPrimitiveNullChecks() throws Exception {
|
public void testPrimitiveNullChecks() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user