IR: extract IrOverrideChecker to separate file
This commit is contained in:
+3
-3
@@ -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<IrClass, FakeOverrideInfo>()
|
||||
|
||||
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,
|
||||
|
||||
@@ -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<IrTypeParameter>
|
||||
val subTypeParameters: List<IrTypeParameter>
|
||||
|
||||
val superValueParameters: List<IrValueParameter>
|
||||
val subValueParameters: List<IrValueParameter>
|
||||
|
||||
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<IrValueParameter>
|
||||
get() = ArrayList<IrValueParameter>(valueParameters.size + 1).apply {
|
||||
extensionReceiverParameter?.let(::add)
|
||||
addAll(valueParameters)
|
||||
}
|
||||
|
||||
private val IrProperty.compiledValueParameters: List<IrValueParameter>
|
||||
get() = getter?.extensionReceiverParameter?.let(::listOf).orEmpty()
|
||||
|
||||
private val IrProperty.typeParameters: List<IrTypeParameter>
|
||||
get() = getter?.typeParameters.orEmpty()
|
||||
|
||||
private val IrProperty.isInline: Boolean
|
||||
get() = getter?.isInline == true || setter?.isInline == true
|
||||
@@ -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<IrOverridableMember, IrOverridableMember>()
|
||||
private val IrOverridableMember.original get() = originals[this] ?: error("No original for ${this.render()}")
|
||||
private val originalSuperTypes = mutableMapOf<IrOverridableMember, IrType>()
|
||||
@@ -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<IrTypeParameter>
|
||||
val subTypeParameters: List<IrTypeParameter>
|
||||
|
||||
val superValueParameters: List<IrValueParameter>
|
||||
val subValueParameters: List<IrValueParameter>
|
||||
|
||||
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<IrValueParameter>
|
||||
get() = ArrayList<IrValueParameter>(valueParameters.size + 1).apply {
|
||||
extensionReceiverParameter?.let(::add)
|
||||
addAll(valueParameters)
|
||||
}
|
||||
|
||||
private val IrProperty.compiledValueParameters: List<IrValueParameter>
|
||||
get() = getter?.extensionReceiverParameter?.let(::listOf).orEmpty()
|
||||
|
||||
private val IrProperty.typeParameters: List<IrTypeParameter>
|
||||
get() = getter?.typeParameters.orEmpty()
|
||||
|
||||
private val IrProperty.isInline: Boolean
|
||||
get() = getter?.isInline == true || setter?.isInline == true
|
||||
|
||||
private val IrOverridableMember.typeParameters: List<IrTypeParameter>
|
||||
get() = when (this) {
|
||||
is IrSimpleFunction -> typeParameters
|
||||
@@ -655,7 +521,7 @@ private val IrOverridableMember.typeParameters: List<IrTypeParameter>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user