From f30e25aa524a59188d6e212ab72eadf047975a24 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 20 Jan 2021 14:51:07 +0300 Subject: [PATCH] JVM_IR indy-SAM conversions: more cases KT-44278 KT-26060 KT-42621 --- .../FirBlackBoxCodegenTestGenerated.java | 36 +++++++++ .../kotlin/backend/jvm/JvmSymbols.kt | 20 ++++- .../jvm/intrinsics/JvmInvokeDynamic.kt | 68 ++++++++++++++--- .../jvm/lower/FunctionReferenceLowering.kt | 13 +++- .../backend/jvm/lower/TypeOperatorLowering.kt | 19 +++-- .../ir/expressions/IrDeclarationReference.kt | 3 +- .../kotlin/ir/overrides/IrOverridingUtil.kt | 75 ++++++++++--------- .../sam/builtinMemberReference.kt | 16 ++++ .../box/invokedynamic/sam/capturingVar.kt | 18 +++++ .../invokedynamic/sam/constructorReference.kt | 13 ++++ .../invokedynamic/sam/genericFunInterface.kt | 11 +++ .../sam/genericFunInterfaceWithPrimitive.kt | 16 ++++ .../sam/samConversionOnFunctionReference.kt | 22 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 36 +++++++++ .../IrBlackBoxCodegenTestGenerated.java | 36 +++++++++ .../test/backend/handlers/JvmBoxRunner.kt | 8 +- .../LightAnalysisModeTestGenerated.java | 30 ++++++++ 17 files changed, 383 insertions(+), 57 deletions(-) create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt 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 ca2c208fc61..7e4cee4a7cd 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 @@ -18403,6 +18403,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt"); } + @Test + @TestMetadata("builtinMemberReference.kt") + public void testBuiltinMemberReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt"); + } + @Test @TestMetadata("capturedDispatchReceiver.kt") public void testCapturedDispatchReceiver() throws Exception { @@ -18427,12 +18433,42 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt"); } + @Test + @TestMetadata("capturingVar.kt") + public void testCapturingVar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt"); + } + + @Test + @TestMetadata("constructorReference.kt") + public void testConstructorReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt"); + } + + @Test + @TestMetadata("genericFunInterface.kt") + public void testGenericFunInterface() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt"); + } + + @Test + @TestMetadata("genericFunInterfaceWithPrimitive.kt") + public void testGenericFunInterfaceWithPrimitive() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt"); + } + @Test @TestMetadata("primitiveVsWrapperInSam.kt") public void testPrimitiveVsWrapperInSam() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt"); } + @Test + @TestMetadata("samConversionOnFunctionReference.kt") + public void testSamConversionOnFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); + } + @Test @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { 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 ba61122d72f..7b3dfb7812a 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 @@ -604,11 +604,25 @@ class JvmSymbols( }.symbol // Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above). - // Type argument is a possibly substituted method owner type (e.g., 'java.lang.function.Supplier'). // Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get'). - val jvmMethodTypeIntrinsic: IrSimpleFunctionSymbol = + // Resulting method type is unsubstituted. + val jvmOriginalMethodTypeIntrinsic: IrSimpleFunctionSymbol = irFactory.buildFun { - name = Name.special("") + name = Name.special("") + origin = IrDeclarationOrigin.IR_BUILTINS_STUB + }.apply { + parent = kotlinJvmInternalPackage + addValueParameter("method", irBuiltIns.anyType) + returnType = irBuiltIns.anyType + }.symbol + + // Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above). + // Type argument is a substituted method owner type (e.g., 'java.lang.function.Supplier'). + // Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get'). + // Resulting method type is substituted. + val jvmSubstitutedMethodTypeIntrinsic: IrSimpleFunctionSymbol = + irFactory.buildFun { + name = Name.special("") origin = IrDeclarationOrigin.IR_BUILTINS_STUB }.apply { parent = kotlinJvmInternalPackage 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 f00c00d6f93..4b814c4c710 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 @@ -8,10 +8,17 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.* import org.jetbrains.kotlin.codegen.inline.v +import org.jetbrains.kotlin.ir.builders.declarations.buildClass +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction 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.name.Name import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Handle import org.jetbrains.org.objectweb.asm.Opcodes @@ -71,8 +78,10 @@ object JvmInvokeDynamic : IntrinsicMethod() { generateMethodHandle(element, codegen) is IrCall -> when (element.symbol) { - codegen.context.ir.symbols.jvmMethodTypeIntrinsic -> - generateMethodType(element, codegen) + codegen.context.ir.symbols.jvmOriginalMethodTypeIntrinsic -> + generateOriginalMethodType(element, codegen) + codegen.context.ir.symbols.jvmSubstitutedMethodTypeIntrinsic -> + generateSubstitutedMethodType(element, codegen) else -> throw AssertionError("Unexpected callee in bootstrap method argument:\n${element.dump()}") } @@ -92,12 +101,14 @@ object JvmInvokeDynamic : IntrinsicMethod() { throw AssertionError("Unexpected bootstrap method argument:\n${element.dump()}") } - private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Any { + private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Handle { val irFun = irRawFunctionReference.symbol.owner val irParentClass = irFun.parentAsClass val owner = codegen.typeMapper.mapOwner(irParentClass) val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun) val handleTag = when { + irFun is IrConstructor -> + Opcodes.H_NEWINVOKESPECIAL irFun.dispatchReceiverParameter == null -> Opcodes.H_INVOKESTATIC else -> @@ -106,18 +117,57 @@ object JvmInvokeDynamic : IntrinsicMethod() { return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface) } - private fun generateMethodType(jvmMethodTypeCall: IrCall, codegen: ExpressionCodegen): Any { - val irRawFunctionReference = jvmMethodTypeCall.getValueArgument(0) as? IrRawFunctionReference + private fun generateOriginalMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type { + val irRawFunRef = irCall.getValueArgument(0) as? IrRawFunctionReference ?: throw AssertionError( - "Argument in ${jvmMethodTypeCall.symbol.owner.name} call is expected to be a raw function reference:\n" + - jvmMethodTypeCall.dump() + "Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference:\n" + + irCall.dump() ) - val irFun = irRawFunctionReference.symbol.owner - // TODO substitute signature + val irFun = irRawFunRef.symbol.owner val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun) return Type.getMethodType(asmMethod.descriptor) } + private fun generateSubstitutedMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type { + fun fail(message: String): Nothing = + throw AssertionError("$message; irCall:\n${irCall.dump()}") + + val irRawFunRef = irCall.getValueArgument(0) as? IrRawFunctionReference + ?: 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 + ?: 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 fakeClass = codegen.context.irFactory.buildClass { name = Name.special("") } + fakeClass.parent = codegen.context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage + val irFakeOverride = buildFakeOverrideMember(substitutedTypeWithNullableArgs, irOriginalFun, fakeClass) as IrSimpleFunction + irFakeOverride.overriddenSymbols = listOf(irOriginalFun.symbol) + + val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFakeOverride) + return Type.getMethodType(asmMethod.descriptor) + } + 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 5ff5c96c21c..3aaf90526b7 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 @@ -103,13 +103,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) } reference.transformChildrenVoid() - return if (shouldUseIndySamConversions) { + return if (shouldUseIndySamConversions && canUseIndySamConversion(reference)) { wrapSamConversionArgumentWithIndySamConversion(expression) } else { FunctionReferenceBuilder(reference, expression.typeOperand).build() } } + private fun canUseIndySamConversion(reference: IrFunctionReference): Boolean { + // Can't use indy for regular function references by default (because of 'equals'). + // 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 + return true + } + private fun wrapSamConversionArgumentWithIndySamConversion(expression: IrTypeOperatorCall): IrExpression { return when (val argument = expression.argument) { is IrFunctionReference -> diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt index e5e20b37442..e6eac2bdb43 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt @@ -121,10 +121,16 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil putValueArgument(5, irVararg(context.irBuiltIns.anyType, bootstrapMethodArguments)) } - private val methodTypeIntrinsic = context.ir.symbols.jvmMethodTypeIntrinsic + private val originalMethodTypeIntrinsic = context.ir.symbols.jvmOriginalMethodTypeIntrinsic + private val substitutedMethodTypeIntrinsic = context.ir.symbols.jvmSubstitutedMethodTypeIntrinsic - private fun IrBuilderWithScope.jvmMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) = - irCall(methodTypeIntrinsic, context.irBuiltIns.anyType).apply { + private fun IrBuilderWithScope.jvmOriginalMethodType(methodSymbol: IrFunctionSymbol) = + irCall(originalMethodTypeIntrinsic, context.irBuiltIns.anyType).apply { + putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol)) + } + + private fun IrBuilderWithScope.jvmSubstitutedMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) = + irCall(substitutedMethodTypeIntrinsic, context.irBuiltIns.anyType).apply { putTypeArgument(0, ownerType) putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol)) } @@ -181,16 +187,15 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil ?: fail("'method' is expected to be 'IrFunctionReference'") val funSymbol = irFunRef.symbol - val erasedSamType = samClassSymbol.defaultType as IrSimpleType - val dynamicCall = wrapClosureInDynamicCall(erasedSamType, samMethod, irFunRef) + val dynamicCall = wrapClosureInDynamicCall(samType, samMethod, irFunRef) return context.createJvmIrBuilder( funSymbol, // TODO actual symbol for outer scope startOffset, endOffset ).run { - val samMethodType = jvmMethodType(erasedSamType, samMethod.symbol) + val samMethodType = jvmOriginalMethodType(samMethod.symbol) val irRawFunRef = irRawFunctionReferefence(irFunRef.type, funSymbol) - val instanceMethodType = jvmMethodType(samType, samMethod.symbol) + val instanceMethodType = jvmSubstitutedMethodType(samType, samMethod.symbol) jvmInvokeDynamic( dynamicCall, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDeclarationReference.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDeclarationReference.kt index 494d19052d3..8536230156d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDeclarationReference.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDeclarationReference.kt @@ -38,7 +38,8 @@ abstract class IrGetEnumValue : IrGetSingletonValue() { /** * Platform-specific low-level reference to function. * - * On JS platform represent a plain reference to JavaScript function. + * On JS platform it represents a plain reference to JavaScript function. + * On JVM platform it represents a MethodHandle constant. */ abstract class IrRawFunctionReference : IrDeclarationReference() { abstract override val symbol: IrFunctionSymbol diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt index 410bc0479c5..cf1e7c00f3e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt @@ -23,33 +23,8 @@ import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.Variance abstract class FakeOverrideBuilderStrategy { - open fun fakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember{ - require(superType is IrSimpleType) { "superType is $superType, expected IrSimpleType" } - val classifier = superType.classifier - require(classifier is IrClassSymbol) { "superType classifier is not IrClassSymbol: $classifier" } - - val typeParameters = extractTypeParameters(classifier.owner) - val superArguments = superType.arguments - assert(typeParameters.size == superArguments.size) { - "typeParameters = $typeParameters size != typeArguments = $superArguments size " - } - - val substitutionMap = mutableMapOf() - - for (i in typeParameters.indices) { - val tp = typeParameters[i] - val ta = superArguments[i] - require(ta is IrTypeProjection) { "Unexpected super type argument: $ta @ $i" } - assert(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" } - substitutionMap[tp.symbol] = ta.type - } - - val copier = DeepCopyIrTreeWithSymbolsForFakeOverrides(substitutionMap) - val deepCopyFakeOverride = copier.copy(member, clazz) as IrOverridableMember - deepCopyFakeOverride.parent = clazz - - return deepCopyFakeOverride - } + open fun fakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember = + buildFakeOverrideMember(superType, member, clazz) fun linkFakeOverride(fakeOverride: IrOverridableMember) { when (fakeOverride) { @@ -66,6 +41,35 @@ abstract class FakeOverrideBuilderStrategy { val propertyOverriddenSymbols: MutableMap> = mutableMapOf() } +fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember { + require(superType is IrSimpleType) { "superType is $superType, expected IrSimpleType" } + val classifier = superType.classifier + require(classifier is IrClassSymbol) { "superType classifier is not IrClassSymbol: $classifier" } + + val typeParameters = extractTypeParameters(classifier.owner) + val superArguments = superType.arguments + assert(typeParameters.size == superArguments.size) { + "typeParameters = $typeParameters size != typeArguments = $superArguments size " + } + + val substitutionMap = mutableMapOf() + + for (i in typeParameters.indices) { + val tp = typeParameters[i] + val ta = superArguments[i] + require(ta is IrTypeProjection) { "Unexpected super type argument: $ta @ $i" } + assert(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" } + substitutionMap[tp.symbol] = ta.type + } + + val copier = DeepCopyIrTreeWithSymbolsForFakeOverrides(substitutionMap) + val deepCopyFakeOverride = copier.copy(member, clazz) as IrOverridableMember + deepCopyFakeOverride.parent = clazz + + return deepCopyFakeOverride +} + + // TODO: // The below pile of code is basically half of OverridingUtil.java // adapted to IR and converted to Kotlin. @@ -294,7 +298,7 @@ class IrOverridingUtil( } val realOverrides = members - .map{ originals[it]!! } + .map { originals[it]!! } .collectAndFilterRealOverrides() return getMinimalModality(realOverrides, transformAbstractToClassModality, current.modality) } @@ -349,7 +353,10 @@ class IrOverridingUtil( return result } - private fun IrSimpleFunction.updateAccessorModalityAndVisibility(newModality: Modality, newVisibility: DescriptorVisibility): IrSimpleFunction? { + private fun IrSimpleFunction.updateAccessorModalityAndVisibility( + newModality: Modality, + newVisibility: DescriptorVisibility + ): IrSimpleFunction? { require(this is IrFakeOverrideFunction) { "Unexpected fake override accessor kind: $this" } @@ -746,15 +753,15 @@ class IrOverridingUtil( fun IrSimpleFunction.isOverridableFunction(): Boolean = this.visibility != DescriptorVisibilities.PRIVATE && - this.dispatchReceiverParameter != null + this.dispatchReceiverParameter != null fun IrProperty.isOverridableProperty(): Boolean = this.visibility != DescriptorVisibilities.PRIVATE && - (this.getter?.dispatchReceiverParameter != null || - this.setter?.dispatchReceiverParameter != null) + (this.getter?.dispatchReceiverParameter != null || + this.setter?.dispatchReceiverParameter != null) -fun IrDeclaration.isOverridableMemberOrAccessor(): Boolean = when(this) { +fun IrDeclaration.isOverridableMemberOrAccessor(): Boolean = when (this) { is IrSimpleFunction -> isOverridableFunction() is IrProperty -> isOverridableProperty() else -> false -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt b/compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt new file mode 100644 index 00000000000..b740f66d10d --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt @@ -0,0 +1,16 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IntFun { + fun invoke(i: Int): Int +} + +fun invoke1(intFun: IntFun) = intFun.invoke(1) + +fun box(): String { + val test = invoke1(41::plus) + if (test != 42) return "Failed: $test" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt b/compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt new file mode 100644 index 00000000000..154375280e5 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface KRunnable { + fun run() +} + +fun runIt(r: KRunnable) { + r.run() +} + +fun box(): String { + var test = "Failed" + runIt { test = "OK" } + return test +} + diff --git a/compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt b/compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt new file mode 100644 index 00000000000..2dc2e0eba45 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +class C(val test: String) + +fun interface MakeC { + fun make(x: String): C +} + +fun make(makeC: MakeC) = makeC.make("OK") + +fun box() = make(::C).test \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt b/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt new file mode 100644 index 00000000000..cad954025dc --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt @@ -0,0 +1,11 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo(fs: IFoo) = fs.foo("O") + +fun box() = foo { "${it}K" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt b/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt new file mode 100644 index 00000000000..39720de74a1 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt @@ -0,0 +1,16 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFoo { + fun foo(x: T): T +} + +fun foo1(fs: IFoo) = fs.foo(1) + +fun box(): String { + val t = foo1 { it + 41 } + if (t != 42) return "Failed: t=$t" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt b/compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt new file mode 100644 index 00000000000..5f3b249bd09 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt @@ -0,0 +1,22 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface KRunnable { + fun run() +} + +fun runnable(kr: KRunnable) = kr + +fun foo() {} + +fun box(): String { + val foo1 = runnable(::foo) + val foo2 = runnable(::foo) + + if (foo1 != foo2) { + return "Failed: foo1 != foo2" + } + + 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 53fb681de35..b852eac241a 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 @@ -18403,6 +18403,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt"); } + @Test + @TestMetadata("builtinMemberReference.kt") + public void testBuiltinMemberReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt"); + } + @Test @TestMetadata("capturedDispatchReceiver.kt") public void testCapturedDispatchReceiver() throws Exception { @@ -18427,12 +18433,42 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt"); } + @Test + @TestMetadata("capturingVar.kt") + public void testCapturingVar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt"); + } + + @Test + @TestMetadata("constructorReference.kt") + public void testConstructorReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt"); + } + + @Test + @TestMetadata("genericFunInterface.kt") + public void testGenericFunInterface() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt"); + } + + @Test + @TestMetadata("genericFunInterfaceWithPrimitive.kt") + public void testGenericFunInterfaceWithPrimitive() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt"); + } + @Test @TestMetadata("primitiveVsWrapperInSam.kt") public void testPrimitiveVsWrapperInSam() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt"); } + @Test + @TestMetadata("samConversionOnFunctionReference.kt") + public void testSamConversionOnFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); + } + @Test @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { 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 32fec2dfbaf..37d1b98a5ab 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 @@ -18403,6 +18403,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt"); } + @Test + @TestMetadata("builtinMemberReference.kt") + public void testBuiltinMemberReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt"); + } + @Test @TestMetadata("capturedDispatchReceiver.kt") public void testCapturedDispatchReceiver() throws Exception { @@ -18427,12 +18433,42 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt"); } + @Test + @TestMetadata("capturingVar.kt") + public void testCapturingVar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt"); + } + + @Test + @TestMetadata("constructorReference.kt") + public void testConstructorReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt"); + } + + @Test + @TestMetadata("genericFunInterface.kt") + public void testGenericFunInterface() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt"); + } + + @Test + @TestMetadata("genericFunInterfaceWithPrimitive.kt") + public void testGenericFunInterfaceWithPrimitive() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt"); + } + @Test @TestMetadata("primitiveVsWrapperInSam.kt") public void testPrimitiveVsWrapperInSam() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt"); } + @Test + @TestMetadata("samConversionOnFunctionReference.kt") + public void testSamConversionOnFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); + } + @Test @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt index 241a386ba7a..bc6d0f08b22 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt @@ -46,7 +46,11 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe try { for (ktFile in ktFiles) { val className = ktFile.getFacadeFqName() ?: continue - val clazz = classLoader.getGeneratedClass(className) + val clazz = try { + classLoader.getGeneratedClass(className) + } catch (e: LinkageError) { + throw AssertionError("Failed to load class '$className':\n${info.classFileFactory.createText()}", e) + } val method = clazz.getBoxMethodOrNull() ?: continue boxMethodFound = true callBoxMethodAndCheckResultWithCleanup( @@ -128,7 +132,7 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe ): GeneratedClassLoader { val classLoader = createClassLoader(module, classFileFactory) val verificationSucceeded = CodegenTestUtil.verifyAllFilesWithAsm(classFileFactory, classLoader, reportProblems) - if (!verificationSucceeded ) { + if (!verificationSucceeded) { assertions.fail { "Verification failed: see exceptions above" } } return classLoader diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 66256fab17f..9dc6251ccc7 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16138,6 +16138,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt"); } + @TestMetadata("builtinMemberReference.kt") + public void testBuiltinMemberReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt"); + } + @TestMetadata("capturedDispatchReceiver.kt") public void testCapturedDispatchReceiver() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt"); @@ -16158,11 +16163,36 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt"); } + @TestMetadata("capturingVar.kt") + public void testCapturingVar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt"); + } + + @TestMetadata("constructorReference.kt") + public void testConstructorReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt"); + } + + @TestMetadata("genericFunInterface.kt") + public void testGenericFunInterface() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt"); + } + + @TestMetadata("genericFunInterfaceWithPrimitive.kt") + public void testGenericFunInterfaceWithPrimitive() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt"); + } + @TestMetadata("primitiveVsWrapperInSam.kt") public void testPrimitiveVsWrapperInSam() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt"); } + @TestMetadata("samConversionOnFunctionReference.kt") + public void testSamConversionOnFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); + } + @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt");