JVM_IR: copy code from JvmDefaultParameterInjector to JvmTailrecLowering
Some weird edge case for inline classes wrapping primitives?
This commit is contained in:
+20
-32
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.transformStatement
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.explicitParameters
|
||||
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
open class TailrecLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container is IrFunction) {
|
||||
// TODO Shouldn't this be done after local declarations lowering?
|
||||
// Lower local declarations
|
||||
irBody.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
@@ -62,26 +61,22 @@ open class TailrecLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerTailRecursionCalls(function: IrFunction) =
|
||||
lowerTailRecursionCalls(context, function, useProperComputationOrderOfTailrecDefaultParameters(), ::followFunctionReference)
|
||||
|
||||
open fun useProperComputationOrderOfTailrecDefaultParameters() = true
|
||||
open val useProperComputationOrderOfTailrecDefaultParameters: Boolean
|
||||
get() = true
|
||||
|
||||
open fun followFunctionReference(reference: IrFunctionReference): Boolean = false
|
||||
|
||||
open fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression =
|
||||
IrConstImpl.defaultValueForType(startOffset, endOffset, type)
|
||||
}
|
||||
|
||||
private fun lowerTailRecursionCalls(
|
||||
context: BackendContext,
|
||||
irFunction: IrFunction,
|
||||
properComputationOrderOfTailrecDefaultParameters: Boolean,
|
||||
followFunctionReference: (IrFunctionReference) -> Boolean
|
||||
) {
|
||||
val tailRecursionCalls = collectTailRecursionCalls(irFunction, followFunctionReference)
|
||||
private fun TailrecLowering.lowerTailRecursionCalls(irFunction: IrFunction) {
|
||||
val tailRecursionCalls = collectTailRecursionCalls(irFunction, ::followFunctionReference)
|
||||
if (tailRecursionCalls.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val oldBody = irFunction.body as IrBlockBody
|
||||
val oldBody = irFunction.body as? IrBlockBody ?: return
|
||||
val oldBodyStatements = ArrayList(oldBody.statements)
|
||||
val builder = context.createIrBuilder(irFunction.symbol).at(oldBody)
|
||||
|
||||
@@ -104,14 +99,9 @@ private fun lowerTailRecursionCalls(
|
||||
val parameterToNew = parameters.associateWith {
|
||||
createTmpVariable(irGet(parameterToVariable[it]!!), nameHint = it.symbol.suggestVariableName())
|
||||
}
|
||||
|
||||
val transformer = BodyTransformer(
|
||||
builder, irFunction, loop,
|
||||
parameterToNew, parameterToVariable, tailRecursionCalls,
|
||||
properComputationOrderOfTailrecDefaultParameters,
|
||||
followFunctionReference
|
||||
this@lowerTailRecursionCalls, builder, irFunction, loop, parameterToNew, parameterToVariable, tailRecursionCalls
|
||||
)
|
||||
|
||||
oldBodyStatements.forEach {
|
||||
+it.transformStatement(transformer)
|
||||
}
|
||||
@@ -123,14 +113,13 @@ private fun lowerTailRecursionCalls(
|
||||
}
|
||||
|
||||
private class BodyTransformer(
|
||||
val builder: IrBuilderWithScope,
|
||||
val irFunction: IrFunction,
|
||||
val loop: IrLoop,
|
||||
val parameterToNew: Map<IrValueParameter, IrValueDeclaration>,
|
||||
val parameterToVariable: Map<IrValueParameter, IrVariable>,
|
||||
val tailRecursionCalls: Set<IrCall>,
|
||||
val properComputationOrderOfTailrecDefaultParameters: Boolean,
|
||||
val followFunctionReference: (IrFunctionReference) -> Boolean
|
||||
private val lowering: TailrecLowering,
|
||||
private val builder: IrBuilderWithScope,
|
||||
irFunction: IrFunction,
|
||||
private val loop: IrLoop,
|
||||
parameterToNew: Map<IrValueParameter, IrValueDeclaration>,
|
||||
private val parameterToVariable: Map<IrValueParameter, IrVariable>,
|
||||
private val tailRecursionCalls: Set<IrCall>,
|
||||
) : VariableRemapper(parameterToNew) {
|
||||
|
||||
val parameters = irFunction.explicitParameters
|
||||
@@ -144,7 +133,7 @@ private class BodyTransformer(
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
if (followFunctionReference(expression)) {
|
||||
if (lowering.followFunctionReference(expression)) {
|
||||
expression.symbol.owner.body?.transformChildrenVoid(this)
|
||||
}
|
||||
return super.visitFunctionReference(expression)
|
||||
@@ -163,13 +152,12 @@ private class BodyTransformer(
|
||||
defaultValuedParameters.associateWithTo(parameterToArgument) {
|
||||
// Note that we intentionally keep the original type of the parameter for the variable even though that violates type safety
|
||||
// if it's non-null. This ensures that capture parameters have the same types for all copies of `x`.
|
||||
// TODO: on the JVM, this might not be correct for inline classes - copy code from JvmDefaultParameterInjector?
|
||||
irTemporary(IrConstImpl.defaultValueForType(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type.makeNullable()), irType = it.type)
|
||||
irTemporary(lowering.nullConst(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type))
|
||||
}
|
||||
// Now replace those variables with ones containing actual default values. Unused null-valued temporaries will hopefully
|
||||
// be optimized out later.
|
||||
val remapper = VariableRemapper(parameterToArgument)
|
||||
defaultValuedParameters.let { if (properComputationOrderOfTailrecDefaultParameters) it else it.asReversed() }
|
||||
defaultValuedParameters.let { if (lowering.useProperComputationOrderOfTailrecDefaultParameters) it else it.asReversed() }
|
||||
.associateWithTo(parameterToArgument) { parameter ->
|
||||
val originalDefaultValue = parameter.defaultValue?.expression ?: throw Error("no argument specified for $parameter")
|
||||
irTemporary(originalDefaultValue.deepCopyWithVariables().patchDeclarationParents(parent).transform(remapper, null))
|
||||
|
||||
+7
-1
@@ -8,14 +8,20 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
import org.jetbrains.kotlin.backend.common.lower.TailrecLowering
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
|
||||
class JvmTailrecLowering(context: JvmBackendContext) : TailrecLowering(context) {
|
||||
override fun useProperComputationOrderOfTailrecDefaultParameters(): Boolean =
|
||||
override val useProperComputationOrderOfTailrecDefaultParameters: Boolean =
|
||||
context.ir.context.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ProperComputationOrderOfTailrecDefaultParameters)
|
||||
|
||||
override fun followFunctionReference(reference: IrFunctionReference): Boolean =
|
||||
reference.origin == JvmLoweredStatementOrigin.INLINE_LAMBDA
|
||||
|
||||
override fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression =
|
||||
type.defaultValue(startOffset, endOffset, context as JvmBackendContext)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user