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