diff --git a/.github/workflows/githubpages.yaml b/.github/workflows/githubpages.yaml index 1ef65d07097..668b15c8348 100644 --- a/.github/workflows/githubpages.yaml +++ b/.github/workflows/githubpages.yaml @@ -32,7 +32,7 @@ jobs: run: ./gradlew -Pversion=${{ github.event.release.tag_name }} dokkaHtmlMultiModule -Pgithubpages=true - name: Deploy to gh-pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./docs diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index de7319cbe03..62de62a8544 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -254,7 +254,7 @@ jobs: cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/arrow-2' }} - name: JVM (Kotlin 2.0) tests - run: ./gradlew jvmTest -Pkotlin_version=2.0.0-Beta3 -Pksp_version=2.0.0-Beta3-1.0.17 -Pkotlin_language_version=2.0 -Pkotlin_api_version=2.0 + run: ./gradlew jvmTest -Pkotlin_version=2.0.0-RC1 -Pksp_version=2.0.0-RC1-1.0.20 -Pkotlin_language_version=2.0 -Pkotlin_api_version=2.0 - name: Upload reports if: failure() diff --git a/arrow-libs/core/arrow-core-retrofit/build.gradle.kts b/arrow-libs/core/arrow-core-retrofit/build.gradle.kts index 92b0fa63f7c..12d6b301d0b 100644 --- a/arrow-libs/core/arrow-core-retrofit/build.gradle.kts +++ b/arrow-libs/core/arrow-core-retrofit/build.gradle.kts @@ -21,7 +21,7 @@ apply(from = property("ANIMALSNIFFER")) dependencies { compileOnly(libs.kotlin.stdlib) compileOnly(projects.arrowCore) - compileOnly(libs.squareup.retrofit) + compileOnly(libs.squareup.retrofit.lib) testImplementation(projects.arrowCore) testImplementation(libs.kotest.frameworkEngine) @@ -30,10 +30,11 @@ dependencies { testCompileOnly(libs.kotlin.reflect) testRuntimeOnly(libs.kotest.runnerJUnit5) testImplementation(libs.squareup.okhttpMockWebServer) - testImplementation(libs.squareup.retrofitConverterGson) - testImplementation(libs.squareup.retrofitConverterMoshi) + testImplementation(libs.squareup.retrofit.converter.gson) + testImplementation(libs.squareup.retrofit.converter.moshi) testImplementation(libs.kotlinx.serializationJson) - testImplementation(libs.jakewharton.retrofitConverterKotlinxSerialization) + testImplementation(libs.squareup.retrofit.converter.kotlinxSerialization) + testImplementation(libs.squareup.moshi.kotlin) } tasks.jar { diff --git a/arrow-libs/core/arrow-core-retrofit/src/test/kotlin/arrow/retrofit/adapter/either/networkhandling/NetworkEitherCallAdapterTest.kt b/arrow-libs/core/arrow-core-retrofit/src/test/kotlin/arrow/retrofit/adapter/either/networkhandling/NetworkEitherCallAdapterTest.kt index 5f211a1c195..d6c3286512c 100644 --- a/arrow-libs/core/arrow-core-retrofit/src/test/kotlin/arrow/retrofit/adapter/either/networkhandling/NetworkEitherCallAdapterTest.kt +++ b/arrow-libs/core/arrow-core-retrofit/src/test/kotlin/arrow/retrofit/adapter/either/networkhandling/NetworkEitherCallAdapterTest.kt @@ -5,7 +5,8 @@ import arrow.core.left import arrow.core.right import arrow.retrofit.adapter.either.EitherCallAdapterFactory import arrow.retrofit.adapter.mock.ResponseMock -import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import io.kotest.core.spec.style.StringSpec import io.kotest.core.spec.style.stringSpec import io.kotest.matchers.shouldBe @@ -20,6 +21,7 @@ import okhttp3.mockwebserver.SocketPolicy import retrofit2.Converter import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.converter.kotlinx.serialization.asConverterFactory import retrofit2.converter.moshi.MoshiConverterFactory import java.net.SocketException import java.net.SocketTimeoutException @@ -28,8 +30,9 @@ import java.util.concurrent.TimeUnit @ExperimentalSerializationApi class NetworkEitherCallAdapterTestSuite : StringSpec({ include(networkEitherCallAdapterTests(GsonConverterFactory.create())) - include(networkEitherCallAdapterTests(MoshiConverterFactory.create())) include(networkEitherCallAdapterTests(Json.asConverterFactory("application/json".toMediaType()))) + val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build() + include(networkEitherCallAdapterTests(MoshiConverterFactory.create(moshi))) }) private fun networkEitherCallAdapterTests( diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index f985fe498e5..631cf1c913c 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -3595,7 +3595,6 @@ public abstract interface annotation class arrow/core/raise/RaiseDSL : java/lang public final class arrow/core/raise/RaiseKt { public static final fun _fold (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun _foldOrThrow (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun _foldUnsafe (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun _merge (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun catch (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1; diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt index a4729445bf5..d17779492a0 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt @@ -123,44 +123,13 @@ public inline fun fold( * This method should never be wrapped in `try`/`catch` as it will not throw any unexpected errors, * it will only result in [CancellationException], or fatal exceptions such as `OutOfMemoryError`. */ +@OptIn(DelicateRaiseApi::class) @JvmName("_fold") public inline fun fold( @BuilderInference block: Raise.() -> A, catch: (throwable: Throwable) -> B, recover: (error: Error) -> B, transform: (value: A) -> B, -): B { - contract { - callsInPlace(catch, AT_MOST_ONCE) - callsInPlace(recover, AT_MOST_ONCE) - callsInPlace(transform, AT_MOST_ONCE) - } - return foldUnsafe(block, catch, recover) { - if (it is Function<*> || it is Lazy<*> || it is Sequence<*>) - throw IllegalStateException( - """ - Returning a lazy computation or closure from 'fold' breaks the context scope, and may lead to leaked exceptions on later execution. - Make sure all calls to 'raise' and 'bind' occur within the lifecycle of nullable { }, either { } or similar builders. - - See Arrow documentation on 'Typed errors' for further information. - """.trimIndent() - ) - transform(it) - } -} - -/** - * Similar to [fold], but does *not* check for - * potential lazy return types which break the - * [Raise] context barrier. - */ -@JvmName("_foldUnsafe") -@OptIn(DelicateRaiseApi::class) -public inline fun foldUnsafe( - @BuilderInference block: Raise.() -> A, - catch: (throwable: Throwable) -> B, - recover: (error: Error) -> B, - transform: (value: A) -> B, ): B { contract { callsInPlace(catch, AT_MOST_ONCE) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt index 0ed27456725..98de52812c2 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt @@ -144,19 +144,4 @@ class NullableSpec : StringSpec({ one + two } shouldBe 3 } - - "Detects potential leaked exceptions" { - shouldThrow { - nullable { lazy { raise(null) } } - } - } - - "Unsafe leakage of exceptions" { - val l: Lazy = foldUnsafe, Lazy?>( - { lazy { raise("problem") } }, { throw it }, { null }, { it } - ).shouldNotBeNull() - shouldThrow { - l.value - } - } }) diff --git a/arrow-libs/fx/arrow-fx-stm/api/arrow-fx-stm.api b/arrow-libs/fx/arrow-fx-stm/api/arrow-fx-stm.api index 7a885252054..3e6770ca1b5 100644 --- a/arrow-libs/fx/arrow-fx-stm/api/arrow-fx-stm.api +++ b/arrow-libs/fx/arrow-fx-stm/api/arrow-fx-stm.api @@ -239,64 +239,6 @@ public final class arrow/fx/stm/internal/BlockedIndefinitely : java/lang/Throwab public fun ()V } -public abstract class arrow/fx/stm/internal/Branch { -} - -public final class arrow/fx/stm/internal/Branch$Branches : arrow/fx/stm/internal/Branch { - public fun (Larrow/fx/stm/internal/Hamt;)V - public final fun component1 ()Larrow/fx/stm/internal/Hamt; - public final fun copy (Larrow/fx/stm/internal/Hamt;)Larrow/fx/stm/internal/Branch$Branches; - public static synthetic fun copy$default (Larrow/fx/stm/internal/Branch$Branches;Larrow/fx/stm/internal/Hamt;ILjava/lang/Object;)Larrow/fx/stm/internal/Branch$Branches; - public fun equals (Ljava/lang/Object;)Z - public final fun getSub ()Larrow/fx/stm/internal/Hamt; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class arrow/fx/stm/internal/Branch$Leaf : arrow/fx/stm/internal/Branch { - public fun (I[Ljava/lang/Object;)V - public final fun component1 ()I - public final fun component2 ()[Ljava/lang/Object; - public final fun copy (I[Ljava/lang/Object;)Larrow/fx/stm/internal/Branch$Leaf; - public static synthetic fun copy$default (Larrow/fx/stm/internal/Branch$Leaf;I[Ljava/lang/Object;ILjava/lang/Object;)Larrow/fx/stm/internal/Branch$Leaf; - public fun equals (Ljava/lang/Object;)Z - public final fun getHash ()I - public final fun getValue ()[Ljava/lang/Object; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class arrow/fx/stm/internal/Hamt { - public static final field Companion Larrow/fx/stm/internal/Hamt$Companion; - public fun (Larrow/fx/stm/TVar;)V - public final fun component1 ()Larrow/fx/stm/TVar; - public final fun copy (Larrow/fx/stm/TVar;)Larrow/fx/stm/internal/Hamt; - public static synthetic fun copy$default (Larrow/fx/stm/internal/Hamt;Larrow/fx/stm/TVar;ILjava/lang/Object;)Larrow/fx/stm/internal/Hamt; - public fun equals (Ljava/lang/Object;)Z - public final fun getBranches ()Larrow/fx/stm/TVar; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class arrow/fx/stm/internal/Hamt$Companion { - public final fun new (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; -} - -public final class arrow/fx/stm/internal/HamtKt { - public static final field ARR_SIZE I - public static final field DEPTH_STEP I - public static final field MASK I - public static final fun alterHamtWithHash (Larrow/fx/stm/STM;Larrow/fx/stm/internal/Hamt;ILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Z - public static final fun atDepth (II)I - public static final fun clearHamt (Larrow/fx/stm/STM;Larrow/fx/stm/internal/Hamt;)V - public static final fun index (I)I - public static final fun indexAtDepth (II)I - public static final fun lookupHamtWithHash (Larrow/fx/stm/STM;Larrow/fx/stm/internal/Hamt;ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun newHamt (Larrow/fx/stm/STM;)Larrow/fx/stm/internal/Hamt; - public static final fun nextDepth (I)I - public static final fun pair (Larrow/fx/stm/STM;IILarrow/fx/stm/internal/Branch;ILarrow/fx/stm/internal/Branch;)Larrow/fx/stm/internal/Hamt; -} - public final class arrow/fx/stm/internal/RetryException : java/lang/Throwable { public static final field INSTANCE Larrow/fx/stm/internal/RetryException; public fun fillInStackTrace ()Ljava/lang/Throwable; diff --git a/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/STM.kt b/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/STM.kt index 895be245622..9854ff8f9d1 100644 --- a/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/STM.kt +++ b/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/STM.kt @@ -310,7 +310,7 @@ public interface STM { * - When committing the value inside the [TVar], at the time of calling [write], has to be the * same as the current value otherwise the transaction will retry */ - public fun TVar.write(a: A): Unit + public fun TVar.write(a: A) /** * Modify the value of a [TVar] @@ -683,7 +683,7 @@ public interface STM { * * @see TSemaphore.tryAcquire for a version that does not retry. */ - public fun TSemaphore.acquire(n: Int): Unit { + public fun TSemaphore.acquire(n: Int) { val curr = v.read() check(curr - n >= 0) v.write(curr - n) @@ -1103,7 +1103,7 @@ public interface STM { * * > This function has to access both [TVar]'s and thus may lead to increased contention, use sparingly. */ - public fun TQueue.removeAll(pred: (A) -> Boolean): Unit { + public fun TQueue.removeAll(pred: (A) -> Boolean) { reads.modify { it.filter(pred) } writes.modify { it.filter(pred) } } @@ -1332,7 +1332,7 @@ public interface STM { * ``` * */ - public fun TMap.insert(k: K, v: V): Unit { + public fun TMap.insert(k: K, v: V) { alterHamtWithHash(hamt, hashFn(k), { it.first == k }) { k to v } } @@ -1397,8 +1397,8 @@ public interface STM { * ``` * */ - public fun TMap.update(k: K, fn: (V) -> V): Unit { - alterHamtWithHash(hamt, hashFn(k), { it.first == k }) { it?.second?.let(fn)?.let { k to it } } + public fun TMap.update(k: K, fn: (V) -> V) { + alterHamtWithHash(hamt, hashFn(k), { it.first == k }) { it?.second?.let(fn)?.let { r -> k to r } } } /** @@ -1420,7 +1420,7 @@ public interface STM { * ``` * */ - public fun TMap.remove(k: K): Unit { + public fun TMap.remove(k: K) { alterHamtWithHash(hamt, hashFn(k), { it.first == k }) { null } } @@ -1466,7 +1466,7 @@ public interface STM { * ``` * */ - public fun TSet.insert(a: A): Unit { + public fun TSet.insert(a: A) { alterHamtWithHash(hamt, hashFn(a), { it == a }) { a } } @@ -1509,7 +1509,7 @@ public interface STM { * ``` * */ - public fun TSet.remove(a: A): Unit { + public fun TSet.remove(a: A) { alterHamtWithHash(hamt, hashFn(a), { it == a }) { null } } } diff --git a/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Hamt.kt b/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Hamt.kt index 7ee918fdc38..d18312eaf09 100644 --- a/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Hamt.kt +++ b/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Hamt.kt @@ -8,13 +8,13 @@ import arrow.fx.stm.STM * * Based on http://lampwww.epfl.ch/papers/idealhashtrees.pdf and https://hackage.haskell.org/package/stm-hamt. */ -public data class Hamt(val branches: TVar?>>) { - public companion object { - public suspend fun new(): Hamt = Hamt(TVar.new(arrayOfNulls(ARR_SIZE))) +internal data class Hamt(val branches: TVar?>>) { + companion object { + suspend fun new(): Hamt = Hamt(TVar.new(arrayOfNulls(ARR_SIZE))) } } -public inline fun STM.lookupHamtWithHash(hmt: Hamt, hash: Int, test: (A) -> Boolean): A? { +internal fun STM.lookupHamtWithHash(hmt: Hamt, hash: Int, test: (A) -> Boolean): A? { var depth = 0 var hamt = hmt while (true) { @@ -22,7 +22,7 @@ public inline fun STM.lookupHamtWithHash(hmt: Hamt, hash: Int, test: (A) val branches = hamt.branches.read() when (val branch = branches[branchInd]) { null -> return null - is Branch.Leaf -> return@lookupHamtWithHash (branch.value as Array).find(test) + is Branch.Leaf -> return branch.value.find(test) is Branch.Branches -> { depth = depth.nextDepth() hamt = branch.sub @@ -31,7 +31,7 @@ public inline fun STM.lookupHamtWithHash(hmt: Hamt, hash: Int, test: (A) } } -public fun STM.pair(depth: Int, hash1: Int, branch1: Branch, hash2: Int, branch2: Branch): Hamt { +internal fun STM.pair(depth: Int, hash1: Int, branch1: Branch, hash2: Int, branch2: Branch): Hamt { val branchInd1 = hash1.indexAtDepth(depth) val branchInd2 = hash2.indexAtDepth(depth) val branches = arrayOfNulls>(ARR_SIZE) @@ -45,9 +45,9 @@ public fun STM.pair(depth: Int, hash1: Int, branch1: Branch, hash2: Int, return Hamt(newTVar(branches)) } -public fun STM.clearHamt(hamt: Hamt): Unit = hamt.branches.write(arrayOfNulls(ARR_SIZE)) +// internal fun STM.clearHamt(hamt: Hamt): Unit = hamt.branches.write(arrayOfNulls(ARR_SIZE)) -public inline fun STM.alterHamtWithHash( +internal fun STM.alterHamtWithHash( hamt: Hamt, hash: Int, test: (A) -> Boolean, @@ -62,46 +62,35 @@ public inline fun STM.alterHamtWithHash( null -> { val el = fn(null) ?: return false val new = branches.copyOf() - new[branchInd] = Branch.Leaf(hash, arrayOf(el)) + new[branchInd] = Branch.leaf(hash, el) hmt.branches.write(new) return true } is Branch.Leaf -> { - if (hash == branch.hash) { - val ind = (branch.value as Array).indexOfFirst(test).takeIf { it != -1 } + val atIndex = if (hash == branch.hash) { + val ind = branch.value.indexOfFirst(test).takeIf { it != -1 } when (val el = ind?.let { branch.value[it] }) { null -> { // insert new value with a colliding hash val newEl = fn(null) ?: return false - val new = branches.copyOf() - new[branchInd] = Branch.Leaf(hash, arrayOf(newEl, *branch.value)) - hmt.branches.write(new) - return true + Branch.leaf(hash, newEl, *branch.value) } else -> { - when (val newEl = fn(el)) { - null -> { + val newEl = fn(el) + when { + newEl == null && branch.value.size <= 1 -> + null + newEl == null -> { // remove element - if (branch.value.size > 1) { - val newLeafArray: Array = Array(branch.value.size - 1) { i -> - if (i >= ind) branch.value[i + 1] - else branch.value[i] - } - } else { - val new = branches.copyOf() - new[branchInd] = null - hmt.branches.write(new) - } - return true + val newLeafArray = branch.value.copyOf(branch.value.size - 1) as Array + branch.value.copyInto(newLeafArray, ind, ind + 1) + Branch.Leaf(hash, newLeafArray) } else -> { // update element val newLeafArr = branch.value.copyOf() newLeafArr[ind] = newEl - val new = branches.copyOf() - new[branchInd] = Branch.Leaf(hash, newLeafArr as Array) - hmt.branches.write(new) - return true + Branch.Leaf(hash, newLeafArr) } } } @@ -111,15 +100,16 @@ public inline fun STM.alterHamtWithHash( val newHamt = pair( depth.nextDepth(), hash, - Branch.Leaf(hash, arrayOf(el)), + Branch.leaf(hash, el), branch.hash, branch ) - val new = branches.copyOf() - new[branchInd] = Branch.Branches(newHamt) - hmt.branches.write(new) - return true + Branch.Branches(newHamt) } + val new = branches.copyOf() + new[branchInd] = atIndex + hmt.branches.write(new) + return true } is Branch.Branches -> { depth = depth.nextDepth() @@ -129,18 +119,22 @@ public inline fun STM.alterHamtWithHash( } } -public fun STM.newHamt(): Hamt = Hamt(newTVar(arrayOfNulls(ARR_SIZE))) +internal fun STM.newHamt(): Hamt = Hamt(newTVar(arrayOfNulls(ARR_SIZE))) -public sealed class Branch { - public data class Branches(val sub: Hamt) : Branch() - public data class Leaf(val hash: Int, val value: Array) : Branch() +internal sealed class Branch { + data class Branches(val sub: Hamt) : Branch() + data class Leaf(val hash: Int, val value: Array) : Branch() + + companion object { + fun leaf(hash: Int, vararg value: A): Leaf = Leaf(hash, value) as Leaf + } } -public const val ARR_SIZE: Int = 32 // 2^DEPTH_STEP -public const val DEPTH_STEP: Int = 5 -public const val MASK: Int = 1.shl(DEPTH_STEP) - 1 +internal const val ARR_SIZE: Int = 32 // 2^DEPTH_STEP +internal const val DEPTH_STEP: Int = 5 +internal const val MASK: Int = 1.shl(DEPTH_STEP) - 1 -public fun Int.index(): Int = MASK.and(this) -public fun Int.atDepth(d: Int): Int = shr(d) -public fun Int.indexAtDepth(d: Int): Int = atDepth(d).index() -public fun Int.nextDepth(): Int = this + DEPTH_STEP +internal fun Int.index(): Int = MASK.and(this) +internal fun Int.atDepth(d: Int): Int = shr(d) +internal fun Int.indexAtDepth(d: Int): Int = atDepth(d).index() +internal fun Int.nextDepth(): Int = this + DEPTH_STEP diff --git a/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Impl.kt b/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Impl.kt index 327d6a68173..07e7e3aa063 100644 --- a/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Impl.kt +++ b/arrow-libs/fx/arrow-fx-stm/src/commonMain/kotlin/arrow/fx/stm/internal/Impl.kt @@ -10,7 +10,7 @@ import kotlin.coroutines.Continuation * A STMFrame keeps the reads and writes performed by a transaction. * It may have a parent which is only used for read lookups. */ -internal class STMFrame(val parent: STMFrame? = null) : STM { +internal class STMFrame(private val parent: STMFrame? = null) : STM { class Entry(var initialVal: Any?, var newVal: Any?) { object NO_CHANGE @@ -19,7 +19,7 @@ internal class STMFrame(val parent: STMFrame? = null) : STM { fun isWrite(): Boolean = newVal !== NO_CHANGE - fun update(v: Any?): Unit { + fun update(v: Any?) { newVal = if (initialVal === v) NO_CHANGE else v } @@ -31,7 +31,7 @@ internal class STMFrame(val parent: STMFrame? = null) : STM { /** * Helper to search the entire hierarchy for stored previous reads */ - private fun readVar(v: TVar): Any? = + private fun readVar(v: TVar): Any = accessMap[v]?.getValue() ?: parent?.readVar(v) ?: Entry.NOT_PRESENT override fun retry(): Nothing = throw RetryException @@ -56,18 +56,18 @@ internal class STMFrame(val parent: STMFrame? = null) : STM { // If we are already invalid here there is no point in continuing. if (frame.validate()) { this@STMFrame.merge(frame) - return@runLocal res as A + return res } } catch (ignored: RetryException) { if (frame.validate()) { this@STMFrame.mergeReads(frame) - return@runLocal onRetry() + return onRetry() } } catch (e: Throwable) { // An invalid frame retries even if it throws, so our sub-frame also needs to handle this correctly if (frame.validate()) { this@STMFrame.mergeReads(frame) - return@runLocal onError(e) + return onError(e) } } } @@ -87,8 +87,11 @@ internal class STMFrame(val parent: STMFrame? = null) : STM { * * If we have not seen this variable before we add a read which stores it in the read set as well. */ - override fun TVar.write(a: A): Unit = - accessMap[this as TVar]?.update(a) ?: readI().let { accessMap[this] = Entry(it, a) } + @Suppress("UNCHECKED_CAST") + override fun TVar.write(a: A) { + this as TVar + accessMap[this]?.update(a) ?: readI().let { accessMap[this] = Entry(it, a) } + } internal fun validate(): Boolean = accessMap.all { (tv, entry) -> tv.value === entry.initialVal } @@ -139,11 +142,11 @@ internal class STMFrame(val parent: STMFrame? = null) : STM { return true } - private fun mergeReads(other: STMFrame): Unit { + private fun mergeReads(other: STMFrame) { accessMap.putAll(other.accessMap.filter { (_, e) -> e.isWrite().not() }) } - private fun merge(other: STMFrame): Unit { + private fun merge(other: STMFrame) { accessMap.putAll(other.accessMap) } } @@ -188,7 +191,7 @@ internal class STMTransaction(val f: STM.() -> A) { if (frame.accessMap.isEmpty()) throw BlockedIndefinitely() val registered = mutableListOf>() - suspendCancellableCoroutine susp@{ k -> + suspendCancellableCoroutine susp@{ k -> cont.set(k) frame.accessMap diff --git a/arrow-libs/fx/arrow-fx-stm/src/jvmMain/kotlin/arrow/fx/stm/internal/RetryException.kt b/arrow-libs/fx/arrow-fx-stm/src/jvmMain/kotlin/arrow/fx/stm/internal/RetryException.kt index 878222f45a2..6545547486b 100644 --- a/arrow-libs/fx/arrow-fx-stm/src/jvmMain/kotlin/arrow/fx/stm/internal/RetryException.kt +++ b/arrow-libs/fx/arrow-fx-stm/src/jvmMain/kotlin/arrow/fx/stm/internal/RetryException.kt @@ -1,5 +1,6 @@ package arrow.fx.stm.internal public actual object RetryException : Throwable("Arrow STM Retry. This should always be caught by arrow internally. Please report this as a bug if that is not the case!") { + private fun readResolve(): Any = RetryException override fun fillInStackTrace(): Throwable { return this } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d2c4f818104..8a6bbd01e9d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,28 +3,28 @@ animalSniffer = "1.7.1" arrowGradleConfig = "0.12.0-rc.24" assertj = "3.25.3" coroutines = "1.8.0" -classgraph = "4.8.165" -dokka = "1.9.10" +classgraph = "4.8.172" +dokka = "1.9.20" jUnit = "4.13.2" jUnitJupiter = "5.10.2" jUnitVintage = "5.10.2" -kotest = "5.8.0" -kotestGradle = "5.8.0" +kotest = "5.8.1" +kotestGradle = "5.8.1" kover = "0.7.6" -kotlin = "1.9.22" -kotlinxSerializationPlugin = "1.9.22" +kotlin = "1.9.23" +kotlinxSerializationPlugin = "1.9.23" kotlinBinaryCompatibilityValidator = "0.14.0" -kotlinCompileTesting = "0.4.0" +kotlinCompileTesting = "0.4.1" knit = "0.5.0" -kspVersion = "1.9.22-1.0.18" +kspVersion = "1.9.23-1.0.20" kotlinxSerialization = "1.6.3" mockWebServer = "4.12.0" -retrofit = "2.9.0" -retrofitKotlinxSerialization = "1.0.0" +retrofit = "2.11.0" +moshi = "1.15.1" spotlessVersion = "6.25.0" -compose = "1.6.2" -composePlugin = "1.6.0" -agp = "8.3.0" +compose = "1.6.6" +composePlugin = "1.6.2" +agp = "8.3.2" android-compileSdk = "34" cache4k = "0.13.0" @@ -46,10 +46,11 @@ kotlinx-knit = { module = "org.jetbrains.kotlinx:kotlinx-knit", version.ref = "k kotlinx-serializationCore = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerialization" } kotlinx-serializationJson = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" } squareup-okhttpMockWebServer = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "mockWebServer" } -squareup-retrofitConverterGson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } -squareup-retrofitConverterMoshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } -jakewharton-retrofitConverterKotlinxSerialization = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerialization" } -squareup-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +squareup-retrofit-lib = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +squareup-retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } +squareup-retrofit-converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } +squareup-retrofit-converter-kotlinxSerialization = { module = "com.squareup.retrofit2:converter-kotlinx-serialization", version.ref = "retrofit" } +squareup-moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" } ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "kspVersion" } kspGradlePlugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "kspVersion" } assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd491770..e6441136f3d 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22ce5cf..b82aa23a4f0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index cf0d98057ef..8ca60b32cb5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,7 +17,7 @@ pluginManagement { } plugins { - id("com.gradle.enterprise") version "3.16.2" + id("com.gradle.enterprise") version "3.17.2" id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0") }