From 04e81401622569955f1d7bb2e5dd49c39ef60c44 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 22 Jun 2021 16:12:37 +0000 Subject: [PATCH] Native: emit _Nullable_result attribute when generating Objective-C header ^KT-47042 Fixed --- .../objcexport/ObjCExportHeaderGenerator.kt | 15 ++++++++++++++- .../kotlin/backend/konan/objcexport/objcTypes.kt | 16 +++++++++------- .../tests/objcexport/expectedLazy.h | 12 ++++++------ .../tests/objcexport/expectedLazyNoGenerics.h | 12 ++++++------ 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt index 12022bfa701..30e224c5994 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt @@ -654,10 +654,14 @@ internal class ObjCExportTranslatorImpl( ObjCPointerType(ObjCNullableReferenceType(ObjCClassType("NSError")), nullable = true) MethodBridgeValueParameter.SuspendCompletion -> { + val resultType = when (val it = mapReferenceType(method.returnType!!, objCExportScope)) { + is ObjCNonNullReferenceType -> ObjCNullableReferenceType(it, isNullableResult = false) + is ObjCNullableReferenceType -> ObjCNullableReferenceType(it.nonNullType, isNullableResult = true) + } ObjCBlockPointerType( returnType = ObjCVoidType, parameterTypes = listOf( - mapReferenceType(method.returnType!!, objCExportScope).makeNullable(), + resultType, ObjCNullableReferenceType(ObjCClassType("NSError")) ) ) @@ -1049,11 +1053,20 @@ abstract class ObjCExportHeaderGenerator internal constructor( } add("") + // If _Nullable_result is not supported, then use _Nullable: + add("#pragma push_macro(\"$objcNullableResultAttribute\")") + add("#if !__has_feature(nullability_nullable_result)") + add("#undef $objcNullableResultAttribute") + add("#define $objcNullableResultAttribute $objcNullableAttribute") + add("#endif") + add("") + stubs.forEach { addAll(StubRenderer.render(it, shouldExportKDoc)) add("") } + add("#pragma pop_macro(\"$objcNullableResultAttribute\")") add("#pragma clang diagnostic pop") add("NS_ASSUME_NONNULL_END") } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt index 65376d18a94..ff524a98873 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt @@ -30,9 +30,13 @@ sealed class ObjCReferenceType : ObjCType() sealed class ObjCNonNullReferenceType : ObjCReferenceType() data class ObjCNullableReferenceType( - val nonNullType: ObjCNonNullReferenceType + val nonNullType: ObjCNonNullReferenceType, + val isNullableResult: Boolean = false ) : ObjCReferenceType() { - override fun render(attrsAndName: String) = nonNullType.render(" _Nullable".withAttrsAndName(attrsAndName)) + override fun render(attrsAndName: String): String { + val attribute = if (isNullableResult) objcNullableResultAttribute else objcNullableAttribute + return nonNullType.render(" $attribute".withAttrsAndName(attrsAndName)) + } } data class ObjCClassType( @@ -139,7 +143,7 @@ data class ObjCPointerType( ) : ObjCType() { override fun render(attrsAndName: String) = pointee.render("*${if (nullable) { - " _Nullable".withAttrsAndName(attrsAndName) + " $objcNullableAttribute".withAttrsAndName(attrsAndName) } else { attrsAndName }}") @@ -208,7 +212,5 @@ internal fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this) is ObjCNullableReferenceType, is ObjCRawType, is ObjCPrimitiveType, ObjCVoidType -> this } -internal fun ObjCReferenceType.makeNullable(): ObjCNullableReferenceType = when (this) { - is ObjCNonNullReferenceType -> ObjCNullableReferenceType(this) - is ObjCNullableReferenceType -> this -} \ No newline at end of file +const val objcNullableAttribute = "_Nullable" +const val objcNullableResultAttribute = "_Nullable_result" \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h index 04022cf5128..6e0e4f0784c 100644 --- a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h +++ b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h @@ -174,7 +174,7 @@ __attribute__((swift_name("SuspendBridge"))) @note This method converts instances of CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -- (void)intAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("intAsAny(value:completionHandler:)"))); +- (void)intAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("intAsAny(value:completionHandler:)"))); /** @note This method converts instances of CancellationException to errors. @@ -186,7 +186,7 @@ __attribute__((swift_name("SuspendBridge"))) @note This method converts instances of CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -- (void)unitAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("unitAsAny(value:completionHandler:)"))); +- (void)unitAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("unitAsAny(value:completionHandler:)"))); /** @note This method converts all Kotlin exceptions to errors. @@ -201,7 +201,7 @@ __attribute__((swift_name("SuspendBridge"))) /** @note This method converts all Kotlin exceptions to errors. */ -- (void)nothingAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("nothingAsAny(value:completionHandler:)"))); +- (void)nothingAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("nothingAsAny(value:completionHandler:)"))); /** @note This method converts all Kotlin exceptions to errors. @@ -275,13 +275,13 @@ __attribute__((swift_name("CoroutinesKt"))) @note This method converts instances of CoroutineException, CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -+ (void)suspendFunResult:(id _Nullable)result doSuspend:(BOOL)doSuspend doThrow:(BOOL)doThrow completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFun(result:doSuspend:doThrow:completionHandler:)"))); ++ (void)suspendFunResult:(id _Nullable)result doSuspend:(BOOL)doSuspend doThrow:(BOOL)doThrow completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFun(result:doSuspend:doThrow:completionHandler:)"))); /** @note This method converts instances of CoroutineException, CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -+ (void)suspendFunAsyncResult:(id _Nullable)result continuationHolder:(KtContinuationHolder *)continuationHolder completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFunAsync(result:continuationHolder:completionHandler:)"))); ++ (void)suspendFunAsyncResult:(id _Nullable)result continuationHolder:(KtContinuationHolder *)continuationHolder completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFunAsync(result:continuationHolder:completionHandler:)"))); /** @note This method converts instances of CoroutineException, CancellationException to errors. @@ -315,7 +315,7 @@ __attribute__((swift_name("CoroutinesKt"))) @note This method converts instances of CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -+ (void)invoke1Block:(id)block argument:(id _Nullable)argument completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("invoke1(block:argument:completionHandler:)"))); ++ (void)invoke1Block:(id)block argument:(id _Nullable)argument completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("invoke1(block:argument:completionHandler:)"))); @end; __attribute__((swift_name("DeallocRetainBase"))) diff --git a/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h b/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h index e4ef6ca9ab2..4a62093e58a 100644 --- a/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h +++ b/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h @@ -174,7 +174,7 @@ __attribute__((swift_name("SuspendBridge"))) @note This method converts instances of CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -- (void)intAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("intAsAny(value:completionHandler:)"))); +- (void)intAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("intAsAny(value:completionHandler:)"))); /** @note This method converts instances of CancellationException to errors. @@ -186,7 +186,7 @@ __attribute__((swift_name("SuspendBridge"))) @note This method converts instances of CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -- (void)unitAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("unitAsAny(value:completionHandler:)"))); +- (void)unitAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("unitAsAny(value:completionHandler:)"))); /** @note This method converts all Kotlin exceptions to errors. @@ -201,7 +201,7 @@ __attribute__((swift_name("SuspendBridge"))) /** @note This method converts all Kotlin exceptions to errors. */ -- (void)nothingAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("nothingAsAny(value:completionHandler:)"))); +- (void)nothingAsAnyValue:(id _Nullable)value completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("nothingAsAny(value:completionHandler:)"))); /** @note This method converts all Kotlin exceptions to errors. @@ -275,13 +275,13 @@ __attribute__((swift_name("CoroutinesKt"))) @note This method converts instances of CoroutineException, CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -+ (void)suspendFunResult:(id _Nullable)result doSuspend:(BOOL)doSuspend doThrow:(BOOL)doThrow completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFun(result:doSuspend:doThrow:completionHandler:)"))); ++ (void)suspendFunResult:(id _Nullable)result doSuspend:(BOOL)doSuspend doThrow:(BOOL)doThrow completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFun(result:doSuspend:doThrow:completionHandler:)"))); /** @note This method converts instances of CoroutineException, CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -+ (void)suspendFunAsyncResult:(id _Nullable)result continuationHolder:(KtContinuationHolder *)continuationHolder completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFunAsync(result:continuationHolder:completionHandler:)"))); ++ (void)suspendFunAsyncResult:(id _Nullable)result continuationHolder:(KtContinuationHolder *)continuationHolder completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("suspendFunAsync(result:continuationHolder:completionHandler:)"))); /** @note This method converts instances of CoroutineException, CancellationException to errors. @@ -315,7 +315,7 @@ __attribute__((swift_name("CoroutinesKt"))) @note This method converts instances of CancellationException to errors. Other uncaught Kotlin exceptions are fatal. */ -+ (void)invoke1Block:(id)block argument:(id _Nullable)argument completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("invoke1(block:argument:completionHandler:)"))); ++ (void)invoke1Block:(id)block argument:(id _Nullable)argument completionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("invoke1(block:argument:completionHandler:)"))); @end; __attribute__((swift_name("DeallocRetainBase")))