From 74cbc01a04fd7b6a092d3428ada254fdb22a762b Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Wed, 6 May 2020 12:08:51 +0300 Subject: [PATCH] =?UTF-8?q?Avoid=20duplicated=20selectors=20when=20Kotlin?= =?UTF-8?q?=20class=20inherits=20from=20muliple=20ba=E2=80=A6=20(#4145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: RuntimeAssert in AddMethods (ObjCInterop.mm) when kotlin class overrides the same selector from multiple bases, e.g. from the base objc class and a protocol(s). --- .../kotlin/backend/konan/lower/InteropLowering.kt | 6 ++++-- .../tests/interop/objc/tests/KT38234_override.h | 9 +++++++++ .../tests/interop/objc/tests/KT38234_override.kt | 10 ++++++++++ .../tests/interop/objc/tests/KT38234_override.m | 10 ++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 backend.native/tests/interop/objc/tests/KT38234_override.h create mode 100644 backend.native/tests/interop/objc/tests/KT38234_override.kt create mode 100644 backend.native/tests/interop/objc/tests/KT38234_override.m diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index dc237d76ed7..183ddbd285e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -864,12 +864,14 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi override fun visitClass(declaration: IrClass): IrStatement { super.visitClass(declaration) if (declaration.isKotlinObjCClass()) { + val uniq = mutableSetOf() // remove duplicates [KT-38234] val imps = declaration.simpleFunctions().filter { it.isReal }.flatMap { function -> function.overriddenSymbols.mapNotNull { - val info = it.owner.getExternalObjCMethodInfo() - if (info == null) { + val selector = it.owner.getExternalObjCMethodInfo()?.selector + if (selector == null || selector in uniq) { null } else { + uniq += selector generateWithStubs(it.owner) { generateCFunctionAndFakeKotlinExternalFunction( function, diff --git a/backend.native/tests/interop/objc/tests/KT38234_override.h b/backend.native/tests/interop/objc/tests/KT38234_override.h new file mode 100644 index 00000000000..8a1561d8513 --- /dev/null +++ b/backend.native/tests/interop/objc/tests/KT38234_override.h @@ -0,0 +1,9 @@ +#import + +@protocol KT38234_P1 +-(int)foo; +@end; + +@interface KT38234_Base : NSObject +-(int)callFoo; +@end; diff --git a/backend.native/tests/interop/objc/tests/KT38234_override.kt b/backend.native/tests/interop/objc/tests/KT38234_override.kt new file mode 100644 index 00000000000..5e5ea4c5b1b --- /dev/null +++ b/backend.native/tests/interop/objc/tests/KT38234_override.kt @@ -0,0 +1,10 @@ +import kotlin.test.* +import objcTests.* + +class KT38234_Impl : KT38234_P1Protocol, KT38234_Base() { + override fun foo(): Int = 566 +} + +@Test fun testKT38234() { + assertEquals(566, KT38234_Impl().callFoo()) +} diff --git a/backend.native/tests/interop/objc/tests/KT38234_override.m b/backend.native/tests/interop/objc/tests/KT38234_override.m new file mode 100644 index 00000000000..675baa38af0 --- /dev/null +++ b/backend.native/tests/interop/objc/tests/KT38234_override.m @@ -0,0 +1,10 @@ +#include "KT38234_override.h" + +@implementation KT38234_Base +-(int)foo { + return 1; +} +-(int)callFoo { + return [self foo]; +} +@end;