diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index 92239187b51..f0869360e3a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -209,11 +209,12 @@ class GenerationState private constructor( val samConversionsScheme = run { val fromConfig = configuration.get(JVMConfigurationKeys.SAM_CONVERSIONS) - ?: JvmClosureGenerationScheme.DEFAULT - if (target >= fromConfig.minJvmTarget) + if (fromConfig != null && target >= fromConfig.minJvmTarget) fromConfig + else if (target < JvmTarget.JVM_1_8) + JvmClosureGenerationScheme.CLASS else - JvmClosureGenerationScheme.DEFAULT + JvmClosureGenerationScheme.INDY } val lambdasScheme = run { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 3ec06a446bc..09b3be63e37 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -19957,6 +19957,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); } + @Test + @TestMetadata("simpleFunInterfaceConstructor.kt") + public void testSimpleFunInterfaceConstructor() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt"); + } + @Test @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { @@ -19993,12 +19999,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt"); } - @Test - @TestMetadata("voidReturnTypeAsGeneric.kt") - public void testVoidReturnTypeAsGeneric() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt"); - } - @Nested @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature") @TestDataPath("$PROJECT_ROOT") @@ -20080,6 +20080,94 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + public class SpecializedGenerics { + @Test + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("covariantOverride.kt") + public void testCovariantOverride() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt"); + } + + @Test + @TestMetadata("covariantOverrideWithNNothing.kt") + public void testCovariantOverrideWithNNothing() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt"); + } + + @Test + @TestMetadata("inheritedWithChar.kt") + public void testInheritedWithChar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt"); + } + + @Test + @TestMetadata("inheritedWithCharDiamond.kt") + public void testInheritedWithCharDiamond() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt"); + } + + @Test + @TestMetadata("inheritedWithCharExplicitlyOverridden.kt") + public void testInheritedWithCharExplicitlyOverridden() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt"); + } + + @Test + @TestMetadata("inheritedWithInt.kt") + public void testInheritedWithInt() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt"); + } + + @Test + @TestMetadata("inheritedWithString.kt") + public void testInheritedWithString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt"); + } + + @Test + @TestMetadata("inheritedWithUnit.kt") + public void testInheritedWithUnit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt"); + } + + @Test + @TestMetadata("mixGenericAndIntArray.kt") + public void testMixGenericAndIntArray() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt"); + } + + @Test + @TestMetadata("mixGenericAndString.kt") + public void testMixGenericAndString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt"); + } + + @Test + @TestMetadata("mixGenericArrayAndArrayOfString.kt") + public void testMixGenericArrayAndArrayOfString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt"); + } + + @Test + @TestMetadata("mixPrimitiveAndBoxed.kt") + public void testMixPrimitiveAndBoxed() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt"); + } + + @Test + @TestMetadata("voidReturnTypeAsGeneric.kt") + public void testVoidReturnTypeAsGeneric() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.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 185fdb02864..7bd0daf7d21 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 @@ -545,19 +545,53 @@ class JvmSymbols( returnType = dst.defaultType }.symbol - val indySamConversionIntrinsic: IrSimpleFunctionSymbol = + val arrayOfAnyType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType) + + // Intrinsic to represent closure creation using INVOKEDYNAMIC with LambdaMetafactory.{metafactory, altMetafactory} + // as a bootstrap method. + // fun ``( + // samMethodType, + // implMethodReference, + // instantiatedMethodType, + // vararg extraOverriddenMethodTypes + // ): SAM_TYPE + // where: + // `SAM_TYPE` is a single abstract method interface, which is implemented by a resulting closure; + // `samMethodType` is a method type (signature and return type) of a method to be implemented by a closure; + // `implMethodReference` is an actual implementation method (e.g., method for a lambda function); + // `instantiatedMethodType` is a specialized implementation method type; + // `extraOverriddenMethodTypes` is a possibly empty vararg of additional methods to be implemented by a closure. + // + // At this stage, "method types" are represented as IrRawFunctionReference nodes for the functions with corresponding signature. + // `` call rewriting selects a particular bootstrap method (`metafactory` or `altMetafactory`) + // and takes care about low-level detains of bootstrap method arguments representation. + // Note that `instantiatedMethodType` is a raw function reference to a "fake" specialized function (belonging to a "fake" specialized + // class) that doesn't exist in the bytecode and serves only the purpose of representing a corresponding method signature. + // + // Resulting closure produced by INVOKEDYNAMIC instruction has (approximately) the following shape: + // object : ${SAM_TYPE} { + // override fun ${samMethodName}(${instantiatedMethodType}) = ${implMethod}(...) + // // bridge fun ${samMethodName}(${bridgeMethodType}) = ${instantiatedMethod}(...) + // // for each 'bridgeMethodType' in [ ${samMethodType}, *${extraOverriddenMethodTypes} ] + // } + val indyLambdaMetafactoryIntrinsic: IrSimpleFunctionSymbol = irFactory.buildFun { - name = Name.special("") + name = Name.special("") origin = IrDeclarationOrigin.IR_BUILTINS_STUB }.apply { parent = kotlinJvmInternalPackage val samType = addTypeParameter("SAM_TYPE", irBuiltIns.anyType) - addValueParameter("method", irBuiltIns.anyNType) + addValueParameter("samMethodType", irBuiltIns.anyNType) + addValueParameter("implMethodReference", irBuiltIns.anyNType) + addValueParameter("instantiatedMethodType", irBuiltIns.anyNType) + addValueParameter { + name = Name.identifier("extraOverriddenMethodTypes") + type = arrayOfAnyType + varargElementType = irBuiltIns.anyType + } returnType = samType.defaultType }.symbol - val arrayOfAnyType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType) - // Intrinsic to represent INVOKEDYNAMIC calls in IR. // fun ``( // dynamicCall: T, 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 5593a189ee2..f7c11bec877 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 @@ -136,9 +136,9 @@ 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 superType = irCall.getTypeArgument(0) as? IrSimpleType ?: fail("Type argument expected") - val patchedSuperType = replaceTypeArgumentsWithNullable(superType) val fakeClass = codegen.context.irFactory.buildClass { name = Name.special("") } 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 a640e7a7325..8df71804e22 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 @@ -25,13 +25,14 @@ import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.overrides.buildFakeOverrideMember import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.* 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, @@ -92,20 +93,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) expression.statements.dropLast(1).forEach { it.transform(this, null) } reference.transformChildrenVoid(this) - if (shouldGenerateIndyLambdas && canUseIndySamConversion(reference, reference.type, true)) { - return wrapLambdaReferenceWithIndySamConversion(expression, reference) + if (shouldGenerateIndyLambdas) { + val lambdaMetafactoryArguments = getLambdaMetafactoryArgumentsOrNull(reference, reference.type, true) + if (lambdaMetafactoryArguments != null) { + return wrapLambdaReferenceWithIndySamConversion(expression, reference, lambdaMetafactoryArguments) + } } return FunctionReferenceBuilder(reference).build() } - private fun wrapLambdaReferenceWithIndySamConversion(expression: IrBlock, reference: IrFunctionReference): IrBlock { - expression.statements[expression.statements.size - 1] = wrapWithIndySamConversion(reference.type, reference) - val irLambda = reference.symbol.owner - // JDK LambdaMetafactory can't adapt '(...)V' to '(...)Lkotlin/Unit;'. - if (irLambda.returnType.isUnit()) { - irLambda.returnType = irLambda.returnType.makeNullable() - } + private fun wrapLambdaReferenceWithIndySamConversion( + expression: IrBlock, + reference: IrFunctionReference, + lambdaMetafactoryArguments: LambdaMetafactoryArguments + ): IrBlock { + val indySamConversion = wrapWithIndySamConversion(reference.type, lambdaMetafactoryArguments) + expression.statements[expression.statements.size - 1] = indySamConversion + expression.type = indySamConversion.type return expression } @@ -140,49 +145,389 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) reference.transformChildrenVoid() val samSuperType = expression.typeOperand - return if (shouldGenerateIndySamConversions && canUseIndySamConversion(reference, samSuperType, false)) { - wrapSamConversionArgumentWithIndySamConversion(expression) - } else { - FunctionReferenceBuilder(reference, samSuperType).build() + + if (shouldGenerateIndySamConversions) { + val lambdaMetafactoryArguments = getLambdaMetafactoryArgumentsOrNull(reference, samSuperType, false) + if (lambdaMetafactoryArguments != null) { + return wrapSamConversionArgumentWithIndySamConversion(expression, lambdaMetafactoryArguments) + } } + + return FunctionReferenceBuilder(reference, samSuperType).build() } - private fun canUseIndySamConversion(reference: IrFunctionReference, samSuperType: IrType, plainLambda: Boolean): Boolean { + private class LambdaMetafactoryArguments( + val samMethod: IrSimpleFunction, + val fakeInstanceMethod: IrSimpleFunction, + val implMethodReference: IrFunctionReference, + val extraOverriddenMethods: List + ) + + /** + * @see java.lang.invoke.LambdaMetafactory + */ + private fun getLambdaMetafactoryArgumentsOrNull( + reference: IrFunctionReference, + samType: IrType, + plainLambda: Boolean + ): LambdaMetafactoryArguments? { // Can't use JDK LambdaMetafactory for function references by default (because of 'equals'). // TODO special mode that would generate indy everywhere? if (reference.origin != IrStatementOrigin.LAMBDA) - return false + return null - // TODO wrap intrinsic function in lambda? - if (context.irIntrinsics.getIntrinsic(reference.symbol) != null) - return false + val samClass = samType.getClass() + ?: throw AssertionError("SAM type is not a class: ${samType.render()}") + val samMethod = samClass.getSingleAbstractMethod() + ?: throw AssertionError("SAM class has no single abstract method: ${samClass.render()}") - // Can't use JDK LambdaMetafactory for fun interface with suspend fun - if (samSuperType.getSingleAbstractMethod()?.isSuspend == true) - return false + // Can't use JDK LambdaMetafactory for fun interface with suspend fun. + if (samMethod.isSuspend) + return null - // 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 + // Can't use JDK LambdaMetafactory for fun interfaces that require delegation to $DefaultImpls. + if (samClass.requiresDelegationToDefaultImpls()) + return null + val target = reference.symbol.owner as? IrSimpleFunction + ?: throw AssertionError("Simple function expected: ${reference.symbol.owner.render()}") + + // Can't use JDK LambdaMetafactory for annotated lambdas. + // JDK LambdaMetafactory doesn't copy annotations from implementation method to an instance method in a + // corresponding synthetic class, which doesn't look like a binary compatible change. + // TODO relaxed mode? + if (target.annotations.isNotEmpty()) + return null + + // Don't use JDK LambdaMetafactory for big arity lambdas. if (plainLambda) { var parametersCount = target.valueParameters.size if (target.extensionReceiverParameter != null) ++parametersCount if (parametersCount >= BuiltInFunctionArity.BIG_ARITY) - return false + return null } // Can't use indy-based SAM conversion inside inline fun (Ok in inline lambda). if (target.parents.any { it.isInlineFunction() || it.isCrossinlineLambda() }) - return false + return null - return true + // Do the hard work of matching Kotlin functional interface hierarchy against LambdaMetafactory constraints. + // Briefly: sometimes we have to force boxing on the primitive and inline class values, sometimes we have to keep them unboxed. + // If this results in conflicting requirements, we can't use INVOKEDYNAMIC with LambdaMetafactory for creating a closure. + return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, target) } + private fun IrClass.requiresDelegationToDefaultImpls(): Boolean { + for (irMemberFun in functions) { + if (irMemberFun.modality == Modality.ABSTRACT) + continue + val irImplFun = + if (irMemberFun.isFakeOverride) + irMemberFun.findInterfaceImplementation(context.state.jvmDefaultMode) + ?: continue + else + irMemberFun + if (irImplFun.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) + continue + if (!irImplFun.isCompiledToJvmDefault(context.state.jvmDefaultMode)) + return true + } + return false + } + + private fun getLambdaMetafactoryArgsOrNullInner( + reference: IrFunctionReference, + samMethod: IrSimpleFunction, + samType: IrType, + implLambda: IrSimpleFunction + ): LambdaMetafactoryArguments? { + val nonFakeOverriddenFuns = samMethod.allOverridden().filterNot { it.isFakeOverride } + val relevantOverriddenFuns = if (samMethod.isFakeOverride) nonFakeOverriddenFuns else nonFakeOverriddenFuns + samMethod + + // Create a fake instance method as if it was defined in a class implementing SAM interface + // (such class would be eventually created by LambdaMetafactory at run-time). + val fakeClass = context.irFactory.buildClass { name = Name.special("") } + fakeClass.parent = context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage + val fakeInstanceMethod = buildFakeOverrideMember(samType, samMethod, fakeClass) as IrSimpleFunction + (fakeInstanceMethod as IrFakeOverrideFunction).acquireSymbol(IrSimpleFunctionSymbolImpl()) + fakeInstanceMethod.overriddenSymbols = listOf(samMethod.symbol) + + // Compute signature adaptation constraints for a fake instance method signature against all relevant overrides. + // If at any step we encounter a conflict (e.g., one override requires boxing a parameter, and another requires + // to keep it unboxed), we can't adapt this signature and can't use LambdaMetafactory to create a closure. + // + // Note that those constraints are not checked precisely in JDK 1.8 (jdk1.8.0_231), but are checked more strictly + // in later JDK versions and in D8 (so if you see an exception from D8 in codegen test failures, corresponding code + // with INVOKEDYNAMIC would quite likely fail on JDK 9 and beyond). + // + // Example 1 (requires boxing): + // fun interface IFoo { + // fun foo(x: T) + // } + // val t = IFoo { println(it + 1) } + // Here IFoo::foo requires 'x' to be reference type (even though corresponding lambda accepts a primitive int). + // this + // + // Example 2 (no explicit override, boxing-unboxing conflict): + // fun interface IFooT { + // fun foo(x: T) + // } + // fun interface IFooInt { + // fun foo(x: Int) + // } + // fun interface IFooMix : IFooT, IFooInt + // val t = IFooMix { println(it + 1) } + // Here IFooT::foo requires 'x' to be of a reference type, and IFooInt::foo requires 'x' to be of a primitive type. + // LambdaMetafactory can't handle such case. + // + // Example 3 (explicit override, boxing-unboxing conflict): + // fun interface IFooT { + // fun foo(x: T) + // } + // fun interface IFooInt { + // fun foo(x: Int) + // } + // fun interface IFooMix : IFooT, IFooInt { + // override fun foo(x: Int) + // } + // val t = IFooMix { println(it + 1) } + // Here, even though we have an explicit 'override fun foo(x: Int)' in IFooMix, we don't generate a bridge for 'foo' in IFooMix. + // Thus, class for a lambda created by LambdaMetafactory should provide a bridge for 'foo'. + // Thus, 'x' should be of a reference type. + // On the other hand, it should also override IFooInt#foo, where 'x' should be a primitive type. + // LambdaMetafactory can't handle such case. + // + // TODO accept Example 3 if IFooMix is compiled with default interface methods + // Note that this is a conservative check; if we reject LambdaMetafactory-based closure generation scheme, compiler would still + // generate proper (although somewhat sub-optimal) code with explicit class for a corresponding SAM-converted lambda. + val signatureAdaptationConstraints = run { + var result = SignatureAdaptationConstraints(emptyMap(), null) + for (overriddenFun in relevantOverriddenFuns) { + val constraintsFromOverridden = computeSignatureAdaptationConstraints(fakeInstanceMethod, overriddenFun) + ?: return null + result = joinSignatureAdaptationConstraints(result, constraintsFromOverridden) + ?: return null + } + result + } + + // We should have bailed out before if we encountered any kind of type adaptation conflict. + // Still, check that we are fine - just in case. + if (signatureAdaptationConstraints.returnType == TypeAdaptationConstraint.CONFLICT || + signatureAdaptationConstraints.valueParameters.values.any { it == TypeAdaptationConstraint.CONFLICT } + ) + return null + + adaptFakeInstanceMethodSignature(fakeInstanceMethod, signatureAdaptationConstraints) + + adaptLambdaSignature(implLambda, fakeInstanceMethod, signatureAdaptationConstraints) + + if (samMethod.isFakeOverride && nonFakeOverriddenFuns.size == 1) { + return LambdaMetafactoryArguments(nonFakeOverriddenFuns.single(), fakeInstanceMethod, reference, listOf()) + } + return LambdaMetafactoryArguments(samMethod, fakeInstanceMethod, reference, nonFakeOverriddenFuns) + } + + private fun adaptLambdaSignature( + lambda: IrSimpleFunction, + fakeInstanceMethod: IrSimpleFunction, + constraints: SignatureAdaptationConstraints + ) { + val lambdaParameters = collectValueParameters(lambda) + val methodParameters = collectValueParameters(fakeInstanceMethod) + if (lambdaParameters.size != methodParameters.size) + throw AssertionError( + "Mismatching lambda and instance method parameters:\n" + + "lambda: ${lambda.render()}\n" + + " (${lambdaParameters.size} parameters)\n" + + "instance method: ${fakeInstanceMethod.render()}\n" + + " (${methodParameters.size} parameters)" + ) + for ((lambdaParameter, methodParameter) in lambdaParameters.zip(methodParameters)) { + // TODO box inline class parameters only? + val parameterConstraint = constraints.valueParameters[methodParameter] + if (parameterConstraint == TypeAdaptationConstraint.FORCE_BOXING) { + lambdaParameter.type = lambdaParameter.type.makeNullable() + } + } + if (constraints.returnType == TypeAdaptationConstraint.FORCE_BOXING) { + lambda.returnType = lambda.returnType.makeNullable() + } + } + + private fun adaptFakeInstanceMethodSignature(fakeInstanceMethod: IrSimpleFunction, constraints: SignatureAdaptationConstraints) { + for ((valueParameter, constraint) in constraints.valueParameters) { + if (valueParameter.parent != fakeInstanceMethod) + throw AssertionError( + "Unexpected value parameter: ${valueParameter.render()}; fakeInstanceMethod:\n" + + fakeInstanceMethod.dump() + ) + if (constraint == TypeAdaptationConstraint.FORCE_BOXING) { + valueParameter.type = valueParameter.type.makeNullable() + } + } + if (constraints.returnType == TypeAdaptationConstraint.FORCE_BOXING) { + fakeInstanceMethod.returnType = fakeInstanceMethod.returnType.makeNullable() + } + } + + private enum class TypeAdaptationConstraint { + FORCE_BOXING, + KEEP_UNBOXED, + CONFLICT + } + + private class SignatureAdaptationConstraints( + val valueParameters: Map, + val returnType: TypeAdaptationConstraint? + ) + + private fun computeSignatureAdaptationConstraints( + adapteeFun: IrSimpleFunction, + expectedFun: IrSimpleFunction + ): SignatureAdaptationConstraints? { + val returnTypeConstraint = computeReturnTypeAdaptationConstraint(adapteeFun, expectedFun) + if (returnTypeConstraint == TypeAdaptationConstraint.CONFLICT) + return null + + val valueParameterConstraints = HashMap() + val adapteeParameters = collectValueParameters(adapteeFun) + val expectedParameters = collectValueParameters(expectedFun) + if (adapteeParameters.size != expectedParameters.size) + throw AssertionError( + "Mismatching value parameters:\n" + + "adaptee: ${adapteeFun.render()}\n" + + " ${adapteeParameters.size} value parameters;\n" + + "expected: ${expectedFun.render()}\n" + + " ${expectedParameters.size} value parameters." + ) + for ((adapteeParameter, expectedParameter) in adapteeParameters.zip(expectedParameters)) { + val parameterConstraint = computeParameterTypeAdaptationConstraint(adapteeParameter.type, expectedParameter.type) + ?: continue + if (parameterConstraint == TypeAdaptationConstraint.CONFLICT) + return null + valueParameterConstraints[adapteeParameter] = parameterConstraint + } + + return SignatureAdaptationConstraints( + if (valueParameterConstraints.isEmpty()) emptyMap() else valueParameterConstraints, + returnTypeConstraint + ) + } + + private fun computeParameterTypeAdaptationConstraint(adapteeType: IrType, expectedType: IrType): TypeAdaptationConstraint? { + if (adapteeType !is IrSimpleType) + throw AssertionError("Simple type expected: ${adapteeType.render()}") + if (expectedType !is IrSimpleType) + throw AssertionError("Simple type expected: ${expectedType.render()}") + + // TODO what if adapteeType and/or expectedType are type parameters with JVM primitive type upper bounds? + + if (adapteeType.isNothing() || adapteeType.isNullableNothing()) + return TypeAdaptationConstraint.CONFLICT + + // ** JVM primitives ** + // All Kotlin types mapped to JVM primitive are final, + // and their supertypes are trivially mapped reference types. + if (adapteeType.isJvmPrimitiveType()) { + return if (expectedType.isJvmPrimitiveType()) + TypeAdaptationConstraint.KEEP_UNBOXED + else + TypeAdaptationConstraint.FORCE_BOXING + } + + // ** Inline classes ** + // All Kotlin inline classes are final, + // and their supertypes are trivially mapped to reference types. + val erasedAdapteeClass = getErasedClassForSignatureAdaptation(adapteeType) + if (erasedAdapteeClass.isInline) { + // Inline classes mapped to non-null reference types are a special case because they can't be boxed trivially. + // TODO consider adding a special type annotation to force boxing on an inline class type regardless of its underlying type. + val underlyingAdapteeType = getInlineClassUnderlyingType(erasedAdapteeClass) as? IrSimpleType + ?: throw AssertionError("Underlying type for inline class should be a simple type: ${erasedAdapteeClass.render()}") + if (!underlyingAdapteeType.hasQuestionMark && !underlyingAdapteeType.isJvmPrimitiveType()) { + return TypeAdaptationConstraint.CONFLICT + } + + val erasedExpectedClass = getErasedClassForSignatureAdaptation(expectedType) + return if (erasedExpectedClass.isInline) { + // LambdaMetafactory doesn't know about method mangling. + TypeAdaptationConstraint.CONFLICT + } else { + // Trying to pass inline class value as non-inline class value (Any or other supertype) + // => box it + TypeAdaptationConstraint.FORCE_BOXING + } + } + + // Other cases don't enforce type adaptation + return null + } + + private fun getErasedClassForSignatureAdaptation(irType: IrSimpleType): IrClass = + when (val classifier = irType.classifier.owner) { + is IrTypeParameter -> classifier.erasedUpperBound + is IrClass -> classifier + else -> + throw AssertionError("Unexpected classifier: ${classifier.render()}") + } + + private fun computeReturnTypeAdaptationConstraint( + adapteeFun: IrSimpleFunction, + expectedFun: IrSimpleFunction + ): TypeAdaptationConstraint? { + val adapteeReturnType = adapteeFun.returnType + if (adapteeReturnType.isUnit()) { + // Can't mix '()V' and '()Lkotlin.Unit;' or '()Ljava.lang.Object;' in supertype method signatures. + return if (expectedFun.returnType.isUnit()) + TypeAdaptationConstraint.KEEP_UNBOXED + else { + TypeAdaptationConstraint.FORCE_BOXING + } + } + + val expectedReturnType = expectedFun.returnType + return computeParameterTypeAdaptationConstraint(adapteeReturnType, expectedReturnType) + } + + private fun joinSignatureAdaptationConstraints( + sig1: SignatureAdaptationConstraints, + sig2: SignatureAdaptationConstraints + ): SignatureAdaptationConstraints? { + val newReturnTypeConstraint = composeTypeAdaptationConstraints(sig1.returnType, sig2.returnType) + if (newReturnTypeConstraint == TypeAdaptationConstraint.CONFLICT) + return null + + val newValueParameterConstraints = + when { + sig1.valueParameters.isEmpty() -> sig2.valueParameters + sig2.valueParameters.isEmpty() -> sig1.valueParameters + else -> { + val joined = HashMap() + joined.putAll(sig1.valueParameters) + for ((vp2, t2) in sig2.valueParameters.entries) { + val tx = composeTypeAdaptationConstraints(joined[vp2], t2) ?: continue + if (tx == TypeAdaptationConstraint.CONFLICT) + return null + joined[vp2] = tx + } + joined + } + } + + return SignatureAdaptationConstraints(newValueParameterConstraints, newReturnTypeConstraint) + } + + private fun composeTypeAdaptationConstraints(t1: TypeAdaptationConstraint?, t2: TypeAdaptationConstraint?): TypeAdaptationConstraint? = + when { + t1 == null -> t2 + t2 == null -> t1 + t1 == t2 -> t1 + else -> + TypeAdaptationConstraint.CONFLICT + } + + private fun IrDeclarationParent.isInlineFunction() = this is IrSimpleFunction && isInline && origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA @@ -192,42 +537,29 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) inlineLambdaToValueParameter[irFun]?.isCrossinline == true } - private fun IrType.isProhibitedTypeForIndySamConversion(): Boolean { - if (this !is IrSimpleType) return false - - val erasedClass = when (val classifier = classifier.owner) { - is IrTypeParameter -> classifier.erasedUpperBound - is IrClass -> classifier - else -> throw AssertionError("Unexpected classifier: ${classifier.render()}") - } - if (!erasedClass.isInline) 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 { + private fun wrapSamConversionArgumentWithIndySamConversion( + expression: IrTypeOperatorCall, + lambdaMetafactoryArguments: LambdaMetafactoryArguments + ): IrExpression { val samType = expression.typeOperand return when (val argument = expression.argument) { is IrFunctionReference -> { - wrapWithIndySamConversion(samType, argument) + wrapWithIndySamConversion(samType, lambdaMetafactoryArguments) } 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(samType, functionReference) + val indySamConversion = wrapWithIndySamConversion(samType, lambdaMetafactoryArguments) + argument.statements[argument.statements.size - 1] = indySamConversion + argument.type = indySamConversion.type return argument } else -> throw AssertionError("Block or function reference expected: ${expression.render()}") } } - private val jvmIndySamConversionIntrinsic = context.ir.symbols.indySamConversionIntrinsic + private val jvmIndyLambdaMetafactoryIntrinsic = context.ir.symbols.indyLambdaMetafactoryIntrinsic private val specialNullabilityAnnotationsFqNames = setOf( @@ -235,59 +567,37 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) context.ir.symbols.enhancedNullabilityAnnotationFqName ) - private fun wrapWithIndySamConversion(samType: IrType, irFunRef: IrFunctionReference): IrCall { - patchSignatureForIndySamConversion(irFunRef.symbol.owner, samType) + private fun wrapWithIndySamConversion( + samType: IrType, + lambdaMetafactoryArguments: LambdaMetafactoryArguments + ): IrCall { val notNullSamType = samType.makeNotNull() .removeAnnotations { it.type.classFqName in specialNullabilityAnnotationsFqNames } return context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run { - // We should produce the following expression: - // ``(method) - // where: - // - 'samType' is a substituted SAM type; - // - 'method' is a function reference to the actual method we are going to call - // (note that we need an IrFunctionReference here, so that further transformations would extract closure properly). - irCall(jvmIndySamConversionIntrinsic, notNullSamType).apply { + // See [org.jetbrains.kotlin.backend.jvm.JvmSymbols::indyLambdaMetafactoryIntrinsic]. + irCall(jvmIndyLambdaMetafactoryIntrinsic, notNullSamType).apply { putTypeArgument(0, notNullSamType) - putValueArgument(0, irFunRef) + putValueArgument(0, irRawFunctionRef(lambdaMetafactoryArguments.samMethod)) + putValueArgument(1, lambdaMetafactoryArguments.implMethodReference) + putValueArgument(2, irRawFunctionRef(lambdaMetafactoryArguments.fakeInstanceMethod)) + putValueArgument(3, irVarargOfRawFunctionRefs(lambdaMetafactoryArguments.extraOverriddenMethods)) } } } - 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()}") + private fun IrBuilderWithScope.irRawFunctionRef(irFun: IrFunction) = + irRawFunctionReferefence(context.irBuiltIns.anyType, irFun.symbol) - val samMethod = samType.getSingleAbstractMethod() - ?: throw AssertionError("SAM method not found:\n${samType.render()}") + private fun IrBuilderWithScope.irVarargOfRawFunctionRefs(irFuns: List) = + irVararg(context.irBuiltIns.anyType, irFuns.map { irRawFunctionRef(it) }) - 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()}" - ) + private fun collectValueParameters(irFun: IrFunction): List { + if (irFun.extensionReceiverParameter == null) + return irFun.valueParameters + return ArrayList().apply { + add(irFun.extensionReceiverParameter!!) + addAll(irFun.valueParameters) } - - 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() = 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 04f6a0f3af8..bc52a44af97 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 @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.fileParent import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound -import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* @@ -37,6 +36,8 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Handle import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.commons.Method +import java.lang.invoke.LambdaMetafactory // After this pass runs there are only four kinds of IrTypeOperatorCalls left: // @@ -101,7 +102,7 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil builder.irAs(argument, type) } - private val indySamConversionIntrinsic = context.ir.symbols.indySamConversionIntrinsic + private val jvmIndyLambdaMetafactoryIntrinsic = context.ir.symbols.indyLambdaMetafactoryIntrinsic private val indyIntrinsic = context.ir.symbols.jvmIndyIntrinsic @@ -128,13 +129,17 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol)) } + @Suppress("unused") private fun IrBuilderWithScope.jvmSubstitutedMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) = irCall(substitutedMethodTypeIntrinsic, context.irBuiltIns.anyType).apply { putTypeArgument(0, ownerType) putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol)) } - private val lambdaMetafactoryHandle = + /** + * @see java.lang.invoke.LambdaMetafactory.metafactory + */ + private val jdkMetafactoryHandle = Handle( Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", @@ -150,9 +155,26 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil false ) + /** + * @see java.lang.invoke.LambdaMetafactory.altMetafactory + */ + private val jdkAltMetafactoryHandle = + Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "altMetafactory", + "(" + + "Ljava/lang/invoke/MethodHandles\$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "[Ljava/lang/Object;" + + ")Ljava/lang/invoke/CallSite;", + false + ) + override fun visitCall(expression: IrCall): IrExpression { return when (expression.symbol) { - indySamConversionIntrinsic -> updateIndySamConversionIntrinsicCall(expression) + jvmIndyLambdaMetafactoryIntrinsic -> rewriteIndyLambdaMetafactoryCall(expression) else -> super.visitCall(expression) } } @@ -160,46 +182,86 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil /** * @see FunctionReferenceLowering.wrapWithIndySamConversion */ - private fun updateIndySamConversionIntrinsicCall(call: IrCall): IrCall { + private fun rewriteIndyLambdaMetafactoryCall(call: IrCall): IrCall { fun fail(message: String): Nothing = throw AssertionError("$message, call:\n${call.dump()}") - // We expect: - // ``(method) - // where - // - 'samType' is a substituted SAM type; - // - 'method' is an IrFunctionReference to an actual method that should be called, - // with arguments captured by closure stored as function reference arguments. - // We replace it with JVM INVOKEDYNAMIC intrinsic. - val startOffset = call.startOffset val endOffset = call.endOffset val samType = call.getTypeArgument(0) as? IrSimpleType ?: fail("'samType' is expected to be a simple type") - val samMethod = samType.getSingleAbstractMethod() - ?: fail("'${samType.render()}' is not a SAM-type") - val irFunRef = call.getValueArgument(0) as? IrFunctionReference - ?: fail("'method' is expected to be 'IrFunctionReference'") - val funSymbol = irFunRef.symbol + val samMethodRef = call.getValueArgument(0) as? IrRawFunctionReference + ?: fail("'samMethodType' should be 'IrRawFunctionReference'") + val implFunRef = call.getValueArgument(1) as? IrFunctionReference + ?: fail("'implMethodReference' is expected to be 'IrFunctionReference'") + val implFunSymbol = implFunRef.symbol + val instanceMethodRef = call.getValueArgument(2) as? IrRawFunctionReference + ?: fail("'instantiatedMethodType' is expected to be 'IrRawFunctionReference'") - val dynamicCall = wrapClosureInDynamicCall(samType, samMethod, irFunRef) - - return context.createJvmIrBuilder( - funSymbol, // TODO actual symbol for outer scope - startOffset, endOffset - ).run { - val samMethodType = jvmOriginalMethodType(samMethod.symbol) - val irRawFunRef = irRawFunctionReferefence(irFunRef.type, funSymbol) - val instanceMethodType = jvmSubstitutedMethodType(samType, samMethod.symbol) - - jvmInvokeDynamic( - dynamicCall, - lambdaMetafactoryHandle, - listOf(samMethodType, irRawFunRef, instanceMethodType) - ) + val extraOverriddenMethods = run { + val extraOverriddenMethodVararg = call.getValueArgument(3) as? IrVararg + ?: fail("'extraOverriddenMethodTypes' is expected to be 'IrVararg'") + extraOverriddenMethodVararg.elements.map { + val ref = it as? IrRawFunctionReference + ?: fail("'extraOverriddenMethodTypes' elements are expected to be 'IrRawFunctionReference'") + ref.symbol.owner as? IrSimpleFunction + ?: fail("Extra overridden method is expected to be 'IrSimpleFunction': ${ref.symbol.owner.render()}") + } } + + val samMethod = samMethodRef.symbol.owner as? IrSimpleFunction + ?: fail("SAM method is expected to be 'IrSimpleFunction': ${samMethodRef.symbol.owner.render()}") + val instanceMethod = instanceMethodRef.symbol.owner as? IrSimpleFunction + ?: fail("Instance method is expected to be 'IrSimpleFunction': ${instanceMethodRef.symbol.owner.render()}") + + val dynamicCall = wrapClosureInDynamicCall(samType, samMethod, implFunRef) + + val requiredBridges = getOverriddenMethodsRequiringBridges(instanceMethod, samMethod, extraOverriddenMethods) + + return context.createJvmIrBuilder(implFunSymbol, startOffset, endOffset).run { + val samMethodType = jvmOriginalMethodType(samMethod.symbol) + val irRawFunRef = irRawFunctionReferefence(implFunRef.type, implFunSymbol) + val instanceMethodType = jvmOriginalMethodType(instanceMethodRef.symbol) + + if (requiredBridges.isNotEmpty()) { + val bridgeMethodTypes = requiredBridges.map { jvmOriginalMethodType(it.symbol) } + jvmInvokeDynamic( + dynamicCall, + jdkAltMetafactoryHandle, + listOf( + samMethodType, irRawFunRef, instanceMethodType, + irInt(LambdaMetafactory.FLAG_BRIDGES), + irInt(requiredBridges.size) + ) + bridgeMethodTypes + ) + } else { + jvmInvokeDynamic( + dynamicCall, + jdkMetafactoryHandle, + listOf(samMethodType, irRawFunRef, instanceMethodType) + ) + } + } + } + + private fun getOverriddenMethodsRequiringBridges( + instanceMethod: IrSimpleFunction, + samMethod: IrSimpleFunction, + extraOverriddenMethods: List + ): Collection { + val jvmInstanceMethod = context.methodSignatureMapper.mapAsmMethod(instanceMethod) + val jvmSamMethod = context.methodSignatureMapper.mapAsmMethod(samMethod) + + val signatureToNonFakeOverride = LinkedHashMap() + for (overridden in extraOverriddenMethods) { + val jvmOverriddenMethod = context.methodSignatureMapper.mapAsmMethod(overridden) + if (jvmOverriddenMethod != jvmInstanceMethod && jvmOverriddenMethod != jvmSamMethod) { + signatureToNonFakeOverride[jvmOverriddenMethod] = overridden + } + } + return signatureToNonFakeOverride.values } private fun wrapClosureInDynamicCall( diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt index 82829791295..ad70cbe9834 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt @@ -96,6 +96,7 @@ fun IrType.isArray(): Boolean = isNotNullClassType(IdSignatureValues.array) fun IrType.isNullableArray(): Boolean = isNullableClassType(IdSignatureValues.array) fun IrType.isCollection(): Boolean = isNotNullClassType(IdSignatureValues.collection) fun IrType.isNothing(): Boolean = isNotNullClassType(IdSignatureValues.nothing) +fun IrType.isNullableNothing(): Boolean = isNullableClassType(IdSignatureValues.nothing) fun IrType.isPrimitiveType(hasQuestionMark: Boolean = false): Boolean = (this is IrSimpleType && hasQuestionMark == this.hasQuestionMark) && diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index 671a132170b..5f08ccf3df4 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -600,6 +600,15 @@ open class DeepCopyIrTreeWithSymbols( }.copyAttributes(expression) } + override fun visitRawFunctionReference(expression: IrRawFunctionReference): IrRawFunctionReference { + val symbol = symbolRemapper.getReferencedFunction(expression.symbol) + return IrRawFunctionReferenceImpl( + expression.startOffset, expression.endOffset, + expression.type.remapType(), + symbol + ).copyAttributes(expression) + } + override fun visitPropertyReference(expression: IrPropertyReference): IrPropertyReference = IrPropertyReferenceImpl( expression.startOffset, expression.endOffset, diff --git a/compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt b/compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt index 7d5fecf3740..77828ed619b 100644 --- a/compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt +++ b/compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt @@ -1,5 +1,6 @@ // TARGET_BACKEND: JVM - +// SAM_CONVERSIONS: CLASS +// ^ test checks reflection for synthetic classes // WITH_RUNTIME // FILE: Test.java @@ -9,9 +10,10 @@ class Test { } } -// FILE: test.kt +// FILE: samLambda.kt import java.lang.reflect.Method + import kotlin.test.assertEquals @Target(AnnotationTarget.FUNCTION) diff --git a/compiler/testData/codegen/box/invokedynamic/lambdas/lambdaSerializable.kt b/compiler/testData/codegen/box/invokedynamic/lambdas/lambdaSerializable.kt index 9cf4a35003e..dad517e3d5c 100644 --- a/compiler/testData/codegen/box/invokedynamic/lambdas/lambdaSerializable.kt +++ b/compiler/testData/codegen/box/invokedynamic/lambdas/lambdaSerializable.kt @@ -8,6 +8,6 @@ fun lambdaIsSerializable(fn: () -> Unit) = fn is java.io.Serializable fun box(): String { if (lambdaIsSerializable {}) - return "Failed: indy lambdas are not serializable" + return "Failed: indy lambdas should not be serializable" return "OK" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt b/compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt new file mode 100644 index 00000000000..3cfb14ea8a4 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt @@ -0,0 +1,14 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface KRunnable { + fun run() +} + +var test = "Failed" + +fun box(): String { + KRunnable { test = "OK" }.run() + return test +} diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt new file mode 100644 index 00000000000..8589d7572d6 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFooAny { + fun foo(x: Any): Any +} + +fun interface IFooStr : IFooAny { + override fun foo(x: Any): String +} + +fun box() = IFooStr { x: Any -> x.toString() }.foo("OK") \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt new file mode 100644 index 00000000000..c0d925020a0 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt @@ -0,0 +1,20 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFooNStr { + fun foo(x: Any): String? +} + +fun interface IFooNN : IFooNStr { + override fun foo(x: Any): Nothing? +} + +fun box(): String { + var r = "Failed" + IFooNN { + r = it.toString() + null + }.foo("OK") + return r +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt new file mode 100644 index 00000000000..aa997eb4743 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt @@ -0,0 +1,15 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY +// IGNORE_DEXING + +fun interface GenericToAny { + fun invoke(x: T): Any +} + +fun interface GenericCharToAny : GenericToAny + +fun withK(fn: GenericCharToAny) = fn.invoke('K').toString() + +fun box(): String = + withK { "O" + it } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt new file mode 100644 index 00000000000..7422e8b3bb5 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface GenericToAny { + fun invoke(x: T): Any +} + +fun interface CharToAny { + fun invoke(x: Char): Any +} + +fun interface GenericCharToAny : GenericToAny, CharToAny + +fun withK(fn: GenericCharToAny) = fn.invoke('K').toString() + +fun box(): String = + withK { "O" + it } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt new file mode 100644 index 00000000000..1e40c61d9c8 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt @@ -0,0 +1,16 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface GenericToAny { + fun invoke(x: T): Any +} + +fun interface GenericCharToAny : GenericToAny { + override fun invoke(x: Char): Any +} + +fun withK(fn: GenericCharToAny) = fn.invoke('K').toString() + +fun box(): String = + withK { "O" + it } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt new file mode 100644 index 00000000000..6ecf41feff3 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt @@ -0,0 +1,17 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface GenericToAny { + fun invoke(x: T): Any +} + +fun interface GenericIntToAny : GenericToAny + +fun with4(fn: GenericIntToAny) = fn.invoke(4).toString() + +fun box(): String = + with4 { + if (it != 4) throw Exception() + "OK" + } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt new file mode 100644 index 00000000000..c122aeadce9 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt @@ -0,0 +1,14 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface GenericToAny { + fun invoke(x: T): Any +} + +fun interface GenericStringToAny : GenericToAny + +fun withK(fn: GenericStringToAny) = fn.invoke("K").toString() + +fun box(): String = + withK { "O" + it } \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt new file mode 100644 index 00000000000..22d0c781187 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt @@ -0,0 +1,22 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFoo { + fun foo(): T +} + +fun interface IFooUnit : IFoo { + override fun foo() +} + +fun fooT(iFoo: IFoo) = iFoo.foo() +fun fooUnit(iFooUnit: IFooUnit) { iFooUnit.foo() } + +var ok = "Failed" + +fun box(): String { + fooT { ok = "O" } + fooUnit { ok += "K" } + return ok +} diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt new file mode 100644 index 00000000000..99ff969a98d --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt @@ -0,0 +1,40 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY +// WITH_RUNTIME + +fun interface IFooT { + fun foo(x: T): T +} + +fun interface IFooIntArray { + fun foo(x: IntArray): IntArray +} + +fun interface IFooMix0 : IFooT, IFooIntArray + +fun interface IFooMix1 : IFooT, IFooIntArray { + override fun foo(x: IntArray): IntArray +} + +fun box(): String { + var t0 = "Failed 0" + val f0 = IFooMix0 { + t0 = "O" + it[0].toChar() + it + } + f0.foo(intArrayOf('K'.toInt())) + if (t0 != "OK") + return "Failed: t0=$t0" + + var t1 = "Failed 1" + val f1 = IFooMix1 { + t1 = it[0].toChar() + "K" + it + } + f1.foo(intArrayOf('O'.toInt())) + if (t1 != "OK") + return "Failed: t1=$t1" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt new file mode 100644 index 00000000000..21ca535bfc8 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt @@ -0,0 +1,29 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFooT { + fun foo(x: T): T +} + +fun interface IFooStr { + fun foo(x: String): String +} + +fun interface IFooMix0 : IFooT, IFooStr + +fun interface IFooMix1 : IFooT, IFooStr { + override fun foo(x: String): String +} + +fun box(): String { + val f0 = IFooMix0 { "O" + it } + if (f0.foo("K") != "OK") + return "Failed: f0.foo(\"K\")=${f0.foo("K")}" + + val f1 = IFooMix1 { it + "K" } + if (f1.foo("O") != "OK") + return "Failed: f1.foo(\"O\")=${f1.foo("O")}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt new file mode 100644 index 00000000000..1d05b5df422 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt @@ -0,0 +1,32 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY +// WITH_RUNTIME + +fun interface IFooT { + fun foo(x: Array): T +} + +fun interface IFooStr { + fun foo(x: Array): String +} + +fun interface IFooMix0 : IFooT, IFooStr + +fun interface IFooMix1 : IFooT, IFooStr { + override fun foo(x: Array): String +} + +fun box(): String { + val f0 = IFooMix0 { "O" + it[0] } + val t0 = f0.foo(arrayOf("K")) + if (t0 != "OK") + return "Failed: t0=$t0" + + val f1 = IFooMix1 { it[0] + "K" } + val t1 = f1.foo(arrayOf("O")) + if (t1 != "OK") + return "Failed: t1=$t1" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt new file mode 100644 index 00000000000..b1db5015f9a --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt @@ -0,0 +1,32 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// IGNORE_LIGHT_ANALYSIS +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +fun interface IFooT { + fun foo(x: T): T +} + +fun interface IFooInt { + fun foo(x: Int): Int +} + +fun interface IFooMixed0 : IFooInt, IFooT + +fun interface IFooMixed1 : IFooInt, IFooT { + override fun foo(x: Int): Int +} + +fun box(): String { + val f0 = IFooMixed0 { it * 2 } + if (f0.foo(21) != 42) + return "Failed: f0.foo(21)=${f0.foo(21)}" + + val f1 = IFooMixed1 { it * 2 } + if (f1.foo(21) != 42) + return "Failed: f1.foo(21)=${f1.foo(21)}" + + return "OK" +} + diff --git a/compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.kt similarity index 89% rename from compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt rename to compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.kt index 6392915e1cc..73b1e97efd6 100644 --- a/compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt +++ b/compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.kt @@ -1,6 +1,6 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// LAMBDAS: INDY +// SAM_CONVERSIONS: INDY fun interface IFoo { fun foo(): T diff --git a/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt b/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt index 622554630a0..617c2c56555 100644 --- a/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt +++ b/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt @@ -1,4 +1,6 @@ // TARGET_BACKEND: JVM +// SAM_CONVERSIONS: CLASS +// ^ SAM-convertion classes created with LambdaMetafactory have 'enclosingMethod' and 'enclosingClass' // WITH_REFLECT package test @@ -17,7 +19,7 @@ fun box(): String { val javaClass = lambda.javaClass val enclosingMethod = javaClass.getEnclosingMethod() - if (enclosingMethod?.getName() != "run") return "method: $enclosingMethod" + if (enclosingMethod?.getName() != "run") return "enclosing method: $enclosingMethod" val enclosingClass = javaClass.getEnclosingClass()!!.getName() if (enclosingClass != "test.A\$prop\$1") return "enclosing class: $enclosingClass" diff --git a/compiler/testData/codegen/box/sam/adapters/genericSignature.kt b/compiler/testData/codegen/box/sam/adapters/genericSignature.kt index 3f0d4f9b8c3..5f5dacff672 100644 --- a/compiler/testData/codegen/box/sam/adapters/genericSignature.kt +++ b/compiler/testData/codegen/box/sam/adapters/genericSignature.kt @@ -1,4 +1,6 @@ // TARGET_BACKEND: JVM +// SAM_CONVERSIONS: CLASS +// ^ test checks reflection for synthetic classes // MODULE: lib // FILE: JavaClass.java diff --git a/compiler/testData/codegen/box/sam/kt11519.kt b/compiler/testData/codegen/box/sam/kt11519.kt index 767a30b21aa..4cf0692636d 100644 --- a/compiler/testData/codegen/box/sam/kt11519.kt +++ b/compiler/testData/codegen/box/sam/kt11519.kt @@ -1,5 +1,7 @@ // TARGET_BACKEND: JVM // SKIP_JDK6 +// SAM_CONVERSIONS: CLASS +// ^ test checks reflection for synthetic classes // MODULE: lib // FILE: Custom.java diff --git a/compiler/testData/codegen/box/sam/kt11519Constructor.kt b/compiler/testData/codegen/box/sam/kt11519Constructor.kt index 05d1a47a2a7..c57a48d4b62 100644 --- a/compiler/testData/codegen/box/sam/kt11519Constructor.kt +++ b/compiler/testData/codegen/box/sam/kt11519Constructor.kt @@ -1,5 +1,7 @@ // TARGET_BACKEND: JVM // SKIP_JDK6 +// SAM_CONVERSIONS: CLASS +// ^ test checks reflection for synthetic classes // MODULE: lib // FILE: Custom.java diff --git a/compiler/testData/codegen/box/sam/kt11696.kt b/compiler/testData/codegen/box/sam/kt11696.kt index e4582355d9c..e2ca195926f 100644 --- a/compiler/testData/codegen/box/sam/kt11696.kt +++ b/compiler/testData/codegen/box/sam/kt11696.kt @@ -1,6 +1,8 @@ // TARGET_BACKEND: JVM // IGNORE_BACKEND_FIR: JVM_IR // WITH_RUNTIME +// SAM_CONVERSIONS: CLASS +// ^ test checks reflection for synthetic classes // MODULE: lib // FILE: Promise.java import org.jetbrains.annotations.NotNull; diff --git a/compiler/testData/codegen/box/sam/recordSubstitutedTypeForCallableSamParameter.kt b/compiler/testData/codegen/box/sam/recordSubstitutedTypeForCallableSamParameter.kt index 56ae5eedccf..595ad2c364e 100644 --- a/compiler/testData/codegen/box/sam/recordSubstitutedTypeForCallableSamParameter.kt +++ b/compiler/testData/codegen/box/sam/recordSubstitutedTypeForCallableSamParameter.kt @@ -2,6 +2,8 @@ // WITH_REFLECT // FULL_JDK // TARGET_BACKEND: JVM +// SAM_CONVERSIONS: CLASS +// ^ SAM-convertion classes created with LambdaMetafactory have no generic signatures // FILE: Provider.java diff --git a/compiler/testData/codegen/box/sam/samConstructorGenericSignature.kt b/compiler/testData/codegen/box/sam/samConstructorGenericSignature.kt index 331393f18c7..177123f353c 100644 --- a/compiler/testData/codegen/box/sam/samConstructorGenericSignature.kt +++ b/compiler/testData/codegen/box/sam/samConstructorGenericSignature.kt @@ -2,6 +2,8 @@ // TARGET_BACKEND: JVM // SKIP_JDK6 // WITH_RUNTIME +// SAM_CONVERSIONS: CLASS +// ^ test checks reflection for synthetic classes // MODULE: lib // FILE: JavaClass.java diff --git a/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.kt b/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.kt index 97199cbce74..20802d611b7 100644 --- a/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.kt +++ b/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.kt @@ -1,3 +1,4 @@ +// SAM_CONVERSIONS: CLASS // FILE: samAdapterForJavaInterfaceWithNullability.kt fun testNullable(s: String) = JNullable { s } fun testNotNull(s: String) = JNotNull { s } diff --git a/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.txt b/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.txt index 6e13d1f0c1f..6fedbee2322 100644 --- a/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.txt +++ b/compiler/testData/codegen/bytecodeListing/nullabilityAnnotations/samAdapterForJavaInterfaceWithNullability.txt @@ -1,40 +1,10 @@ -@kotlin.Metadata -final class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1 { - // source: 'samAdapterForJavaInterfaceWithNullability.kt' - enclosing method SamAdapterForJavaInterfaceWithNullabilityKt.testNoAnnotation(Ljava/lang/String;)LJNoAnnotation; - synthetic final field $s: java.lang.String - inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1 - method (p0: java.lang.String): void - public final method getString(): java.lang.String -} - -@kotlin.Metadata -final class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1 { - // source: 'samAdapterForJavaInterfaceWithNullability.kt' - enclosing method SamAdapterForJavaInterfaceWithNullabilityKt.testNotNull(Ljava/lang/String;)LJNotNull; - synthetic final field $s: java.lang.String - inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1 - method (p0: java.lang.String): void - public final @org.jetbrains.annotations.NotNull method getNullableString(): java.lang.String -} - -@kotlin.Metadata -final class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1 { - // source: 'samAdapterForJavaInterfaceWithNullability.kt' - enclosing method SamAdapterForJavaInterfaceWithNullabilityKt.testNullable(Ljava/lang/String;)LJNullable; - synthetic final field $s: java.lang.String - inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1 - method (p0: java.lang.String): void - public final @org.jetbrains.annotations.Nullable method getNullableString(): java.lang.String -} - @kotlin.Metadata public final class SamAdapterForJavaInterfaceWithNullabilityKt { // source: 'samAdapterForJavaInterfaceWithNullability.kt' - inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1 - inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1 - inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1 + private final static method testNoAnnotation$lambda-2(p0: java.lang.String): java.lang.String public final static @org.jetbrains.annotations.NotNull method testNoAnnotation(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNoAnnotation + private final static method testNotNull$lambda-1(p0: java.lang.String): java.lang.String public final static @org.jetbrains.annotations.NotNull method testNotNull(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNotNull + private final static method testNullable$lambda-0(p0: java.lang.String): java.lang.String public final static @org.jetbrains.annotations.NotNull method testNullable(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNullable } diff --git a/compiler/testData/codegen/bytecodeListing/sam/kt16650.kt b/compiler/testData/codegen/bytecodeListing/sam/kt16650.kt index 3ae957c0fa2..8a0e7b6a313 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/kt16650.kt +++ b/compiler/testData/codegen/bytecodeListing/sam/kt16650.kt @@ -1,3 +1,4 @@ +// SAM_CONVERSIONS: CLASS // WITH_SIGNATURES // FILE: t.kt fun main(x: DataStream) { diff --git a/compiler/testData/codegen/bytecodeListing/sam/kt16650_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/kt16650_ir.txt index 50b30869177..1b1bb19c3cc 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/kt16650_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/sam/kt16650_ir.txt @@ -1,31 +1,7 @@ -@kotlin.Metadata -final class<Ljava/lang/Object;LKeySelector;> TKt$main$1 { - // source: 't.kt' - static method (): void - method (): void - public final method getKey(p0: java.lang.Integer): java.lang.Long - public synthetic bridge method getKey(p0: java.lang.Object): java.lang.Object - enclosing method TKt.main(LDataStream;)V - public final static field ;> INSTANCE: TKt$main$1 - inner (anonymous) class TKt$main$1 -} - -@kotlin.Metadata -final class<Ljava/lang/Object;LKeySelector;> TKt$main$2 { - // source: 't.kt' - static method (): void - method (): void - public final method getKey(p0: java.lang.Integer): java.lang.Long - public synthetic bridge method getKey(p0: java.lang.Object): java.lang.Object - enclosing method TKt.main(LDataStream;)V - public final static field ;> INSTANCE: TKt$main$2 - inner (anonymous) class TKt$main$2 -} - @kotlin.Metadata public final class TKt { // source: 't.kt' public final static <(LDataStream;)V> method main(@org.jetbrains.annotations.NotNull p0: DataStream): void - inner (anonymous) class TKt$main$1 - inner (anonymous) class TKt$main$2 + private final static method main$lambda-0(p0: java.lang.Integer): java.lang.Long + private final static method main$lambda-1(p0: java.lang.Integer): java.lang.Long } diff --git a/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericFunInterface_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericFunInterface_ir.txt index 58ebc83375c..06aebcc78e9 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericFunInterface_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericFunInterface_ir.txt @@ -4,20 +4,10 @@ public interface<Ljava/lang/Object;> Sam { public abstract <()TT;> method get(): java.lang.Object } -@kotlin.Metadata -final class<Ljava/lang/Object;LSam;> TKt$genericSamGet$1 { - // source: 't.kt' - public final <()TT;> method get(): java.lang.Object - <(Lkotlin/jvm/functions/Function0<+TT;>;)V> method (p0: kotlin.jvm.functions.Function0): void - enclosing method TKt.genericSamGet(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - synthetic final field ;> $f: kotlin.jvm.functions.Function0 - inner (anonymous) class TKt$genericSamGet$1 -} - @kotlin.Metadata public final class TKt { // source: 't.kt' public final static <(LSam;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object + private final static <(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.Object public final static <(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object - inner (anonymous) class TKt$genericSamGet$1 } diff --git a/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericSamInterface_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericSamInterface_ir.txt index 023cc600dfa..7c5f65a0533 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericSamInterface_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/sam/lambdaGenericSamInterface_ir.txt @@ -1,28 +1,8 @@ -@kotlin.Metadata -final class<Ljava/lang/Object;LSam;> TKt$genericSam$1 { - // source: 't.kt' - public final <()TT;> method get(): java.lang.Object - <(Lkotlin/jvm/functions/Function0<+TT;>;)V> method (p0: kotlin.jvm.functions.Function0): void - enclosing method TKt.genericSam(Lkotlin/jvm/functions/Function0;)LSam; - synthetic final field ;> $f: kotlin.jvm.functions.Function0 - inner (anonymous) class TKt$genericSam$1 -} - -@kotlin.Metadata -final class<Ljava/lang/Object;LSam;> TKt$genericSamGet$1 { - // source: 't.kt' - public final <()TT;> method get(): java.lang.Object - <(Lkotlin/jvm/functions/Function0<+TT;>;)V> method (p0: kotlin.jvm.functions.Function0): void - enclosing method TKt.genericSamGet(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - synthetic final field ;> $f: kotlin.jvm.functions.Function0 - inner (anonymous) class TKt$genericSamGet$1 -} - @kotlin.Metadata public final class TKt { // source: 't.kt' public final static @org.jetbrains.annotations.NotNull <(Lkotlin/jvm/functions/Function0<+TT;>;)LSam;> method genericSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): Sam + private final static <(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.Object + private final static <(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet$lambda-1(p0: kotlin.jvm.functions.Function0): java.lang.Object public final static <(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object - inner (anonymous) class TKt$genericSam$1 - inner (anonymous) class TKt$genericSamGet$1 } diff --git a/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface.kt b/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface.kt index 7e4453b74d6..7cb672329d5 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface.kt +++ b/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface.kt @@ -1,3 +1,4 @@ + // WITH_SIGNATURES // FILE: t.kt diff --git a/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface_ir.txt index 8020d43de86..9d30b5549c0 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedFunInterface_ir.txt @@ -4,21 +4,10 @@ public interface<Ljava/lang/Object;> Sam { public abstract <()TT;> method get(): java.lang.Object } -@kotlin.Metadata -final class<Ljava/lang/Object;LSam;> TKt$specializedSam$1 { - // source: 't.kt' - <(Lkotlin/jvm/functions/Function0;)V> method (p0: kotlin.jvm.functions.Function0): void - public synthetic bridge method get(): java.lang.Object - public final @org.jetbrains.annotations.NotNull method get(): java.lang.String - enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String; - synthetic final field ;> $f: kotlin.jvm.functions.Function0 - inner (anonymous) class TKt$specializedSam$1 -} - @kotlin.Metadata public final class TKt { // source: 't.kt' + private final static <(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;> method specializedSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.String public final static @org.jetbrains.annotations.NotNull <(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String public final static <(LSam;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object - inner (anonymous) class TKt$specializedSam$1 } diff --git a/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedSamInterface_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedSamInterface_ir.txt index 9333ea1d30f..6274ccb7d0b 100644 --- a/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedSamInterface_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/sam/lambdaSpecializedSamInterface_ir.txt @@ -1,17 +1,6 @@ -@kotlin.Metadata -final class<Ljava/lang/Object;LSam;> TKt$specializedSam$1 { - // source: 't.kt' - <(Lkotlin/jvm/functions/Function0;)V> method (p0: kotlin.jvm.functions.Function0): void - public synthetic bridge method get(): java.lang.Object - public final method get(): java.lang.String - enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String; - synthetic final field ;> $f: kotlin.jvm.functions.Function0 - inner (anonymous) class TKt$specializedSam$1 -} - @kotlin.Metadata public final class TKt { // source: 't.kt' + private final static <(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;> method specializedSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.String public final static <(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String - inner (anonymous) class TKt$specializedSam$1 } diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt index c369f8b779d..ed3a450e24b 100644 --- a/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt @@ -16,9 +16,9 @@ fun test() { } // @TestKt.class: -// 1 NEW TestKt\$ +// 0 NEW TestKt\$ // 1 NEW kotlin/jvm/internal/Ref\$IntRef -// 2 NEW +// 1 NEW // 0 IFNONNULL // 0 IFNULL // 1 ACONST_NULL diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt index 757821e3886..719ef304308 100644 --- a/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt @@ -16,16 +16,16 @@ fun test() { JFoo.foo2({}, runnable()) } -// 2 NEW - // JVM_TEMPLATES // @TestKt.class: +// 2 NEW // 0 IFNONNULL // 1 IFNULL // 1 ACONST_NULL // JVM_IR_TEMPLATES // @TestKt.class +// 1 NEW // 1 IFNONNULL // 0 IFNULL // 2 ACONST_NULL diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperOfLambda.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperOfLambda.kt index f091753e2a0..75e0b5741f7 100644 --- a/compiler/testData/codegen/bytecodeText/sam/samWrapperOfLambda.kt +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperOfLambda.kt @@ -12,5 +12,5 @@ fun test() { } // Lambda inlined into run(), no wrapper class generated: -// 1 NEW +// 0 NEW // 0 INVOKEINTERFACE 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 ae9e296f7eb..fe03be4e4ec 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 @@ -19957,6 +19957,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); } + @Test + @TestMetadata("simpleFunInterfaceConstructor.kt") + public void testSimpleFunInterfaceConstructor() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt"); + } + @Test @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { @@ -19993,12 +19999,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt"); } - @Test - @TestMetadata("voidReturnTypeAsGeneric.kt") - public void testVoidReturnTypeAsGeneric() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt"); - } - @Nested @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature") @TestDataPath("$PROJECT_ROOT") @@ -20080,6 +20080,94 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + public class SpecializedGenerics { + @Test + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @Test + @TestMetadata("covariantOverride.kt") + public void testCovariantOverride() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt"); + } + + @Test + @TestMetadata("covariantOverrideWithNNothing.kt") + public void testCovariantOverrideWithNNothing() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt"); + } + + @Test + @TestMetadata("inheritedWithChar.kt") + public void testInheritedWithChar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt"); + } + + @Test + @TestMetadata("inheritedWithCharDiamond.kt") + public void testInheritedWithCharDiamond() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt"); + } + + @Test + @TestMetadata("inheritedWithCharExplicitlyOverridden.kt") + public void testInheritedWithCharExplicitlyOverridden() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt"); + } + + @Test + @TestMetadata("inheritedWithInt.kt") + public void testInheritedWithInt() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt"); + } + + @Test + @TestMetadata("inheritedWithString.kt") + public void testInheritedWithString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt"); + } + + @Test + @TestMetadata("inheritedWithUnit.kt") + public void testInheritedWithUnit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt"); + } + + @Test + @TestMetadata("mixGenericAndIntArray.kt") + public void testMixGenericAndIntArray() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt"); + } + + @Test + @TestMetadata("mixGenericAndString.kt") + public void testMixGenericAndString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt"); + } + + @Test + @TestMetadata("mixGenericArrayAndArrayOfString.kt") + public void testMixGenericArrayAndArrayOfString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt"); + } + + @Test + @TestMetadata("mixPrimitiveAndBoxed.kt") + public void testMixPrimitiveAndBoxed() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt"); + } + + @Test + @TestMetadata("voidReturnTypeAsGeneric.kt") + public void testVoidReturnTypeAsGeneric() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.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 cf4d445ac06..dc868d9b42d 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 @@ -19957,6 +19957,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); } + @Test + @TestMetadata("simpleFunInterfaceConstructor.kt") + public void testSimpleFunInterfaceConstructor() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt"); + } + @Test @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { @@ -19993,12 +19999,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt"); } - @Test - @TestMetadata("voidReturnTypeAsGeneric.kt") - public void testVoidReturnTypeAsGeneric() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt"); - } - @Nested @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature") @TestDataPath("$PROJECT_ROOT") @@ -20080,6 +20080,94 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + public class SpecializedGenerics { + @Test + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("covariantOverride.kt") + public void testCovariantOverride() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt"); + } + + @Test + @TestMetadata("covariantOverrideWithNNothing.kt") + public void testCovariantOverrideWithNNothing() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt"); + } + + @Test + @TestMetadata("inheritedWithChar.kt") + public void testInheritedWithChar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt"); + } + + @Test + @TestMetadata("inheritedWithCharDiamond.kt") + public void testInheritedWithCharDiamond() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt"); + } + + @Test + @TestMetadata("inheritedWithCharExplicitlyOverridden.kt") + public void testInheritedWithCharExplicitlyOverridden() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt"); + } + + @Test + @TestMetadata("inheritedWithInt.kt") + public void testInheritedWithInt() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt"); + } + + @Test + @TestMetadata("inheritedWithString.kt") + public void testInheritedWithString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt"); + } + + @Test + @TestMetadata("inheritedWithUnit.kt") + public void testInheritedWithUnit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt"); + } + + @Test + @TestMetadata("mixGenericAndIntArray.kt") + public void testMixGenericAndIntArray() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt"); + } + + @Test + @TestMetadata("mixGenericAndString.kt") + public void testMixGenericAndString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt"); + } + + @Test + @TestMetadata("mixGenericArrayAndArrayOfString.kt") + public void testMixGenericArrayAndArrayOfString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt"); + } + + @Test + @TestMetadata("mixPrimitiveAndBoxed.kt") + public void testMixPrimitiveAndBoxed() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt"); + } + + @Test + @TestMetadata("voidReturnTypeAsGeneric.kt") + public void testVoidReturnTypeAsGeneric() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.kt"); + } + } } } diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 56cb38f9750..f3e8c2b3486 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16733,6 +16733,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt"); } + @TestMetadata("simpleFunInterfaceConstructor.kt") + public void testSimpleFunInterfaceConstructor() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt"); + } + @TestMetadata("simpleIndyFunInterface.kt") public void testSimpleIndyFunInterface() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt"); @@ -16758,11 +16763,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt"); } - @TestMetadata("voidReturnTypeAsGeneric.kt") - public void testVoidReturnTypeAsGeneric() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/voidReturnTypeAsGeneric.kt"); - } - @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -16835,6 +16835,84 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt"); } } + + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SpecializedGenerics extends AbstractLightAnalysisModeTest { + @TestMetadata("mixPrimitiveAndBoxed.kt") + public void ignoreMixPrimitiveAndBoxed() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixPrimitiveAndBoxed.kt"); + } + + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("covariantOverride.kt") + public void testCovariantOverride() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverride.kt"); + } + + @TestMetadata("covariantOverrideWithNNothing.kt") + public void testCovariantOverrideWithNNothing() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt"); + } + + @TestMetadata("inheritedWithChar.kt") + public void testInheritedWithChar() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithChar.kt"); + } + + @TestMetadata("inheritedWithCharDiamond.kt") + public void testInheritedWithCharDiamond() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharDiamond.kt"); + } + + @TestMetadata("inheritedWithCharExplicitlyOverridden.kt") + public void testInheritedWithCharExplicitlyOverridden() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithCharExplicitlyOverridden.kt"); + } + + @TestMetadata("inheritedWithInt.kt") + public void testInheritedWithInt() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithInt.kt"); + } + + @TestMetadata("inheritedWithString.kt") + public void testInheritedWithString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithString.kt"); + } + + @TestMetadata("inheritedWithUnit.kt") + public void testInheritedWithUnit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/inheritedWithUnit.kt"); + } + + @TestMetadata("mixGenericAndIntArray.kt") + public void testMixGenericAndIntArray() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndIntArray.kt"); + } + + @TestMetadata("mixGenericAndString.kt") + public void testMixGenericAndString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericAndString.kt"); + } + + @TestMetadata("mixGenericArrayAndArrayOfString.kt") + public void testMixGenericArrayAndArrayOfString() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/mixGenericArrayAndArrayOfString.kt"); + } + + @TestMetadata("voidReturnTypeAsGeneric.kt") + public void testVoidReturnTypeAsGeneric() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/voidReturnTypeAsGeneric.kt"); + } + } } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 52a8968ba1f..c21c768bbfd 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -14580,6 +14580,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); } } + + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SpecializedGenerics extends AbstractIrJsCodegenBoxES6Test { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath); + } + + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + } } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 0ef0133f9be..096a949eac2 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -14065,6 +14065,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } } + + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SpecializedGenerics extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 7ffcaac194e..90693bc4ef8 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -14130,6 +14130,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } } + + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SpecializedGenerics extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + } } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 38d21ec3cdd..b81237dbc68 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -8171,6 +8171,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); } } + + @TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SpecializedGenerics extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInSpecializedGenerics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + } } }