From ea3713f051717edf70c5c4ecddb1c1b1454e9419 Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Tue, 27 Sep 2022 12:04:33 +0200 Subject: [PATCH] Fix building fake overrides for sam and function references --- .../lower/SingleAbstractMethodLowering.kt | 10 ++++- .../kotlin/ir/overrides/IrOverridingUtil.kt | 5 ++- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 11 ++++- .../funInterface/kt50950.kt | 13 +++++- .../konan/lower/FunctionReferenceLowering.kt | 40 ++++++++----------- 5 files changed, 48 insertions(+), 31 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt index 365f4713229..b12ae3e0473 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt @@ -219,7 +219,7 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : isSuspend = originalSuperMethod.isSuspend setSourceRange(createFor) }.apply { - overriddenSymbols = listOf(transformedSuperMethod.symbol) + overriddenSymbols = listOf(originalSuperMethod.symbol) dispatchReceiverParameter = subclass.thisReceiver!!.copyTo(this) extensionReceiverParameter = originalSuperMethod.extensionReceiverParameter?.copyTo(this) valueParameters = originalSuperMethod.valueParameters.map { it.copyTo(this) } @@ -239,7 +239,13 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : if (superType.needEqualsHashCodeMethods) generateEqualsHashCode(subclass, superType, field) - subclass.addFakeOverrides(context.typeSystem) + subclass.addFakeOverrides( + context.typeSystem, + // Built function overrides originalSuperMethod, while, if parent class is already lowered, it would + // transformedSuperMethod in its declaration list. We need not fake override in that case. + // Later lowerings will fix it and replace function with one overriding transformedSuperMethod. + ignoredParentSymbols = listOf(transformedSuperMethod.symbol) + ) return subclass } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt index dbb9a4c4ece..45b9643b6b6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt @@ -171,7 +171,8 @@ class IrOverridingUtil( fun buildFakeOverridesForClassUsingOverriddenSymbols( clazz: IrClass, implementedMembers: List = emptyList(), - compatibilityMode: Boolean + compatibilityMode: Boolean, + ignoredParentSymbols: List = emptyList() ): List { val overriddenMembers = (clazz.declarations.filterIsInstance() + implementedMembers) .flatMap { member -> member.overriddenSymbols.map { it.owner } } @@ -182,7 +183,7 @@ class IrOverridingUtil( superClass.declarations .filterIsInstance() .filterNot { - it in overriddenMembers || it.isStaticMember || DescriptorVisibilities.isPrivate(it.visibility) + it in overriddenMembers || it.symbol in ignoredParentSymbols || it.isStaticMember || DescriptorVisibilities.isPrivate(it.visibility) } .map { overriddenMember -> val fakeOverride = fakeOverrideBuilder.fakeOverrideMember(superType, overriddenMember, clazz) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 255dbe5533b..f4f2b2a3867 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -1125,9 +1125,16 @@ private class FakeOverrideBuilderForLowerings : FakeOverrideBuilderStrategy(empt } } -fun IrClass.addFakeOverrides(typeSystem: IrTypeSystemContext, implementedMembers: List = emptyList()) { +fun IrClass.addFakeOverrides( + typeSystem: IrTypeSystemContext, + implementedMembers: List = emptyList(), + ignoredParentSymbols: List = emptyList() +) { IrOverridingUtil(typeSystem, FakeOverrideBuilderForLowerings()) - .buildFakeOverridesForClassUsingOverriddenSymbols(this, implementedMembers, compatibilityMode = false) + .buildFakeOverridesForClassUsingOverriddenSymbols(this, + implementedMembers = implementedMembers, + compatibilityMode = false, + ignoredParentSymbols = ignoredParentSymbols) .forEach { addChild(it) } } diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt index 365cff9fe62..3321e23a4b2 100644 --- a/compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt @@ -11,11 +11,20 @@ import kotlin.coroutines.* import kotlin.coroutines.intrinsics.* import helpers.EmptyContinuation -suspend fun run(block: suspend () -> Unit) = A(block).run() +suspend fun runA(block: suspend () -> Unit) = A(block).run() +suspend fun runC(block: suspend () -> Unit) = C(block).run() fun box(): String { suspend { - run {} + runA {} + runC {} + A { }.run() + C { }.run() }.startCoroutine(EmptyContinuation) return "OK" } + +// FILE: c.kt +fun interface C { + suspend fun run() +} diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt index daad9aa5fa6..3bfa203d726 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl @@ -194,8 +193,6 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas private val isKFunction = functionReference.type.isKFunction() private val isKSuspendFunction = functionReference.type.isKSuspendFunction() - private val samSuperClass = samSuperType?.let { it.classOrNull ?: error("Expected a class but was: ${it.render()}") } - private val adaptedReferenceOriginalTarget: IrFunction? = functionReference.reflectionTarget?.owner private val functionReferenceTarget = adaptedReferenceOriginalTarget ?: referencedFunction @@ -251,31 +248,25 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas else -> kFunctionImplSymbol.typeWith(functionReturnType) } val superTypes = mutableListOf(superClass) + val transformedSuperMethod: IrSimpleFunction if (samSuperType != null) { superTypes += samSuperType - - val sam = samSuperClass!!.functions.single { it.owner.modality == Modality.ABSTRACT } - buildInvokeMethod(sam.owner) + val samSuperClass = samSuperType.classOrNull ?: error("Expected a class but was: ${samSuperType.render()}") + transformedSuperMethod = samSuperClass.functions.single { it.owner.modality == Modality.ABSTRACT }.owner } else { val numberOfParameters = unboundFunctionParameters.size - val functionClass: IrClass? - val suspendFunctionClass: IrClass? if (isKSuspendFunction) { - functionClass = null - suspendFunctionClass = symbols.kSuspendFunctionN(numberOfParameters).owner + val suspendFunctionClass = symbols.kSuspendFunctionN(numberOfParameters).owner superTypes += suspendFunctionClass.typeWith(functionParameterAndReturnTypes) + transformedSuperMethod = suspendFunctionClass.getInvokeFunction() } else { - functionClass = (if (isKFunction) symbols.kFunctionN(numberOfParameters) else symbols.functionN(numberOfParameters)).owner - suspendFunctionClass = null + val functionClass = (if (isKFunction) symbols.kFunctionN(numberOfParameters) else symbols.functionN(numberOfParameters)).owner superTypes += functionClass.typeWith(functionParameterAndReturnTypes) - } - - if (functionClass != null) - buildInvokeMethod(functionClass.getInvokeFunction()) - if (suspendFunctionClass != null) { - buildInvokeMethod(suspendFunctionClass.getInvokeFunction()) + transformedSuperMethod = functionClass.getInvokeFunction() } } + val originalSuperMethod = context.mapping.functionWithContinuationsToSuspendFunctions[transformedSuperMethod] ?: transformedSuperMethod + buildInvokeMethod(originalSuperMethod) functionReferenceClass.superTypes += superTypes if (!isLambda) { @@ -329,7 +320,13 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas } } - functionReferenceClass.addFakeOverrides(context.typeSystem) + functionReferenceClass.addFakeOverrides( + context.typeSystem, + // Built function overrides originalSuperMethod, while, if parent class is already lowered, it would + // transformedSuperMethod in its declaration list. We need not fake override in that case. + // Later lowerings will fix it and replace function with one overriding transformedSuperMethod. + ignoredParentSymbols = listOf(transformedSuperMethod.symbol) + ) return functionReferenceClass } @@ -428,10 +425,7 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas return false } - private fun buildInvokeMethod(superFunction: IrSimpleFunction) = - buildInvokeMethodImpl(context.mapping.functionWithContinuationsToSuspendFunctions[superFunction] ?: superFunction) - - private fun buildInvokeMethodImpl(superFunction: IrSimpleFunction): IrSimpleFunction { + private fun buildInvokeMethod(superFunction: IrSimpleFunction): IrSimpleFunction { return IrFunctionImpl( startOffset, endOffset, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,