Native: add KotlinThrowable.asError() to the generated Obj-C framework

This method can be useful when overriding a throwing Kotlin method in
Swift or Obj-C. In this case, a user can call asError to wrap Kotlin exception
to (NS)Error and then throw it to Kotlin, which will unwrap it back.

^KT-45127 Fixed
This commit is contained in:
Svyatoslav Scherbina
2021-04-15 08:21:30 +00:00
committed by Space
parent c988ecf59b
commit d531df1643
12 changed files with 224 additions and 0 deletions
@@ -805,6 +805,44 @@ __attribute__((swift_name("OverrideMethodsOfAnyKt")))
+ (BOOL)testObj:(id)obj other:(id)other swift:(BOOL)swift error:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("test(obj:other:swift:)")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("ThrowableAsError")))
@interface KtThrowableAsError : KtKotlinThrowable
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
- (instancetype)initWithMessage:(NSString * _Nullable)message __attribute__((swift_name("init(message:)"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
- (instancetype)initWithCause:(KtKotlinThrowable * _Nullable)cause __attribute__((swift_name("init(cause:)"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
- (instancetype)initWithMessage:(NSString * _Nullable)message cause:(KtKotlinThrowable * _Nullable)cause __attribute__((swift_name("init(message:cause:)"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
@end;
__attribute__((swift_name("ThrowsThrowableAsError")))
@protocol KtThrowsThrowableAsError
@required
/**
@note This method converts all Kotlin exceptions to errors.
*/
- (BOOL)throwErrorAndReturnError:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("throwError()")));
@end;
__attribute__((swift_name("ThrowsThrowableAsErrorSuspend")))
@protocol KtThrowsThrowableAsErrorSuspend
@required
/**
@note This method converts instances of CancellationException to errors.
Other uncaught Kotlin exceptions are fatal.
*/
- (void)throwErrorWithCompletionHandler:(void (^)(KtKotlinUnit * _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("throwError(completionHandler:)")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("ThrowableAsErrorKt")))
@interface KtThrowableAsErrorKt : KtBase
+ (KtThrowableAsError * _Nullable)callAndCatchThrowableAsErrorThrowsThrowableAsError:(id<KtThrowsThrowableAsError>)throwsThrowableAsError __attribute__((swift_name("callAndCatchThrowableAsError(throwsThrowableAsError:)")));
+ (KtThrowableAsError * _Nullable)callAndCatchThrowableAsErrorSuspendThrowsThrowableAsErrorSuspend:(id<KtThrowsThrowableAsErrorSuspend>)throwsThrowableAsErrorSuspend __attribute__((swift_name("callAndCatchThrowableAsErrorSuspend(throwsThrowableAsErrorSuspend:)")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("ThrowsEmptyKt")))
@interface KtThrowsEmptyKt : KtBase
@@ -778,6 +778,44 @@ __attribute__((swift_name("OverrideMethodsOfAnyKt")))
+ (BOOL)testObj:(id)obj other:(id)other swift:(BOOL)swift error:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("test(obj:other:swift:)")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("ThrowableAsError")))
@interface KtThrowableAsError : KtKotlinThrowable
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
- (instancetype)initWithMessage:(NSString * _Nullable)message __attribute__((swift_name("init(message:)"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
- (instancetype)initWithCause:(KtKotlinThrowable * _Nullable)cause __attribute__((swift_name("init(cause:)"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
- (instancetype)initWithMessage:(NSString * _Nullable)message cause:(KtKotlinThrowable * _Nullable)cause __attribute__((swift_name("init(message:cause:)"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
@end;
__attribute__((swift_name("ThrowsThrowableAsError")))
@protocol KtThrowsThrowableAsError
@required
/**
@note This method converts all Kotlin exceptions to errors.
*/
- (BOOL)throwErrorAndReturnError:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("throwError()")));
@end;
__attribute__((swift_name("ThrowsThrowableAsErrorSuspend")))
@protocol KtThrowsThrowableAsErrorSuspend
@required
/**
@note This method converts instances of CancellationException to errors.
Other uncaught Kotlin exceptions are fatal.
*/
- (void)throwErrorWithCompletionHandler:(void (^)(KtKotlinUnit * _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("throwError(completionHandler:)")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("ThrowableAsErrorKt")))
@interface KtThrowableAsErrorKt : KtBase
+ (KtThrowableAsError * _Nullable)callAndCatchThrowableAsErrorThrowsThrowableAsError:(id<KtThrowsThrowableAsError>)throwsThrowableAsError __attribute__((swift_name("callAndCatchThrowableAsError(throwsThrowableAsError:)")));
+ (KtThrowableAsError * _Nullable)callAndCatchThrowableAsErrorSuspendThrowsThrowableAsErrorSuspend:(id<KtThrowsThrowableAsErrorSuspend>)throwsThrowableAsErrorSuspend __attribute__((swift_name("callAndCatchThrowableAsErrorSuspend(throwsThrowableAsErrorSuspend:)")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("ThrowsEmptyKt")))
@interface KtThrowsEmptyKt : KtBase
@@ -0,0 +1,38 @@
package throwableAsError
import kotlin.coroutines.*
class ThrowableAsError : Throwable()
interface ThrowsThrowableAsError {
@Throws(Throwable::class)
fun throwError()
}
fun callAndCatchThrowableAsError(throwsThrowableAsError: ThrowsThrowableAsError): ThrowableAsError? {
try {
throwsThrowableAsError.throwError()
} catch (e: ThrowableAsError) {
return e
}
return null
}
interface ThrowsThrowableAsErrorSuspend {
suspend fun throwError()
}
fun callAndCatchThrowableAsErrorSuspend(throwsThrowableAsErrorSuspend: ThrowsThrowableAsErrorSuspend): ThrowableAsError? {
var throwable: ThrowableAsError? = null
suspend {
throwsThrowableAsErrorSuspend.throwError()
}.startCoroutine(object : Continuation<Unit> {
override val context = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {
throwable = result.exceptionOrNull() as? ThrowableAsError
}
})
return throwable
}
@@ -0,0 +1,54 @@
import Kt
private func testUnwrapsToSame() throws {
let throwable = ThrowableAsError()
try assertSame(actual: throwable.asError().kotlinException as AnyObject, expected: throwable)
}
private func testCanThrowAndCatch() throws {
let throwable = ThrowableAsError()
let impl = ThrowsThrowableAsErrorImpl(throwable: throwable)
let caught = ThrowableAsErrorKt.callAndCatchThrowableAsError(throwsThrowableAsError: impl)
try assertSame(actual: caught, expected: throwable)
}
private class ThrowsThrowableAsErrorImpl : ThrowsThrowableAsError {
var throwable: KotlinThrowable
init(throwable: KotlinThrowable) {
self.throwable = throwable
}
func throwError() throws {
throw throwable.asError()
}
}
private func testCanThrowAndCatchSuspend() throws {
let throwable = ThrowableAsError()
let impl = ThrowsThrowableAsErrorSuspendImpl(throwable: throwable)
let caught = ThrowableAsErrorKt.callAndCatchThrowableAsErrorSuspend(throwsThrowableAsErrorSuspend: impl)
try assertSame(actual: caught, expected: throwable)
}
private class ThrowsThrowableAsErrorSuspendImpl : ThrowsThrowableAsErrorSuspend {
var throwable: KotlinThrowable
init(throwable: KotlinThrowable) {
self.throwable = throwable
}
func throwError(completionHandler: @escaping (KotlinUnit?, Error?) -> Void) {
completionHandler(nil, throwable.asError())
}
}
class ThrowableAsErrorTests : SimpleTestProvider {
override init() {
super.init()
test("TestUnwrapsToSame", testUnwrapsToSame)
test("TestCanThrowAndCatch", testCanThrowAndCatch)
test("TestCanThrowAndCatchSuspend", testCanThrowAndCatchSuspend)
}
}