diff --git a/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/ZiplineServiceAdapter.kt b/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/ZiplineServiceAdapter.kt index 611129cee9..e14cb2df63 100644 --- a/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/ZiplineServiceAdapter.kt +++ b/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/ZiplineServiceAdapter.kt @@ -93,7 +93,12 @@ internal fun serialName(typeName: String, serializers: List>): St } } -private fun descriptorName(typeName: SerialDescriptor): String { +private fun descriptorName(typeName: SerialDescriptor, visited: MutableSet = mutableSetOf()): String { + // Check if we've already visited this descriptor to avoid infinite recursion + if (!visited.add(typeName)) { + return typeName.serialName + } + return buildString { append(typeName.serialName) @@ -102,7 +107,7 @@ private fun descriptorName(typeName: SerialDescriptor): String { val elementIndices = 0 until typeName.elementsCount for (i in elementIndices) { - append(descriptorName(typeName.getElementDescriptor(i))) + append(descriptorName(typeName.getElementDescriptor(i), visited)) if (i < elementIndices.last) { append(',') } diff --git a/zipline/src/hostTest/kotlin/app/cash/zipline/internal/bridge/SerialNameTest.kt b/zipline/src/hostTest/kotlin/app/cash/zipline/internal/bridge/SerialNameTest.kt index 09ca77c9cc..cc3a327ea5 100644 --- a/zipline/src/hostTest/kotlin/app/cash/zipline/internal/bridge/SerialNameTest.kt +++ b/zipline/src/hostTest/kotlin/app/cash/zipline/internal/bridge/SerialNameTest.kt @@ -17,6 +17,7 @@ package app.cash.zipline.internal.bridge import kotlin.test.Test import kotlin.test.assertEquals +import kotlinx.serialization.Serializable import kotlinx.serialization.serializer class SerialNameTest { @@ -79,4 +80,26 @@ class SerialNameTest { serialName, ) } + + @Test + fun recursiveSerializer() { + val serialName = serialName( + "SomeType", + serializers = listOf( + serializer(), + ), + ) + assertEquals( + expected = "SomeType<" + + "app.cash.zipline.internal.bridge.SomeRecursiveType<" + + "app.cash.zipline.internal.bridge.SomeRecursiveType?" + + ">>", + actual = serialName, + ) + } } + +@Serializable +private data class SomeRecursiveType( + val someData: SomeRecursiveType?, +)