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.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendErrors
|
import org.jetbrains.kotlin.backend.common.CommonBackendErrors
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||||
@@ -38,6 +37,7 @@ internal class ActualFakeOverridesAdder(
|
|||||||
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext,
|
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext,
|
||||||
private val typeSystemContext: IrTypeSystemContext
|
private val typeSystemContext: IrTypeSystemContext
|
||||||
) : IrElementVisitorVoid {
|
) : IrElementVisitorVoid {
|
||||||
|
private val overrideChecker = IrOverrideChecker(typeSystemContext)
|
||||||
private val missingActualMembersMap = mutableMapOf<IrClass, FakeOverrideInfo>()
|
private val missingActualMembersMap = mutableMapOf<IrClass, FakeOverrideInfo>()
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
override fun visitClass(declaration: IrClass) {
|
||||||
@@ -93,7 +93,7 @@ internal class ActualFakeOverridesAdder(
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val override = klass.declarations.firstOrNull {
|
val override = klass.declarations.firstOrNull {
|
||||||
it is IrOverridableMember &&
|
it is IrOverridableMember &&
|
||||||
typeSystemContext.isOverridableByWithoutExternalConditions(
|
overrideChecker.isOverridableByWithoutExternalConditions(
|
||||||
superMember = memberFromSupertype,
|
superMember = memberFromSupertype,
|
||||||
subMember = it,
|
subMember = it,
|
||||||
checkIsInlineFlag = false,
|
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.isReal
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
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.resolve.OverridingUtil.OverrideCompatibilityInfo.*
|
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||||
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
|
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
|
||||||
@@ -36,6 +35,7 @@ class IrOverridingUtil(
|
|||||||
private val typeSystem: IrTypeSystemContext,
|
private val typeSystem: IrTypeSystemContext,
|
||||||
private val fakeOverrideBuilder: FakeOverrideBuilderStrategy
|
private val fakeOverrideBuilder: FakeOverrideBuilderStrategy
|
||||||
) {
|
) {
|
||||||
|
private val overrideChecker = IrOverrideChecker(typeSystem)
|
||||||
private val originals = mutableMapOf<IrOverridableMember, IrOverridableMember>()
|
private val originals = mutableMapOf<IrOverridableMember, IrOverridableMember>()
|
||||||
private val IrOverridableMember.original get() = originals[this] ?: error("No original for ${this.render()}")
|
private val IrOverridableMember.original get() = originals[this] ?: error("No original for ${this.render()}")
|
||||||
private val originalSuperTypes = mutableMapOf<IrOverridableMember, IrType>()
|
private val originalSuperTypes = mutableMapOf<IrOverridableMember, IrType>()
|
||||||
@@ -166,7 +166,7 @@ class IrOverridingUtil(
|
|||||||
|
|
||||||
for (fromSupertype in descriptorsFromSuper) {
|
for (fromSupertype in descriptorsFromSuper) {
|
||||||
// Note: We do allow overriding multiple FOs at once one of which is `isInline=true`.
|
// 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 -> {
|
OverrideCompatibilityInfo.Result.OVERRIDABLE -> {
|
||||||
val isVisibleFake = fromSupertype.visibility != DescriptorVisibilities.INVISIBLE_FAKE
|
val isVisibleFake = fromSupertype.visibility != DescriptorVisibilities.INVISIBLE_FAKE
|
||||||
if (isVisibleFake && isVisibleForOverride(fromCurrent, fromSupertype.original))
|
if (isVisibleFake && isVisibleForOverride(fromCurrent, fromSupertype.original))
|
||||||
@@ -502,11 +502,7 @@ class IrOverridingUtil(
|
|||||||
iterator.remove()
|
iterator.remove()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val finalResult =
|
val finalResult = overrideChecker.getBothWaysOverridability(overrider, candidate)
|
||||||
getBothWaysOverridability(
|
|
||||||
overrider,
|
|
||||||
candidate
|
|
||||||
)
|
|
||||||
if (finalResult == OverrideCompatibilityInfo.Result.OVERRIDABLE) {
|
if (finalResult == OverrideCompatibilityInfo.Result.OVERRIDABLE) {
|
||||||
overridable.add(candidate)
|
overridable.add(candidate)
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
@@ -516,138 +512,8 @@ class IrOverridingUtil(
|
|||||||
}
|
}
|
||||||
return overridable
|
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>
|
private val IrOverridableMember.typeParameters: List<IrTypeParameter>
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is IrSimpleFunction -> typeParameters
|
is IrSimpleFunction -> typeParameters
|
||||||
@@ -655,7 +521,7 @@ private val IrOverridableMember.typeParameters: List<IrTypeParameter>
|
|||||||
else -> error("Unexpected type of declaration: ${this::class.java}, $this")
|
else -> error("Unexpected type of declaration: ${this::class.java}, $this")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrOverridableMember.returnType
|
private val IrOverridableMember.returnType: IrType
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is IrSimpleFunction -> returnType
|
is IrSimpleFunction -> returnType
|
||||||
is IrProperty -> getter!!.returnType
|
is IrProperty -> getter!!.returnType
|
||||||
|
|||||||
Reference in New Issue
Block a user