[K/N] Fix references for inline function

Corresponding lowering creating wrappers from JS Backend was used.

Also, the lowering was changed to create local function, instead of
normal one in outer scope, as a lot of logic from local declarations
lowering should be duplicated otherwise for correct type parameters
handling.

^KT-38535
This commit is contained in:
Pavel Kunyavskiy
2022-08-02 16:00:47 +02:00
committed by Space
parent 2f75ea585e
commit 5034581788
19 changed files with 235 additions and 42 deletions
@@ -119,3 +119,5 @@ fun CommonBackendContext.createArrayOfExpression(
putValueArgument(0, arg0)
}
}
fun IrFunction.isInlineFunWithReifiedParameter() = isInline && typeParameters.any { it.isReified }
@@ -0,0 +1,113 @@
/*
* 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.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ir.isInlineFunWithReifiedParameter
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.types.IrTypeArgument
import org.jetbrains.kotlin.ir.types.IrTypeSubstitutor
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.ir.util.typeSubstitutionMap
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
// Replace callable reference on inline function with reified parameter
// with callable reference on new non inline function with substituted types
class WrapInlineDeclarationsWithReifiedTypeParametersLowering(val context: BackendContext) : BodyLoweringPass {
private val irFactory
get() = context.irFactory
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid()
val owner = expression.symbol.owner as? IrSimpleFunction
?: return expression
if (!owner.isInlineFunWithReifiedParameter()) {
return expression
}
val substitutionMap = expression.typeSubstitutionMap
.entries
.map { (key, value) ->
key to (value as IrTypeArgument)
}
val typeSubstitutor = IrTypeSubstitutor(
substitutionMap.map { it.first },
substitutionMap.map { it.second },
context.irBuiltIns
)
val function = irFactory.buildFun {
name = Name.identifier("${owner.name}${"$"}wrap")
returnType = typeSubstitutor.substitute(owner.returnType)
visibility = DescriptorVisibilities.LOCAL
origin = IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE
startOffset = SYNTHETIC_OFFSET
endOffset = SYNTHETIC_OFFSET
}.apply {
parent = container as IrDeclarationParent
val irBuilder = context.createIrBuilder(symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET)
owner.valueParameters.forEach { valueParameter ->
addValueParameter(
valueParameter.name,
typeSubstitutor.substitute(valueParameter.type)
)
}
body = irFactory.createBlockBody(
expression.startOffset,
expression.endOffset
) {
statements.add(
irBuilder.irReturn(
irBuilder.irCall(owner.symbol).also { call ->
call.dispatchReceiver = expression.dispatchReceiver
call.extensionReceiver = expression.extensionReceiver
valueParameters.forEachIndexed { index, valueParameter ->
call.putValueArgument(index, irBuilder.irGet(valueParameter))
}
for (i in 0 until expression.typeArgumentsCount) {
call.putTypeArgument(i, expression.getTypeArgument(i))
}
},
)
)
}
}
return context.createIrBuilder(container.symbol).irBlock(
expression,
origin = IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
) {
+function
+IrFunctionReferenceImpl.fromSymbolOwner(
expression.startOffset,
expression.endOffset,
expression.type,
function.symbol,
function.typeParameters.size,
expression.reflectionTarget
)
}
}
})
}
}