Repository: JetBrains/kotlin
File: kotlin-native/runtime/src/main/cpp/ObjCExportCoroutines.mm (Objective-C++)

Code before:
#import "ObjCExportErrors.h"

typedef void (^Completion)(id _Nullable, NSError* _Nullable);

extern "C" void Kotlin_ObjCExport_runCompletionSuccess(KRef completionHolder, KRef result) {
  Completion completion = (Completion)GetAssociatedObject(completionHolder);
  id objCResult = Kotlin_ObjCExport_refToLocalObjC(result);
  kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
  completion(objCResult, nullptr);
}

extern "C" void Kotlin_ObjCExport_runCompletionFailure(
  KRef completionHolder,
  KRef exception,
  const TypeInfo** exceptionTypes
) {
  id error = Kotlin_ObjCExport_ExceptionAsNSError(exception, exceptionTypes);
  Completion completion = (Completion)GetAssociatedObject(completionHolder);
  kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
  completion(nullptr, error);
}

extern "C" OBJ_GETTER(Kotlin_ObjCExport_createContinuationArgumentImpl,
    KRef completionHolder, const TypeInfo** exceptionTypes);

extern "C" OBJ_GETTER(Kotlin_ObjCExport_createContinuationArgument, KBoolean allowAnyThread, id completion, const TypeInfo** exceptionTypes) {
  if (!allowAnyThread && pthread_main_np() != 1) {
    [NSException raise:NSGenericException
        format:@"Calling Kotlin suspend functions from Swift/Objective-C is currently supported only on main thread"];
  }
  ObjHolder slot;
  KRef completionHolder = AllocInstanceWithAssociatedObject(theForeignObjCObjectTypeInfo,
      objc_retainBlock(completion), slot.slot());

  RETURN_RESULT_OF(Kotlin_ObjCExport_createContinuationArgumentImpl, completionHolder, exceptionTypes);
}

extern "C" OBJ_GETTER(Kotlin_ObjCExport_createUnitContinuationArgument, KBoolean allowAnyThread, id completion, const TypeInfo** exceptionTypes) {
  void (^typedCompletion)(NSError * _Nullable) = completion;
  Completion twoArgumentCompletion = ^(_Nullable id result, NSError* _Nullable error) {
    // typedCompletion will be retained by the containing block when the latter is copied
    // from stack to heap via objc_retainBlock.
    typedCompletion(error);
  };

  RETURN_RESULT_OF(Kotlin_ObjCExport_createContinuationArgument, allowAnyThread, twoArgumentCompletion, exceptionTypes);
}

extern "C" void Kotlin_ObjCExport_resumeContinuationSuccess(KRef continuation, KRef result);
extern "C" void Kotlin_ObjCExport_resumeContinuationFailure(KRef continuation, KRef exception);


Review comment (suggestion):
There is a significantly simpler way to pass the value from compiler arguments to runtime.
See e.g. https://github.com/JetBrains/kotlin/blob/19658b3a4706284eeb21480f53fe2740ba60ce88/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt#L2779 and https://github.com/JetBrains/kotlin/blob/3798920183e9180795726ac89d18c4355dac4520/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp#L17

Please use this approach.

Code after:
#import "ObjCExportErrors.h"

typedef void (^Completion)(id _Nullable, NSError* _Nullable);

extern "C" void Kotlin_ObjCExport_runCompletionSuccess(KRef completionHolder, KRef result) {
  Completion completion = (Completion)GetAssociatedObject(completionHolder);
  id objCResult = Kotlin_ObjCExport_refToLocalObjC(result);
  kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
  completion(objCResult, nullptr);
}

extern "C" void Kotlin_ObjCExport_runCompletionFailure(
  KRef completionHolder,
  KRef exception,
  const TypeInfo** exceptionTypes
) {
  id error = Kotlin_ObjCExport_ExceptionAsNSError(exception, exceptionTypes);
  Completion completion = (Completion)GetAssociatedObject(completionHolder);
  kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
  completion(nullptr, error);
}

extern "C" OBJ_GETTER(Kotlin_ObjCExport_createContinuationArgumentImpl,
    KRef completionHolder, const TypeInfo** exceptionTypes);

extern "C" OBJ_GETTER(Kotlin_ObjCExport_createContinuationArgument, id completion, const TypeInfo** exceptionTypes) {
  if (!kotlin::compiler::suspendFunctionsFromAnyThreadFromObjCEnabled() && pthread_main_np() != 1) {
    [NSException raise:NSGenericException
        format:@"Calling Kotlin suspend functions from Swift/Objective-C is currently supported only on main thread"];
  }
  ObjHolder slot;
  KRef completionHolder = AllocInstanceWithAssociatedObject(theForeignObjCObjectTypeInfo,
      objc_retainBlock(completion), slot.slot());

  RETURN_RESULT_OF(Kotlin_ObjCExport_createContinuationArgumentImpl, completionHolder, exceptionTypes);
}

extern "C" OBJ_GETTER(Kotlin_ObjCExport_createUnitContinuationArgument, id completion, const TypeInfo** exceptionTypes) {
  void (^typedCompletion)(NSError * _Nullable) = completion;
  Completion twoArgumentCompletion = ^(_Nullable id result, NSError* _Nullable error) {
    // typedCompletion will be retained by the containing block when the latter is copied
    // from stack to heap via objc_retainBlock.
    typedCompletion(error);
  };

  RETURN_RESULT_OF(Kotlin_ObjCExport_createContinuationArgument, twoArgumentCompletion, exceptionTypes);
}

extern "C" void Kotlin_ObjCExport_resumeContinuationSuccess(KRef continuation, KRef result);
extern "C" void Kotlin_ObjCExport_resumeContinuationFailure(KRef continuation, KRef exception);