From 5f224cf0b24c4103ad049d9796ad435dab5e2b2f Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Tue, 14 May 2019 14:42:40 +0300 Subject: [PATCH] Support nullable string return type in reverse C interop. (#2967) --- backend.native/tests/build.gradle | 8 ++++---- .../tests/produce_dynamic/simple/hello.kt | 15 ++++++++++++--- .../tests/produce_dynamic/simple/main.c | 13 +++++++++---- runtime/src/main/cpp/KString.cpp | 2 ++ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 1c10a9f7eea..d4aec0d9925 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -3285,12 +3285,12 @@ task produce_dynamic(type: DynamicKonanTest) { cSource = "$projectDir/produce_dynamic/simple/main.c" goldValue = "Hello, dynamic!\n" + "Base.foo\n" + - "Base.fooParam: a 1\n" + - "Child.fooParam: b 2\n" + - "Child.fooParam: c 3\n" + + "Base.fooParam: a 1 q\n" + + "Child.fooParam: b 2 null\n" + + "Child.fooParam: c 3 null\n" + "Impl1.I: d 4 Impl1\n" + "Impl2.I: e 5 Impl2\n" + - "String is Kotlin/Native\n" + + "String is Kotlin/Native nullable is Hi null is OK\n" + "RO property is 42\n" + "RW property is 239\n" + "enum100 = 100\n" + diff --git a/backend.native/tests/produce_dynamic/simple/hello.kt b/backend.native/tests/produce_dynamic/simple/hello.kt index acb33e61222..9fd8d5e80f8 100644 --- a/backend.native/tests/produce_dynamic/simple/hello.kt +++ b/backend.native/tests/produce_dynamic/simple/hello.kt @@ -23,7 +23,8 @@ fun getMutable() = Data("foo") open class Base { open fun foo() = println("Base.foo") - open fun fooParam(arg0: String, arg1: Int) = println("Base.fooParam: $arg0 $arg1") + open fun fooParam(arg0: String, arg1: Int, arg2: String?) = + println("Base.fooParam: $arg0 $arg1 ${arg2 ?: "null"}") @CName(externName = "", shortName = "strangeName") fun странноеИмя() = 111 @@ -60,7 +61,8 @@ object Singleton { } class Child : Base() { - override fun fooParam(arg0: String, arg1: Int) = println("Child.fooParam: $arg0 $arg1") + override fun fooParam(arg0: String, arg1: Int, arg2: String?) = + println("Child.fooParam: $arg0 $arg1 ${arg2 ?: "null"}") val roProperty: Int get() = 42 @@ -97,7 +99,6 @@ fun useInlineClasses(ic1: IC1, ic2: IC2, ic3: IC3) { assert(ic2.value == "bar") assert(ic3.value is Base) } - fun setCErrorHandler(callback: CPointer) -> Unit>>?) { setUnhandledExceptionHook({ throwable: Throwable -> @@ -111,3 +112,11 @@ fun setCErrorHandler(callback: CPointer) -> Unit>>? fun throwException() { throw Error("Expected error") } + +fun getNullableString(param: Int) : String? { + if (param == 0) { + return "Hi" + } else { + return null + } +} \ No newline at end of file diff --git a/backend.native/tests/produce_dynamic/simple/main.c b/backend.native/tests/produce_dynamic/simple/main.c index f060aa88013..36816932d92 100644 --- a/backend.native/tests/produce_dynamic/simple/main.c +++ b/backend.native/tests/produce_dynamic/simple/main.c @@ -25,16 +25,19 @@ int main(void) { const char* string1 = __ kotlin.root.getString(); const char* string2 = __ kotlin.root.Singleton.toString(singleton); const char* string3 = __ kotlin.root.Data.get_string(data); + const char* string4 = __ kotlin.root.getNullableString(0); + const char* string5 = __ kotlin.root.getNullableString(1); __ kotlin.root.hello(); __ kotlin.root.Base.foo(base); - __ kotlin.root.Base.fooParam(base, "a", 1); - __ kotlin.root.Child.fooParam(child, "b", 2); - __ kotlin.root.Base.fooParam(casted_child, "c", 3); + __ kotlin.root.Base.fooParam(base, "a", 1, "q"); + __ kotlin.root.Child.fooParam(child, "b", 2, (char*)0); + __ kotlin.root.Base.fooParam(casted_child, "c", 3, (char*)0); __ kotlin.root.I.foo(casted_impl1, "d", 4, casted_impl1); __ kotlin.root.I.foo(casted_impl2, "e", 5, casted_impl2); - printf("String is %s\n", string1); + printf("String is %s nullable is %s null is %s\n", string1, string4, + string5 ? "BAD" : "OK"); printf("RO property is %d\n", __ kotlin.root.Child.get_roProperty(child)); __ kotlin.root.Child.set_rwProperty(child, 238); @@ -58,6 +61,8 @@ int main(void) { __ DisposeString(string1); __ DisposeString(string2); __ DisposeString(string3); + __ DisposeString(string4); + __ DisposeString(string5); __ DisposeStablePointer(base.pinned); __ DisposeStablePointer(child.pinned); __ DisposeStablePointer(impl1.pinned); diff --git a/runtime/src/main/cpp/KString.cpp b/runtime/src/main/cpp/KString.cpp index 57bb4f730b2..56a7b06c45a 100644 --- a/runtime/src/main/cpp/KString.cpp +++ b/runtime/src/main/cpp/KString.cpp @@ -41,6 +41,7 @@ KStdStringInserter utf16toUtf8OrThrow(const KChar* start, const KChar* end, KStd template OBJ_GETTER(utf8ToUtf16Impl, const char* rawString, const char* end, uint32_t charCount) { + if (rawString == nullptr) RETURN_OBJ(nullptr); ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, charCount, OBJ_RESULT)->array(); KChar* rawResult = CharArrayAddressOfElementAt(result, 0); auto convertResult = conversion(rawString, end, rawResult); @@ -712,6 +713,7 @@ OBJ_GETTER(CreateStringFromUtf8, const char* utf8, uint32_t lengthBytes) { } char* CreateCStringFromString(KConstRef kref) { + if (kref == nullptr) return nullptr; KString kstring = kref->array(); const KChar* utf16 = CharArrayAddressOfElementAt(kstring, 0); KStdString utf8;