[K/N] Fix equality on fun-interface constructor references

^KT-50204
This commit is contained in:
Pavel Kunyavskiy
2022-01-11 15:36:50 +03:00
committed by Space
parent a378e1e128
commit afc548d5d9
3 changed files with 22 additions and 22 deletions
@@ -6,20 +6,18 @@
// IGNORE_BACKEND: WASM // IGNORE_BACKEND: WASM
// ^ wasm-function[1893]:0x1cf8a: RuntimeError: dereferencing a null pointer // ^ wasm-function[1893]:0x1cf8a: RuntimeError: dereferencing a null pointer
// IGNORE_BACKEND: NATIVE
// ^ Fail due to the initialization order. Doesn't fail with new MM
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// ^ TypeError: tmp is not a function // ^ TypeError: tmp is not a function
// FILE: funInterfaceConstructorEquality.kt // FILE: funInterfaceConstructedObjectsEquality.kt
val ks1: (() -> String) -> KSupplier<String> = val ks1: (() -> String) -> KSupplier<String> =
::KSupplier ::KSupplier
val ks11Foo = ks1(::foo) val ks11Foo = ks1(::foo)
val ks21Foo = ks2(::foo) // getter is used to avoid dependency on lazy initialization support
val ks21Foo get() = ks2(::foo)
fun interface KStringSupplier { fun interface KStringSupplier {
fun get(): String fun get(): String
@@ -71,5 +69,5 @@ fun bar() = "def"
val ks2: (() -> String) -> KSupplier<String> = val ks2: (() -> String) -> KSupplier<String> =
::KSupplier ::KSupplier
val ks12Foo = ks1(::foo) val ks12Foo get() = ks1(::foo)
val ks22Foo = ks2(::foo) val ks22Foo = ks2(::foo)
@@ -6,9 +6,6 @@
// IGNORE_BACKEND: WASM // IGNORE_BACKEND: WASM
// ^ Failed: ks1 != ks2 (same file, same SAM type) // ^ Failed: ks1 != ks2 (same file, same SAM type)
// IGNORE_BACKEND: NATIVE
// ^ Fail due to the initialization order. Doesn't fail with new MM
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// ^ Failed: ks1 != ks2 (same file, same SAM type) // ^ Failed: ks1 != ks2 (same file, same SAM type)
@@ -318,7 +318,7 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
val name = ((functionReferenceTarget as? IrSimpleFunction)?.attributeOwnerId as? IrSimpleFunction)?.name val name = ((functionReferenceTarget as? IrSimpleFunction)?.attributeOwnerId as? IrSimpleFunction)?.name
?: functionReferenceTarget.name ?: functionReferenceTarget.name
addOverride("computeName") { irString(name.asString()) } addOverride("computeName") { irString(name.asString()) }
addOverride("computeFqName") { irString(functionReferenceTarget.computeFullName()) } addOverride("computeFqName") { irString(getFqName()) }
listOfNotNull( listOfNotNull(
@@ -390,22 +390,27 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
return BuiltFunctionReference(clazz, expression) return BuiltFunctionReference(clazz, expression)
} }
// this value is used only for hashCode and equals, to distinguish different wrappers on same functions
private fun getFlags() = private fun getFlags() =
(if (referencedFunction.isSuspend) 1 else 0) + getAdaptedCallableReferenceFlags() shl 1 listOfNotNull(
(1 shl 0).takeIf { referencedFunction.isSuspend },
(1 shl 1).takeIf { hasVarargMappedToElement() },
(1 shl 2).takeIf { adaptedReferenceOriginalTarget?.isSuspend == false && referencedFunction.isSuspend },
(1 shl 3).takeIf { isCoercedToUnit() },
(1 shl 4).takeIf { isFunInterfaceConstructorAdapter() }
).sum()
private fun getAdaptedCallableReferenceFlags(): Int { private fun getFqName() =
if (adaptedReferenceOriginalTarget == null) return 0 if (isFunInterfaceConstructorAdapter())
referencedFunction.returnType.getClass()!!.fqNameForIrSerialization.toString()
else
functionReferenceTarget.computeFullName()
val isVarargMappedToElementBit = if (hasVarargMappedToElement()) 1 else 0 private fun isFunInterfaceConstructorAdapter() =
val isSuspendConvertedBit = referencedFunction.origin == IrDeclarationOrigin.ADAPTER_FOR_FUN_INTERFACE_CONSTRUCTOR
if (!adaptedReferenceOriginalTarget.isSuspend && referencedFunction.isSuspend) 1 else 0
val isCoercedToUnitBit =
if (!adaptedReferenceOriginalTarget.returnType.isUnit() && referencedFunction.returnType.isUnit()) 1 else 0
return isVarargMappedToElementBit + private fun isCoercedToUnit() =
(isSuspendConvertedBit shl 1) + adaptedReferenceOriginalTarget?.returnType?.isUnit() == true && referencedFunction.returnType.isUnit()
(isCoercedToUnitBit shl 2)
}
private fun hasVarargMappedToElement(): Boolean { private fun hasVarargMappedToElement(): Boolean {
if (adaptedReferenceOriginalTarget == null) return false if (adaptedReferenceOriginalTarget == null) return false