[PL] Special handling of function references produced by FIR
This commit is contained in:
committed by
Space Team
parent
85b5a4521e
commit
850879375a
+23
-1
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
@@ -716,7 +717,28 @@ internal class PartiallyLinkedIrTreePatcher(
|
||||
val actualDispatchReceiverClassifier: IrClassifierSymbol? =
|
||||
(referenceType.arguments.firstOrNull() as? IrSimpleType)?.classifier
|
||||
|
||||
expectedDispatchReceiverClassifier == actualDispatchReceiverClassifier
|
||||
/*
|
||||
* FIR generates function references for certain overridden functions in a different way than K1. Example:
|
||||
* class A
|
||||
*
|
||||
* fun test(a: A): Boolean {
|
||||
* return (A::equals)(a, a)
|
||||
* // ^^^ IrFunctionReferenceImpl slightly differs:
|
||||
* // | Frontend | Attribute | Value |
|
||||
* // +----------+--------------------------+--------------------------------+
|
||||
* // | K1 | dispatchReceiver | null |
|
||||
* // | K1 | symbol.parent as IrClass | "class A" |
|
||||
* // | K1 | type as IrSimpleType | "KFunction2<A, Any?, Boolean>" |
|
||||
* // | FIR | dispatchReceiver | null |
|
||||
* // | FIR | symbol.parent as IrClass | "class Any" |
|
||||
* // | FIR | type as IrSimpleType | "KFunction2<A, Any?, Boolean>" |
|
||||
* }
|
||||
*
|
||||
* So instead of checking that `expectedDispatchReceiverClassifier == actualDispatchReceiverClassifier` it's
|
||||
* safer to check that `actualDispatchReceiverClassifier` is the same or subclass of `expectedDispatchReceiverClassifier`.
|
||||
*/
|
||||
// expectedDispatchReceiverClassifier == actualDispatchReceiverClassifier
|
||||
actualDispatchReceiverClassifier?.isSubtypeOfClass(expectedDispatchReceiverClassifier) ?: false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
@@ -72,3 +72,19 @@ fun referenceFunctionWithRemovedTypeParameter(): String {
|
||||
*/
|
||||
return listOf<Any?>(null).map<Any?, RemovedClassImpl>(::functionWithRemovedTypeParameter).joinToString()
|
||||
}
|
||||
|
||||
abstract class StableAbstractFunctionsHolder {
|
||||
abstract fun foo(): String
|
||||
open fun bar(): String = "bar"
|
||||
}
|
||||
class StableFunctionsHolder: StableAbstractFunctionsHolder() {
|
||||
override fun foo(): String = "foo"
|
||||
fun baz(): String = "baz"
|
||||
}
|
||||
data class StableClassWithEquals(val value: Int)
|
||||
|
||||
fun referencingMemberFunctionFoo(sfh: StableFunctionsHolder): String = run(sfh::foo)
|
||||
fun referencingMemberFunctionBar(sfh: StableFunctionsHolder): String = run(sfh::bar)
|
||||
fun referencingMemberFunctionBaz(sfh: StableFunctionsHolder): String = run(sfh::baz)
|
||||
fun referencingAnyEquals(any: Any): String = if ((Any::equals)(any, any)) "OK" else "FAIL"
|
||||
fun referencingStableClassWithEquals(stwe: StableClassWithEquals): String = if ((StableClassWithEquals::equals)(stwe, stwe)) "OK" else "FAIL"
|
||||
|
||||
@@ -3,6 +3,7 @@ import abitestutils.abiTest
|
||||
fun box() = abiTest {
|
||||
val stableClass = StableClass()
|
||||
val stableClassInner = stableClass.Inner()
|
||||
val sfh = StableFunctionsHolder()
|
||||
|
||||
expectFailure(linkage("Reference to class 'RemovedClass' can not be evaluated: No class found for symbol '/RemovedClass'")) { referenceRemovedClassReference() }
|
||||
expectFailure(linkage("Reference to constructor 'RemovedClass.<init>' can not be evaluated: No constructor found for symbol '/RemovedClass.<init>'")) { referenceRemovedClassConstructorReference() }
|
||||
@@ -46,4 +47,10 @@ fun box() = abiTest {
|
||||
expectFailure(linkage("Reference to function 'functionWithUnlinkedParameter' can not be evaluated: Function uses unlinked class symbol '/RemovedClass'")) { referenceFunctionWithUnlinkedParameter() }
|
||||
expectFailure(linkage("Reference to function 'functionWithUnlinkedReturnValue' can not be evaluated: Function uses unlinked class symbol '/RemovedClass'")) { referenceFunctionWithUnlinkedReturnValue() }
|
||||
expectFailure(linkage("Reference to function 'functionWithRemovedTypeParameter' can not be evaluated: Function uses unlinked class symbol '/RemovedClass' (via type parameter 'T')")) { referenceFunctionWithRemovedTypeParameter() }
|
||||
|
||||
expectSuccess("foo") { referencingMemberFunctionFoo(sfh) }
|
||||
expectSuccess("bar") { referencingMemberFunctionBar(sfh) }
|
||||
expectSuccess("baz") { referencingMemberFunctionBaz(sfh) }
|
||||
expectSuccess { referencingAnyEquals(Any()) }
|
||||
expectSuccess { referencingStableClassWithEquals(StableClassWithEquals(42)) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user