JVM_IR indy-SAM conversions: more cases
KT-44278 KT-26060 KT-42621
This commit is contained in:
+36
@@ -18403,6 +18403,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("builtinMemberReference.kt")
|
||||||
|
public void testBuiltinMemberReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("capturedDispatchReceiver.kt")
|
@TestMetadata("capturedDispatchReceiver.kt")
|
||||||
public void testCapturedDispatchReceiver() throws Exception {
|
public void testCapturedDispatchReceiver() throws Exception {
|
||||||
@@ -18427,12 +18433,42 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingVar.kt")
|
||||||
|
public void testCapturingVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("constructorReference.kt")
|
||||||
|
public void testConstructorReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("genericFunInterface.kt")
|
||||||
|
public void testGenericFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("genericFunInterfaceWithPrimitive.kt")
|
||||||
|
public void testGenericFunInterfaceWithPrimitive() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("samConversionOnFunctionReference.kt")
|
||||||
|
public void testSamConversionOnFunctionReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
|
|||||||
@@ -604,11 +604,25 @@ class JvmSymbols(
|
|||||||
}.symbol
|
}.symbol
|
||||||
|
|
||||||
// Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above).
|
// Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above).
|
||||||
// Type argument is a possibly substituted method owner type (e.g., 'java.lang.function.Supplier<String>').
|
|
||||||
// Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get').
|
// Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get').
|
||||||
val jvmMethodTypeIntrinsic: IrSimpleFunctionSymbol =
|
// Resulting method type is unsubstituted.
|
||||||
|
val jvmOriginalMethodTypeIntrinsic: IrSimpleFunctionSymbol =
|
||||||
irFactory.buildFun {
|
irFactory.buildFun {
|
||||||
name = Name.special("<jvm-method-type>")
|
name = Name.special("<jvm-original-method-type>")
|
||||||
|
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||||
|
}.apply {
|
||||||
|
parent = kotlinJvmInternalPackage
|
||||||
|
addValueParameter("method", irBuiltIns.anyType)
|
||||||
|
returnType = irBuiltIns.anyType
|
||||||
|
}.symbol
|
||||||
|
|
||||||
|
// Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above).
|
||||||
|
// Type argument is a substituted method owner type (e.g., 'java.lang.function.Supplier<String>').
|
||||||
|
// Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get').
|
||||||
|
// Resulting method type is substituted.
|
||||||
|
val jvmSubstitutedMethodTypeIntrinsic: IrSimpleFunctionSymbol =
|
||||||
|
irFactory.buildFun {
|
||||||
|
name = Name.special("<jvm-substituted-method-type>")
|
||||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = kotlinJvmInternalPackage
|
parent = kotlinJvmInternalPackage
|
||||||
|
|||||||
+59
-9
@@ -8,10 +8,17 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
|
|||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.inline.v
|
import org.jetbrains.kotlin.codegen.inline.v
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.overrides.buildFakeOverrideMember
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
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
|
||||||
@@ -71,8 +78,10 @@ object JvmInvokeDynamic : IntrinsicMethod() {
|
|||||||
generateMethodHandle(element, codegen)
|
generateMethodHandle(element, codegen)
|
||||||
is IrCall ->
|
is IrCall ->
|
||||||
when (element.symbol) {
|
when (element.symbol) {
|
||||||
codegen.context.ir.symbols.jvmMethodTypeIntrinsic ->
|
codegen.context.ir.symbols.jvmOriginalMethodTypeIntrinsic ->
|
||||||
generateMethodType(element, codegen)
|
generateOriginalMethodType(element, codegen)
|
||||||
|
codegen.context.ir.symbols.jvmSubstitutedMethodTypeIntrinsic ->
|
||||||
|
generateSubstitutedMethodType(element, codegen)
|
||||||
else ->
|
else ->
|
||||||
throw AssertionError("Unexpected callee in bootstrap method argument:\n${element.dump()}")
|
throw AssertionError("Unexpected callee in bootstrap method argument:\n${element.dump()}")
|
||||||
}
|
}
|
||||||
@@ -92,12 +101,14 @@ object JvmInvokeDynamic : IntrinsicMethod() {
|
|||||||
throw AssertionError("Unexpected bootstrap method argument:\n${element.dump()}")
|
throw AssertionError("Unexpected bootstrap method argument:\n${element.dump()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Any {
|
private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Handle {
|
||||||
val irFun = irRawFunctionReference.symbol.owner
|
val irFun = irRawFunctionReference.symbol.owner
|
||||||
val irParentClass = irFun.parentAsClass
|
val irParentClass = irFun.parentAsClass
|
||||||
val owner = codegen.typeMapper.mapOwner(irParentClass)
|
val owner = codegen.typeMapper.mapOwner(irParentClass)
|
||||||
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
|
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
|
||||||
val handleTag = when {
|
val handleTag = when {
|
||||||
|
irFun is IrConstructor ->
|
||||||
|
Opcodes.H_NEWINVOKESPECIAL
|
||||||
irFun.dispatchReceiverParameter == null ->
|
irFun.dispatchReceiverParameter == null ->
|
||||||
Opcodes.H_INVOKESTATIC
|
Opcodes.H_INVOKESTATIC
|
||||||
else ->
|
else ->
|
||||||
@@ -106,18 +117,57 @@ object JvmInvokeDynamic : IntrinsicMethod() {
|
|||||||
return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface)
|
return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMethodType(jvmMethodTypeCall: IrCall, codegen: ExpressionCodegen): Any {
|
private fun generateOriginalMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type {
|
||||||
val irRawFunctionReference = jvmMethodTypeCall.getValueArgument(0) as? IrRawFunctionReference
|
val irRawFunRef = irCall.getValueArgument(0) as? IrRawFunctionReference
|
||||||
?: throw AssertionError(
|
?: throw AssertionError(
|
||||||
"Argument in ${jvmMethodTypeCall.symbol.owner.name} call is expected to be a raw function reference:\n" +
|
"Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference:\n" +
|
||||||
jvmMethodTypeCall.dump()
|
irCall.dump()
|
||||||
)
|
)
|
||||||
val irFun = irRawFunctionReference.symbol.owner
|
val irFun = irRawFunRef.symbol.owner
|
||||||
// TODO substitute signature
|
|
||||||
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
|
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
|
||||||
return Type.getMethodType(asmMethod.descriptor)
|
return Type.getMethodType(asmMethod.descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateSubstitutedMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type {
|
||||||
|
fun fail(message: String): Nothing =
|
||||||
|
throw AssertionError("$message; irCall:\n${irCall.dump()}")
|
||||||
|
|
||||||
|
val irRawFunRef = irCall.getValueArgument(0) as? IrRawFunctionReference
|
||||||
|
?: fail("Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference")
|
||||||
|
val irOriginalFun = irRawFunRef.symbol.owner as? IrSimpleFunction
|
||||||
|
?: fail("IrSimpleFunction expected: ${irRawFunRef.symbol.owner.render()}")
|
||||||
|
val substitutedType = irCall.getTypeArgument(0) as? IrSimpleType
|
||||||
|
?: fail("Type argument expected")
|
||||||
|
|
||||||
|
// Force boxing on primitive types, otherwise D8 fails to accept resulting MethodType in presence of primitive types in arguments
|
||||||
|
// (LambdaMetafactory is ok with such types, though).
|
||||||
|
val substitutedTypeWithNullableArgs =
|
||||||
|
substitutedType.classifier.typeWithArguments(
|
||||||
|
substitutedType.arguments.map {
|
||||||
|
when (it) {
|
||||||
|
is IrStarProjection -> it
|
||||||
|
is IrTypeProjection -> {
|
||||||
|
val type = it.type
|
||||||
|
if (type !is IrSimpleType || type.hasQuestionMark)
|
||||||
|
it
|
||||||
|
else
|
||||||
|
makeTypeProjection(type.withHasQuestionMark(true), it.variance)
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
fail("Unexpected type argument '${it}' :: ${it::class.simpleName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val fakeClass = codegen.context.irFactory.buildClass { name = Name.special("<fake>") }
|
||||||
|
fakeClass.parent = codegen.context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage
|
||||||
|
val irFakeOverride = buildFakeOverrideMember(substitutedTypeWithNullableArgs, irOriginalFun, fakeClass) as IrSimpleFunction
|
||||||
|
irFakeOverride.overriddenSymbols = listOf(irOriginalFun.symbol)
|
||||||
|
|
||||||
|
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFakeOverride)
|
||||||
|
return Type.getMethodType(asmMethod.descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrExpression.getIntConst() =
|
private fun IrExpression.getIntConst() =
|
||||||
if (this is IrConst<*> && kind == IrConstKind.Int)
|
if (this is IrConst<*> && kind == IrConstKind.Int)
|
||||||
this.value as Int
|
this.value as Int
|
||||||
|
|||||||
+12
-1
@@ -103,13 +103,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
}
|
}
|
||||||
reference.transformChildrenVoid()
|
reference.transformChildrenVoid()
|
||||||
|
|
||||||
return if (shouldUseIndySamConversions) {
|
return if (shouldUseIndySamConversions && canUseIndySamConversion(reference)) {
|
||||||
wrapSamConversionArgumentWithIndySamConversion(expression)
|
wrapSamConversionArgumentWithIndySamConversion(expression)
|
||||||
} else {
|
} else {
|
||||||
FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun canUseIndySamConversion(reference: IrFunctionReference): Boolean {
|
||||||
|
// Can't use indy for regular function references by default (because of 'equals').
|
||||||
|
// TODO special mode that would generate indy everywhere?
|
||||||
|
if (reference.origin != IrStatementOrigin.LAMBDA)
|
||||||
|
return false
|
||||||
|
// TODO wrap intrinsic function in lambda?
|
||||||
|
if (context.irIntrinsics.getIntrinsic(reference.symbol) != null)
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun wrapSamConversionArgumentWithIndySamConversion(expression: IrTypeOperatorCall): IrExpression {
|
private fun wrapSamConversionArgumentWithIndySamConversion(expression: IrTypeOperatorCall): IrExpression {
|
||||||
return when (val argument = expression.argument) {
|
return when (val argument = expression.argument) {
|
||||||
is IrFunctionReference ->
|
is IrFunctionReference ->
|
||||||
|
|||||||
+12
-7
@@ -121,10 +121,16 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
putValueArgument(5, irVararg(context.irBuiltIns.anyType, bootstrapMethodArguments))
|
putValueArgument(5, irVararg(context.irBuiltIns.anyType, bootstrapMethodArguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val methodTypeIntrinsic = context.ir.symbols.jvmMethodTypeIntrinsic
|
private val originalMethodTypeIntrinsic = context.ir.symbols.jvmOriginalMethodTypeIntrinsic
|
||||||
|
private val substitutedMethodTypeIntrinsic = context.ir.symbols.jvmSubstitutedMethodTypeIntrinsic
|
||||||
|
|
||||||
private fun IrBuilderWithScope.jvmMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) =
|
private fun IrBuilderWithScope.jvmOriginalMethodType(methodSymbol: IrFunctionSymbol) =
|
||||||
irCall(methodTypeIntrinsic, context.irBuiltIns.anyType).apply {
|
irCall(originalMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
|
||||||
|
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.jvmSubstitutedMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) =
|
||||||
|
irCall(substitutedMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
|
||||||
putTypeArgument(0, ownerType)
|
putTypeArgument(0, ownerType)
|
||||||
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
||||||
}
|
}
|
||||||
@@ -181,16 +187,15 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
?: fail("'method' is expected to be 'IrFunctionReference'")
|
?: fail("'method' is expected to be 'IrFunctionReference'")
|
||||||
val funSymbol = irFunRef.symbol
|
val funSymbol = irFunRef.symbol
|
||||||
|
|
||||||
val erasedSamType = samClassSymbol.defaultType as IrSimpleType
|
val dynamicCall = wrapClosureInDynamicCall(samType, samMethod, irFunRef)
|
||||||
val dynamicCall = wrapClosureInDynamicCall(erasedSamType, samMethod, irFunRef)
|
|
||||||
|
|
||||||
return context.createJvmIrBuilder(
|
return context.createJvmIrBuilder(
|
||||||
funSymbol, // TODO actual symbol for outer scope
|
funSymbol, // TODO actual symbol for outer scope
|
||||||
startOffset, endOffset
|
startOffset, endOffset
|
||||||
).run {
|
).run {
|
||||||
val samMethodType = jvmMethodType(erasedSamType, samMethod.symbol)
|
val samMethodType = jvmOriginalMethodType(samMethod.symbol)
|
||||||
val irRawFunRef = irRawFunctionReferefence(irFunRef.type, funSymbol)
|
val irRawFunRef = irRawFunctionReferefence(irFunRef.type, funSymbol)
|
||||||
val instanceMethodType = jvmMethodType(samType, samMethod.symbol)
|
val instanceMethodType = jvmSubstitutedMethodType(samType, samMethod.symbol)
|
||||||
|
|
||||||
jvmInvokeDynamic(
|
jvmInvokeDynamic(
|
||||||
dynamicCall,
|
dynamicCall,
|
||||||
|
|||||||
+2
-1
@@ -38,7 +38,8 @@ abstract class IrGetEnumValue : IrGetSingletonValue() {
|
|||||||
/**
|
/**
|
||||||
* Platform-specific low-level reference to function.
|
* Platform-specific low-level reference to function.
|
||||||
*
|
*
|
||||||
* On JS platform represent a plain reference to JavaScript function.
|
* On JS platform it represents a plain reference to JavaScript function.
|
||||||
|
* On JVM platform it represents a MethodHandle constant.
|
||||||
*/
|
*/
|
||||||
abstract class IrRawFunctionReference : IrDeclarationReference() {
|
abstract class IrRawFunctionReference : IrDeclarationReference() {
|
||||||
abstract override val symbol: IrFunctionSymbol
|
abstract override val symbol: IrFunctionSymbol
|
||||||
|
|||||||
@@ -23,33 +23,8 @@ import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
|||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
abstract class FakeOverrideBuilderStrategy {
|
abstract class FakeOverrideBuilderStrategy {
|
||||||
open fun fakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember{
|
open fun fakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember =
|
||||||
require(superType is IrSimpleType) { "superType is $superType, expected IrSimpleType" }
|
buildFakeOverrideMember(superType, member, clazz)
|
||||||
val classifier = superType.classifier
|
|
||||||
require(classifier is IrClassSymbol) { "superType classifier is not IrClassSymbol: $classifier" }
|
|
||||||
|
|
||||||
val typeParameters = extractTypeParameters(classifier.owner)
|
|
||||||
val superArguments = superType.arguments
|
|
||||||
assert(typeParameters.size == superArguments.size) {
|
|
||||||
"typeParameters = $typeParameters size != typeArguments = $superArguments size "
|
|
||||||
}
|
|
||||||
|
|
||||||
val substitutionMap = mutableMapOf<IrTypeParameterSymbol, IrType>()
|
|
||||||
|
|
||||||
for (i in typeParameters.indices) {
|
|
||||||
val tp = typeParameters[i]
|
|
||||||
val ta = superArguments[i]
|
|
||||||
require(ta is IrTypeProjection) { "Unexpected super type argument: $ta @ $i" }
|
|
||||||
assert(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" }
|
|
||||||
substitutionMap[tp.symbol] = ta.type
|
|
||||||
}
|
|
||||||
|
|
||||||
val copier = DeepCopyIrTreeWithSymbolsForFakeOverrides(substitutionMap)
|
|
||||||
val deepCopyFakeOverride = copier.copy(member, clazz) as IrOverridableMember
|
|
||||||
deepCopyFakeOverride.parent = clazz
|
|
||||||
|
|
||||||
return deepCopyFakeOverride
|
|
||||||
}
|
|
||||||
|
|
||||||
fun linkFakeOverride(fakeOverride: IrOverridableMember) {
|
fun linkFakeOverride(fakeOverride: IrOverridableMember) {
|
||||||
when (fakeOverride) {
|
when (fakeOverride) {
|
||||||
@@ -66,6 +41,35 @@ abstract class FakeOverrideBuilderStrategy {
|
|||||||
val propertyOverriddenSymbols: MutableMap<IrOverridableMember, List<IrSymbol>> = mutableMapOf()
|
val propertyOverriddenSymbols: MutableMap<IrOverridableMember, List<IrSymbol>> = mutableMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember {
|
||||||
|
require(superType is IrSimpleType) { "superType is $superType, expected IrSimpleType" }
|
||||||
|
val classifier = superType.classifier
|
||||||
|
require(classifier is IrClassSymbol) { "superType classifier is not IrClassSymbol: $classifier" }
|
||||||
|
|
||||||
|
val typeParameters = extractTypeParameters(classifier.owner)
|
||||||
|
val superArguments = superType.arguments
|
||||||
|
assert(typeParameters.size == superArguments.size) {
|
||||||
|
"typeParameters = $typeParameters size != typeArguments = $superArguments size "
|
||||||
|
}
|
||||||
|
|
||||||
|
val substitutionMap = mutableMapOf<IrTypeParameterSymbol, IrType>()
|
||||||
|
|
||||||
|
for (i in typeParameters.indices) {
|
||||||
|
val tp = typeParameters[i]
|
||||||
|
val ta = superArguments[i]
|
||||||
|
require(ta is IrTypeProjection) { "Unexpected super type argument: $ta @ $i" }
|
||||||
|
assert(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" }
|
||||||
|
substitutionMap[tp.symbol] = ta.type
|
||||||
|
}
|
||||||
|
|
||||||
|
val copier = DeepCopyIrTreeWithSymbolsForFakeOverrides(substitutionMap)
|
||||||
|
val deepCopyFakeOverride = copier.copy(member, clazz) as IrOverridableMember
|
||||||
|
deepCopyFakeOverride.parent = clazz
|
||||||
|
|
||||||
|
return deepCopyFakeOverride
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// The below pile of code is basically half of OverridingUtil.java
|
// The below pile of code is basically half of OverridingUtil.java
|
||||||
// adapted to IR and converted to Kotlin.
|
// adapted to IR and converted to Kotlin.
|
||||||
@@ -294,7 +298,7 @@ class IrOverridingUtil(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val realOverrides = members
|
val realOverrides = members
|
||||||
.map{ originals[it]!! }
|
.map { originals[it]!! }
|
||||||
.collectAndFilterRealOverrides()
|
.collectAndFilterRealOverrides()
|
||||||
return getMinimalModality(realOverrides, transformAbstractToClassModality, current.modality)
|
return getMinimalModality(realOverrides, transformAbstractToClassModality, current.modality)
|
||||||
}
|
}
|
||||||
@@ -349,7 +353,10 @@ class IrOverridingUtil(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrSimpleFunction.updateAccessorModalityAndVisibility(newModality: Modality, newVisibility: DescriptorVisibility): IrSimpleFunction? {
|
private fun IrSimpleFunction.updateAccessorModalityAndVisibility(
|
||||||
|
newModality: Modality,
|
||||||
|
newVisibility: DescriptorVisibility
|
||||||
|
): IrSimpleFunction? {
|
||||||
require(this is IrFakeOverrideFunction) {
|
require(this is IrFakeOverrideFunction) {
|
||||||
"Unexpected fake override accessor kind: $this"
|
"Unexpected fake override accessor kind: $this"
|
||||||
}
|
}
|
||||||
@@ -746,15 +753,15 @@ class IrOverridingUtil(
|
|||||||
|
|
||||||
fun IrSimpleFunction.isOverridableFunction(): Boolean =
|
fun IrSimpleFunction.isOverridableFunction(): Boolean =
|
||||||
this.visibility != DescriptorVisibilities.PRIVATE &&
|
this.visibility != DescriptorVisibilities.PRIVATE &&
|
||||||
this.dispatchReceiverParameter != null
|
this.dispatchReceiverParameter != null
|
||||||
|
|
||||||
fun IrProperty.isOverridableProperty(): Boolean =
|
fun IrProperty.isOverridableProperty(): Boolean =
|
||||||
this.visibility != DescriptorVisibilities.PRIVATE &&
|
this.visibility != DescriptorVisibilities.PRIVATE &&
|
||||||
(this.getter?.dispatchReceiverParameter != null ||
|
(this.getter?.dispatchReceiverParameter != null ||
|
||||||
this.setter?.dispatchReceiverParameter != null)
|
this.setter?.dispatchReceiverParameter != null)
|
||||||
|
|
||||||
fun IrDeclaration.isOverridableMemberOrAccessor(): Boolean = when(this) {
|
fun IrDeclaration.isOverridableMemberOrAccessor(): Boolean = when (this) {
|
||||||
is IrSimpleFunction -> isOverridableFunction()
|
is IrSimpleFunction -> isOverridableFunction()
|
||||||
is IrProperty -> isOverridableProperty()
|
is IrProperty -> isOverridableProperty()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface IntFun {
|
||||||
|
fun invoke(i: Int): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invoke1(intFun: IntFun) = intFun.invoke(1)
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val test = invoke1(41::plus)
|
||||||
|
if (test != 42) return "Failed: $test"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface KRunnable {
|
||||||
|
fun run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runIt(r: KRunnable) {
|
||||||
|
r.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var test = "Failed"
|
||||||
|
runIt { test = "OK" }
|
||||||
|
return test
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
class C(val test: String)
|
||||||
|
|
||||||
|
fun interface MakeC {
|
||||||
|
fun make(x: String): C
|
||||||
|
}
|
||||||
|
|
||||||
|
fun make(makeC: MakeC) = makeC.make("OK")
|
||||||
|
|
||||||
|
fun box() = make(::C).test
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface IFoo<T> {
|
||||||
|
fun foo(x: T): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(fs: IFoo<String>) = fs.foo("O")
|
||||||
|
|
||||||
|
fun box() = foo { "${it}K" }
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface IFoo<T> {
|
||||||
|
fun foo(x: T): T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo1(fs: IFoo<Int>) = fs.foo(1)
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val t = foo1 { it + 41 }
|
||||||
|
if (t != 42) return "Failed: t=$t"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
|
||||||
|
fun interface KRunnable {
|
||||||
|
fun run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runnable(kr: KRunnable) = kr
|
||||||
|
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val foo1 = runnable(::foo)
|
||||||
|
val foo2 = runnable(::foo)
|
||||||
|
|
||||||
|
if (foo1 != foo2) {
|
||||||
|
return "Failed: foo1 != foo2"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+36
@@ -18403,6 +18403,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("builtinMemberReference.kt")
|
||||||
|
public void testBuiltinMemberReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("capturedDispatchReceiver.kt")
|
@TestMetadata("capturedDispatchReceiver.kt")
|
||||||
public void testCapturedDispatchReceiver() throws Exception {
|
public void testCapturedDispatchReceiver() throws Exception {
|
||||||
@@ -18427,12 +18433,42 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingVar.kt")
|
||||||
|
public void testCapturingVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("constructorReference.kt")
|
||||||
|
public void testConstructorReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("genericFunInterface.kt")
|
||||||
|
public void testGenericFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("genericFunInterfaceWithPrimitive.kt")
|
||||||
|
public void testGenericFunInterfaceWithPrimitive() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("samConversionOnFunctionReference.kt")
|
||||||
|
public void testSamConversionOnFunctionReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
|
|||||||
+36
@@ -18403,6 +18403,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("builtinMemberReference.kt")
|
||||||
|
public void testBuiltinMemberReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("capturedDispatchReceiver.kt")
|
@TestMetadata("capturedDispatchReceiver.kt")
|
||||||
public void testCapturedDispatchReceiver() throws Exception {
|
public void testCapturedDispatchReceiver() throws Exception {
|
||||||
@@ -18427,12 +18433,42 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingVar.kt")
|
||||||
|
public void testCapturingVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("constructorReference.kt")
|
||||||
|
public void testConstructorReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("genericFunInterface.kt")
|
||||||
|
public void testGenericFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("genericFunInterfaceWithPrimitive.kt")
|
||||||
|
public void testGenericFunInterfaceWithPrimitive() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("samConversionOnFunctionReference.kt")
|
||||||
|
public void testSamConversionOnFunctionReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@TestMetadata("simpleIndyFunInterface.kt")
|
||||||
public void testSimpleIndyFunInterface() throws Exception {
|
public void testSimpleIndyFunInterface() throws Exception {
|
||||||
|
|||||||
+6
-2
@@ -46,7 +46,11 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe
|
|||||||
try {
|
try {
|
||||||
for (ktFile in ktFiles) {
|
for (ktFile in ktFiles) {
|
||||||
val className = ktFile.getFacadeFqName() ?: continue
|
val className = ktFile.getFacadeFqName() ?: continue
|
||||||
val clazz = classLoader.getGeneratedClass(className)
|
val clazz = try {
|
||||||
|
classLoader.getGeneratedClass(className)
|
||||||
|
} catch (e: LinkageError) {
|
||||||
|
throw AssertionError("Failed to load class '$className':\n${info.classFileFactory.createText()}", e)
|
||||||
|
}
|
||||||
val method = clazz.getBoxMethodOrNull() ?: continue
|
val method = clazz.getBoxMethodOrNull() ?: continue
|
||||||
boxMethodFound = true
|
boxMethodFound = true
|
||||||
callBoxMethodAndCheckResultWithCleanup(
|
callBoxMethodAndCheckResultWithCleanup(
|
||||||
@@ -128,7 +132,7 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe
|
|||||||
): GeneratedClassLoader {
|
): GeneratedClassLoader {
|
||||||
val classLoader = createClassLoader(module, classFileFactory)
|
val classLoader = createClassLoader(module, classFileFactory)
|
||||||
val verificationSucceeded = CodegenTestUtil.verifyAllFilesWithAsm(classFileFactory, classLoader, reportProblems)
|
val verificationSucceeded = CodegenTestUtil.verifyAllFilesWithAsm(classFileFactory, classLoader, reportProblems)
|
||||||
if (!verificationSucceeded ) {
|
if (!verificationSucceeded) {
|
||||||
assertions.fail { "Verification failed: see exceptions above" }
|
assertions.fail { "Verification failed: see exceptions above" }
|
||||||
}
|
}
|
||||||
return classLoader
|
return classLoader
|
||||||
|
|||||||
+30
@@ -16138,6 +16138,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("builtinMemberReference.kt")
|
||||||
|
public void testBuiltinMemberReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/builtinMemberReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("capturedDispatchReceiver.kt")
|
@TestMetadata("capturedDispatchReceiver.kt")
|
||||||
public void testCapturedDispatchReceiver() throws Exception {
|
public void testCapturedDispatchReceiver() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt");
|
||||||
@@ -16158,11 +16163,36 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("capturingVar.kt")
|
||||||
|
public void testCapturingVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("constructorReference.kt")
|
||||||
|
public void testConstructorReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/constructorReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("genericFunInterface.kt")
|
||||||
|
public void testGenericFunInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("genericFunInterfaceWithPrimitive.kt")
|
||||||
|
public void testGenericFunInterfaceWithPrimitive() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/genericFunInterfaceWithPrimitive.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("samConversionOnFunctionReference.kt")
|
||||||
|
public void testSamConversionOnFunctionReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samConversionOnFunctionReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simpleIndyFunInterface.kt")
|
@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");
|
||||||
|
|||||||
Reference in New Issue
Block a user