JVM_IR indy-SAM conversions: inline classes

KT-44278 KT-26060 KT-42621
This commit is contained in:
Dmitry Petrov
2021-01-21 17:39:46 +03:00
parent f30e25aa52
commit 1f16b96796
28 changed files with 721 additions and 50 deletions
@@ -18480,6 +18480,88 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testSimpleIndySam() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
}
@Nested
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
public class InlineClassInSignature extends AbstractFirBlackBoxCodegenTest {
@Test
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("funInterfaceWithInlineAny.kt")
public void testFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineInt.kt")
public void testFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNAny.kt")
public void testFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNInt.kt")
public void testFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNString.kt")
public void testFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineString.kt")
public void testFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineAny.kt")
public void testGenericFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineInt.kt")
public void testGenericFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNAny.kt")
public void testGenericFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNInt.kt")
public void testGenericFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNString.kt")
public void testGenericFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineString.kt")
public void testGenericFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
}
}
}
}
@@ -454,7 +454,7 @@ class JvmSymbols(
}
val receiverFieldName = Name.identifier("receiver")
klass.addProperty() {
klass.addProperty {
name = receiverFieldName
}.apply {
backingField = irFactory.buildField {
@@ -658,7 +658,7 @@ class JvmSymbols(
collectionToArrayClass.functions.single { it.owner.name.asString() == "toArray" && it.owner.valueParameters.size == 2 }
val kClassJava: IrPropertySymbol =
irFactory.buildProperty() {
irFactory.buildProperty {
name = Name.identifier("java")
}.apply {
parent = kotlinJvmPackage
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.overrides.buildFakeOverrideMember
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Handle
@@ -136,38 +134,46 @@ object JvmInvokeDynamic : IntrinsicMethod() {
?: fail("Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference")
val irOriginalFun = irRawFunRef.symbol.owner as? IrSimpleFunction
?: fail("IrSimpleFunction expected: ${irRawFunRef.symbol.owner.render()}")
val substitutedType = irCall.getTypeArgument(0) as? IrSimpleType
val superType = irCall.getTypeArgument(0) as? IrSimpleType
?: fail("Type argument expected")
// Force boxing on primitive types, otherwise D8 fails to accept resulting MethodType in presence of primitive types in arguments
// (LambdaMetafactory is ok with such types, though).
val substitutedTypeWithNullableArgs =
substitutedType.classifier.typeWithArguments(
substitutedType.arguments.map {
when (it) {
is IrStarProjection -> it
is IrTypeProjection -> {
val type = it.type
if (type !is IrSimpleType || type.hasQuestionMark)
it
else
makeTypeProjection(type.withHasQuestionMark(true), it.variance)
}
else ->
fail("Unexpected type argument '${it}' :: ${it::class.simpleName}")
}
}
)
val patchedSuperType = replaceTypeArgumentsWithNullable(superType)
val fakeClass = codegen.context.irFactory.buildClass { name = Name.special("<fake>") }
fakeClass.parent = codegen.context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage
val irFakeOverride = buildFakeOverrideMember(substitutedTypeWithNullableArgs, irOriginalFun, fakeClass) as IrSimpleFunction
val irFakeOverride = buildFakeOverrideMember(patchedSuperType, irOriginalFun, fakeClass) as IrSimpleFunction
irFakeOverride.overriddenSymbols = listOf(irOriginalFun.symbol)
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFakeOverride)
return Type.getMethodType(asmMethod.descriptor)
}
// Given the following functional interface
// fun interface IFoo<T> {
// fun foo(x: T): T
// }
// To comply with java.lang.invoke.LambdaMetafactory requirements, we need an instance method that accepts references
// (not primitives, and not unboxed inline classes).
// In order to do so, we replace type arguments with nullable types.
private fun replaceTypeArgumentsWithNullable(substitutedType: IrSimpleType) =
substitutedType.classifier.typeWithArguments(
substitutedType.arguments.map { typeArgument ->
when (typeArgument) {
is IrStarProjection -> typeArgument
is IrTypeProjection -> {
val type = typeArgument.type
if (type !is IrSimpleType || type.hasQuestionMark)
typeArgument
else {
makeTypeProjection(type.withHasQuestionMark(true), typeArgument.variance)
}
}
else ->
throw AssertionError("Unexpected type argument '$typeArgument' :: ${typeArgument::class.simpleName}")
}
}
)
private fun IrExpression.getIntConst() =
if (this is IrConst<*> && kind == IrConstKind.Int)
this.value as Int
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.lower.SamEqualsHashCodeMethodsGenerat
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.representativeUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.config.JvmSamConversions
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.utils.addIfNotNull
internal val functionReferencePhase = makeIrFilePhase(
::FunctionReferenceLowering,
@@ -115,21 +117,54 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
// TODO special mode that would generate indy everywhere?
if (reference.origin != IrStatementOrigin.LAMBDA)
return false
// TODO wrap intrinsic function in lambda?
if (context.irIntrinsics.getIntrinsic(reference.symbol) != null)
return false
// Can't use JDK LambdaMetafactory if lambda signature contains an inline class mapped to a non-null reference type.
val target = reference.symbol.owner
if (target.extensionReceiverParameter?.run { type.isProhibitedTypeForIndySamConversion() } == true ||
target.valueParameters.any { it.type.isProhibitedTypeForIndySamConversion() } ||
target.returnType.isProhibitedTypeForIndySamConversion()
)
return false
return true
}
private fun IrType.isProhibitedTypeForIndySamConversion(): Boolean {
if (this !is IrSimpleType) return false
val erasedType = when (val classifier = classifier.owner) {
is IrTypeParameter ->
classifier.representativeUpperBound.withHasQuestionMark(hasQuestionMark)
else ->
this
}
val erasedClass = erasedType.getClass() ?: return false
if (!erasedType.isInlined()) return false
val underlyingType = getInlineClassUnderlyingType(erasedClass) as? IrSimpleType
?: throw AssertionError("Underlying type for inline class should be a simple type: ${erasedClass.render()}")
return !underlyingType.hasQuestionMark && !underlyingType.isJvmPrimitiveType()
}
private fun IrType.isJvmPrimitiveType() =
isBoolean() || isChar() || isByte() || isShort() || isInt() || isLong() || isFloat() || isDouble()
private fun wrapSamConversionArgumentWithIndySamConversion(expression: IrTypeOperatorCall): IrExpression {
val samType = expression.typeOperand
return when (val argument = expression.argument) {
is IrFunctionReference ->
wrapWithIndySamConversion(expression.typeOperand, argument)
is IrFunctionReference -> {
wrapWithIndySamConversion(samType, argument)
}
is IrBlock -> {
val last = argument.statements.last()
val functionReference = last as? IrFunctionReference
?: throw AssertionError("Function reference expected: ${last.render()}")
argument.statements[argument.statements.size - 1] = wrapWithIndySamConversion(expression.typeOperand, functionReference)
argument.statements[argument.statements.size - 1] = wrapWithIndySamConversion(samType, functionReference)
return argument
}
else -> throw AssertionError("Block or function reference expected: ${expression.render()}")
@@ -145,6 +180,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
)
private fun wrapWithIndySamConversion(samType: IrType, irFunRef: IrFunctionReference): IrCall {
patchSignatureForIndySamConversion(irFunRef.symbol.owner, samType)
val notNullSamType = samType.makeNotNull()
.removeAnnotations { it.type.classFqName in specialNullabilityAnnotationsFqNames }
return context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
@@ -161,6 +197,48 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
}
}
private fun patchSignatureForIndySamConversion(irLambda: IrFunction, samType: IrType) {
if (irLambda.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA)
throw AssertionError("Can't patch a signature of a non-lambda: ${irLambda.render()}")
val samClass = samType.classOrNull?.owner
?: throw AssertionError("SAM type should be a class type: '${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 irLambdaParameters = collectValueParameters(irLambda)
if (samMethodParameters.size != irLambdaParameters.size) {
throw AssertionError(
"SAM method and implementing lambda have mismatching value parameters " +
"(${samMethodParameters.size} != ${irLambdaParameters.size}:\n" +
"samMethod: ${samMethod.render()}\n" +
"lambda: ${irLambda.render()}"
)
}
for ((irLambdaParameter, samMethodParameter) in irLambdaParameters.zip(samMethodParameters)) {
irLambdaParameter.type = patchTypeForIndySamConversion(irLambdaParameter.type, samMethodParameter.type)
}
irLambda.returnType = patchTypeForIndySamConversion(irLambda.returnType, samMethod.returnType)
}
private fun collectValueParameters(irFunction: IrFunction): List<IrValueParameter> =
ArrayList<IrValueParameter>().apply {
addIfNotNull(irFunction.extensionReceiverParameter)
addAll(irFunction.valueParameters)
}
private fun patchTypeForIndySamConversion(originalType: IrType, targetType: IrType): IrType {
if (originalType.isUnboxedInlineClassType() && !targetType.isUnboxedInlineClassType())
return targetType
return originalType
}
private fun IrType.isUnboxedInlineClassType() =
this is IrSimpleType && isInlined() && !hasQuestionMark
private inner class FunctionReferenceBuilder(val irFunctionReference: IrFunctionReference, val samSuperType: IrType? = null) {
private val isLambda = irFunctionReference.origin.isLambda
@@ -6,11 +6,21 @@ fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Int>) = fs.foo(1)
fun interface IBar<T : Any> {
fun bar(x: T): T
}
fun foo1(foo: IFoo<Int>) = foo.foo(1)
fun bar1(bar: IBar<Int>) = bar.bar(1)
fun box(): String {
val t = foo1 { it + 41 }
if (t != 42) return "Failed: t=$t"
val tt = bar1 { it + 41 }
if (tt != 42) return "Failed: tt=$tt"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Any)
fun interface IFooZ {
fun foo(x: Z): Z
}
fun foo1(fs: IFooZ) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z((it.value as Int) + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Int)
fun interface IFooZ {
fun foo(x: Z): Z
}
fun foo1(fs: IFooZ) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z(it.value + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Any?)
fun interface IFooZ {
fun foo(x: Z): Z
}
fun foo1(fs: IFooZ) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z((it.value as Int) + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Int?)
fun interface IFooZ {
fun foo(x: Z): Z
}
fun foo1(fs: IFooZ) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z(it.value!! + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: String?)
fun interface IFooZ {
fun foo(x: Z): Z
}
fun foo1(fs: IFooZ) = fs.foo(Z("O"))
fun box(): String {
val t = foo1 { Z(it.value!! + "K") }
if (t.value != "OK") return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: String)
fun interface IFooZ {
fun foo(x: Z): Z
}
fun foo1(fs: IFooZ) = fs.foo(Z("O"))
fun box(): String {
val t = foo1 { Z(it.value + "K") }
if (t.value != "OK") return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Any)
fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Z>) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z((it.value as Int) + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Int)
fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Z>) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z(it.value + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Any?)
fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Z>) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z((it.value as Int) + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: Int?)
fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Z>) = fs.foo(Z(1))
fun box(): String {
val t = foo1 { Z(it.value!! + 41) }
if (t.value != 42) return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: String?)
fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Z>) = fs.foo(Z("O"))
fun box(): String {
val t = foo1 { Z(it.value!! + "K") }
if (t.value != "OK") return "Failed: t=$t"
return "OK"
}
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
inline class Z(val value: String)
fun interface IFoo<T> {
fun foo(x: T): T
}
fun foo1(fs: IFoo<Z>) = fs.foo(Z("O"))
fun box(): String {
val t = foo1 { Z(it.value + "K") }
if (t.value != "OK") return "Failed: t=$t"
return "OK"
}
@@ -18480,6 +18480,88 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testSimpleIndySam() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
}
@Nested
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
public class InlineClassInSignature extends AbstractBlackBoxCodegenTest {
@Test
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@Test
@TestMetadata("funInterfaceWithInlineAny.kt")
public void testFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineInt.kt")
public void testFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNAny.kt")
public void testFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNInt.kt")
public void testFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNString.kt")
public void testFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineString.kt")
public void testFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineAny.kt")
public void testGenericFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineInt.kt")
public void testGenericFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNAny.kt")
public void testGenericFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNInt.kt")
public void testGenericFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNString.kt")
public void testGenericFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineString.kt")
public void testGenericFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
}
}
}
}
@@ -18480,6 +18480,88 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testSimpleIndySam() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
}
@Nested
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
public class InlineClassInSignature extends AbstractIrBlackBoxCodegenTest {
@Test
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("funInterfaceWithInlineAny.kt")
public void testFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineInt.kt")
public void testFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNAny.kt")
public void testFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNInt.kt")
public void testFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineNString.kt")
public void testFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt");
}
@Test
@TestMetadata("funInterfaceWithInlineString.kt")
public void testFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineAny.kt")
public void testGenericFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineInt.kt")
public void testGenericFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNAny.kt")
public void testGenericFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNInt.kt")
public void testGenericFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineNString.kt")
public void testGenericFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt");
}
@Test
@TestMetadata("genericFunInterfaceWithInlineString.kt")
public void testGenericFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
}
}
}
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.test.directives
import org.jetbrains.kotlin.config.JvmSamConversions
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.handlers.BytecodeTextHandler
import org.jetbrains.kotlin.test.backend.handlers.IrPrettyKotlinDumpHandler
@@ -91,6 +90,4 @@ object CodegenTestDirectives : SimpleDirectivesContainer() {
val TREAT_AS_ONE_FILE by directive(
description = "Treat bytecode from all files as one in ${BytecodeTextHandler::class}"
)
val SAM_CONVERSIONS by enumDirective<JvmSamConversions>("SAM conversion code generation scheme")
}
@@ -5,10 +5,7 @@
package org.jetbrains.kotlin.test.directives
import org.jetbrains.kotlin.config.JVMAssertionsMode
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
import org.jetbrains.kotlin.config.JvmStringConcat
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
@@ -56,4 +53,9 @@ object JvmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
description = "Configure jvm constructor call normalization mode",
additionalParser = JVMConstructorCallNormalizationMode.Companion::fromStringOrNull
)
val SAM_CONVERSIONS by enumDirective<JvmSamConversions>(
description = "SAM conversion code generation scheme",
additionalParser = JvmSamConversions.Companion::fromString
)
}
@@ -40,13 +40,3 @@ abstract class AbstractJvmBlackBoxCodegenTestBase<R : ResultingArtifact.Frontend
}
}
// This class configures various JVM-specific codegen minutiae.
// Ideally, test directives could take care of such things themselves.
class JvmCodegenEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule, project: MockProject) {
val samConversions = module.directives[CodegenTestDirectives.SAM_CONVERSIONS].lastOrNull()
if (samConversions != null) {
configuration.put(JVMConfigurationKeys.SAM_CONVERSIONS, samConversions)
}
}
}
@@ -18,10 +18,10 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.CONSTRUCTOR_CALL_NORMALIZATION_MODE
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.SAM_CONVERSIONS
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.STRING_CONCAT
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.test.model.DependencyDescription
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.DirectiveToConfigurationKeyExtractor
import org.jetbrains.kotlin.test.services.jvm.CompiledClassesManager
import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager
import org.jetbrains.kotlin.test.util.KtTestUtil
@@ -53,6 +52,7 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
register(STRING_CONCAT, JVMConfigurationKeys.STRING_CONCAT)
register(ASSERTIONS_MODE, JVMConfigurationKeys.ASSERTIONS_MODE)
register(CONSTRUCTOR_CALL_NORMALIZATION_MODE, JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE)
register(SAM_CONVERSIONS, JVMConfigurationKeys.SAM_CONVERSIONS)
}
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule, project: MockProject) {
@@ -162,7 +162,8 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
}
private fun extractConfigurationKind(registeredDirectives: RegisteredDirectives): ConfigurationKind {
val withRuntime = JvmEnvironmentConfigurationDirectives.WITH_RUNTIME in registeredDirectives || JvmEnvironmentConfigurationDirectives.WITH_STDLIB in registeredDirectives
val withRuntime = JvmEnvironmentConfigurationDirectives.WITH_RUNTIME in registeredDirectives ||
JvmEnvironmentConfigurationDirectives.WITH_STDLIB in registeredDirectives
val withReflect = JvmEnvironmentConfigurationDirectives.WITH_REFLECT in registeredDirectives
val noRuntime = JvmEnvironmentConfigurationDirectives.NO_RUNTIME in registeredDirectives
if (noRuntime && withRuntime) {
@@ -16202,6 +16202,79 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testSimpleIndySam() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineClassInSignature extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("funInterfaceWithInlineAny.kt")
public void testFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt");
}
@TestMetadata("funInterfaceWithInlineInt.kt")
public void testFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt");
}
@TestMetadata("funInterfaceWithInlineNAny.kt")
public void testFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt");
}
@TestMetadata("funInterfaceWithInlineNInt.kt")
public void testFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt");
}
@TestMetadata("funInterfaceWithInlineNString.kt")
public void testFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt");
}
@TestMetadata("funInterfaceWithInlineString.kt")
public void testFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt");
}
@TestMetadata("genericFunInterfaceWithInlineAny.kt")
public void testGenericFunInterfaceWithInlineAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt");
}
@TestMetadata("genericFunInterfaceWithInlineInt.kt")
public void testGenericFunInterfaceWithInlineInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt");
}
@TestMetadata("genericFunInterfaceWithInlineNAny.kt")
public void testGenericFunInterfaceWithInlineNAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt");
}
@TestMetadata("genericFunInterfaceWithInlineNInt.kt")
public void testGenericFunInterfaceWithInlineNInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt");
}
@TestMetadata("genericFunInterfaceWithInlineNString.kt")
public void testGenericFunInterfaceWithInlineNString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt");
}
@TestMetadata("genericFunInterfaceWithInlineString.kt")
public void testGenericFunInterfaceWithInlineString() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
}
}
}
}
@@ -13902,6 +13902,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
public void testAllFilesPresentInSam() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineClassInSignature extends AbstractIrJsCodegenBoxES6Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
}
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
}
}
@@ -13902,6 +13902,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
public void testAllFilesPresentInSam() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineClassInSignature extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
}
}
@@ -13967,6 +13967,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInSam() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineClassInSignature extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
}
}
@@ -8063,6 +8063,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
public void testAllFilesPresentInSam() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineClassInSignature extends AbstractIrCodegenBoxWasmTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
}
public void testAllFilesPresentInInlineClassInSignature() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
}
}