Rename SuccessOrFailure to Result and hide Failure from ABI

* The members of Result are isSuccess, isFailure, exceptionOrNull, getOrNull
* The rest of API is implemented via inline-only extensions
* There are two internal functions to hide detailed mechanics of an internal
  Result.Failure class: createFailure and throwOnFailure
* Result.toString is explicit: either Success(v) or Failure(x)

See KT-26538
This commit is contained in:
Roman Elizarov
2018-09-09 11:34:31 +03:00
parent 69ee88871f
commit e2713501ce
81 changed files with 968 additions and 612 deletions
@@ -99,7 +99,7 @@ fun box(): String {
if (res != "first") {
return "" + res
}
continuation!!.resumeWith(SuccessOrFailure.success(Unit))
continuation!!.resumeWith(Result.success(Unit))
res = (continuation!! as BaseContinuationImpl).getSpilledVariableFieldMapping()!!.toMap()["I$0"] ?: "multipleLocalsInOneSlot fail 2"
if (res != "second") {
return "" + res
@@ -10,30 +10,30 @@ fun builder(c: suspend () -> Unit) {
}
@Suppress("UNSUPPORTED_FEATURE")
inline class SuccessOrFailure<T>(val a: Any?) {
inline class Result<T>(val a: Any?) {
fun getOrThrow(): T = a as T
}
abstract class SuccessOrFailureReceiver<T> {
abstract suspend fun receive(result: SuccessOrFailure<T>)
abstract class ResultReceiver<T> {
abstract suspend fun receive(result: Result<T>)
}
inline fun <T> SuccessOrFailureReceiver(crossinline f: (SuccessOrFailure<T>) -> Unit): SuccessOrFailureReceiver<T> =
object : SuccessOrFailureReceiver<T>() {
override suspend fun receive(result: SuccessOrFailure<T>) {
inline fun <T> ResultReceiver(crossinline f: (Result<T>) -> Unit): ResultReceiver<T> =
object : ResultReceiver<T>() {
override suspend fun receive(result: Result<T>) {
f(result)
}
}
fun test() {
var invoked = false
val receiver = SuccessOrFailureReceiver<String> { result ->
val receiver = ResultReceiver<String> { result ->
val intResult = result.getOrThrow()
invoked = true
}
builder {
receiver.receive(SuccessOrFailure("42"))
receiver.receive(Result("42"))
}
if (!invoked) {
throw RuntimeException("Fail")
@@ -10,30 +10,30 @@ fun builder(c: suspend () -> Unit) {
}
@Suppress("UNSUPPORTED_FEATURE")
inline class SuccessOrFailure<T>(val a: Any?) {
inline class Result<T>(val a: Any?) {
fun getOrThrow(): T = a as T
}
abstract class SuccessOrFailureReceiver<T> {
abstract suspend fun receive(result: SuccessOrFailure<T>)
abstract class ResultReceiver<T> {
abstract suspend fun receive(result: Result<T>)
}
fun <T> SuccessOrFailureReceiver(f: (SuccessOrFailure<T>) -> Unit): SuccessOrFailureReceiver<T> =
object : SuccessOrFailureReceiver<T>() {
override suspend fun receive(result: SuccessOrFailure<T>) {
fun <T> ResultReceiver(f: (Result<T>) -> Unit): ResultReceiver<T> =
object : ResultReceiver<T>() {
override suspend fun receive(result: Result<T>) {
f(result)
}
}
fun test() {
var invoked = false
val receiver = SuccessOrFailureReceiver<Int> { result ->
val receiver = ResultReceiver<Int> { result ->
val intResult = result.getOrThrow()
invoked = true
}
builder {
receiver.receive(SuccessOrFailure(42))
receiver.receive(Result(42))
}
if (!invoked) {
throw RuntimeException("Fail")
@@ -30,7 +30,7 @@ var proceed = {}
suspend fun suspendHere() = suspendCoroutineUninterceptedOrReturn<Unit> { cont ->
proceed = {
cont.resumeWith(SuccessOrFailure.success(Unit))
cont.resumeWith(Result.success(Unit))
}
COROUTINE_SUSPENDED
}
@@ -32,7 +32,7 @@ var proceed = {}
suspend fun suspendHere() = suspendCoroutineUninterceptedOrReturn<Unit> { cont ->
proceed = {
cont.resumeWith(SuccessOrFailure.success(Unit))
cont.resumeWith(Result.success(Unit))
}
COROUTINE_SUSPENDED
}
@@ -1,29 +1,29 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
inline class SuccessOrFailure<T>(val a: Any?) {
inline class Result<T>(val a: Any?) {
fun getOrThrow(): T = a as T
}
abstract class SuccessOrFailureReceiver<T> {
abstract fun receive(result: SuccessOrFailure<T>)
abstract class ResultReceiver<T> {
abstract fun receive(result: Result<T>)
}
fun <T> SuccessOrFailureReceiver(f: (SuccessOrFailure<T>) -> Unit): SuccessOrFailureReceiver<T> =
object : SuccessOrFailureReceiver<T>() {
override fun receive(result: SuccessOrFailure<T>) {
fun <T> ResultReceiver(f: (Result<T>) -> Unit): ResultReceiver<T> =
object : ResultReceiver<T>() {
override fun receive(result: Result<T>) {
f(result)
}
}
fun test() {
var invoked = false
val receiver = SuccessOrFailureReceiver<Int> { result ->
val receiver = ResultReceiver<Int> { result ->
val intResult = result.getOrThrow()
invoked = true
}
receiver.receive(SuccessOrFailure(42))
receiver.receive(Result(42))
if (!invoked) {
throw RuntimeException("Fail")
}
@@ -1,29 +1,29 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
inline class SuccessOrFailure<T>(val a: Any?) {
inline class Result<T>(val a: Any?) {
fun getOrThrow(): T = a as T
}
abstract class SuccessOrFailureReceiver<T> {
abstract fun receive(result: SuccessOrFailure<T>)
abstract class ResultReceiver<T> {
abstract fun receive(result: Result<T>)
}
inline fun <T> SuccessOrFailureReceiver(crossinline f: (SuccessOrFailure<T>) -> Unit): SuccessOrFailureReceiver<T> =
object : SuccessOrFailureReceiver<T>() {
override fun receive(result: SuccessOrFailure<T>) {
inline fun <T> ResultReceiver(crossinline f: (Result<T>) -> Unit): ResultReceiver<T> =
object : ResultReceiver<T>() {
override fun receive(result: Result<T>) {
f(result)
}
}
fun test() {
var invoked = false
val receiver = SuccessOrFailureReceiver<String> { result ->
val receiver = ResultReceiver<String> { result ->
val intResult = result.getOrThrow()
invoked = true
}
receiver.receive(SuccessOrFailure("42"))
receiver.receive(Result("42"))
if (!invoked) {
throw RuntimeException("Fail")
}
+8 -8
View File
@@ -1,15 +1,15 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
inline class SuccessOrFailure<out T>(val value: Any?) {
inline class Result<out T>(val value: Any?) {
val isFailure: Boolean get() = value is Failure
public companion object {
public inline fun <T> success(value: T): SuccessOrFailure<T> =
SuccessOrFailure(value)
public inline fun <T> success(value: T): Result<T> =
Result(value)
public inline fun <T> failure(exception: Throwable): SuccessOrFailure<T> =
SuccessOrFailure(Failure(exception))
public inline fun <T> failure(exception: Throwable): Result<T> =
Result(Failure(exception))
}
class Failure (
@@ -17,11 +17,11 @@ inline class SuccessOrFailure<out T>(val value: Any?) {
)
}
inline fun <R> runCatching(block: () -> R): SuccessOrFailure<R> {
inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
SuccessOrFailure.success(block())
Result.success(block())
} catch (e: Throwable) {
SuccessOrFailure.failure(e)
Result.failure(e)
}
}
@@ -20,7 +20,7 @@ fun builder(c: suspend () -> Unit) {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: SuccessOrFailure<Unit>) {
override fun resumeWith(result: Result<Unit>) {
result.getOrThrow()
}
})
@@ -18,7 +18,7 @@ fun builder(c: suspend () -> Unit) {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: SuccessOrFailure<Unit>) {
override fun resumeWith(result: Result<Unit>) {
result.getOrThrow()
}
})
@@ -38,7 +38,7 @@ fun builder(c: suspend () -> Unit) {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(r: SuccessOrFailure<Unit>) {
override fun resumeWith(r: Result<Unit>) {
r.getOrThrow()
proceed = {
result = "OK"
@@ -36,7 +36,7 @@ fun builder(c: suspend () -> Unit) {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(r: SuccessOrFailure<Unit>) {
override fun resumeWith(r: Result<Unit>) {
r.getOrThrow()
proceed = {
result = "OK"
@@ -4,7 +4,7 @@
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendHere(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.resumeWith(SuccessOrFailure.success("OK"))
x.resumeWith(Result.success("OK"))
}
suspend fun suspendThere(param: Int, param2: String, param3: Long): String {
@@ -0,0 +1,37 @@
// WITH_COROUTINES
// FILE: test.kt
fun test() {
val result = Result.success("yes!")
val failure = Result.failure<String>(Exception())
if (result.isSuccess) println("success")
if (result.isFailure) println("failure")
println(result.getOrThrow())
println(failure.getOrNull())
println(failure.exceptionOrNull())
val other = Result.success("nope")
if (result == other) println("==")
if (result != other) println("!=")
if (result.equals(other)) println("equals")
if (!result.equals(other)) println("!equals")
println(result.hashCode())
println(result.toString())
println("$result")
val ans1 = runCatching { 42 }
println(ans1)
val ans2 = 42.runCatching { this }
println(ans2)
println(result.getOrElse { "oops" })
println(result.getOrDefault("oops"))
}
// @TestKt.class:
// 0 INVOKESTATIC Result.box-impl
// 0 INVOKESTATIC Result.unbox-impl
// 0 Result\$Failure
// 53 Result
@@ -1,36 +0,0 @@
// WITH_COROUTINES
// FILE: test.kt
fun testSoF() {
val sof = SuccessOrFailure.success("yes!")
val failure = SuccessOrFailure.failure<String>(Exception())
if (sof.isSuccess) println("success")
if (sof.isFailure) println("failure")
println(sof.getOrThrow())
println(failure.getOrNull())
println(failure.exceptionOrNull())
val other = SuccessOrFailure.success("nope")
if (sof == other) println("==")
if (sof != other) println("!=")
if (sof.equals(other)) println("equals")
if (!sof.equals(other)) println("!equals")
println(sof.hashCode())
println(sof.toString())
println("$sof")
val ans1 = runCatching { 42 }
println(ans1)
val ans2 = 42.runCatching { this }
println(ans2)
println(sof.getOrElse { "oops" })
println(sof.getOrDefault("oops"))
}
// @TestKt.class:
// 0 SuccessOrFailure\$Erased
// 0 SuccessOrFailure\-Erased
// 58 SuccessOrFailure