Collect classes for JVM that must be regenerated after IR inline
This commit is contained in:
+7
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common.lower
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
@@ -120,6 +121,12 @@ abstract class InventNamesForLocalClasses(private val allowTopLevelCallables: Bo
|
||||
expression.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
override fun visitFunctionExpression(expression: IrFunctionExpression, data: Data) {
|
||||
expression.acceptChildren(this, data)
|
||||
val internalName = localFunctionNames[expression.function.symbol] ?: inventName(null, data)
|
||||
putLocalClassName(expression, internalName)
|
||||
}
|
||||
|
||||
override fun visitPropertyReference(expression: IrPropertyReference, data: Data) {
|
||||
val internalName = inventName(null, data)
|
||||
putLocalClassName(expression, internalName)
|
||||
|
||||
+49
-14
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.common.lower.InnerClassesSupport
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
@@ -29,9 +30,7 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
fun IrValueParameter.isInlineParameter(type: IrType = this.type) =
|
||||
@@ -85,9 +84,10 @@ class FunctionInlining(
|
||||
val innerClassesSupport: InnerClassesSupport? = null,
|
||||
val insertAdditionalImplicitCasts: Boolean = false,
|
||||
val alwaysCreateTemporaryVariablesForArguments: Boolean = false,
|
||||
val inlinePureArguments: Boolean = true,
|
||||
val regenerateInlinedAnonymousObjects: Boolean = false,
|
||||
val inlineArgumentsWithTheirOriginalType: Boolean = false,
|
||||
) : IrElementTransformerVoidWithContext(), BodyLoweringPass {
|
||||
|
||||
constructor(context: CommonBackendContext) : this(context, DefaultInlineFunctionResolver(context), null)
|
||||
constructor(context: CommonBackendContext, innerClassesSupport: InnerClassesSupport) : this(
|
||||
context,
|
||||
@@ -133,13 +133,34 @@ class FunctionInlining(
|
||||
return expression
|
||||
}
|
||||
|
||||
withinScope(actualCallee) {
|
||||
actualCallee.body?.transformChildrenVoid()
|
||||
}
|
||||
|
||||
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
|
||||
?: allScopes.map { it.irElement }.filterIsInstance<IrDeclaration>().lastOrNull()?.parent
|
||||
?: containerScope?.irElement as? IrDeclarationParent
|
||||
?: (containerScope?.irElement as? IrDeclaration)?.parent
|
||||
|
||||
val inliner = Inliner(expression, actualCallee, currentScope ?: containerScope!!, parent, context)
|
||||
return inliner.inline()
|
||||
return inliner.inline().markAsRegenerated()
|
||||
}
|
||||
|
||||
private fun IrReturnableBlock.markAsRegenerated(): IrReturnableBlock {
|
||||
if (!regenerateInlinedAnonymousObjects) return this
|
||||
acceptVoid(object : IrElementVisitorVoid {
|
||||
private fun IrAttributeContainer.setUpCorrectAttributeOwner() {
|
||||
if (this.attributeOwnerId == this) return
|
||||
this.attributeOwnerIdBeforeInline = this.attributeOwnerId
|
||||
this.attributeOwnerId = this
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
if (element is IrAttributeContainer) element.setUpCorrectAttributeOwner()
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
private val IrFunction.needsInlining get() = this.isInline && !this.isExternal
|
||||
@@ -248,7 +269,6 @@ class FunctionInlining(
|
||||
//---------------------------------------------------------------------//
|
||||
|
||||
private inner class ParameterSubstitutor : IrElementTransformerVoid() {
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val newExpression = super.visitGetValue(expression) as IrGetValue
|
||||
val argument = substituteMap[newExpression.symbol.owner] ?: return newExpression
|
||||
@@ -267,13 +287,17 @@ class FunctionInlining(
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
// TODO extract to common utils OR reuse ContractDSLRemoverLowering
|
||||
if (expression.symbol.owner.hasAnnotation(ContractsDslNames.CONTRACTS_DSL_ANNOTATION_FQN)) {
|
||||
return IrCompositeImpl(expression.startOffset, expression.endOffset, context.irBuiltIns.unitType)
|
||||
}
|
||||
|
||||
if (!isLambdaCall(expression))
|
||||
return super.visitCall(expression)
|
||||
|
||||
val dispatchReceiver = expression.dispatchReceiver?.unwrapAdditionalImplicitCastsIfNeeded() as IrGetValue
|
||||
val functionArgument = substituteMap[dispatchReceiver.symbol.owner] ?: return super.visitCall(expression)
|
||||
if ((dispatchReceiver.symbol.owner as? IrValueParameter)?.isNoinline == true)
|
||||
return super.visitCall(expression)
|
||||
if ((dispatchReceiver.symbol.owner as? IrValueParameter)?.isNoinline == true) return super.visitCall(expression)
|
||||
|
||||
return when {
|
||||
functionArgument is IrFunctionReference ->
|
||||
@@ -370,7 +394,8 @@ class FunctionInlining(
|
||||
endOffset,
|
||||
inlinedFunction.returnType,
|
||||
inlinedFunction.symbol,
|
||||
classTypeParametersCount
|
||||
classTypeParametersCount,
|
||||
INLINED_FUNCTION_REFERENCE
|
||||
)
|
||||
}
|
||||
is IrSimpleFunction ->
|
||||
@@ -380,7 +405,8 @@ class FunctionInlining(
|
||||
inlinedFunction.returnType,
|
||||
inlinedFunction.symbol,
|
||||
inlinedFunction.typeParameters.size,
|
||||
inlinedFunction.valueParameters.size
|
||||
inlinedFunction.valueParameters.size,
|
||||
INLINED_FUNCTION_REFERENCE
|
||||
)
|
||||
else ->
|
||||
error("Unknown function kind : ${inlinedFunction.render()}")
|
||||
@@ -468,15 +494,16 @@ class FunctionInlining(
|
||||
val argumentExpression: IrExpression,
|
||||
val isDefaultArg: Boolean = false
|
||||
) {
|
||||
|
||||
val isInlinableLambdaArgument: Boolean
|
||||
get() = parameter.isInlineParameter() &&
|
||||
// must take "original" parameter because it can have generic type and so considered as no inline; see `lambdaAsGeneric.kt`
|
||||
get() = parameter.getOriginalParameter().isInlineParameter() &&
|
||||
(argumentExpression is IrFunctionReference
|
||||
|| argumentExpression is IrFunctionExpression
|
||||
|| argumentExpression.isAdaptedFunctionReference())
|
||||
|
||||
val isInlinablePropertyReference: Boolean
|
||||
get() = parameter.isInlineParameter() && argumentExpression is IrPropertyReference
|
||||
// must take "original" parameter because it can have generic type and so considered as no inline; see `lambdaAsGeneric.kt`
|
||||
get() = parameter.getOriginalParameter().isInlineParameter() && argumentExpression is IrPropertyReference
|
||||
|
||||
val isImmutableVariableLoad: Boolean
|
||||
get() = argumentExpression.let { argument ->
|
||||
@@ -631,6 +658,12 @@ class FunctionInlining(
|
||||
return evaluationStatements
|
||||
}
|
||||
|
||||
private fun IrValueParameter.getOriginalParameter(): IrValueParameter {
|
||||
if (this.parent !is IrFunction) return this
|
||||
val original = (this.parent as IrFunction).originalFunction
|
||||
return original.allParameters.singleOrNull { it.name == this.name && it.startOffset == this.startOffset } ?: this
|
||||
}
|
||||
|
||||
// In short this is needed for `kt44429` test. We need to get original generic type to trick type system on JVM backend.
|
||||
private fun IrValueParameter.getOriginalType(): IrType {
|
||||
if (this.parent !is IrFunction) return type
|
||||
@@ -679,6 +712,7 @@ class FunctionInlining(
|
||||
val shouldCreateTemporaryVariable =
|
||||
(alwaysCreateTemporaryVariablesForArguments && !parameter.isInlineParameter()) ||
|
||||
argument.shouldBeSubstitutedViaTemporaryVariable()
|
||||
|
||||
if (shouldCreateTemporaryVariable) {
|
||||
val newVariable = createTemporaryVariable(parameter, variableInitializer, callee)
|
||||
|
||||
@@ -710,7 +744,7 @@ class FunctionInlining(
|
||||
}
|
||||
|
||||
private fun ParameterToArgument.shouldBeSubstitutedViaTemporaryVariable(): Boolean =
|
||||
!isImmutableVariableLoad && !argumentExpression.isPure(false, context = context)
|
||||
!isImmutableVariableLoad && !(argumentExpression.isPure(false, context = context) && inlinePureArguments)
|
||||
|
||||
private fun createTemporaryVariable(parameter: IrValueParameter, variableInitializer: IrExpression, callee: IrFunction): IrVariable {
|
||||
val variable = currentScope.scope.createTemporaryVariable(
|
||||
@@ -760,6 +794,7 @@ class FunctionInlining(
|
||||
}
|
||||
}
|
||||
|
||||
object INLINED_FUNCTION_REFERENCE : IrStatementOriginImpl("INLINED_FUNCTION_REFERENCE")
|
||||
object INLINED_FUNCTION_ARGUMENTS : IrStatementOriginImpl("INLINED_FUNCTION_ARGUMENTS")
|
||||
object INLINED_FUNCTION_DEFAULT_ARGUMENTS : IrStatementOriginImpl("INLINED_FUNCTION_DEFAULT_ARGUMENTS")
|
||||
|
||||
|
||||
+17
-5
@@ -25,8 +25,8 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
@@ -67,8 +67,19 @@ fun IrFrameMap.leave(irDeclaration: IrSymbolOwner): Int {
|
||||
return leave(irDeclaration.symbol)
|
||||
}
|
||||
|
||||
fun IrClass.getOriginalDeclaration(): IrDeclaration? {
|
||||
val originalClass = this.attributeOwnerIdBeforeInline ?: return null
|
||||
return when (originalClass) {
|
||||
is IrClass -> return originalClass
|
||||
is IrFunctionExpression -> originalClass.function
|
||||
is IrFunctionReference -> originalClass.symbol.owner
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun JvmBackendContext.getSourceMapper(declaration: IrClass): SourceMapper {
|
||||
val fileEntry = declaration.fileParent.fileEntry
|
||||
val originalDeclarationBeforeInline = declaration.getOriginalDeclaration() ?: declaration
|
||||
val fileEntry = originalDeclarationBeforeInline.fileParent.fileEntry
|
||||
// NOTE: apparently inliner requires the source range to cover the
|
||||
// whole file the class is declared in rather than the class only.
|
||||
val endLineNumber = when (fileEntry) {
|
||||
@@ -77,12 +88,13 @@ fun JvmBackendContext.getSourceMapper(declaration: IrClass): SourceMapper {
|
||||
}
|
||||
val sourceFileName = when (fileEntry) {
|
||||
is MultifileFacadeFileEntry -> fileEntry.partFiles.singleOrNull()?.name
|
||||
else -> declaration.fileParent.name
|
||||
else -> originalDeclarationBeforeInline.fileParent.name
|
||||
}
|
||||
val type = declaration.attributeOwnerIdBeforeInline?.let { getLocalClassType(it)!! } ?: defaultTypeMapper.mapClass(declaration)
|
||||
return SourceMapper(
|
||||
SourceInfo(
|
||||
sourceFileName,
|
||||
defaultTypeMapper.mapClass(declaration).internalName,
|
||||
type.internalName,
|
||||
endLineNumber + 1
|
||||
)
|
||||
)
|
||||
|
||||
+1
@@ -70,6 +70,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
||||
irBuiltIns.ororSymbol.toKey()!! to OrOr,
|
||||
irBuiltIns.dataClassArrayMemberHashCodeSymbol.toKey()!! to IrDataClassArrayMemberHashCode,
|
||||
irBuiltIns.dataClassArrayMemberToStringSymbol.toKey()!! to IrDataClassArrayMemberToString,
|
||||
symbols.singleArgumentInlineFunction.toKey()!! to SingleArgumentInlineFunctionIntrinsic,
|
||||
symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce,
|
||||
symbols.signatureStringIntrinsic.toKey()!! to SignatureString,
|
||||
symbols.throwNullPointerException.toKey()!! to ThrowException(Type.getObjectType("java/lang/NullPointerException")),
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.unwrapInlineLambda
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
|
||||
object SingleArgumentInlineFunctionIntrinsic : IntrinsicMethod() {
|
||||
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
|
||||
val sourceCompiler = IrSourceCompilerForInline(codegen.state, expression, expression.symbol.owner, codegen, data)
|
||||
val argumentExpression = expression.getValueArgument(0)!!
|
||||
val inlineLambda = argumentExpression.unwrapInlineLambda()
|
||||
if (inlineLambda != null) {
|
||||
val lambdaInfo = IrExpressionLambdaImpl(codegen, inlineLambda)
|
||||
lambdaInfo.generateLambdaBody(sourceCompiler)
|
||||
}
|
||||
|
||||
return codegen.unitValue
|
||||
}
|
||||
}
|
||||
@@ -120,33 +120,35 @@ internal val IrClass.isGeneratedLambdaClass: Boolean
|
||||
origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
|
||||
origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||
|
||||
private class JvmVisibilityPolicy : VisibilityPolicy {
|
||||
// Note: any condition that results in non-`LOCAL` visibility here should be duplicated in `JvmLocalClassPopupLowering`,
|
||||
// else it won't detect the class as local.
|
||||
override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (declaration.isGeneratedLambdaClass) {
|
||||
scopedVisibility(inInlineFunctionScope)
|
||||
} else {
|
||||
declaration.visibility
|
||||
}
|
||||
|
||||
override fun forConstructor(declaration: IrConstructor, inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (declaration.parentAsClass.isAnonymousObject)
|
||||
scopedVisibility(inInlineFunctionScope)
|
||||
else
|
||||
declaration.visibility
|
||||
|
||||
override fun forCapturedField(value: IrValueSymbol): DescriptorVisibility =
|
||||
JavaDescriptorVisibilities.PACKAGE_VISIBILITY // avoid requiring a synthetic accessor for it
|
||||
|
||||
private fun scopedVisibility(inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
}
|
||||
|
||||
internal val localDeclarationsPhase = makeIrFilePhase(
|
||||
{ context ->
|
||||
LocalDeclarationsLowering(
|
||||
context,
|
||||
NameUtils::sanitizeAsJavaIdentifier,
|
||||
object : VisibilityPolicy {
|
||||
// Note: any condition that results in non-`LOCAL` visibility here should be duplicated in `JvmLocalClassPopupLowering`,
|
||||
// else it won't detect the class as local.
|
||||
override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (declaration.isGeneratedLambdaClass) {
|
||||
scopedVisibility(inInlineFunctionScope)
|
||||
} else {
|
||||
declaration.visibility
|
||||
}
|
||||
|
||||
override fun forConstructor(declaration: IrConstructor, inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (declaration.parentAsClass.isAnonymousObject)
|
||||
scopedVisibility(inInlineFunctionScope)
|
||||
else
|
||||
declaration.visibility
|
||||
|
||||
override fun forCapturedField(value: IrValueSymbol): DescriptorVisibility =
|
||||
JavaDescriptorVisibilities.PACKAGE_VISIBILITY // avoid requiring a synthetic accessor for it
|
||||
|
||||
private fun scopedVisibility(inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
},
|
||||
JvmVisibilityPolicy(),
|
||||
compatibilityModeForInlinedLocalDelegatedPropertyAccessors = true,
|
||||
forceFieldsForInlineCaptures = true,
|
||||
postLocalDeclarationLoweringCallback = context.localDeclarationsLoweringData?.let {
|
||||
@@ -280,7 +282,7 @@ private val kotlinNothingValueExceptionPhase = makeIrFilePhase<CommonBackendCont
|
||||
description = "Throw proper exception for calls returning value of type 'kotlin.Nothing'"
|
||||
)
|
||||
|
||||
private val functionInliningPhase = makeIrModulePhase<JvmBackendContext>(
|
||||
internal val functionInliningPhase = makeIrModulePhase<JvmBackendContext>(
|
||||
{ context ->
|
||||
class JvmInlineFunctionResolver : InlineFunctionResolver {
|
||||
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
|
||||
@@ -293,6 +295,8 @@ private val functionInliningPhase = makeIrModulePhase<JvmBackendContext>(
|
||||
}
|
||||
FunctionInlining(
|
||||
context, JvmInlineFunctionResolver(), context.innerClassesSupport,
|
||||
inlinePureArguments = false,
|
||||
regenerateInlinedAnonymousObjects = true,
|
||||
inlineArgumentsWithTheirOriginalType = true
|
||||
)
|
||||
},
|
||||
@@ -355,6 +359,7 @@ private val jvmFilePhases = listOf(
|
||||
localDeclarationsPhase,
|
||||
// makePatchParentsPhase(),
|
||||
|
||||
removeDuplicatedInlinedLocalClasses,
|
||||
jvmLocalClassExtractionPhase,
|
||||
staticCallableReferencePhase,
|
||||
|
||||
@@ -440,6 +445,8 @@ private fun buildJvmLoweringPhases(
|
||||
repeatedAnnotationPhase then
|
||||
|
||||
functionInliningPhase then
|
||||
createSeparateCallForInlinedLambdas then
|
||||
markNecessaryInlinedClassesAsRegenerated then
|
||||
|
||||
buildLoweringsPhase(phases) then
|
||||
generateMultifileFacadesPhase then
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.ir.getAdditionalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.ir.isFunctionInlining
|
||||
import org.jetbrains.kotlin.backend.common.ir.putStatementBeforeActualInline
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.functionInliningPhase
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
|
||||
internal val createSeparateCallForInlinedLambdas = makeIrModulePhase(
|
||||
::CreateSeparateCallForInlinedLambdasLowering,
|
||||
name = "CreateSeparateCallForInlinedLambdasLowering",
|
||||
description = "This lowering will create separate call `singleArgumentInlineFunction` with previously inlined lambda as argument",
|
||||
prerequisite = setOf(functionInliningPhase)
|
||||
)
|
||||
|
||||
class CreateSeparateCallForInlinedLambdasLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
|
||||
if (expression is IrInlinedFunctionBlock && expression.isFunctionInlining()) {
|
||||
val newCalls = expression.getOnlyInlinableArguments().map { arg ->
|
||||
IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.ir.symbols.singleArgumentInlineFunction)
|
||||
.also { it.putValueArgument(0, arg.transform(this, null)) }
|
||||
}
|
||||
|
||||
// we don't need to transform body of original function, just arguments that were extracted as variables
|
||||
expression.getAdditionalStatementsFromInlinedBlock().forEach { it.transformChildrenVoid() }
|
||||
newCalls.reversed().forEach {
|
||||
expression.putStatementBeforeActualInline(context.createJvmIrBuilder(it.symbol), it)
|
||||
}
|
||||
return expression
|
||||
}
|
||||
|
||||
return super.visitContainerExpression(expression)
|
||||
}
|
||||
|
||||
private fun IrInlinedFunctionBlock.getOnlyInlinableArguments(): List<IrExpression> {
|
||||
return this.inlineCall.getArgumentsWithIr()
|
||||
.filter { (param, arg) -> param.isInlineParameter() && arg.isInlinableExpression() }
|
||||
.map { it.second }
|
||||
}
|
||||
|
||||
private fun IrExpression.isInlinableExpression(): Boolean {
|
||||
return this is IrFunctionExpression || this is IrFunctionReference || this is IrPropertyReference
|
||||
|| (this is IrBlock && origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
|
||||
}
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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.ir.inlineDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.ir.isFunctionInlining
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.INLINED_FUNCTION_REFERENCE
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.functionInliningPhase
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||
import org.jetbrains.kotlin.ir.util.getAllArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
internal val markNecessaryInlinedClassesAsRegenerated = makeIrModulePhase(
|
||||
::MarkNecessaryInlinedClassesAsRegeneratedLowering,
|
||||
name = "MarkNecessaryInlinedClassesAsRegeneratedLowering",
|
||||
description = "Will scan all inlined functions and mark anonymous objects that must be later regenerated at backend",
|
||||
prerequisite = setOf(functionInliningPhase, createSeparateCallForInlinedLambdas)
|
||||
)
|
||||
|
||||
class MarkNecessaryInlinedClassesAsRegeneratedLowering(val context: JvmBackendContext) : IrElementVisitorVoid, FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitBlock(expression: IrBlock) {
|
||||
if (expression is IrInlinedFunctionBlock && expression.isFunctionInlining()) {
|
||||
val element = expression.inlineDeclaration
|
||||
if (context.visitedDeclarationsForRegenerationLowering.add(element)) {
|
||||
// Note: functions from other module will not be affected here, they are loaded as IrLazy declarations.
|
||||
// BUT during IR serialization support we need to carefully test this logic.
|
||||
element.acceptVoid(this)
|
||||
}
|
||||
|
||||
val mustBeRegenerated = expression.collectDeclarationsThatMustBeRegenerated()
|
||||
expression.setUpCorrectAttributesForAllInnerElements(mustBeRegenerated)
|
||||
return
|
||||
}
|
||||
|
||||
super.visitBlock(expression)
|
||||
}
|
||||
|
||||
private fun IrInlinedFunctionBlock.collectDeclarationsThatMustBeRegenerated(): Set<IrAttributeContainer> {
|
||||
val classesToRegenerate = mutableSetOf<IrAttributeContainer>()
|
||||
this.acceptVoid(object : IrElementVisitorVoid {
|
||||
private val containersStack = mutableListOf<IrAttributeContainer>()
|
||||
private val inlinableParameters = mutableListOf<IrValueParameter>()
|
||||
private val reifiedArguments = mutableListOf<IrType>()
|
||||
private var processingBeforeInlineDeclaration = false
|
||||
|
||||
fun IrInlinedFunctionBlock.getInlinableParameters(): List<IrValueParameter> {
|
||||
val callee = this.inlineDeclaration
|
||||
if (callee !is IrFunction) return emptyList()
|
||||
// Must pass `callee` explicitly because there can be problems if call was created for fake override
|
||||
return this.inlineCall.getAllArgumentsWithIr(callee)
|
||||
.filter { (param, arg) ->
|
||||
param.isInlineParameter() && (arg ?: param.defaultValue?.expression) is IrFunctionExpression ||
|
||||
arg is IrGetValue && arg.symbol.owner in inlinableParameters
|
||||
}
|
||||
.map { it.first }
|
||||
}
|
||||
|
||||
fun IrInlinedFunctionBlock.getReifiedArguments(): List<IrType> {
|
||||
val callee = this.inlineDeclaration
|
||||
if (callee !is IrFunction) return emptyList()
|
||||
return callee.typeParameters.mapIndexedNotNull { index, param ->
|
||||
this.inlineCall.getTypeArgument(index)?.takeIf { param.isReified }
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveDeclarationsFromStackIntoRegenerationPool() {
|
||||
containersStack.forEach {
|
||||
classesToRegenerate += it
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
|
||||
|
||||
private fun visitAnonymousDeclaration(declaration: IrAttributeContainer) {
|
||||
containersStack += declaration
|
||||
if (declaration.hasReifiedTypeArguments(reifiedArguments)) {
|
||||
saveDeclarationsFromStackIntoRegenerationPool()
|
||||
}
|
||||
if (!processingBeforeInlineDeclaration) {
|
||||
processingBeforeInlineDeclaration = true
|
||||
declaration.attributeOwnerIdBeforeInline?.acceptChildrenVoid(this) // check if we need to save THIS declaration
|
||||
processingBeforeInlineDeclaration = false
|
||||
}
|
||||
declaration.acceptChildrenVoid(this) // check if we need to save INNER declarations
|
||||
containersStack.removeLast()
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
visitAnonymousDeclaration(declaration)
|
||||
}
|
||||
|
||||
override fun visitFunctionExpression(expression: IrFunctionExpression) {
|
||||
visitAnonymousDeclaration(expression)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||
visitAnonymousDeclaration(expression)
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue) {
|
||||
super.visitGetValue(expression)
|
||||
if (
|
||||
expression.symbol.owner in inlinableParameters ||
|
||||
expression.type.getClass()?.let { classesToRegenerate.contains(it) } == true
|
||||
) {
|
||||
saveDeclarationsFromStackIntoRegenerationPool()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
if (expression.symbol == context.ir.symbols.singleArgumentInlineFunction) {
|
||||
when (val lambda = expression.getValueArgument(0)) {
|
||||
is IrBlock -> (lambda.statements.last() as IrFunctionReference).acceptVoid(this)
|
||||
is IrFunctionExpression -> lambda.function.acceptVoid(this)
|
||||
else -> lambda?.acceptVoid(this) // for example IrFunctionReference
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (expression.origin == INLINED_FUNCTION_REFERENCE) {
|
||||
saveDeclarationsFromStackIntoRegenerationPool()
|
||||
}
|
||||
super.visitCall(expression)
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression) {
|
||||
if (expression is IrInlinedFunctionBlock && expression.isFunctionInlining()) {
|
||||
val additionalInlinableParameters = expression.getInlinableParameters()
|
||||
val additionalTypeArguments = expression.getReifiedArguments()
|
||||
|
||||
inlinableParameters.addAll(additionalInlinableParameters)
|
||||
reifiedArguments.addAll(additionalTypeArguments)
|
||||
super.visitContainerExpression(expression)
|
||||
inlinableParameters.dropLast(additionalInlinableParameters.size)
|
||||
reifiedArguments.dropLast(additionalTypeArguments.size)
|
||||
return
|
||||
}
|
||||
|
||||
super.visitContainerExpression(expression)
|
||||
}
|
||||
})
|
||||
return classesToRegenerate
|
||||
}
|
||||
|
||||
private fun IrAttributeContainer.hasReifiedTypeArguments(reifiedArguments: List<IrType>): Boolean {
|
||||
var hasReified = false
|
||||
|
||||
fun IrType.recursiveWalkDown(visitor: IrElementVisitorVoid) {
|
||||
hasReified = hasReified || this@recursiveWalkDown in reifiedArguments
|
||||
(this@recursiveWalkDown as? IrSimpleType)?.arguments?.forEach { it.typeOrNull?.recursiveWalkDown(visitor) }
|
||||
}
|
||||
|
||||
this.acceptVoid(object : IrElementVisitorVoid {
|
||||
private val visitedClasses = mutableSetOf<IrClass>()
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
if (hasReified) return
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (!visitedClasses.add(declaration)) return
|
||||
declaration.superTypes.forEach { it.recursiveWalkDown(this) }
|
||||
super.visitClass(declaration)
|
||||
}
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall) {
|
||||
expression.typeOperand.takeIf { it is IrSimpleType }?.recursiveWalkDown(this)
|
||||
super.visitTypeOperator(expression)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
(0 until expression.typeArgumentsCount).forEach {
|
||||
expression.getTypeArgument(it)?.recursiveWalkDown(this)
|
||||
}
|
||||
super.visitCall(expression)
|
||||
}
|
||||
|
||||
override fun visitClassReference(expression: IrClassReference) {
|
||||
expression.classType.recursiveWalkDown(this)
|
||||
super.visitClassReference(expression)
|
||||
}
|
||||
})
|
||||
return hasReified
|
||||
}
|
||||
|
||||
private fun IrElement.setUpCorrectAttributesForAllInnerElements(mustBeRegenerated: Set<IrAttributeContainer>) {
|
||||
this.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
private fun checkAndSetUpCorrectAttributes(element: IrAttributeContainer) {
|
||||
when {
|
||||
element !in mustBeRegenerated && element.attributeOwnerIdBeforeInline != null -> element.setUpOriginalAttributes()
|
||||
else -> element.acceptChildrenVoid(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
checkAndSetUpCorrectAttributes(declaration)
|
||||
}
|
||||
|
||||
override fun visitFunctionExpression(expression: IrFunctionExpression) {
|
||||
checkAndSetUpCorrectAttributes(expression)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||
checkAndSetUpCorrectAttributes(expression)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrElement.setUpOriginalAttributes() {
|
||||
acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
if (element is IrAttributeContainer && element.attributeOwnerIdBeforeInline != null) {
|
||||
// Basically we need to generate SEQUENCE of `element.attributeOwnerIdBeforeInline` and find the original one.
|
||||
// But we process nested inlined functions first, so `element.attributeOwnerIdBeforeInline` will be processed already.
|
||||
// This mean that when we start to precess current container, all inner ones in SEQUENCE will already be processed.
|
||||
element.attributeOwnerId = element.attributeOwnerIdBeforeInline!!.attributeOwnerId
|
||||
element.attributeOwnerIdBeforeInline = null
|
||||
}
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.ir.getDefaultAdditionalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.ir.getNonDefaultAdditionalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.ir.getOriginalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.functionInliningPhase
|
||||
import org.jetbrains.kotlin.backend.jvm.localDeclarationsPhase
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
internal val removeDuplicatedInlinedLocalClasses = makeIrFilePhase(
|
||||
::RemoveDuplicatedInlinedLocalClassesLowering,
|
||||
name = "RemoveDuplicatedInlinedLocalClasses",
|
||||
description = "Drop excess local classes that were copied by ir inliner",
|
||||
prerequisite = setOf(functionInliningPhase, localDeclarationsPhase)
|
||||
)
|
||||
|
||||
// There are three types of inlined local classes:
|
||||
// 1. MUST BE regenerated according to set of rules in AnonymousObjectTransformationInfo.
|
||||
// They all have `attributeOwnerIdBeforeInline != null`.
|
||||
// 2. MUST NOT BE regenerated and MUST BE CREATED only once because they are copied from call site.
|
||||
// This lambda will not exist after inline, so we copy declaration into new temporary inline call `singleArgumentInlineFunction`.
|
||||
// 3. MUST NOT BE created at all because will be created at callee site.
|
||||
// This lowering drops declarations that correspond to second and third type.
|
||||
class RemoveDuplicatedInlinedLocalClassesLowering(val context: JvmBackendContext) : IrElementTransformer<Boolean>, FileLoweringPass {
|
||||
private var insideInlineBlock = false
|
||||
private val visited = mutableSetOf<IrElement>()
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildren(this, false)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Boolean): IrElement {
|
||||
if (expression.symbol == context.ir.symbols.singleArgumentInlineFunction) return expression
|
||||
return super.visitCall(expression, data)
|
||||
}
|
||||
|
||||
override fun visitBlock(expression: IrBlock, data: Boolean): IrExpression {
|
||||
if (expression is IrInlinedFunctionBlock) {
|
||||
val oldInsideInlineBlock = insideInlineBlock
|
||||
insideInlineBlock = true
|
||||
expression.getNonDefaultAdditionalStatementsFromInlinedBlock().forEach { it.transform(this, false) }
|
||||
expression.getDefaultAdditionalStatementsFromInlinedBlock().forEach { it.transform(this, true) }
|
||||
expression.getOriginalStatementsFromInlinedBlock().forEach { it.transform(this, true) }
|
||||
insideInlineBlock = oldInsideInlineBlock
|
||||
return expression
|
||||
}
|
||||
|
||||
return super.visitBlock(expression, data)
|
||||
}
|
||||
|
||||
// Basically we want to remove all anonymous classes after inline. Exceptions are:
|
||||
// 1. classes that must be regenerated (declaration.attributeOwnerIdBeforeInline != null)
|
||||
// 2. classes that are originally declared on call site or are default lambdas (data == true)
|
||||
override fun visitClass(declaration: IrClass, data: Boolean): IrStatement {
|
||||
if (!insideInlineBlock || declaration.attributeOwnerIdBeforeInline != null || !data) {
|
||||
return super.visitClass(declaration, data)
|
||||
}
|
||||
|
||||
// TODO big note. Here we drop anonymous class declaration but there still present a constructor call that has reference to this class.
|
||||
// Everything works fine because somewhere in code we still have class declaration with the same name. So this doesn't ruin code
|
||||
// generation and will not drop on runtime, but this is something to be aware of.
|
||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.irBuiltIns.unitType)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: Boolean): IrElement {
|
||||
if (!visited.add(expression.symbol.owner)) return expression
|
||||
expression.symbol.owner.accept(this, data)
|
||||
return super.visitFunctionReference(expression, data)
|
||||
}
|
||||
}
|
||||
@@ -173,6 +173,8 @@ class JvmBackendContext(
|
||||
|
||||
val publicAbiSymbols = mutableSetOf<IrClassSymbol>()
|
||||
|
||||
val visitedDeclarationsForRegenerationLowering: MutableSet<IrDeclaration> = ConcurrentHashMap.newKeySet()
|
||||
|
||||
init {
|
||||
state.mapInlineClass = { descriptor ->
|
||||
defaultTypeMapper.mapType(referenceClass(descriptor).defaultType)
|
||||
|
||||
@@ -150,6 +150,9 @@ class JvmSymbols(
|
||||
addValueParameter("message", irBuiltIns.stringType)
|
||||
}
|
||||
klass.addFunction("throwNpe", irBuiltIns.unitType, isStatic = true)
|
||||
klass.addFunction("singleArgumentInlineFunction", irBuiltIns.unitType, isStatic = true, isInline = true).apply {
|
||||
addValueParameter("arg", irBuiltIns.functionClass.defaultType)
|
||||
}
|
||||
|
||||
klass.declarations.add(irFactory.buildClass {
|
||||
name = Name.identifier("Kotlin")
|
||||
@@ -159,6 +162,11 @@ class JvmSymbols(
|
||||
})
|
||||
}
|
||||
|
||||
// This function is used only with ir inliner. It is needed to ensure that all local declarations inside lambda will be generated,
|
||||
// because after inline these lambdas can be dropped.
|
||||
val singleArgumentInlineFunction: IrSimpleFunctionSymbol =
|
||||
intrinsicsClass.functions.single { it.owner.name.asString() == "singleArgumentInlineFunction" }
|
||||
|
||||
val checkExpressionValueIsNotNull: IrSimpleFunctionSymbol =
|
||||
intrinsicsClass.functions.single { it.owner.name.asString() == "checkExpressionValueIsNotNull" }
|
||||
|
||||
|
||||
+2
@@ -198,6 +198,7 @@ fun IrClass.addFunction(
|
||||
isStatic: Boolean = false,
|
||||
isSuspend: Boolean = false,
|
||||
isFakeOverride: Boolean = false,
|
||||
isInline: Boolean = false,
|
||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
|
||||
startOffset: Int = UNDEFINED_OFFSET,
|
||||
endOffset: Int = UNDEFINED_OFFSET
|
||||
@@ -211,6 +212,7 @@ fun IrClass.addFunction(
|
||||
this.visibility = visibility
|
||||
this.isSuspend = isSuspend
|
||||
this.isFakeOverride = isFakeOverride
|
||||
this.isInline = isInline
|
||||
this.origin = origin
|
||||
}.apply {
|
||||
if (!isStatic) {
|
||||
|
||||
@@ -92,11 +92,10 @@ fun IrFunctionAccessExpression.getArgumentsWithSymbols(): List<Pair<IrValueParam
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
|
||||
* Binds all arguments represented in the IR to the parameters of the accessed function.
|
||||
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
||||
*/
|
||||
fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter, IrExpression>> {
|
||||
val res = mutableListOf<Pair<IrValueParameter, IrExpression>>()
|
||||
fun IrMemberAccessExpression<*>.getAllArgumentsWithIr(): List<Pair<IrValueParameter, IrExpression?>> {
|
||||
val irFunction = when (this) {
|
||||
is IrFunctionAccessExpression -> this.symbol.owner
|
||||
is IrFunctionReference -> this.symbol.owner
|
||||
@@ -107,6 +106,16 @@ fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter
|
||||
else -> error(this)
|
||||
}
|
||||
|
||||
return getAllArgumentsWithIr(irFunction)
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds all arguments represented in the IR to the parameters of the explicitly given function.
|
||||
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
||||
*/
|
||||
fun IrMemberAccessExpression<*>.getAllArgumentsWithIr(irFunction: IrFunction): List<Pair<IrValueParameter, IrExpression?>> {
|
||||
val res = mutableListOf<Pair<IrValueParameter, IrExpression?>>()
|
||||
|
||||
dispatchReceiver?.let { arg ->
|
||||
irFunction.dispatchReceiverParameter?.let { parameter -> res += (parameter to arg) }
|
||||
}
|
||||
@@ -116,15 +125,21 @@ fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter
|
||||
}
|
||||
|
||||
irFunction.valueParameters.forEachIndexed { index, it ->
|
||||
val arg = getValueArgument(index)
|
||||
if (arg != null) {
|
||||
res += (it to arg)
|
||||
}
|
||||
res += it to getValueArgument(index)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
|
||||
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter, IrExpression>> {
|
||||
return getAllArgumentsWithIr().filter { it.second != null } as List<Pair<IrValueParameter, IrExpression>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets arguments that are specified by given mapping of parameters.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user