JVM_IR: use indy SAM conversions in jvmTarget 1.8+, fix bridges
KT-44278 KT-26060 KT-42621
This commit is contained in:
@@ -209,11 +209,12 @@ class GenerationState private constructor(
|
|||||||
|
|
||||||
val samConversionsScheme = run {
|
val samConversionsScheme = run {
|
||||||
val fromConfig = configuration.get(JVMConfigurationKeys.SAM_CONVERSIONS)
|
val fromConfig = configuration.get(JVMConfigurationKeys.SAM_CONVERSIONS)
|
||||||
?: JvmClosureGenerationScheme.DEFAULT
|
if (fromConfig != null && target >= fromConfig.minJvmTarget)
|
||||||
if (target >= fromConfig.minJvmTarget)
|
|
||||||
fromConfig
|
fromConfig
|
||||||
|
else if (target < JvmTarget.JVM_1_8)
|
||||||
|
JvmClosureGenerationScheme.CLASS
|
||||||
else
|
else
|
||||||
JvmClosureGenerationScheme.DEFAULT
|
JvmClosureGenerationScheme.INDY
|
||||||
}
|
}
|
||||||
|
|
||||||
val lambdasScheme = run {
|
val lambdasScheme = run {
|
||||||
|
|||||||
+94
-6
@@ -19957,6 +19957,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
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
|
@Test
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
@@ -19993,12 +19999,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@@ -20080,6 +20080,94 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -545,19 +545,53 @@ class JvmSymbols(
|
|||||||
returnType = dst.defaultType
|
returnType = dst.defaultType
|
||||||
}.symbol
|
}.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 <SAM_TYPE> `<jvm-indy-lambda-metafactory>`(
|
||||||
|
// 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.
|
||||||
|
// `<jvm-indy-lambda-metafactory>` 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 {
|
irFactory.buildFun {
|
||||||
name = Name.special("<jvm-indy-sam-conversion>")
|
name = Name.special("<jvm-indy-lambda-metafactory>")
|
||||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = kotlinJvmInternalPackage
|
parent = kotlinJvmInternalPackage
|
||||||
val samType = addTypeParameter("SAM_TYPE", irBuiltIns.anyType)
|
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
|
returnType = samType.defaultType
|
||||||
}.symbol
|
}.symbol
|
||||||
|
|
||||||
val arrayOfAnyType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType)
|
|
||||||
|
|
||||||
// Intrinsic to represent INVOKEDYNAMIC calls in IR.
|
// Intrinsic to represent INVOKEDYNAMIC calls in IR.
|
||||||
// fun <T> `<jvm-indy>`(
|
// fun <T> `<jvm-indy>`(
|
||||||
// dynamicCall: T,
|
// dynamicCall: T,
|
||||||
|
|||||||
+1
-1
@@ -136,9 +136,9 @@ object JvmInvokeDynamic : IntrinsicMethod() {
|
|||||||
?: fail("Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference")
|
?: fail("Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference")
|
||||||
val irOriginalFun = irRawFunRef.symbol.owner as? IrSimpleFunction
|
val irOriginalFun = irRawFunRef.symbol.owner as? IrSimpleFunction
|
||||||
?: fail("IrSimpleFunction expected: ${irRawFunRef.symbol.owner.render()}")
|
?: fail("IrSimpleFunction expected: ${irRawFunRef.symbol.owner.render()}")
|
||||||
|
|
||||||
val superType = irCall.getTypeArgument(0) as? IrSimpleType
|
val superType = irCall.getTypeArgument(0) as? IrSimpleType
|
||||||
?: fail("Type argument expected")
|
?: fail("Type argument expected")
|
||||||
|
|
||||||
val patchedSuperType = replaceTypeArgumentsWithNullable(superType)
|
val patchedSuperType = replaceTypeArgumentsWithNullable(superType)
|
||||||
|
|
||||||
val fakeClass = codegen.context.irFactory.buildClass { name = Name.special("<fake>") }
|
val fakeClass = codegen.context.irFactory.buildClass { name = Name.special("<fake>") }
|
||||||
|
|||||||
+406
-96
@@ -25,13 +25,14 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
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.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
|
|
||||||
internal val functionReferencePhase = makeIrFilePhase(
|
internal val functionReferencePhase = makeIrFilePhase(
|
||||||
::FunctionReferenceLowering,
|
::FunctionReferenceLowering,
|
||||||
@@ -92,20 +93,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
expression.statements.dropLast(1).forEach { it.transform(this, null) }
|
expression.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||||
reference.transformChildrenVoid(this)
|
reference.transformChildrenVoid(this)
|
||||||
|
|
||||||
if (shouldGenerateIndyLambdas && canUseIndySamConversion(reference, reference.type, true)) {
|
if (shouldGenerateIndyLambdas) {
|
||||||
return wrapLambdaReferenceWithIndySamConversion(expression, reference)
|
val lambdaMetafactoryArguments = getLambdaMetafactoryArgumentsOrNull(reference, reference.type, true)
|
||||||
|
if (lambdaMetafactoryArguments != null) {
|
||||||
|
return wrapLambdaReferenceWithIndySamConversion(expression, reference, lambdaMetafactoryArguments)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FunctionReferenceBuilder(reference).build()
|
return FunctionReferenceBuilder(reference).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapLambdaReferenceWithIndySamConversion(expression: IrBlock, reference: IrFunctionReference): IrBlock {
|
private fun wrapLambdaReferenceWithIndySamConversion(
|
||||||
expression.statements[expression.statements.size - 1] = wrapWithIndySamConversion(reference.type, reference)
|
expression: IrBlock,
|
||||||
val irLambda = reference.symbol.owner
|
reference: IrFunctionReference,
|
||||||
// JDK LambdaMetafactory can't adapt '(...)V' to '(...)Lkotlin/Unit;'.
|
lambdaMetafactoryArguments: LambdaMetafactoryArguments
|
||||||
if (irLambda.returnType.isUnit()) {
|
): IrBlock {
|
||||||
irLambda.returnType = irLambda.returnType.makeNullable()
|
val indySamConversion = wrapWithIndySamConversion(reference.type, lambdaMetafactoryArguments)
|
||||||
}
|
expression.statements[expression.statements.size - 1] = indySamConversion
|
||||||
|
expression.type = indySamConversion.type
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,49 +145,389 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
reference.transformChildrenVoid()
|
reference.transformChildrenVoid()
|
||||||
|
|
||||||
val samSuperType = expression.typeOperand
|
val samSuperType = expression.typeOperand
|
||||||
return if (shouldGenerateIndySamConversions && canUseIndySamConversion(reference, samSuperType, false)) {
|
|
||||||
wrapSamConversionArgumentWithIndySamConversion(expression)
|
if (shouldGenerateIndySamConversions) {
|
||||||
} else {
|
val lambdaMetafactoryArguments = getLambdaMetafactoryArgumentsOrNull(reference, samSuperType, false)
|
||||||
FunctionReferenceBuilder(reference, samSuperType).build()
|
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<IrSimpleFunction>
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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').
|
// Can't use JDK LambdaMetafactory for function references by default (because of 'equals').
|
||||||
// TODO special mode that would generate indy everywhere?
|
// TODO special mode that would generate indy everywhere?
|
||||||
if (reference.origin != IrStatementOrigin.LAMBDA)
|
if (reference.origin != IrStatementOrigin.LAMBDA)
|
||||||
return false
|
return null
|
||||||
|
|
||||||
// TODO wrap intrinsic function in lambda?
|
val samClass = samType.getClass()
|
||||||
if (context.irIntrinsics.getIntrinsic(reference.symbol) != null)
|
?: throw AssertionError("SAM type is not a class: ${samType.render()}")
|
||||||
return false
|
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
|
// Can't use JDK LambdaMetafactory for fun interface with suspend fun.
|
||||||
if (samSuperType.getSingleAbstractMethod()?.isSuspend == true)
|
if (samMethod.isSuspend)
|
||||||
return false
|
return null
|
||||||
|
|
||||||
// Can't use JDK LambdaMetafactory if lambda signature contains an inline class mapped to a non-null reference type.
|
// Can't use JDK LambdaMetafactory for fun interfaces that require delegation to $DefaultImpls.
|
||||||
val target = reference.symbol.owner
|
if (samClass.requiresDelegationToDefaultImpls())
|
||||||
if (target.extensionReceiverParameter?.run { type.isProhibitedTypeForIndySamConversion() } == true ||
|
return null
|
||||||
target.valueParameters.any { it.type.isProhibitedTypeForIndySamConversion() } ||
|
|
||||||
target.returnType.isProhibitedTypeForIndySamConversion()
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
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) {
|
if (plainLambda) {
|
||||||
var parametersCount = target.valueParameters.size
|
var parametersCount = target.valueParameters.size
|
||||||
if (target.extensionReceiverParameter != null) ++parametersCount
|
if (target.extensionReceiverParameter != null) ++parametersCount
|
||||||
if (parametersCount >= BuiltInFunctionArity.BIG_ARITY)
|
if (parametersCount >= BuiltInFunctionArity.BIG_ARITY)
|
||||||
return false
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can't use indy-based SAM conversion inside inline fun (Ok in inline lambda).
|
// Can't use indy-based SAM conversion inside inline fun (Ok in inline lambda).
|
||||||
if (target.parents.any { it.isInlineFunction() || it.isCrossinlineLambda() })
|
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("<fake>") }
|
||||||
|
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<T> {
|
||||||
|
// fun foo(x: T)
|
||||||
|
// }
|
||||||
|
// val t = IFoo<Int> { println(it + 1) }
|
||||||
|
// Here IFoo<T>::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<T> {
|
||||||
|
// fun foo(x: T)
|
||||||
|
// }
|
||||||
|
// fun interface IFooInt {
|
||||||
|
// fun foo(x: Int)
|
||||||
|
// }
|
||||||
|
// fun interface IFooMix : IFooT<Int>, IFooInt
|
||||||
|
// val t = IFooMix { println(it + 1) }
|
||||||
|
// Here IFooT<T>::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<T> {
|
||||||
|
// fun foo(x: T)
|
||||||
|
// }
|
||||||
|
// fun interface IFooInt {
|
||||||
|
// fun foo(x: Int)
|
||||||
|
// }
|
||||||
|
// fun interface IFooMix : IFooT<Int>, 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<IrValueParameter, TypeAdaptationConstraint>,
|
||||||
|
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<IrValueParameter, TypeAdaptationConstraint>()
|
||||||
|
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<IrValueParameter, TypeAdaptationConstraint>()
|
||||||
|
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() =
|
private fun IrDeclarationParent.isInlineFunction() =
|
||||||
this is IrSimpleFunction && isInline && origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
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
|
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() =
|
private fun IrType.isJvmPrimitiveType() =
|
||||||
isBoolean() || isChar() || isByte() || isShort() || isInt() || isLong() || isFloat() || isDouble()
|
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
|
val samType = expression.typeOperand
|
||||||
return when (val argument = expression.argument) {
|
return when (val argument = expression.argument) {
|
||||||
is IrFunctionReference -> {
|
is IrFunctionReference -> {
|
||||||
wrapWithIndySamConversion(samType, argument)
|
wrapWithIndySamConversion(samType, lambdaMetafactoryArguments)
|
||||||
}
|
}
|
||||||
is IrBlock -> {
|
is IrBlock -> {
|
||||||
val last = argument.statements.last()
|
val indySamConversion = wrapWithIndySamConversion(samType, lambdaMetafactoryArguments)
|
||||||
val functionReference = last as? IrFunctionReference
|
argument.statements[argument.statements.size - 1] = indySamConversion
|
||||||
?: throw AssertionError("Function reference expected: ${last.render()}")
|
argument.type = indySamConversion.type
|
||||||
argument.statements[argument.statements.size - 1] = wrapWithIndySamConversion(samType, functionReference)
|
|
||||||
return argument
|
return argument
|
||||||
}
|
}
|
||||||
else -> throw AssertionError("Block or function reference expected: ${expression.render()}")
|
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 =
|
private val specialNullabilityAnnotationsFqNames =
|
||||||
setOf(
|
setOf(
|
||||||
@@ -235,59 +567,37 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
context.ir.symbols.enhancedNullabilityAnnotationFqName
|
context.ir.symbols.enhancedNullabilityAnnotationFqName
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun wrapWithIndySamConversion(samType: IrType, irFunRef: IrFunctionReference): IrCall {
|
private fun wrapWithIndySamConversion(
|
||||||
patchSignatureForIndySamConversion(irFunRef.symbol.owner, samType)
|
samType: IrType,
|
||||||
|
lambdaMetafactoryArguments: LambdaMetafactoryArguments
|
||||||
|
): IrCall {
|
||||||
val notNullSamType = samType.makeNotNull()
|
val notNullSamType = samType.makeNotNull()
|
||||||
.removeAnnotations { it.type.classFqName in specialNullabilityAnnotationsFqNames }
|
.removeAnnotations { it.type.classFqName in specialNullabilityAnnotationsFqNames }
|
||||||
return context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
|
return context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
|
||||||
// We should produce the following expression:
|
// See [org.jetbrains.kotlin.backend.jvm.JvmSymbols::indyLambdaMetafactoryIntrinsic].
|
||||||
// `<jvm-indy-sam-conversion>`<samType>(method)
|
irCall(jvmIndyLambdaMetafactoryIntrinsic, notNullSamType).apply {
|
||||||
// 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 {
|
|
||||||
putTypeArgument(0, notNullSamType)
|
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) {
|
private fun IrBuilderWithScope.irRawFunctionRef(irFun: IrFunction) =
|
||||||
if (irLambda.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA)
|
irRawFunctionReferefence(context.irBuiltIns.anyType, irFun.symbol)
|
||||||
throw AssertionError("Can't patch a signature of a non-lambda: ${irLambda.render()}")
|
|
||||||
|
|
||||||
val samMethod = samType.getSingleAbstractMethod()
|
private fun IrBuilderWithScope.irVarargOfRawFunctionRefs(irFuns: List<IrFunction>) =
|
||||||
?: throw AssertionError("SAM method not found:\n${samType.render()}")
|
irVararg(context.irBuiltIns.anyType, irFuns.map { irRawFunctionRef(it) })
|
||||||
|
|
||||||
val samMethodParameters = collectValueParameters(samMethod)
|
private fun collectValueParameters(irFun: IrFunction): List<IrValueParameter> {
|
||||||
val irLambdaParameters = collectValueParameters(irLambda)
|
if (irFun.extensionReceiverParameter == null)
|
||||||
if (samMethodParameters.size != irLambdaParameters.size) {
|
return irFun.valueParameters
|
||||||
throw AssertionError(
|
return ArrayList<IrValueParameter>().apply {
|
||||||
"SAM method and implementing lambda have mismatching value parameters " +
|
add(irFun.extensionReceiverParameter!!)
|
||||||
"(${samMethodParameters.size} != ${irLambdaParameters.size}:\n" +
|
addAll(irFun.valueParameters)
|
||||||
"samMethod: ${samMethod.render()}\n" +
|
|
||||||
"lambda: ${irLambda.render()}"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((irLambdaParameter, samMethodParameter) in irLambdaParameters.zip(samMethodParameters)) {
|
|
||||||
irLambdaParameter.type = patchTypeForIndySamConversion(irLambdaParameter.type, samMethodParameter.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
irLambda.returnType = patchTypeForIndySamConversion(irLambda.returnType, samMethod.returnType)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectValueParameters(irFunction: IrFunction): List<IrValueParameter> =
|
|
||||||
ArrayList<IrValueParameter>().apply {
|
|
||||||
addIfNotNull(irFunction.extensionReceiverParameter)
|
|
||||||
addAll(irFunction.valueParameters)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun patchTypeForIndySamConversion(originalType: IrType, targetType: IrType): IrType {
|
|
||||||
if (originalType.isUnboxedInlineClassType() && !targetType.isUnboxedInlineClassType())
|
|
||||||
return targetType
|
|
||||||
return originalType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrType.isUnboxedInlineClassType() =
|
private fun IrType.isUnboxedInlineClassType() =
|
||||||
|
|||||||
+95
-33
@@ -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.codegen.fileParent
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
@@ -37,6 +36,8 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import org.jetbrains.org.objectweb.asm.Handle
|
import org.jetbrains.org.objectweb.asm.Handle
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
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:
|
// 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)
|
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
|
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))
|
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
private fun IrBuilderWithScope.jvmSubstitutedMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) =
|
private fun IrBuilderWithScope.jvmSubstitutedMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) =
|
||||||
irCall(substitutedMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
|
irCall(substitutedMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
|
||||||
putTypeArgument(0, ownerType)
|
putTypeArgument(0, ownerType)
|
||||||
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lambdaMetafactoryHandle =
|
/**
|
||||||
|
* @see java.lang.invoke.LambdaMetafactory.metafactory
|
||||||
|
*/
|
||||||
|
private val jdkMetafactoryHandle =
|
||||||
Handle(
|
Handle(
|
||||||
Opcodes.H_INVOKESTATIC,
|
Opcodes.H_INVOKESTATIC,
|
||||||
"java/lang/invoke/LambdaMetafactory",
|
"java/lang/invoke/LambdaMetafactory",
|
||||||
@@ -150,9 +155,26 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
false
|
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 {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
return when (expression.symbol) {
|
return when (expression.symbol) {
|
||||||
indySamConversionIntrinsic -> updateIndySamConversionIntrinsicCall(expression)
|
jvmIndyLambdaMetafactoryIntrinsic -> rewriteIndyLambdaMetafactoryCall(expression)
|
||||||
else -> super.visitCall(expression)
|
else -> super.visitCall(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,46 +182,86 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
/**
|
/**
|
||||||
* @see FunctionReferenceLowering.wrapWithIndySamConversion
|
* @see FunctionReferenceLowering.wrapWithIndySamConversion
|
||||||
*/
|
*/
|
||||||
private fun updateIndySamConversionIntrinsicCall(call: IrCall): IrCall {
|
private fun rewriteIndyLambdaMetafactoryCall(call: IrCall): IrCall {
|
||||||
fun fail(message: String): Nothing =
|
fun fail(message: String): Nothing =
|
||||||
throw AssertionError("$message, call:\n${call.dump()}")
|
throw AssertionError("$message, call:\n${call.dump()}")
|
||||||
|
|
||||||
// We expect:
|
|
||||||
// `<jvm-indy-sam-conversion>`<samType>(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 startOffset = call.startOffset
|
||||||
val endOffset = call.endOffset
|
val endOffset = call.endOffset
|
||||||
|
|
||||||
val samType = call.getTypeArgument(0) as? IrSimpleType
|
val samType = call.getTypeArgument(0) as? IrSimpleType
|
||||||
?: fail("'samType' is expected to be a simple type")
|
?: fail("'samType' is expected to be a simple type")
|
||||||
val samMethod = samType.getSingleAbstractMethod()
|
|
||||||
?: fail("'${samType.render()}' is not a SAM-type")
|
|
||||||
|
|
||||||
val irFunRef = call.getValueArgument(0) as? IrFunctionReference
|
val samMethodRef = call.getValueArgument(0) as? IrRawFunctionReference
|
||||||
?: fail("'method' is expected to be 'IrFunctionReference'")
|
?: fail("'samMethodType' should be 'IrRawFunctionReference'")
|
||||||
val funSymbol = irFunRef.symbol
|
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)
|
val extraOverriddenMethods = run {
|
||||||
|
val extraOverriddenMethodVararg = call.getValueArgument(3) as? IrVararg
|
||||||
return context.createJvmIrBuilder(
|
?: fail("'extraOverriddenMethodTypes' is expected to be 'IrVararg'")
|
||||||
funSymbol, // TODO actual symbol for outer scope
|
extraOverriddenMethodVararg.elements.map {
|
||||||
startOffset, endOffset
|
val ref = it as? IrRawFunctionReference
|
||||||
).run {
|
?: fail("'extraOverriddenMethodTypes' elements are expected to be 'IrRawFunctionReference'")
|
||||||
val samMethodType = jvmOriginalMethodType(samMethod.symbol)
|
ref.symbol.owner as? IrSimpleFunction
|
||||||
val irRawFunRef = irRawFunctionReferefence(irFunRef.type, funSymbol)
|
?: fail("Extra overridden method is expected to be 'IrSimpleFunction': ${ref.symbol.owner.render()}")
|
||||||
val instanceMethodType = jvmSubstitutedMethodType(samType, samMethod.symbol)
|
}
|
||||||
|
|
||||||
jvmInvokeDynamic(
|
|
||||||
dynamicCall,
|
|
||||||
lambdaMetafactoryHandle,
|
|
||||||
listOf(samMethodType, irRawFunRef, instanceMethodType)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<IrSimpleFunction>
|
||||||
|
): Collection<IrSimpleFunction> {
|
||||||
|
val jvmInstanceMethod = context.methodSignatureMapper.mapAsmMethod(instanceMethod)
|
||||||
|
val jvmSamMethod = context.methodSignatureMapper.mapAsmMethod(samMethod)
|
||||||
|
|
||||||
|
val signatureToNonFakeOverride = LinkedHashMap<Method, IrSimpleFunction>()
|
||||||
|
for (overridden in extraOverriddenMethods) {
|
||||||
|
val jvmOverriddenMethod = context.methodSignatureMapper.mapAsmMethod(overridden)
|
||||||
|
if (jvmOverriddenMethod != jvmInstanceMethod && jvmOverriddenMethod != jvmSamMethod) {
|
||||||
|
signatureToNonFakeOverride[jvmOverriddenMethod] = overridden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return signatureToNonFakeOverride.values
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapClosureInDynamicCall(
|
private fun wrapClosureInDynamicCall(
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ fun IrType.isArray(): Boolean = isNotNullClassType(IdSignatureValues.array)
|
|||||||
fun IrType.isNullableArray(): Boolean = isNullableClassType(IdSignatureValues.array)
|
fun IrType.isNullableArray(): Boolean = isNullableClassType(IdSignatureValues.array)
|
||||||
fun IrType.isCollection(): Boolean = isNotNullClassType(IdSignatureValues.collection)
|
fun IrType.isCollection(): Boolean = isNotNullClassType(IdSignatureValues.collection)
|
||||||
fun IrType.isNothing(): Boolean = isNotNullClassType(IdSignatureValues.nothing)
|
fun IrType.isNothing(): Boolean = isNotNullClassType(IdSignatureValues.nothing)
|
||||||
|
fun IrType.isNullableNothing(): Boolean = isNullableClassType(IdSignatureValues.nothing)
|
||||||
|
|
||||||
fun IrType.isPrimitiveType(hasQuestionMark: Boolean = false): Boolean =
|
fun IrType.isPrimitiveType(hasQuestionMark: Boolean = false): Boolean =
|
||||||
(this is IrSimpleType && hasQuestionMark == this.hasQuestionMark) &&
|
(this is IrSimpleType && hasQuestionMark == this.hasQuestionMark) &&
|
||||||
|
|||||||
@@ -600,6 +600,15 @@ open class DeepCopyIrTreeWithSymbols(
|
|||||||
}.copyAttributes(expression)
|
}.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 =
|
override fun visitPropertyReference(expression: IrPropertyReference): IrPropertyReference =
|
||||||
IrPropertyReferenceImpl(
|
IrPropertyReferenceImpl(
|
||||||
expression.startOffset, expression.endOffset,
|
expression.startOffset, expression.endOffset,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ test checks reflection for synthetic classes
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// FILE: Test.java
|
// FILE: Test.java
|
||||||
|
|
||||||
@@ -9,9 +10,10 @@ class Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FILE: test.kt
|
// FILE: samLambda.kt
|
||||||
|
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ fun lambdaIsSerializable(fn: () -> Unit) = fn is java.io.Serializable
|
|||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
if (lambdaIsSerializable {})
|
if (lambdaIsSerializable {})
|
||||||
return "Failed: indy lambdas are not serializable"
|
return "Failed: indy lambdas should not be serializable"
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
+14
@@ -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
|
||||||
|
}
|
||||||
+13
@@ -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")
|
||||||
compiler/testData/codegen/box/invokedynamic/sam/specializedGenerics/covariantOverrideWithNNothing.kt
Vendored
+20
@@ -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
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
// IGNORE_DEXING
|
||||||
|
|
||||||
|
fun interface GenericToAny<T> {
|
||||||
|
fun invoke(x: T): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface GenericCharToAny : GenericToAny<Char>
|
||||||
|
|
||||||
|
fun withK(fn: GenericCharToAny) = fn.invoke('K').toString()
|
||||||
|
|
||||||
|
fun box(): String =
|
||||||
|
withK { "O" + it }
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface GenericToAny<T> {
|
||||||
|
fun invoke(x: T): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface CharToAny {
|
||||||
|
fun invoke(x: Char): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface GenericCharToAny : GenericToAny<Char>, CharToAny
|
||||||
|
|
||||||
|
fun withK(fn: GenericCharToAny) = fn.invoke('K').toString()
|
||||||
|
|
||||||
|
fun box(): String =
|
||||||
|
withK { "O" + it }
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface GenericToAny<T> {
|
||||||
|
fun invoke(x: T): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface GenericCharToAny : GenericToAny<Char> {
|
||||||
|
override fun invoke(x: Char): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun withK(fn: GenericCharToAny) = fn.invoke('K').toString()
|
||||||
|
|
||||||
|
fun box(): String =
|
||||||
|
withK { "O" + it }
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface GenericToAny<T> {
|
||||||
|
fun invoke(x: T): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface GenericIntToAny : GenericToAny<Int>
|
||||||
|
|
||||||
|
fun with4(fn: GenericIntToAny) = fn.invoke(4).toString()
|
||||||
|
|
||||||
|
fun box(): String =
|
||||||
|
with4 {
|
||||||
|
if (it != 4) throw Exception()
|
||||||
|
"OK"
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface GenericToAny<T> {
|
||||||
|
fun invoke(x: T): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface GenericStringToAny : GenericToAny<String>
|
||||||
|
|
||||||
|
fun withK(fn: GenericStringToAny) = fn.invoke("K").toString()
|
||||||
|
|
||||||
|
fun box(): String =
|
||||||
|
withK { "O" + it }
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface IFoo<T> {
|
||||||
|
fun foo(): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooUnit : IFoo<Unit> {
|
||||||
|
override fun foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> fooT(iFoo: IFoo<T>) = iFoo.foo()
|
||||||
|
fun fooUnit(iFooUnit: IFooUnit) { iFooUnit.foo() }
|
||||||
|
|
||||||
|
var ok = "Failed"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
fooT { ok = "O" }
|
||||||
|
fooUnit { ok += "K" }
|
||||||
|
return ok
|
||||||
|
}
|
||||||
Vendored
+40
@@ -0,0 +1,40 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun interface IFooT<T> {
|
||||||
|
fun foo(x: T): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooIntArray {
|
||||||
|
fun foo(x: IntArray): IntArray
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooMix0 : IFooT<IntArray>, IFooIntArray
|
||||||
|
|
||||||
|
fun interface IFooMix1 : IFooT<IntArray>, 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"
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface IFooT<T> {
|
||||||
|
fun foo(x: T): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooStr {
|
||||||
|
fun foo(x: String): String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooMix0 : IFooT<String>, IFooStr
|
||||||
|
|
||||||
|
fun interface IFooMix1 : IFooT<String>, 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"
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun interface IFooT<T> {
|
||||||
|
fun foo(x: Array<T>): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooStr {
|
||||||
|
fun foo(x: Array<String>): String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooMix0 : IFooT<String>, IFooStr
|
||||||
|
|
||||||
|
fun interface IFooMix1 : IFooT<String>, IFooStr {
|
||||||
|
override fun foo(x: Array<String>): 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"
|
||||||
|
}
|
||||||
Vendored
+32
@@ -0,0 +1,32 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// IGNORE_BACKEND: JVM
|
||||||
|
// IGNORE_LIGHT_ANALYSIS
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface IFooT<T> {
|
||||||
|
fun foo(x: T): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooInt {
|
||||||
|
fun foo(x: Int): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface IFooMixed0 : IFooInt, IFooT<Int>
|
||||||
|
|
||||||
|
fun interface IFooMixed1 : IFooInt, IFooT<Int> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// JVM_TARGET: 1.8
|
// JVM_TARGET: 1.8
|
||||||
// LAMBDAS: INDY
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
fun interface IFoo<T> {
|
fun interface IFoo<T> {
|
||||||
fun foo(): T
|
fun foo(): T
|
||||||
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ SAM-convertion classes created with LambdaMetafactory have 'enclosingMethod' and 'enclosingClass'
|
||||||
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
package test
|
package test
|
||||||
@@ -17,7 +19,7 @@ fun box(): String {
|
|||||||
val javaClass = lambda.javaClass
|
val javaClass = lambda.javaClass
|
||||||
|
|
||||||
val enclosingMethod = javaClass.getEnclosingMethod()
|
val enclosingMethod = javaClass.getEnclosingMethod()
|
||||||
if (enclosingMethod?.getName() != "run") return "method: $enclosingMethod"
|
if (enclosingMethod?.getName() != "run") return "enclosing method: $enclosingMethod"
|
||||||
|
|
||||||
val enclosingClass = javaClass.getEnclosingClass()!!.getName()
|
val enclosingClass = javaClass.getEnclosingClass()!!.getName()
|
||||||
if (enclosingClass != "test.A\$prop\$1") return "enclosing class: $enclosingClass"
|
if (enclosingClass != "test.A\$prop\$1") return "enclosing class: $enclosingClass"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ test checks reflection for synthetic classes
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: JavaClass.java
|
// FILE: JavaClass.java
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ test checks reflection for synthetic classes
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: Custom.java
|
// FILE: Custom.java
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ test checks reflection for synthetic classes
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: Custom.java
|
// FILE: Custom.java
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ test checks reflection for synthetic classes
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: Promise.java
|
// FILE: Promise.java
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|||||||
+2
@@ -2,6 +2,8 @@
|
|||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ SAM-convertion classes created with LambdaMetafactory have no generic signatures
|
||||||
|
|
||||||
// FILE: Provider.java
|
// FILE: Provider.java
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
|
// ^ test checks reflection for synthetic classes
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: JavaClass.java
|
// FILE: JavaClass.java
|
||||||
|
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
// FILE: samAdapterForJavaInterfaceWithNullability.kt
|
// FILE: samAdapterForJavaInterfaceWithNullability.kt
|
||||||
fun testNullable(s: String) = JNullable { s }
|
fun testNullable(s: String) = JNullable { s }
|
||||||
fun testNotNull(s: String) = JNotNull { s }
|
fun testNotNull(s: String) = JNotNull { s }
|
||||||
|
|||||||
+3
-33
@@ -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 <init>(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 <init>(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 <init>(p0: java.lang.String): void
|
|
||||||
public final @org.jetbrains.annotations.Nullable method getNullableString(): java.lang.String
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public final class SamAdapterForJavaInterfaceWithNullabilityKt {
|
public final class SamAdapterForJavaInterfaceWithNullabilityKt {
|
||||||
// source: 'samAdapterForJavaInterfaceWithNullability.kt'
|
// source: 'samAdapterForJavaInterfaceWithNullability.kt'
|
||||||
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1
|
private final static method testNoAnnotation$lambda-2(p0: java.lang.String): java.lang.String
|
||||||
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1
|
|
||||||
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1
|
|
||||||
public final static @org.jetbrains.annotations.NotNull method testNoAnnotation(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNoAnnotation
|
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
|
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
|
public final static @org.jetbrains.annotations.NotNull method testNullable(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNullable
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// SAM_CONVERSIONS: CLASS
|
||||||
// WITH_SIGNATURES
|
// WITH_SIGNATURES
|
||||||
// FILE: t.kt
|
// FILE: t.kt
|
||||||
fun main(x: DataStream<Int>) {
|
fun main(x: DataStream<Int>) {
|
||||||
|
|||||||
@@ -1,31 +1,7 @@
|
|||||||
@kotlin.Metadata
|
|
||||||
final class<<IN:Ljava/lang/Object;KEY:Ljava/lang/Object;>Ljava/lang/Object;LKeySelector<Ljava/lang/Integer;Ljava/lang/Long;>;> TKt$main$1 {
|
|
||||||
// source: 't.kt'
|
|
||||||
static <null> method <clinit>(): void
|
|
||||||
<null> method <init>(): void
|
|
||||||
public final <null> method getKey(p0: java.lang.Integer): java.lang.Long
|
|
||||||
public synthetic bridge <null> method getKey(p0: java.lang.Object): java.lang.Object
|
|
||||||
enclosing method TKt.main(LDataStream;)V
|
|
||||||
public final static field <LTKt$main$1<TIN;TKEY;>;> INSTANCE: TKt$main$1
|
|
||||||
inner (anonymous) class TKt$main$1
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
|
||||||
final class<<IN:Ljava/lang/Object;KEY:Ljava/lang/Object;>Ljava/lang/Object;LKeySelector<Ljava/lang/Integer;Ljava/lang/Long;>;> TKt$main$2 {
|
|
||||||
// source: 't.kt'
|
|
||||||
static <null> method <clinit>(): void
|
|
||||||
<null> method <init>(): void
|
|
||||||
public final <null> method getKey(p0: java.lang.Integer): java.lang.Long
|
|
||||||
public synthetic bridge <null> method getKey(p0: java.lang.Object): java.lang.Object
|
|
||||||
enclosing method TKt.main(LDataStream;)V
|
|
||||||
public final static field <LTKt$main$2<TIN;TKEY;>;> INSTANCE: TKt$main$2
|
|
||||||
inner (anonymous) class TKt$main$2
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public final class<null> TKt {
|
public final class<null> TKt {
|
||||||
// source: 't.kt'
|
// source: 't.kt'
|
||||||
public final static <(LDataStream<Ljava/lang/Integer;>;)V> method main(@org.jetbrains.annotations.NotNull p0: DataStream): void
|
public final static <(LDataStream<Ljava/lang/Integer;>;)V> method main(@org.jetbrains.annotations.NotNull p0: DataStream): void
|
||||||
inner (anonymous) class TKt$main$1
|
private final static <null> method main$lambda-0(p0: java.lang.Integer): java.lang.Long
|
||||||
inner (anonymous) class TKt$main$2
|
private final static <null> method main$lambda-1(p0: java.lang.Integer): java.lang.Long
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-11
@@ -4,20 +4,10 @@ public interface<<T:Ljava/lang/Object;>Ljava/lang/Object;> Sam {
|
|||||||
public abstract <()TT;> method get(): java.lang.Object
|
public abstract <()TT;> method get(): java.lang.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.Metadata
|
|
||||||
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<TT;>;> TKt$genericSamGet$1 {
|
|
||||||
// source: 't.kt'
|
|
||||||
public final <()TT;> method get(): java.lang.Object
|
|
||||||
<(Lkotlin/jvm/functions/Function0<+TT;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
|
|
||||||
enclosing method TKt.genericSamGet(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
|
||||||
synthetic final field <Lkotlin/jvm/functions/Function0<TT;>;> $f: kotlin.jvm.functions.Function0
|
|
||||||
inner (anonymous) class TKt$genericSamGet$1
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public final class<null> TKt {
|
public final class<null> TKt {
|
||||||
// source: 't.kt'
|
// source: 't.kt'
|
||||||
public final static <<T:Ljava/lang/Object;>(LSam<TT;>;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object
|
public final static <<T:Ljava/lang/Object;>(LSam<TT;>;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object
|
||||||
|
private final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.Object
|
||||||
public final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object
|
public final static <<T:Ljava/lang/Object;>(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
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-22
@@ -1,28 +1,8 @@
|
|||||||
@kotlin.Metadata
|
|
||||||
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<TT;>;> TKt$genericSam$1 {
|
|
||||||
// source: 't.kt'
|
|
||||||
public final <()TT;> method get(): java.lang.Object
|
|
||||||
<(Lkotlin/jvm/functions/Function0<+TT;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
|
|
||||||
enclosing method TKt.genericSam(Lkotlin/jvm/functions/Function0;)LSam;
|
|
||||||
synthetic final field <Lkotlin/jvm/functions/Function0<TT;>;> $f: kotlin.jvm.functions.Function0
|
|
||||||
inner (anonymous) class TKt$genericSam$1
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
|
||||||
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<TT;>;> TKt$genericSamGet$1 {
|
|
||||||
// source: 't.kt'
|
|
||||||
public final <()TT;> method get(): java.lang.Object
|
|
||||||
<(Lkotlin/jvm/functions/Function0<+TT;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
|
|
||||||
enclosing method TKt.genericSamGet(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
|
||||||
synthetic final field <Lkotlin/jvm/functions/Function0<TT;>;> $f: kotlin.jvm.functions.Function0
|
|
||||||
inner (anonymous) class TKt$genericSamGet$1
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public final class<null> TKt {
|
public final class<null> TKt {
|
||||||
// source: 't.kt'
|
// source: 't.kt'
|
||||||
public final static @org.jetbrains.annotations.NotNull <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)LSam<TT;>;> method genericSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): Sam
|
public final static @org.jetbrains.annotations.NotNull <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)LSam<TT;>;> method genericSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): Sam
|
||||||
|
private final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.Object
|
||||||
|
private final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet$lambda-1(p0: kotlin.jvm.functions.Function0): java.lang.Object
|
||||||
public final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object
|
public final static <<T:Ljava/lang/Object;>(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
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
// WITH_SIGNATURES
|
// WITH_SIGNATURES
|
||||||
// FILE: t.kt
|
// FILE: t.kt
|
||||||
|
|
||||||
|
|||||||
+1
-12
@@ -4,21 +4,10 @@ public interface<<T:Ljava/lang/Object;>Ljava/lang/Object;> Sam {
|
|||||||
public abstract <()TT;> method get(): java.lang.Object
|
public abstract <()TT;> method get(): java.lang.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.Metadata
|
|
||||||
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<Ljava/lang/String;>;> TKt$specializedSam$1 {
|
|
||||||
// source: 't.kt'
|
|
||||||
<(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
|
|
||||||
public synthetic bridge <null> method get(): java.lang.Object
|
|
||||||
public final @org.jetbrains.annotations.NotNull <null> method get(): java.lang.String
|
|
||||||
enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
|
|
||||||
synthetic final field <Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;> $f: kotlin.jvm.functions.Function0
|
|
||||||
inner (anonymous) class TKt$specializedSam$1
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public final class<null> TKt {
|
public final class<null> TKt {
|
||||||
// source: 't.kt'
|
// source: 't.kt'
|
||||||
|
private final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)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;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
|
public final static @org.jetbrains.annotations.NotNull <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
|
||||||
public final static <<T:Ljava/lang/Object;>(LSam<TT;>;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object
|
public final static <<T:Ljava/lang/Object;>(LSam<TT;>;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object
|
||||||
inner (anonymous) class TKt$specializedSam$1
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-12
@@ -1,17 +1,6 @@
|
|||||||
@kotlin.Metadata
|
|
||||||
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<Ljava/lang/String;>;> TKt$specializedSam$1 {
|
|
||||||
// source: 't.kt'
|
|
||||||
<(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
|
|
||||||
public synthetic bridge <null> method get(): java.lang.Object
|
|
||||||
public final <null> method get(): java.lang.String
|
|
||||||
enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
|
|
||||||
synthetic final field <Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;> $f: kotlin.jvm.functions.Function0
|
|
||||||
inner (anonymous) class TKt$specializedSam$1
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public final class<null> TKt {
|
public final class<null> TKt {
|
||||||
// source: 't.kt'
|
// source: 't.kt'
|
||||||
|
private final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)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;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
|
public final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
|
||||||
inner (anonymous) class TKt$specializedSam$1
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -16,9 +16,9 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @TestKt.class:
|
// @TestKt.class:
|
||||||
// 1 NEW TestKt\$
|
// 0 NEW TestKt\$
|
||||||
// 1 NEW kotlin/jvm/internal/Ref\$IntRef
|
// 1 NEW kotlin/jvm/internal/Ref\$IntRef
|
||||||
// 2 NEW
|
// 1 NEW
|
||||||
// 0 IFNONNULL
|
// 0 IFNONNULL
|
||||||
// 0 IFNULL
|
// 0 IFNULL
|
||||||
// 1 ACONST_NULL
|
// 1 ACONST_NULL
|
||||||
|
|||||||
+2
-2
@@ -16,16 +16,16 @@ fun test() {
|
|||||||
JFoo.foo2({}, runnable())
|
JFoo.foo2({}, runnable())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 NEW
|
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// @TestKt.class:
|
// @TestKt.class:
|
||||||
|
// 2 NEW
|
||||||
// 0 IFNONNULL
|
// 0 IFNONNULL
|
||||||
// 1 IFNULL
|
// 1 IFNULL
|
||||||
// 1 ACONST_NULL
|
// 1 ACONST_NULL
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// @TestKt.class
|
// @TestKt.class
|
||||||
|
// 1 NEW
|
||||||
// 1 IFNONNULL
|
// 1 IFNONNULL
|
||||||
// 0 IFNULL
|
// 0 IFNULL
|
||||||
// 2 ACONST_NULL
|
// 2 ACONST_NULL
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lambda inlined into run(), no wrapper class generated:
|
// Lambda inlined into run(), no wrapper class generated:
|
||||||
// 1 NEW
|
// 0 NEW
|
||||||
// 0 INVOKEINTERFACE
|
// 0 INVOKEINTERFACE
|
||||||
|
|||||||
+94
-6
@@ -19957,6 +19957,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
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
|
@Test
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
@@ -19993,12 +19999,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@@ -20080,6 +20080,94 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-6
@@ -19957,6 +19957,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
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
|
@Test
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
@@ -19993,12 +19999,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@@ -20080,6 +20080,94 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+83
-5
@@ -16733,6 +16733,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
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")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt");
|
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");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
@@ -16835,6 +16835,84 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature/genericFunInterfaceWithInlineString.kt");
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+13
@@ -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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+13
@@ -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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+13
@@ -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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+13
@@ -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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user