[IR] Consider flexibility of the return type for intersection overrides

^KT-65207 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-02-16 09:38:26 +02:00
committed by Space Team
parent 9302c8c14d
commit 3c86a4f9df
4 changed files with 74 additions and 74 deletions
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.ir.util.isClass
import org.jetbrains.kotlin.ir.util.render
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
import org.jetbrains.kotlin.utils.memoryOptimizedMap
import org.jetbrains.kotlin.utils.memoryOptimizedMapNotNull
@@ -233,7 +232,6 @@ class IrFakeOverrideBuilder(
return member ?: error("Could not find a visible member")
}
private fun createAndBindFakeOverrides(
current: IrClass,
notOverridden: Collection<FakeOverride>,
@@ -242,9 +240,9 @@ class IrFakeOverrideBuilder(
) {
val fromSuper = notOverridden.toMutableSet()
while (fromSuper.isNotEmpty()) {
val notOverriddenFromSuper = findMemberWithMaxVisibility(filterOutCustomizedFakeOverrides(fromSuper))
val notOverriddenFromSuper = filterOutCustomizedFakeOverrides(fromSuper)
val overridables = extractMembersOverridableInBothWays(
notOverriddenFromSuper,
notOverriddenFromSuper.first(),
fromSuper
)
createAndBindFakeOverride(overridables, current, addedFakeOverrides, compatibilityMode)
@@ -367,73 +365,77 @@ class IrFakeOverrideBuilder(
strategy.postProcessGeneratedFakeOverride(fakeOverride, currentClass)
}
private fun isVisibilityMoreSpecific(
private fun isReturnTypeIsSubtypeOfOtherReturnType(
a: IrOverridableMember,
b: IrOverridableMember
): Boolean {
val result =
DescriptorVisibilities.compare(a.visibility, b.visibility)
return result == null || result >= 0
}
private fun isAccessorMoreSpecific(
a: IrSimpleFunction?,
b: IrSimpleFunction?
): Boolean {
return if (a == null || b == null) true else isVisibilityMoreSpecific(a, b)
}
private fun TypeCheckerState.isSubtypeOf(a: IrType, b: IrType) =
AbstractTypeChecker.isSubtypeOf(this, a, b)
private fun TypeCheckerState.equalTypes(a: IrType, b: IrType) =
AbstractTypeChecker.equalTypes(this, a, b)
private fun createTypeCheckerState(a: List<IrTypeParameter>, b: List<IrTypeParameter>): TypeCheckerState =
createIrTypeCheckerState(IrTypeSystemContextWithAdditionalAxioms(typeSystem, a, b))
private fun isReturnTypeMoreSpecific(
a: IrOverridableMember,
aReturnType: IrType,
b: IrOverridableMember,
bReturnType: IrType
): Boolean {
val typeCheckerState = createTypeCheckerState(a.typeParameters, b.typeParameters)
return typeCheckerState.isSubtypeOf(aReturnType, bReturnType)
val typeCheckerState = createIrTypeCheckerState(
IrTypeSystemContextWithAdditionalAxioms(typeSystem, a.typeParameters, b.typeParameters)
)
return AbstractTypeChecker.isSubtypeOf(typeCheckerState, a.returnType, b.returnType)
}
private fun isMoreSpecific(
a: IrOverridableMember,
b: IrOverridableMember
): Boolean {
val aReturnType = a.returnType
val bReturnType = b.returnType
if (!isVisibilityMoreSpecific(a, b)) return false
if (a is IrSimpleFunction) {
require(b is IrSimpleFunction) { "b is " + b.javaClass }
return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType)
return a > b
}
// Based on compareTo from FirOverrideService.kt
private operator fun IrOverridableMember.compareTo(other: IrOverridableMember): Int {
fun merge(preferA: Boolean, preferB: Boolean, previous: Int): Int = when {
preferA == preferB -> previous
preferA && previous >= 0 -> 1
preferB && previous <= 0 -> -1
else -> 0
}
if (a is IrProperty) {
require(b is IrProperty) { "b is " + b.javaClass }
if (!isAccessorMoreSpecific(
a.setter,
b.setter
)
) return false
return if (a.isVar && b.isVar) {
createTypeCheckerState(
a.getter!!.typeParameters,
b.getter!!.typeParameters
).equalTypes(aReturnType, bReturnType)
} else {
// both vals or var vs val: val can't be more specific then var
!(!a.isVar && b.isVar) && isReturnTypeMoreSpecific(
a, aReturnType,
b, bReturnType
val aIr = this@compareTo
val bIr = other
val byVisibility = DescriptorVisibilities.compare(aIr.visibility, bIr.visibility) ?: 0
val aReturnType = aIr.returnType
val bReturnType = bIr.returnType
val aSubtypesB = isReturnTypeIsSubtypeOfOtherReturnType(aIr, bIr)
val bSubtypesA = isReturnTypeIsSubtypeOfOtherReturnType(bIr, aIr)
val byVisibilityAndType = when {
// Could be that one of them is flexible, in which case the types are not equal but still subtypes of one another;
// make the inflexible one more specific.
aSubtypesB && bSubtypesA -> merge(!aReturnType.isFlexible(), !bReturnType.isFlexible(), byVisibility)
aSubtypesB && byVisibility >= 0 -> 1
bSubtypesA && byVisibility <= 0 -> -1
else -> 0
}
return when (aIr) {
is IrSimpleFunction -> byVisibilityAndType
is IrProperty -> {
require(bIr is IrProperty)
val settersComparison = if (aIr.isVar && bIr.isVar) {
val aSetter = aIr.setter
val bSetter = bIr.setter
when {
aSetter != null && bSetter != null -> aSetter.compareTo(bSetter)
else -> 0
}
} else {
0
}
val bySetters = merge(
preferA = settersComparison >= 0,
preferB = settersComparison <= 0,
byVisibilityAndType
)
merge(aIr.isVar, bIr.isVar, bySetters)
}
else -> error("Unexpected type: $aIr")
}
error("Unexpected callable: $a")
}
private fun IrType.isFlexible(): Boolean {
return with(typeSystem) { isFlexible() }
}
private fun isMoreSpecificThenAllOf(
@@ -450,9 +452,7 @@ class IrFakeOverrideBuilder(
return true
}
private fun selectMostSpecificMember(
overridables: Collection<FakeOverride>
): FakeOverride {
private fun selectMostSpecificMember(overridables: Collection<FakeOverride>): FakeOverride {
require(!overridables.isEmpty()) { "Should have at least one overridable member" }
if (overridables.size == 1) {
return overridables.first()
@@ -13,4 +13,4 @@ abstract class J {
abstract fun foo(): Child
}
abstract class A : I, J()
abstract class A : I, J()
@@ -7,22 +7,22 @@ FILE fqName:<root> fileName:/1.kt
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () declared in <root>.Java1'
<T>: R of <root>.C
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:ABSTRACT visibility:public superTypes:[<root>.Java1<R of <root>.C>; <root>.KotlinInterface<R of <root>.C>]'
FUN FAKE_OVERRIDE name:bar visibility:public modality:OPEN <> ($this:<root>.Java1<R of <root>.C>) returnType:@[FlexibleNullability] java.util.ArrayList<@[FlexibleNullability] kotlin.Int?>? [fake_override]
FUN FAKE_OVERRIDE name:bar visibility:public modality:OPEN <> ($this:<root>.KotlinInterface<R of <root>.C>) returnType:java.util.ArrayList<kotlin.Int> [fake_override]
overridden:
public open fun bar (): @[FlexibleNullability] java.util.ArrayList<@[FlexibleNullability] kotlin.Int?>? declared in <root>.Java1
public abstract fun bar (): java.util.ArrayList<kotlin.Int> declared in <root>.KotlinInterface
$this: VALUE_PARAMETER name:<this> type:<root>.Java1<R of <root>.C>
$this: VALUE_PARAMETER name:<this> type:<root>.KotlinInterface<R of <root>.C>
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in <root>.Java1
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in <root>.KotlinInterface
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:foo visibility:public modality:OPEN <> ($this:<root>.Java1<R of <root>.C>) returnType:@[FlexibleNullability] R of <root>.C? [fake_override]
FUN FAKE_OVERRIDE name:foo visibility:public modality:OPEN <> ($this:<root>.KotlinInterface<R of <root>.C>) returnType:R of <root>.C [fake_override]
overridden:
public open fun foo (): @[FlexibleNullability] T of <root>.Java1? declared in <root>.Java1
public abstract fun foo (): T of <root>.KotlinInterface declared in <root>.KotlinInterface
$this: VALUE_PARAMETER name:<this> type:<root>.Java1<R of <root>.C>
$this: VALUE_PARAMETER name:<this> type:<root>.KotlinInterface<R of <root>.C>
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in <root>.Java1
@@ -9,16 +9,16 @@ abstract class C<R : Any?> : Java1<R>, KotlinInterface<R> {
constructor() /* primary */
// CHECK JVM_IR:
// Mangled name: C#bar(){}java.util.ArrayList<kotlin.Int?>?
// Public signature: /C.bar|6344786471503787921[0]
// Public signature debug description: bar(){}java.util.ArrayList<kotlin.Int?>?
/* fake */ override fun bar(): ArrayList<Int?>?
// Mangled name: C#bar(){}java.util.ArrayList<kotlin.Int>
// Public signature: /C.bar|3123552224271008170[0]
// Public signature debug description: bar(){}java.util.ArrayList<kotlin.Int>
/* fake */ override fun bar(): ArrayList<Int>
// CHECK JVM_IR:
// Mangled name: C#foo(){}1:0?
// Public signature: /C.foo|-1179576840814333363[0]
// Public signature debug description: foo(){}1:0?
/* fake */ override fun foo(): R?
// Mangled name: C#foo(){}1:0
// Public signature: /C.foo|-5478580208809996038[0]
// Public signature debug description: foo(){}1:0
/* fake */ override fun foo(): R
}