[IR Actualizer] Fix fake-override generation in actual A -> common B -> actual C hierarchy

...  where C defines a member x and A overrides the member x

#KT-61166 Fixed
This commit is contained in:
Kirill Rakhman
2023-08-29 16:32:32 +02:00
committed by Space Team
parent 293474ee50
commit ac102dedac
10 changed files with 155 additions and 72 deletions
@@ -11,6 +11,7 @@ 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.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil
/**
* It adds fake overrides to non-expect classes inside common or multi-platform module,
@@ -79,6 +81,32 @@ internal class ActualFakeOverridesAdder(
) {
for (symbolFromSupertype in membersFromSupertype) {
val memberFromSupertype = symbolFromSupertype.owner as IrDeclaration
if (memberFromSupertype is IrOverridableMember) {
// We can land here because of a hierarchy like
// actual A -> common B -> actual C
// where C defines a member x and A overrides the member x.
// We will first add a fake-override x to B and then land here.
// In this case we don't want to add a fake-override on top of the real override to A.
// Instead, we add the fake-override x to the overridden symbols of A.x.
@Suppress("UNCHECKED_CAST")
val override = klass.declarations.firstOrNull {
it is IrOverridableMember &&
typeSystemContext.isOverridableByWithoutExternalConditions(
superMember = memberFromSupertype,
subMember = it,
checkIsInlineFlag = false,
checkReturnType = false
).result == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
} as? IrOverridableDeclaration<IrSymbol>
if (override != null) {
override.overriddenSymbols += symbolFromSupertype
continue
}
}
val newMember = createFakeOverrideMember(listOf(memberFromSupertype), klass)
val matchingFakeOverrides = collectActualCallablesMatchingToSpecificExpect(
newMember.symbol,
@@ -627,63 +627,64 @@ class IrOverridingUtil(
checkIsInlineFlag: Boolean,
checkReturnType: Boolean
): OverrideCompatibilityInfo {
return isOverridableByWithoutExternalConditions(superMember, subMember, checkIsInlineFlag, checkReturnType)
return typeSystem.isOverridableByWithoutExternalConditions(superMember, subMember, checkIsInlineFlag, checkReturnType)
// The frontend goes into external overridability condition details here, but don't deal with them in IR (yet?).
}
}
private fun isOverridableByWithoutExternalConditions(
superMember: IrOverridableMember,
subMember: IrOverridableMember,
checkIsInlineFlag: Boolean,
checkReturnType: Boolean
): OverrideCompatibilityInfo {
val superTypeParameters: List<IrTypeParameter>
val subTypeParameters: List<IrTypeParameter>
fun IrTypeSystemContext.isOverridableByWithoutExternalConditions(
superMember: IrOverridableMember,
subMember: IrOverridableMember,
checkIsInlineFlag: Boolean,
checkReturnType: Boolean
): OverrideCompatibilityInfo {
val superTypeParameters: List<IrTypeParameter>
val subTypeParameters: List<IrTypeParameter>
val superValueParameters: List<IrValueParameter>
val subValueParameters: List<IrValueParameter>
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")
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
}
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")
}
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 -> {
superTypeParameters = superMember.typeParameters
subTypeParameters = subMember.typeParameters
superValueParameters = superMember.compiledValueParameters
subValueParameters = subMember.compiledValueParameters
}
else -> error("Unexpected type of declaration: ${superMember::class.java}, $superMember")
}
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")
}
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")
}
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()
// TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent()
// superTypeParameters.forEachIndexed { index, parameter ->
// if (!AbstractTypeChecker.areTypeParametersEquivalent(
// typeCheckerContext as AbstractTypeCheckerContext,
@@ -693,34 +694,33 @@ class IrOverridingUtil(
// ) return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch")
// }
val typeCheckerState = createIrTypeCheckerState(
IrTypeSystemContextWithAdditionalAxioms(
typeSystem,
superTypeParameters,
subTypeParameters
)
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")
}
if (checkReturnType) {
if (!AbstractTypeChecker.isSubtypeOf(
typeCheckerState,
subMember.returnType,
superMember.returnType
)
) return conflict("Return type mismatch")
}
return success()
superValueParameters.forEachIndexed { index, parameter ->
if (!AbstractTypeChecker.equalTypes(
typeCheckerState,
subValueParameters[index].type,
parameter.type
)
) return incompatible("Value parameter type mismatch")
}
if (checkReturnType) {
if (!AbstractTypeChecker.isSubtypeOf(
typeCheckerState,
subMember.returnType,
superMember.returnType
)
) return conflict("Return type mismatch")
}
return success()
}
private val IrSimpleFunction?.hasExtensionReceiver: Boolean