JVM_IR indy-SAM conversions: prohibit in crossinline lambdas
KT-44278 KT-26060 KT-42621
This commit is contained in:
+11
-4
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
|
||||
internal val fakeInliningLocalVariablesLowering = makeIrFilePhase(
|
||||
@@ -56,16 +57,22 @@ internal class FakeInliningLocalVariablesLowering(val context: JvmBackendContext
|
||||
}
|
||||
|
||||
private fun IrFunction.addFakeLocalVariable(name: String) {
|
||||
val oldBody = body
|
||||
context.createIrBuilder(symbol).run {
|
||||
body = irBlockBody {
|
||||
// Create temporary variable, but make sure it's origin is `DEFINED` so that
|
||||
// it will materialize in the code.
|
||||
// Also, do not forget to remove $$forInline suffix, otherwise, IDE will not be able to navigate to inline function.
|
||||
createTmpVariable(irInt(0), name.removeSuffix(FOR_INLINE_SUFFIX), origin = IrDeclarationOrigin.DEFINED)
|
||||
if (body is IrExpressionBody) {
|
||||
+irReturn((body as IrExpressionBody).expression)
|
||||
} else {
|
||||
(body as IrBlockBody).statements.forEach { +it }
|
||||
when (oldBody) {
|
||||
is IrExpressionBody -> {
|
||||
+irReturn(oldBody.expression)
|
||||
}
|
||||
is IrBlockBody ->
|
||||
oldBody.statements.forEach { +it }
|
||||
else -> {
|
||||
throw AssertionError("Unexpected body:\n${this@addFakeLocalVariable.dump()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-2
@@ -45,6 +45,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
// function reference classes needed.
|
||||
private val ignoredFunctionReferences = mutableSetOf<IrCallableReference<*>>()
|
||||
|
||||
private val inlineLambdaToValueParameter = HashMap<IrFunction, IrValueParameter>()
|
||||
|
||||
private val IrFunctionReference.isIgnored: Boolean
|
||||
get() = (!type.isFunctionOrKFunction() && !isSuspendFunctionReference()) || ignoredFunctionReferences.contains(this)
|
||||
|
||||
@@ -56,7 +58,20 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
(origin == null || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE || origin == IrStatementOrigin.SUSPEND_CONVERSION)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
ignoredFunctionReferences.addAll(IrInlineReferenceLocator.scan(context, irFile))
|
||||
irFile.accept(
|
||||
object : IrInlineReferenceLocator(context) {
|
||||
override fun visitInlineLambda(
|
||||
argument: IrFunctionReference,
|
||||
callee: IrFunction,
|
||||
parameter: IrValueParameter,
|
||||
scope: IrDeclaration
|
||||
) {
|
||||
ignoredFunctionReferences.add(argument)
|
||||
inlineLambdaToValueParameter[argument.symbol.owner] = parameter
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
irFile.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
@@ -137,12 +152,21 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
return false
|
||||
|
||||
// Can't use indy-based SAM conversion inside inline fun (Ok in inline lambda).
|
||||
if (target.parents.any { it is IrSimpleFunction && it.isInline && it.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA })
|
||||
if (target.parents.any { it.isInlineFunction() || it.isCrossinlineLambda() })
|
||||
return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun IrDeclarationParent.isInlineFunction() =
|
||||
this is IrSimpleFunction && isInline && origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
|
||||
private fun IrDeclarationParent.isCrossinlineLambda(): Boolean {
|
||||
val irFun = this as? IrSimpleFunction ?: return false
|
||||
return origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA &&
|
||||
inlineLambdaToValueParameter[irFun]?.isCrossinline == true
|
||||
}
|
||||
|
||||
private fun IrType.isProhibitedTypeForIndySamConversion(): Boolean {
|
||||
if (this !is IrSimpleType) return false
|
||||
|
||||
|
||||
+1
@@ -221,6 +221,7 @@ private fun IrSimpleFunction.createMultifileDelegateIfNeeded(
|
||||
if (DescriptorVisibilities.isPrivate(originalVisibility) ||
|
||||
name == StaticInitializersLowering.clinitName ||
|
||||
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR ||
|
||||
origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA ||
|
||||
// $annotations methods in the facade are only needed for const properties.
|
||||
(origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS &&
|
||||
(metadata as? MetadataSource.Property)?.isConst != true)
|
||||
|
||||
Reference in New Issue
Block a user