diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/ActualFakeOverridesAdder.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/ActualFakeOverridesAdder.kt index c245b91b8d8..679223160a4 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/ActualFakeOverridesAdder.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/ActualFakeOverridesAdder.kt @@ -8,10 +8,9 @@ package org.jetbrains.kotlin.backend.common.actualizer import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.backend.common.CommonBackendErrors import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.overrides.isOverridableByWithoutExternalConditions +import org.jetbrains.kotlin.ir.overrides.IrOverrideChecker import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrTypeSystemContext @@ -38,6 +37,7 @@ internal class ActualFakeOverridesAdder( private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext, private val typeSystemContext: IrTypeSystemContext ) : IrElementVisitorVoid { + private val overrideChecker = IrOverrideChecker(typeSystemContext) private val missingActualMembersMap = mutableMapOf() override fun visitClass(declaration: IrClass) { @@ -93,7 +93,7 @@ internal class ActualFakeOverridesAdder( @Suppress("UNCHECKED_CAST") val override = klass.declarations.firstOrNull { it is IrOverridableMember && - typeSystemContext.isOverridableByWithoutExternalConditions( + overrideChecker.isOverridableByWithoutExternalConditions( superMember = memberFromSupertype, subMember = it, checkIsInlineFlag = false, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverrideChecker.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverrideChecker.kt new file mode 100644 index 00000000000..886c56648b6 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverrideChecker.kt @@ -0,0 +1,146 @@ +/* + * Copyright 2010-2023 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.ir.overrides + +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.types.IrTypeSystemContext +import org.jetbrains.kotlin.ir.types.IrTypeSystemContextWithAdditionalAxioms +import org.jetbrains.kotlin.ir.types.createIrTypeCheckerState +import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo +import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.* +import org.jetbrains.kotlin.types.AbstractTypeChecker + +class IrOverrideChecker(private val typeSystem: IrTypeSystemContext) { + fun getBothWaysOverridability( + overriderDescriptor: IrOverridableMember, + candidateDescriptor: IrOverridableMember, + ): Result { + val result1 = isOverridableBy( + candidateDescriptor, + overriderDescriptor, + checkIsInlineFlag = false, + ).result + + val result2 = isOverridableBy( + overriderDescriptor, + candidateDescriptor, + checkIsInlineFlag = false, + ).result + + return if (result1 == result2) result1 else Result.INCOMPATIBLE + } + + fun isOverridableBy( + superMember: IrOverridableMember, + subMember: IrOverridableMember, + checkIsInlineFlag: Boolean, + ): OverrideCompatibilityInfo { + return isOverridableByWithoutExternalConditions(superMember, subMember, checkIsInlineFlag) + // The frontend goes into external overridability condition details here, but don't deal with them in IR (yet?). + } + + fun isOverridableByWithoutExternalConditions( + superMember: IrOverridableMember, + subMember: IrOverridableMember, + checkIsInlineFlag: Boolean, + ): OverrideCompatibilityInfo { + val superTypeParameters: List + val subTypeParameters: List + + val superValueParameters: List + val subValueParameters: List + + when (superMember) { + is IrSimpleFunction -> when { + subMember !is IrSimpleFunction -> return incompatible("Member kind mismatch") + superMember.hasExtensionReceiver != subMember.hasExtensionReceiver -> return incompatible("Receiver presence mismatch") + superMember.isSuspend != subMember.isSuspend -> return incompatible("Incompatible suspendability") + checkIsInlineFlag && superMember.isInline -> return incompatible("Inline function can't be overridden") + + else -> { + superTypeParameters = superMember.typeParameters + subTypeParameters = subMember.typeParameters + superValueParameters = superMember.compiledValueParameters + subValueParameters = subMember.compiledValueParameters + } + } + is IrProperty -> when { + subMember !is IrProperty -> return incompatible("Member kind mismatch") + superMember.getter.hasExtensionReceiver != subMember.getter.hasExtensionReceiver -> return incompatible("Receiver presence mismatch") + checkIsInlineFlag && superMember.isInline -> return incompatible("Inline property can't be overridden") + + else -> { + superTypeParameters = superMember.typeParameters + subTypeParameters = subMember.typeParameters + superValueParameters = superMember.compiledValueParameters + subValueParameters = subMember.compiledValueParameters + } + } + else -> error("Unexpected type of declaration: ${superMember::class.java}, $superMember") + } + + when { + superMember.name != subMember.name -> { + // Check name after member kind checks. This way FO builder will first check types of overridable members and crash + // if member types are not supported (ex: IrConstructor). + return incompatible("Name mismatch") + } + + superTypeParameters.size != subTypeParameters.size -> return incompatible("Type parameter number mismatch") + superValueParameters.size != subValueParameters.size -> return incompatible("Value parameter number mismatch") + } + + // TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent() +// superTypeParameters.forEachIndexed { index, parameter -> +// if (!AbstractTypeChecker.areTypeParametersEquivalent( +// typeCheckerContext as AbstractTypeCheckerContext, +// subTypeParameters[index].type, +// parameter.type +// ) +// ) return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch") +// } + + val typeCheckerState = createIrTypeCheckerState( + IrTypeSystemContextWithAdditionalAxioms( + typeSystem, + superTypeParameters, + subTypeParameters + ) + ) + + superValueParameters.forEachIndexed { index, parameter -> + if (!AbstractTypeChecker.equalTypes( + typeCheckerState, + subValueParameters[index].type, + parameter.type + ) + ) return incompatible("Value parameter type mismatch") + } + + return success() + } +} + +private val IrSimpleFunction?.hasExtensionReceiver: Boolean + get() = this?.extensionReceiverParameter != null + +internal val IrSimpleFunction?.hasDispatchReceiver: Boolean + get() = this?.dispatchReceiverParameter != null + +private val IrSimpleFunction.compiledValueParameters: List + get() = ArrayList(valueParameters.size + 1).apply { + extensionReceiverParameter?.let(::add) + addAll(valueParameters) + } + +private val IrProperty.compiledValueParameters: List + get() = getter?.extensionReceiverParameter?.let(::listOf).orEmpty() + +private val IrProperty.typeParameters: List + get() = getter?.typeParameters.orEmpty() + +private val IrProperty.isInline: Boolean + get() = getter?.isInline == true || setter?.isInline == true 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 59efbb2927f..655cb5a3281 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 @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.ir.util.collectAndFilterRealOverrides import org.jetbrains.kotlin.ir.util.isReal import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo -import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.* import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.utils.filterIsInstanceAnd @@ -36,6 +35,7 @@ class IrOverridingUtil( private val typeSystem: IrTypeSystemContext, private val fakeOverrideBuilder: FakeOverrideBuilderStrategy ) { + private val overrideChecker = IrOverrideChecker(typeSystem) private val originals = mutableMapOf() private val IrOverridableMember.original get() = originals[this] ?: error("No original for ${this.render()}") private val originalSuperTypes = mutableMapOf() @@ -166,7 +166,7 @@ class IrOverridingUtil( for (fromSupertype in descriptorsFromSuper) { // Note: We do allow overriding multiple FOs at once one of which is `isInline=true`. - when (isOverridableBy(fromSupertype, fromCurrent, checkIsInlineFlag = true).result) { + when (overrideChecker.isOverridableBy(fromSupertype, fromCurrent, checkIsInlineFlag = true).result) { OverrideCompatibilityInfo.Result.OVERRIDABLE -> { val isVisibleFake = fromSupertype.visibility != DescriptorVisibilities.INVISIBLE_FAKE if (isVisibleFake && isVisibleForOverride(fromCurrent, fromSupertype.original)) @@ -502,11 +502,7 @@ class IrOverridingUtil( iterator.remove() continue } - val finalResult = - getBothWaysOverridability( - overrider, - candidate - ) + val finalResult = overrideChecker.getBothWaysOverridability(overrider, candidate) if (finalResult == OverrideCompatibilityInfo.Result.OVERRIDABLE) { overridable.add(candidate) iterator.remove() @@ -516,138 +512,8 @@ class IrOverridingUtil( } return overridable } - - private fun getBothWaysOverridability( - overriderDescriptor: IrOverridableMember, - candidateDescriptor: IrOverridableMember - ): Result { - val result1 = isOverridableBy( - candidateDescriptor, - overriderDescriptor, - checkIsInlineFlag = false, - ).result - - val result2 = isOverridableBy( - overriderDescriptor, - candidateDescriptor, - checkIsInlineFlag = false, - ).result - - return if (result1 == result2) result1 else OverrideCompatibilityInfo.Result.INCOMPATIBLE - } - - private fun isOverridableBy( - superMember: IrOverridableMember, - subMember: IrOverridableMember, - checkIsInlineFlag: Boolean, - ): OverrideCompatibilityInfo { - return typeSystem.isOverridableByWithoutExternalConditions(superMember, subMember, checkIsInlineFlag) - // The frontend goes into external overridability condition details here, but don't deal with them in IR (yet?). - } } -fun IrTypeSystemContext.isOverridableByWithoutExternalConditions( - superMember: IrOverridableMember, - subMember: IrOverridableMember, - checkIsInlineFlag: Boolean, -): OverrideCompatibilityInfo { - val superTypeParameters: List - val subTypeParameters: List - - val superValueParameters: List - val subValueParameters: List - - when (superMember) { - is IrSimpleFunction -> when { - subMember !is IrSimpleFunction -> return incompatible("Member kind mismatch") - superMember.hasExtensionReceiver != subMember.hasExtensionReceiver -> return incompatible("Receiver presence mismatch") - superMember.isSuspend != subMember.isSuspend -> return incompatible("Incompatible suspendability") - checkIsInlineFlag && superMember.isInline -> return incompatible("Inline function can't be overridden") - - else -> { - superTypeParameters = superMember.typeParameters - subTypeParameters = subMember.typeParameters - superValueParameters = superMember.compiledValueParameters - subValueParameters = subMember.compiledValueParameters - } - } - is IrProperty -> when { - subMember !is IrProperty -> return incompatible("Member kind mismatch") - superMember.getter.hasExtensionReceiver != subMember.getter.hasExtensionReceiver -> return incompatible("Receiver presence mismatch") - checkIsInlineFlag && superMember.isInline -> return incompatible("Inline property can't be overridden") - - else -> { - superTypeParameters = superMember.typeParameters - subTypeParameters = subMember.typeParameters - superValueParameters = superMember.compiledValueParameters - subValueParameters = subMember.compiledValueParameters - } - } - else -> error("Unexpected type of declaration: ${superMember::class.java}, $superMember") - } - - when { - superMember.name != subMember.name -> { - // Check name after member kind checks. This way FO builder will first check types of overridable members and crash - // if member types are not supported (ex: IrConstructor). - return incompatible("Name mismatch") - } - - superTypeParameters.size != subTypeParameters.size -> return incompatible("Type parameter number mismatch") - superValueParameters.size != subValueParameters.size -> return incompatible("Value parameter number mismatch") - } - - // TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent() -// superTypeParameters.forEachIndexed { index, parameter -> -// if (!AbstractTypeChecker.areTypeParametersEquivalent( -// typeCheckerContext as AbstractTypeCheckerContext, -// subTypeParameters[index].type, -// parameter.type -// ) -// ) return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch") -// } - - val typeCheckerState = createIrTypeCheckerState( - IrTypeSystemContextWithAdditionalAxioms( - this, - superTypeParameters, - subTypeParameters - ) - ) - - superValueParameters.forEachIndexed { index, parameter -> - if (!AbstractTypeChecker.equalTypes( - typeCheckerState, - subValueParameters[index].type, - parameter.type - ) - ) return incompatible("Value parameter type mismatch") - } - - return success() -} - -private val IrSimpleFunction?.hasExtensionReceiver: Boolean - get() = this?.extensionReceiverParameter != null - -private val IrSimpleFunction?.hasDispatchReceiver: Boolean - get() = this?.dispatchReceiverParameter != null - -private val IrSimpleFunction.compiledValueParameters: List - get() = ArrayList(valueParameters.size + 1).apply { - extensionReceiverParameter?.let(::add) - addAll(valueParameters) - } - -private val IrProperty.compiledValueParameters: List - get() = getter?.extensionReceiverParameter?.let(::listOf).orEmpty() - -private val IrProperty.typeParameters: List - get() = getter?.typeParameters.orEmpty() - -private val IrProperty.isInline: Boolean - get() = getter?.isInline == true || setter?.isInline == true - private val IrOverridableMember.typeParameters: List get() = when (this) { is IrSimpleFunction -> typeParameters @@ -655,7 +521,7 @@ private val IrOverridableMember.typeParameters: List else -> error("Unexpected type of declaration: ${this::class.java}, $this") } -private val IrOverridableMember.returnType +private val IrOverridableMember.returnType: IrType get() = when (this) { is IrSimpleFunction -> returnType is IrProperty -> getter!!.returnType