JVM_IR indy-SAM on functional expression
This commit is contained in:
+52
@@ -20035,6 +20035,58 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FunctionExpressionArgument {
|
||||
@Test
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedSamArgument.kt")
|
||||
public void testCapturedSamArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturedSamArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingLambda.kt")
|
||||
public void testCapturingLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturingLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda1.kt")
|
||||
public void testExtensionLambda1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda2.kt")
|
||||
public void testExtensionLambda2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam1.kt")
|
||||
public void testGenericSam1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam2.kt")
|
||||
public void testGenericSam2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+34
-4
@@ -13,6 +13,10 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.LambdaMetafactoryArguments
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.LambdaMetafactoryArgumentsBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.SamDelegatingLambdaBlock
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.SamDelegatingLambdaBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
||||
import org.jetbrains.kotlin.config.JvmClosureGenerationScheme
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -142,6 +146,14 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
||||
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||
invokable.statements.last() as IrFunctionReference
|
||||
} else if (shouldGenerateIndySamConversions && canGenerateIndySamConversionOnFunctionalExpression(samSuperType, invokable)) {
|
||||
val lambdaBlock = SamDelegatingLambdaBuilder(context)
|
||||
.build(invokable, samSuperType, currentScope!!.scope.scopeOwnerSymbol)
|
||||
val lambdaMetafactoryArguments = LambdaMetafactoryArgumentsBuilder(context, crossinlineLambdas)
|
||||
.getLambdaMetafactoryArgumentsOrNull(lambdaBlock.ref, samSuperType, false)
|
||||
?: return super.visitTypeOperator(expression)
|
||||
invokable.transformChildrenVoid()
|
||||
return wrapSamDelegatingLambdaWithIndySamConversion(samSuperType, lambdaBlock, lambdaMetafactoryArguments)
|
||||
} else {
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
@@ -159,18 +171,36 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
return FunctionReferenceBuilder(reference, samSuperType).build()
|
||||
}
|
||||
|
||||
private fun canGenerateIndySamConversionOnFunctionalExpression(samSuperType: IrType, expression: IrExpression): Boolean {
|
||||
val samClass = samSuperType.classOrNull
|
||||
?: throw AssertionError("Class type expected: ${samSuperType.render()}")
|
||||
if (!samClass.owner.isFromJava())
|
||||
return false
|
||||
if (expression is IrBlock && expression.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
private fun wrapSamDelegatingLambdaWithIndySamConversion(
|
||||
samSuperType: IrType,
|
||||
lambdaBlock: SamDelegatingLambdaBlock,
|
||||
lambdaMetafactoryArguments: LambdaMetafactoryArguments
|
||||
): IrExpression {
|
||||
val indySamConversion = wrapWithIndySamConversion(samSuperType, lambdaMetafactoryArguments)
|
||||
lambdaBlock.replaceRefWith(indySamConversion)
|
||||
return lambdaBlock.block
|
||||
}
|
||||
|
||||
private fun wrapSamConversionArgumentWithIndySamConversion(
|
||||
expression: IrTypeOperatorCall,
|
||||
lambdaMetafactoryArguments: LambdaMetafactoryArguments
|
||||
): IrExpression {
|
||||
val samType = expression.typeOperand
|
||||
return when (val argument = expression.argument) {
|
||||
is IrFunctionReference -> {
|
||||
is IrFunctionReference ->
|
||||
wrapWithIndySamConversion(samType, lambdaMetafactoryArguments)
|
||||
}
|
||||
is IrBlock -> {
|
||||
is IrBlock ->
|
||||
wrapFunctionReferenceInsideBlockWithIndySamConversion(samType, lambdaMetafactoryArguments, argument)
|
||||
}
|
||||
else -> throw AssertionError("Block or function reference expected: ${expression.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
package org.jetbrains.kotlin.backend.jvm.lower.indy
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.allOverridden
|
||||
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
@@ -30,14 +31,14 @@ import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class LambdaMetafactoryArguments(
|
||||
internal class LambdaMetafactoryArguments(
|
||||
val samMethod: IrSimpleFunction,
|
||||
val fakeInstanceMethod: IrSimpleFunction,
|
||||
val implMethodReference: IrFunctionReference,
|
||||
val extraOverriddenMethods: List<IrSimpleFunction>
|
||||
)
|
||||
|
||||
class LambdaMetafactoryArgumentsBuilder(
|
||||
internal class LambdaMetafactoryArgumentsBuilder(
|
||||
private val context: JvmBackendContext,
|
||||
private val crossinlineLambdas: Set<IrSimpleFunction>
|
||||
) {
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower.indy
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.JvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal sealed class SamDelegatingLambdaBlock {
|
||||
abstract val block: IrContainerExpression
|
||||
abstract val ref: IrFunctionReference
|
||||
abstract fun replaceRefWith(expression: IrExpression)
|
||||
}
|
||||
|
||||
|
||||
internal class RegularDelegatingLambdaBlock(
|
||||
override val block: IrContainerExpression,
|
||||
override val ref: IrFunctionReference
|
||||
) : SamDelegatingLambdaBlock() {
|
||||
|
||||
override fun replaceRefWith(expression: IrExpression) {
|
||||
block.statements[block.statements.size - 1] = expression
|
||||
block.type = expression.type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class NullableDelegatingLambdaBlock(
|
||||
override val block: IrContainerExpression,
|
||||
override val ref: IrFunctionReference,
|
||||
private val ifExpr: IrExpression,
|
||||
private val ifNotNullBlock: IrContainerExpression
|
||||
) : SamDelegatingLambdaBlock() {
|
||||
|
||||
override fun replaceRefWith(expression: IrExpression) {
|
||||
ifNotNullBlock.statements[ifNotNullBlock.statements.size - 1] = expression
|
||||
ifNotNullBlock.type = expression.type
|
||||
ifExpr.type = expression.type
|
||||
block.type = expression.type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class SamDelegatingLambdaBuilder(private val jvmContext: JvmBackendContext) {
|
||||
fun build(expression: IrExpression, superType: IrType, scopeSymbol: IrSymbol): SamDelegatingLambdaBlock {
|
||||
return if (superType.isNullable() && expression.type.isNullable())
|
||||
buildNullableDelegatingLambda(expression, superType, scopeSymbol)
|
||||
else
|
||||
buildRegularDelegatingLambda(expression, superType, scopeSymbol)
|
||||
}
|
||||
|
||||
private fun buildRegularDelegatingLambda(
|
||||
expression: IrExpression,
|
||||
superType: IrType,
|
||||
scopeSymbol: IrSymbol
|
||||
): SamDelegatingLambdaBlock {
|
||||
lateinit var ref: IrFunctionReference
|
||||
val block = jvmContext.createJvmIrBuilder(scopeSymbol, expression.startOffset, expression.endOffset).run {
|
||||
// {
|
||||
// val tmp = <expression>
|
||||
// fun `<anonymous>`(p1: T1, ..., pN: TN): R =
|
||||
// tmp.invoke(p1, ..., pN)
|
||||
// ::`<anonymous>`
|
||||
// }
|
||||
|
||||
irBlock(origin = IrStatementOrigin.LAMBDA) {
|
||||
val tmp = irTemporary(expression)
|
||||
val lambda = createDelegatingLambda(scopeSymbol, expression, superType, tmp)
|
||||
.also { +it }
|
||||
ref = createDelegatingLambdaReference(expression, lambda)
|
||||
.also { +it }
|
||||
}
|
||||
}
|
||||
block.type = expression.type
|
||||
return RegularDelegatingLambdaBlock(block, ref)
|
||||
}
|
||||
|
||||
private fun buildNullableDelegatingLambda(
|
||||
expression: IrExpression,
|
||||
superType: IrType,
|
||||
scopeSymbol: IrSymbol
|
||||
): SamDelegatingLambdaBlock {
|
||||
lateinit var ref: IrFunctionReference
|
||||
lateinit var ifExpr: IrExpression
|
||||
lateinit var ifNotNullBlock: IrContainerExpression
|
||||
val block = jvmContext.createJvmIrBuilder(scopeSymbol, expression.startOffset, expression.endOffset).run {
|
||||
// {
|
||||
// val tmp = <expression>
|
||||
// if (tmp == null)
|
||||
// null
|
||||
// else {
|
||||
// fun `<anonymous>`(p1: T1, ..., pN: TN): R =
|
||||
// tmp.invoke(p1, ..., pN)
|
||||
// ::`<anonymous>`
|
||||
// }
|
||||
// }
|
||||
|
||||
irBlock(origin = IrStatementOrigin.LAMBDA) {
|
||||
val tmp = irTemporary(expression)
|
||||
ifNotNullBlock = irBlock {
|
||||
val lambda = createDelegatingLambda(scopeSymbol, expression, superType, tmp)
|
||||
.also { +it }
|
||||
ref = createDelegatingLambdaReference(expression, lambda)
|
||||
.also { +it }
|
||||
}
|
||||
ifExpr = irIfNull(expression.type, irGet(tmp), irNull(), ifNotNullBlock)
|
||||
.also { +it }
|
||||
}
|
||||
}
|
||||
block.type = expression.type
|
||||
return NullableDelegatingLambdaBlock(block, ref, ifExpr, ifNotNullBlock)
|
||||
}
|
||||
|
||||
private fun createDelegatingLambda(
|
||||
scopeSymbol: IrSymbol,
|
||||
expression: IrExpression,
|
||||
superType: IrType,
|
||||
tmp: IrVariable
|
||||
): IrSimpleFunction {
|
||||
val superMethod = superType.getSingleAbstractMethod()
|
||||
?: throw AssertionError("SAM type expected: ${superType.render()}")
|
||||
val effectiveValueParametersCount = superMethod.valueParameters.size +
|
||||
if (superMethod.extensionReceiverParameter == null) 0 else 1
|
||||
val invocableFunctionClass =
|
||||
if (superMethod.isSuspend)
|
||||
jvmContext.ir.symbols.suspendFunctionN(effectiveValueParametersCount).owner
|
||||
else
|
||||
jvmContext.ir.symbols.functionN(effectiveValueParametersCount).owner
|
||||
val invokeFunction = invocableFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }
|
||||
val typeSubstitutor = createTypeSubstitutor(superType)
|
||||
|
||||
return jvmContext.irFactory.buildFun {
|
||||
name = Name.special("<anonymous>")
|
||||
returnType = typeSubstitutor.substitute(superMethod.returnType)
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
modality = Modality.FINAL
|
||||
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
isSuspend = superMethod.isSuspend
|
||||
}.also { lambda ->
|
||||
lambda.dispatchReceiverParameter = null
|
||||
lambda.extensionReceiverParameter = null
|
||||
lambda.valueParameters = createLambdaValueParameters(superMethod, lambda, typeSubstitutor)
|
||||
lambda.body = jvmContext.createJvmIrBuilder(lambda.symbol, expression.startOffset, expression.endOffset)
|
||||
.irBlockBody {
|
||||
+irReturn(
|
||||
irCall(invokeFunction).also { invokeCall ->
|
||||
invokeCall.dispatchReceiver = irGet(tmp)
|
||||
var parameterIndex = 0
|
||||
invokeFunction.extensionReceiverParameter?.let {
|
||||
invokeCall.extensionReceiver = irGet(lambda.valueParameters[parameterIndex++])
|
||||
}
|
||||
for (argumentIndex in invokeFunction.valueParameters.indices) {
|
||||
invokeCall.putValueArgument(argumentIndex, irGet(lambda.valueParameters[parameterIndex++]))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
lambda.parent = scopeSymbol.owner as IrDeclarationParent
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLambdaValueParameters(
|
||||
superMethod: IrSimpleFunction,
|
||||
lambda: IrSimpleFunction,
|
||||
typeSubstitutor: IrTypeSubstitutor
|
||||
): List<IrValueParameter> {
|
||||
val lambdaParameters = ArrayList<IrValueParameter>()
|
||||
var index = 0
|
||||
superMethod.extensionReceiverParameter?.let { superExtensionReceiver ->
|
||||
lambdaParameters.add(superExtensionReceiver.copySubstituted(lambda, typeSubstitutor, index++, Name.identifier("\$receiver")))
|
||||
}
|
||||
superMethod.valueParameters.mapTo(lambdaParameters) { superValueParameter ->
|
||||
superValueParameter.copySubstituted(lambda, typeSubstitutor, index++)
|
||||
}
|
||||
return lambdaParameters
|
||||
}
|
||||
|
||||
private fun IrValueParameter.copySubstituted(
|
||||
function: IrSimpleFunction,
|
||||
substitutor: IrTypeSubstitutor,
|
||||
newIndex: Int,
|
||||
newName: Name = name
|
||||
) =
|
||||
buildValueParameter(function) {
|
||||
name = newName
|
||||
index = newIndex
|
||||
type = substitutor.substitute(this@copySubstituted.type)
|
||||
}
|
||||
|
||||
private fun JvmIrBuilder.createDelegatingLambdaReference(expression: IrExpression, lambda: IrSimpleFunction): IrFunctionReference {
|
||||
return IrFunctionReferenceImpl(
|
||||
startOffset, endOffset,
|
||||
expression.type,
|
||||
lambda.symbol,
|
||||
typeArgumentsCount = 0,
|
||||
valueArgumentsCount = lambda.valueParameters.size,
|
||||
reflectionTarget = null,
|
||||
origin = IrStatementOrigin.LAMBDA
|
||||
)
|
||||
}
|
||||
|
||||
private fun createTypeSubstitutor(irType: IrType): IrTypeSubstitutor {
|
||||
if (irType !is IrSimpleType)
|
||||
throw AssertionError("Simple type expected: ${irType.render()}")
|
||||
val irClassSymbol = irType.classOrNull
|
||||
?: throw AssertionError("Class type expected: ${irType.render()}")
|
||||
return IrTypeSubstitutor(
|
||||
irClassSymbol.owner.typeParameters.map { it.symbol },
|
||||
irType.arguments,
|
||||
jvmContext.irBuiltIns
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
|
||||
// WITH_RUNTIME
|
||||
// FILE: Test.java
|
||||
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: capturedSamArgument.kt
|
||||
fun box(): String {
|
||||
var lambda = { "OK" }
|
||||
val sam = Sam(lambda)
|
||||
lambda = { "Failed" }
|
||||
return sam.get()
|
||||
}
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam {
|
||||
String get();
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: capturingLambda.kt
|
||||
fun box(): String {
|
||||
val co = 'O'
|
||||
val lambda = { co.toString() + "K" }
|
||||
return Sam(lambda).get()
|
||||
}
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam {
|
||||
String get();
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: extensionLambda1.kt
|
||||
fun samExtLambda(ext: String.() -> String) = Sam(ext)
|
||||
|
||||
fun box(): String {
|
||||
val oChar = 'O'
|
||||
return samExtLambda { oChar.toString() + this }.get("K")
|
||||
}
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam {
|
||||
String get(String s);
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: extensionLambda2.kt
|
||||
fun samExtLambda(ext: String.(String) -> String) = Sam(ext)
|
||||
|
||||
fun box(): String {
|
||||
val oChar = 'O'
|
||||
return samExtLambda { oChar.toString() + this + it }.get("", "K")
|
||||
}
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam {
|
||||
String get(String s1, String s2);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: genericSam1.kt
|
||||
|
||||
fun box(): String = Sam<String, String> { "O" + it }.get("K")
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam<T, R> {
|
||||
R get(T x);
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: genericSam2.kt
|
||||
|
||||
fun <FT, FR> test(lambda: (FT) -> FR) = Sam(lambda)
|
||||
|
||||
fun box(): String = test<String, String> { "O" + it }.get("K")
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam<T, R> {
|
||||
R get(T x);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: simple.kt
|
||||
val lambda = { "OK" }
|
||||
|
||||
fun box() = Sam(lambda).get()
|
||||
|
||||
// FILE: Sam.java
|
||||
public interface Sam {
|
||||
String get();
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
|
||||
fun box(): String {
|
||||
val f = { }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: MyRunnable.java
|
||||
public interface MyRunnable {
|
||||
public void run();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: Foo.kt
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: Foo.kt
|
||||
@file:JvmName("testXX")
|
||||
package test
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: Foo.kt
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("testX")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: Foo.kt
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("testX")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: kt22906_1.kt
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: kt22906_1.kt
|
||||
package test
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// SAM_CONVERSIONS: CLASS
|
||||
// FILE: test.kt
|
||||
// Test that SAM wrappers with type parameters are cached properly.
|
||||
class A {
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ fun test() {
|
||||
|
||||
// JVM_IR_TEMPLATES
|
||||
// @TestKt.class
|
||||
// 1 NEW
|
||||
// 0 NEW
|
||||
// 1 IFNONNULL
|
||||
// 0 IFNULL
|
||||
// 2 ACONST_NULL
|
||||
|
||||
+52
@@ -20035,6 +20035,58 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FunctionExpressionArgument {
|
||||
@Test
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedSamArgument.kt")
|
||||
public void testCapturedSamArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturedSamArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingLambda.kt")
|
||||
public void testCapturingLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturingLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda1.kt")
|
||||
public void testExtensionLambda1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda2.kt")
|
||||
public void testExtensionLambda2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam1.kt")
|
||||
public void testGenericSam1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam2.kt")
|
||||
public void testGenericSam2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+52
@@ -20035,6 +20035,58 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FunctionExpressionArgument {
|
||||
@Test
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedSamArgument.kt")
|
||||
public void testCapturedSamArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturedSamArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingLambda.kt")
|
||||
public void testCapturingLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturingLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda1.kt")
|
||||
public void testExtensionLambda1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda2.kt")
|
||||
public void testExtensionLambda2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam1.kt")
|
||||
public void testGenericSam1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam2.kt")
|
||||
public void testGenericSam2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+48
@@ -16793,6 +16793,54 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FunctionExpressionArgument extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedSamArgument.kt")
|
||||
public void testCapturedSamArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturedSamArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturingLambda.kt")
|
||||
public void testCapturingLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/capturingLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionLambda1.kt")
|
||||
public void testExtensionLambda1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionLambda2.kt")
|
||||
public void testExtensionLambda2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/extensionLambda2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericSam1.kt")
|
||||
public void testGenericSam1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericSam2.kt")
|
||||
public void testGenericSam2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/genericSam2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+13
@@ -14578,6 +14578,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FunctionExpressionArgument extends AbstractIrJsCodegenBoxES6Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+13
@@ -14063,6 +14063,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FunctionExpressionArgument extends AbstractIrJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+13
@@ -14128,6 +14128,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FunctionExpressionArgument extends AbstractJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+13
@@ -8164,6 +8164,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FunctionExpressionArgument extends AbstractIrCodegenBoxWasmTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFunctionExpressionArgument() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExpressionArgument"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user