JVM_IR indy-SAM conversions: use old scheme for suspend funs
KT-44278 KT-26060 KT-42621
This commit is contained in:
+6
@@ -18481,6 +18481,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("suspendFunInterface.kt")
|
||||||
|
public void testSuspendFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/suspendFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
@@ -389,3 +389,9 @@ private fun JvmBackendContext.makeRawTypeAnnotation() =
|
|||||||
|
|
||||||
fun IrClass.rawType(context: JvmBackendContext): IrType =
|
fun IrClass.rawType(context: JvmBackendContext): IrType =
|
||||||
defaultType.addAnnotations(listOf(context.makeRawTypeAnnotation()))
|
defaultType.addAnnotations(listOf(context.makeRawTypeAnnotation()))
|
||||||
|
|
||||||
|
fun IrType.getSingleAbstractMethod(): IrSimpleFunction? =
|
||||||
|
getClass()?.getSingleAbstractMethod()
|
||||||
|
|
||||||
|
fun IrClass.getSingleAbstractMethod(): IrSimpleFunction? =
|
||||||
|
functions.singleOrNull { it.modality == Modality.ABSTRACT }
|
||||||
+15
-11
@@ -105,14 +105,15 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
}
|
}
|
||||||
reference.transformChildrenVoid()
|
reference.transformChildrenVoid()
|
||||||
|
|
||||||
return if (shouldUseIndySamConversions && canUseIndySamConversion(reference)) {
|
val samSuperType = expression.typeOperand
|
||||||
|
return if (shouldUseIndySamConversions && canUseIndySamConversion(reference, samSuperType)) {
|
||||||
wrapSamConversionArgumentWithIndySamConversion(expression)
|
wrapSamConversionArgumentWithIndySamConversion(expression)
|
||||||
} else {
|
} else {
|
||||||
FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
FunctionReferenceBuilder(reference, samSuperType).build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canUseIndySamConversion(reference: IrFunctionReference): Boolean {
|
private fun canUseIndySamConversion(reference: IrFunctionReference, samSuperType: IrType): Boolean {
|
||||||
// Can't use indy for regular function references by default (because of 'equals').
|
// Can't use indy for regular function references by default (because of 'equals').
|
||||||
// TODO special mode that would generate indy everywhere?
|
// TODO special mode that would generate indy everywhere?
|
||||||
if (reference.origin != IrStatementOrigin.LAMBDA)
|
if (reference.origin != IrStatementOrigin.LAMBDA)
|
||||||
@@ -122,6 +123,10 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
if (context.irIntrinsics.getIntrinsic(reference.symbol) != null)
|
if (context.irIntrinsics.getIntrinsic(reference.symbol) != null)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
// Can't use JDK LambdaMetafactory for fun interface with suspend fun
|
||||||
|
if (samSuperType.getSingleAbstractMethod()?.isSuspend == true)
|
||||||
|
return false
|
||||||
|
|
||||||
// Can't use JDK LambdaMetafactory if lambda signature contains an inline class mapped to a non-null reference type.
|
// Can't use JDK LambdaMetafactory if lambda signature contains an inline class mapped to a non-null reference type.
|
||||||
val target = reference.symbol.owner
|
val target = reference.symbol.owner
|
||||||
if (target.extensionReceiverParameter?.run { type.isProhibitedTypeForIndySamConversion() } == true ||
|
if (target.extensionReceiverParameter?.run { type.isProhibitedTypeForIndySamConversion() } == true ||
|
||||||
@@ -201,10 +206,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
if (irLambda.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA)
|
if (irLambda.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA)
|
||||||
throw AssertionError("Can't patch a signature of a non-lambda: ${irLambda.render()}")
|
throw AssertionError("Can't patch a signature of a non-lambda: ${irLambda.render()}")
|
||||||
|
|
||||||
val samClass = samType.classOrNull?.owner
|
val samMethod = samType.getSingleAbstractMethod()
|
||||||
?: throw AssertionError("SAM type should be a class type: '${samType.render()}'")
|
?: throw AssertionError("SAM method not found:\n${samType.render()}")
|
||||||
val samMethod = samClass.functions.singleOrNull { it.modality == Modality.ABSTRACT }
|
|
||||||
?: throw AssertionError("SAM method not found:\n${samClass.dump()}")
|
|
||||||
|
|
||||||
val samMethodParameters = collectValueParameters(samMethod)
|
val samMethodParameters = collectValueParameters(samMethod)
|
||||||
val irLambdaParameters = collectValueParameters(irLambda)
|
val irLambdaParameters = collectValueParameters(irLambda)
|
||||||
@@ -265,7 +268,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
else
|
else
|
||||||
context.ir.symbols.getJvmFunctionClass(argumentTypes.size)
|
context.ir.symbols.getJvmFunctionClass(argumentTypes.size)
|
||||||
private val superMethod =
|
private val superMethod =
|
||||||
functionSuperClass.functions.single { it.owner.modality == Modality.ABSTRACT }
|
functionSuperClass.owner.getSingleAbstractMethod()
|
||||||
|
?: throw AssertionError("Not a SAM class: ${functionSuperClass.owner.render()}")
|
||||||
|
|
||||||
private val useOptimizedSuperClass =
|
private val useOptimizedSuperClass =
|
||||||
context.state.generateOptimizedCallableReferenceSuperClasses
|
context.state.generateOptimizedCallableReferenceSuperClasses
|
||||||
@@ -546,12 +550,12 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
// For functions with inline class return type we need to mangle the invoke method.
|
// For functions with inline class return type we need to mangle the invoke method.
|
||||||
// Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any.
|
// Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any.
|
||||||
val suffix = InlineClassAbi.hashReturnSuffix(callee)
|
val suffix = InlineClassAbi.hashReturnSuffix(callee)
|
||||||
Name.identifier("${superMethod.owner.name.asString()}-${suffix}")
|
Name.identifier("${superMethod.name.asString()}-${suffix}")
|
||||||
} else superMethod.owner.name
|
} else superMethod.name
|
||||||
returnType = callee.returnType
|
returnType = callee.returnType
|
||||||
isSuspend = callee.isSuspend
|
isSuspend = callee.isSuspend
|
||||||
}.apply {
|
}.apply {
|
||||||
overriddenSymbols += superMethod
|
overriddenSymbols += superMethod.symbol
|
||||||
dispatchReceiverParameter = buildReceiverParameter(
|
dispatchReceiverParameter = buildReceiverParameter(
|
||||||
this,
|
this,
|
||||||
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
||||||
|
|||||||
+2
-5
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
|||||||
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
|
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
|
||||||
import org.jetbrains.kotlin.ir.util.isInlined
|
import org.jetbrains.kotlin.ir.util.isInlined
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
@@ -178,9 +177,7 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
|
|
||||||
val samType = call.getTypeArgument(0) as? IrSimpleType
|
val samType = call.getTypeArgument(0) as? IrSimpleType
|
||||||
?: fail("'samType' is expected to be a simple type")
|
?: fail("'samType' is expected to be a simple type")
|
||||||
val samClassSymbol = samType.classOrNull
|
val samMethod = samType.getSingleAbstractMethod()
|
||||||
?: fail("'samType' is expected to be a class type: '${samType.render()}'")
|
|
||||||
val samMethod = samClassSymbol.owner.functions.singleOrNull { it.modality == Modality.ABSTRACT }
|
|
||||||
?: fail("'${samType.render()}' is not a SAM-type")
|
?: fail("'${samType.render()}' is not a SAM-type")
|
||||||
|
|
||||||
val irFunRef = call.getValueArgument(0) as? IrFunctionReference
|
val irFunRef = call.getValueArgument(0) as? IrFunctionReference
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.ir.types.IrType
|
|||||||
import org.jetbrains.kotlin.ir.util.transformIfNeeded
|
import org.jetbrains.kotlin.ir.util.transformIfNeeded
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
|
||||||
|
|
||||||
abstract class IrFunction :
|
abstract class IrFunction :
|
||||||
IrDeclarationBase(),
|
IrDeclarationBase(),
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// !LANGUAGE: +SuspendFunctionsInFunInterfaces +JvmIrEnabledByDefault
|
||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// WITH_COROUTINES
|
||||||
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
|
var c: Continuation<Unit>? = null
|
||||||
|
|
||||||
|
suspend fun suspendMe() = suspendCoroutine<Unit> { continuation ->
|
||||||
|
c = continuation
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(c: suspend () -> Unit) {
|
||||||
|
c.startCoroutine(object: Continuation<Unit> {
|
||||||
|
override val context = EmptyCoroutineContext
|
||||||
|
override fun resumeWith(result: Result<Unit>) {
|
||||||
|
result.getOrThrow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface SuspendFoo {
|
||||||
|
suspend fun foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var test = ""
|
||||||
|
val lambda = SuspendFoo {
|
||||||
|
suspendMe()
|
||||||
|
test += "O"
|
||||||
|
suspendMe()
|
||||||
|
test += "K"
|
||||||
|
}
|
||||||
|
builder {
|
||||||
|
lambda.foo()
|
||||||
|
}
|
||||||
|
c?.resume(Unit)
|
||||||
|
c?.resume(Unit)
|
||||||
|
return test
|
||||||
|
}
|
||||||
+6
@@ -18481,6 +18481,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("suspendFunInterface.kt")
|
||||||
|
public void testSuspendFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/suspendFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+6
@@ -18481,6 +18481,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("suspendFunInterface.kt")
|
||||||
|
public void testSuspendFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/suspendFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+5
@@ -16203,6 +16203,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("suspendFunInterface.kt")
|
||||||
|
public void testSuspendFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/suspendFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user