From 23b315446fffe43ef1dcd6dea1011bc9eebd3e5f Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 5 Aug 2021 13:12:52 +0300 Subject: [PATCH] Support sam conversion in ir interpreter --- ...IrInterpreterAfterFir2IrTestGenerated.java | 6 ++++ ...IrInterpreterAfterPsi2IrTestGenerated.java | 6 ++++ .../kotlin/ir/interpreter/IrInterpreter.kt | 30 ++++++++++++++--- .../jetbrains/kotlin/ir/interpreter/Utils.kt | 9 ++++++ .../checker/IrCompileTimeChecker.kt | 6 ++-- .../proxy/reflection/KClassProxy.kt | 8 ++++- .../proxy/reflection/KFunctionProxy.kt | 6 +++- .../kotlin/ir/interpreter/state/Complex.kt | 10 +++--- .../kotlin/ir/interpreter/state/State.kt | 24 ++++++++++++-- .../state/reflection/KFunctionState.kt | 31 ++++++++++++++++-- .../ir/interpreter/helpers/Collections.kt | 10 ++++++ .../testData/ir/interpreter/samConversion.kt | 32 +++++++++++++++++++ 12 files changed, 156 insertions(+), 22 deletions(-) create mode 100644 compiler/testData/ir/interpreter/samConversion.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterFir2IrTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterFir2IrTestGenerated.java index 3462abf9838..c31e98c58a7 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterFir2IrTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterFir2IrTestGenerated.java @@ -289,6 +289,12 @@ public class IrInterpreterAfterFir2IrTestGenerated extends AbstractIrInterpreter runTest("compiler/testData/ir/interpreter/safeClassCast.kt"); } + @Test + @TestMetadata("samConversion.kt") + public void testSamConversion() throws Exception { + runTest("compiler/testData/ir/interpreter/samConversion.kt"); + } + @Test @TestMetadata("scopeFunctions.kt") public void testScopeFunctions() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterPsi2IrTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterPsi2IrTestGenerated.java index e2286b8a07f..1a5a5198240 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterPsi2IrTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/interpreter/IrInterpreterAfterPsi2IrTestGenerated.java @@ -289,6 +289,12 @@ public class IrInterpreterAfterPsi2IrTestGenerated extends AbstractIrInterpreter runTest("compiler/testData/ir/interpreter/safeClassCast.kt"); } + @Test + @TestMetadata("samConversion.kt") + public void testSamConversion() throws Exception { + runTest("compiler/testData/ir/interpreter/samConversion.kt"); + } + @Test @TestMetadata("scopeFunctions.kt") public void testScopeFunctions() throws Exception { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 56d1b8ff1a7..06ed76ad4ce 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -11,8 +11,7 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl -import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError -import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterTimeOutError +import org.jetbrains.kotlin.ir.interpreter.exceptions.* import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.exceptions.verify import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy @@ -24,6 +23,7 @@ import org.jetbrains.kotlin.ir.interpreter.state.reflection.* import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.util.OperatorNameConventions internal interface Instruction { val element: IrElement? @@ -188,7 +188,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() // 5. store arguments in memory (remap args on actual names) - irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> callStack.addVariable(Variable(it, receiver)) } } + irFunction.getDispatchReceiver()?.let { callStack.addVariable(Variable(it, dispatchReceiver!!)) } irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: callStack.getState(it))) } irFunction.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) } // `call.type` is used in check cast and emptyArray @@ -481,7 +481,29 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal else -> callStack.pushState(state) } } - else -> TODO("${expression.operator} not implemented") + IrTypeOperator.SAM_CONVERSION -> { + val newState = when { + state.isNull() -> state + state is KFunctionState -> state.apply { this.funInterface = typeOperand } + else -> { + // this case supports implicit conversion of `invoke` method from FunctionN to similar in fun interface + val samClass = typeOperand.classOrNull!!.owner + val samFunction = samClass.getSingleAbstractMethod() + + val invokeFunction = state.irClass.declarations.filterIsInstance() + .first { it.name == OperatorNameConventions.INVOKE && it.valueParameters.size == samFunction.valueParameters.size } + val functionClass = invokeFunction.getLastOverridden().parentAsClass + + // receiver will be stored as up value + val dispatchReceiver = Variable(invokeFunction.dispatchReceiverParameter!!.symbol, state) + val newInvoke = invokeFunction.deepCopyWithSymbols(samClass).apply { dispatchReceiverParameter = null } + KFunctionState(newInvoke, functionClass, environment, mutableListOf(dispatchReceiver)) + .apply { this.funInterface = typeOperand } + } + } + callStack.pushState(newState) + } + else -> stop { "Type operator ${expression.operator} is not supported for interpretation" } } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index dfe53032332..0287f9931e5 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.interpreter import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* @@ -272,4 +273,12 @@ internal fun IrFunctionAccessExpression.getSuperEnumCall(): IrEnumConstructorCal is IrTypeOperatorCall -> (delegatingCall.argument as IrFunctionAccessExpression).getSuperEnumCall() else -> TODO("$delegatingCall is unexpected") } +} + +internal fun IrFunction.hasFunInterfaceParent(): Boolean { + return this.parentClassOrNull?.isFun == true +} + +internal fun IrClass.getSingleAbstractMethod(): IrFunction { + return declarations.filterIsInstance().single { it.modality == Modality.ABSTRACT } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt index 79b6b6e1dcb..9daf80b403a 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt @@ -215,14 +215,12 @@ class IrCompileTimeChecker( override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Nothing?): Boolean { return when (expression.operator) { IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF, - IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, - IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST, IrTypeOperator.SAFE_CAST, - IrTypeOperator.IMPLICIT_NOTNULL -> { + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, IrTypeOperator.IMPLICIT_NOTNULL, IrTypeOperator.SAM_CONVERSION, + IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST, IrTypeOperator.SAFE_CAST -> { val operand = expression.typeOperand.classifierOrNull?.owner if (operand is IrTypeParameter && !visitedStack.contains(operand.parent)) return false expression.argument.accept(this, data) } - IrTypeOperator.IMPLICIT_DYNAMIC_CAST -> false else -> false } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt index 7709b364247..3f9b41f0c21 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt @@ -7,9 +7,13 @@ package org.jetbrains.kotlin.ir.interpreter.proxy.reflection import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.interpreter.CallInterceptor +import org.jetbrains.kotlin.ir.interpreter.exceptions.verify import org.jetbrains.kotlin.ir.interpreter.internalName import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy +import org.jetbrains.kotlin.ir.interpreter.state.State +import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf import org.jetbrains.kotlin.ir.interpreter.state.reflection.KClassState +import org.jetbrains.kotlin.ir.util.defaultType import kotlin.reflect.* internal class KClassProxy( @@ -60,7 +64,9 @@ internal class KClassProxy( get() = state.classReference.isInline override fun isInstance(value: Any?): Boolean { - TODO("Not yet implemented") + verify(value is State) { "Cannot interpret `isInstance` method for $value" } + // TODO fix problems with typealias and java classes subtype check + return (value as State).isSubtypeOf(state.classReference.defaultType) } override fun equals(other: Any?): Boolean { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt index c846ab752bc..2fb753510b3 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt @@ -15,8 +15,10 @@ import org.jetbrains.kotlin.ir.expressions.IrReturn import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall import org.jetbrains.kotlin.ir.interpreter.CallInterceptor import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.hasTheSameFieldsWith import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.isSuspend import org.jetbrains.kotlin.ir.util.statements import kotlin.reflect.* @@ -80,7 +82,9 @@ internal class KFunctionProxy( if (this === other) return true if (other !is KFunctionProxy) return false if (arity != other.arity || isSuspend != other.isSuspend) return false - if (state.fields.zip(other.state.fields).any { (first, second) -> first.state !== second.state }) return false + // SAM wrappers for Java do not implement equals + if (this.state.funInterface?.classOrNull?.owner?.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) return this.state === other.state + if (!state.hasTheSameFieldsWith(other.state)) return false return when { state.irFunction.isAdapter() && other.state.irFunction.isAdapter() -> state.irFunction.eqaulsByAdapteeCall(other.state.irFunction) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt index f0b313539ed..6c46e0372e7 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.interpreter.fqName import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.Variable -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.util.overrides import org.jetbrains.kotlin.ir.util.resolveFakeOverride @@ -21,15 +20,14 @@ internal interface Complex : State { fun irClassFqName() = irClass.fqName - private fun getIrFunctionFromGivenClass(irClass: IrClass, symbol: IrFunctionSymbol): IrFunction? { + private fun getIrFunctionFromGivenClass(irClass: IrClass, owner: IrFunction): IrFunction? { val propertyGetters = irClass.declarations.filterIsInstance().mapNotNull { it.getter } val propertySetters = irClass.declarations.filterIsInstance().mapNotNull { it.setter } val functions = irClass.declarations.filterIsInstance() return (propertyGetters + propertySetters + functions).firstOrNull { - val owner = symbol.owner when { it is IrSimpleFunction && owner is IrSimpleFunction -> it.overrides(owner) || owner.overrides(it) - else -> it == symbol.owner + else -> it == owner } } } @@ -40,7 +38,7 @@ internal interface Complex : State { override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { val receiver = expression.superQualifierSymbol?.owner ?: irClass - val irFunction = getIrFunctionFromGivenClass(receiver, expression.symbol) ?: return null + val irFunction = getIrFunctionFromGivenClass(receiver, expression.symbol.owner) ?: return null return (irFunction as IrSimpleFunction).resolveFakeOverride() } @@ -63,4 +61,4 @@ internal interface Complex : State { (variable.state as? StateWithClosure)?.let { callStack.loadUpValues(it) } } } -} \ No newline at end of file +} diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt index f9d4802fda7..5f832fb8285 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt @@ -66,6 +66,10 @@ internal fun State.isSubtypeOf(other: IrType): Boolean { return this.type.arraySubtypeCheck(other) } + if (other.classOrNull?.owner?.isFun == true) { + return this is KFunctionState && this.funInterface?.isSubtypeOfClass(other.classOrNull!!) == true + } + val thisType = this.irClass.defaultType if (other.isFunction() && thisType.isKFunction()/* TODO || (other.isSuspendFunction && thisType.isKSuspendFunction())*/) { // KFunction{n} has no super type of Function{n}, @@ -92,6 +96,20 @@ internal fun State.checkNullability( } internal fun State?.mustBeHandledAsReflection(call: IrCall): Boolean { - if (call.symbol.owner.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) return false - return this is ReflectionState && !(this is KFunctionState && call.symbol.owner.name == OperatorNameConventions.INVOKE) -} \ No newline at end of file + val owner = call.symbol.owner + if (owner.body != null || owner.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) return false + return this is ReflectionState && !(this is KFunctionState && KFunctionState.isCallToInvokeOrMethodFromFunInterface(call)) +} + +internal fun State.hasTheSameFieldsWith(other: State): Boolean { + if (this.fields.size != other.fields.size) return false + for (i in 0 until this.fields.size) { + val firstState = this.fields[i].state + val secondState = other.fields[i].state + when { + firstState is Primitive<*> && secondState is Primitive<*> -> if (firstState.value != secondState.value) return false + else -> if (firstState !== secondState) return false + } + } + return true +} diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt index 8604c2d44c7..8944dc78bfe 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.interpreter.state.reflection +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrFunctionReference @@ -16,9 +17,11 @@ import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.resolveFakeOverride import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.name.SpecialNames @@ -33,6 +36,17 @@ internal class KFunctionState( override val fields: MutableList = mutableListOf() ) : ReflectionState(), StateWithClosure { override val upValues: MutableList = mutableListOf() + + var funInterface: IrType? = null + set(value) { + field = value ?: return + val samFunction = value.classOrNull!!.owner.getSingleAbstractMethod() + if (samFunction.extensionReceiverParameter != null) { + // this change of parameter is needed because of difference in `invoke` and sam calls + invokeSymbol.owner.extensionReceiverParameter = invokeSymbol.owner.valueParameters[0] + invokeSymbol.owner.valueParameters = invokeSymbol.owner.valueParameters.drop(1) + } + } private var _parameters: List? = null private var _returnType: KType? = null private var _typeParameters: List? = null @@ -47,7 +61,7 @@ internal class KFunctionState( } companion object { - fun createInvokeFunction( + private fun createInvokeFunction( irFunction: IrFunction, irClass: IrClass, hasDispatchReceiver: Boolean, hasExtensionReceiver: Boolean ): IrSimpleFunction { val invokeFunction = irClass.declarations @@ -86,14 +100,24 @@ internal class KFunctionState( putArgument(it, it.createGetValue()) newValueParameters += it } - this@impl.valueParameters = newValueParameters } + valueParameters = newValueParameters body = listOf(this.createReturn(call)).wrapWithBlockBody() } functionClass.declarations += newFunctionToInvoke return newFunctionToInvoke } + + private fun isCallToNonAbstractMethodOfFunInterface(expression: IrCall): Boolean { + val owner = expression.symbol.owner + return owner.hasFunInterfaceParent() && owner.modality != Modality.ABSTRACT + } + + fun isCallToInvokeOrMethodFromFunInterface(expression: IrCall): Boolean { + val owner = expression.symbol.owner + return owner.name == OperatorNameConventions.INVOKE || owner.hasFunInterfaceParent() + } } constructor( @@ -112,7 +136,8 @@ internal class KFunctionState( } override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { - if (expression.symbol.owner.name == OperatorNameConventions.INVOKE) return invokeSymbol.owner + if (isCallToNonAbstractMethodOfFunInterface(expression)) return expression.symbol.owner.resolveFakeOverride() + if (isCallToInvokeOrMethodFromFunInterface(expression)) return invokeSymbol.owner return super.getIrFunctionByIrCall(expression) } diff --git a/compiler/testData/ir/interpreter/helpers/Collections.kt b/compiler/testData/ir/interpreter/helpers/Collections.kt index 013607cde2e..7be5fc72afd 100644 --- a/compiler/testData/ir/interpreter/helpers/Collections.kt +++ b/compiler/testData/ir/interpreter/helpers/Collections.kt @@ -136,6 +136,16 @@ public fun > Iterable.toCollection(destination return destination } +public inline fun Iterable.map(transform: (T) -> R): List { + return mapTo(ArrayList(if (this is Collection<*>) this.size else 10), transform) +} + +public inline fun > Iterable.mapTo(destination: C, transform: (T) -> R): C { + for (item in this) + destination.add(transform(item)) + return destination +} + internal fun List.optimizeReadOnlyList() = when (size) { 0 -> emptyList() 1 -> listOf(this[0]) diff --git a/compiler/testData/ir/interpreter/samConversion.kt b/compiler/testData/ir/interpreter/samConversion.kt new file mode 100644 index 00000000000..30d328a63f8 --- /dev/null +++ b/compiler/testData/ir/interpreter/samConversion.kt @@ -0,0 +1,32 @@ +import kotlin.* +import kotlin.collections.* + +@CompileTimeCalculation +fun interface IntPredicate { + fun accept(i: Int): Boolean + + fun defaultMethod() = 1 +} + +const val isEven = IntPredicate { it % 2 == 0 } + .let { predicate -> listOf(1, 2, 3, 4, 5).map { predicate.accept(it) }.joinToString() } +const val isOdd = IntPredicate { it % 2 != 0 } + .let { predicate -> listOf(1, 2, 3, 4, 5).map { predicate.accept(it) }.joinToString() } +const val callToDefault = IntPredicate { false }.defaultMethod() +const val callToString = IntPredicate { false }. kotlin.Boolean`!>toString() + +@CompileTimeCalculation +fun interface KRunnable { + fun invoke(): String +} + +@CompileTimeCalculation +object OK : () -> String { + override fun invoke(): String = "OK" +} + +@CompileTimeCalculation +fun foo(k: KRunnable) = k.invoke() + +const val invokeFromObject = foo(OK) +const val invokeFromFunInterface = foo(KRunnable { "OK" })