diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 7e4cee4a7cd..b053ab04fff 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -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"); + } + } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 7b3dfb7812a..185fdb02864 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt index 4b814c4c710..a7911e1bd52 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt @@ -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("") } 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 { + // 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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt index 3aaf90526b7..afecc5eaefc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt @@ -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 = + ArrayList().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 diff --git a/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt b/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt index 39720de74a1..1e0089f0b94 100644 --- a/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt +++ b/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt @@ -6,11 +6,21 @@ fun interface IFoo { fun foo(x: T): T } -fun foo1(fs: IFoo) = fs.foo(1) +fun interface IBar { + fun bar(x: T): T +} + + +fun foo1(foo: IFoo) = foo.foo(1) + +fun bar1(bar: IBar) = 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" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt new file mode 100644 index 00000000000..2de01599722 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineAny.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt new file mode 100644 index 00000000000..56dd6f9f7a7 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineInt.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt new file mode 100644 index 00000000000..cb73273e940 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNAny.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt new file mode 100644 index 00000000000..772f4ce7d5f --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNInt.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt new file mode 100644 index 00000000000..eea458ecb5d --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineNString.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt new file mode 100644 index 00000000000..0406d90261f --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/funInterfaceWithInlineString.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt new file mode 100644 index 00000000000..fd947fd82a5 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineAny.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +inline class Z(val value: Any) + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = 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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt new file mode 100644 index 00000000000..09a6bdb34c8 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineInt.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +inline class Z(val value: Int) + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = fs.foo(Z(1)) + +fun box(): String { + val t = foo1 { Z(it.value + 41) } + if (t.value != 42) return "Failed: t=$t" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt new file mode 100644 index 00000000000..1f78a6f08c5 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNAny.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +inline class Z(val value: Any?) + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = 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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt new file mode 100644 index 00000000000..e25d329567e --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNInt.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +inline class Z(val value: Int?) + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = fs.foo(Z(1)) + +fun box(): String { + val t = foo1 { Z(it.value!! + 41) } + if (t.value != 42) return "Failed: t=$t" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt new file mode 100644 index 00000000000..2117696068f --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineNString.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +inline class Z(val value: String?) + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = fs.foo(Z("O")) + +fun box(): String { + val t = foo1 { Z(it.value!! + "K") } + if (t.value != "OK") return "Failed: t=$t" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt new file mode 100644 index 00000000000..972673c3156 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +inline class Z(val value: String) + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = fs.foo(Z("O")) + +fun box(): String { + val t = foo1 { Z(it.value + "K") } + if (t.value != "OK") return "Failed: t=$t" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index b852eac241a..cdce1fbec58 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); + } + } } } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 37d1b98a5ab..43130867dd2 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -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"); + } + } } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/CodegenTestDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/CodegenTestDirectives.kt index 620dbdeada9..dbb639e7e88 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/CodegenTestDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/CodegenTestDirectives.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("SAM conversion code generation scheme") } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt index 23b8513d982..7284c782bea 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt @@ -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( + description = "SAM conversion code generation scheme", + additionalParser = JvmSamConversions.Companion::fromString + ) } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/codegen/AbstractJvmBlackBoxCodegenTestBase.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/codegen/AbstractJvmBlackBoxCodegenTestBase.kt index 2548fd55c73..39058915bb5 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/codegen/AbstractJvmBlackBoxCodegenTestBase.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/codegen/AbstractJvmBlackBoxCodegenTestBase.kt @@ -40,13 +40,3 @@ abstract class AbstractJvmBlackBoxCodegenTestBase