dokka icon indicating copy to clipboard operation
dokka copied to clipboard

AssertionError: Recursion detected in a lazy value under LockBasedStorageManager in multiplatform project

Open illarionov opened this issue 1 year ago • 2 comments

Describe the bug

./gradle dokkaGfm fails on a multiplatform project with the following exception: java.lang.AssertionError: Recursion detected in a lazy value under LockBasedStorageManager@61bed5ef (Dokka).

Repository with an example project: https://github.com/illarionov/playground-android-composite-build/tree/dokka-typealias-recursion (dokka-typealias-recursion branch).
This project has a shared Jvm + Android source set and some typealias defined.

To Reproduce Clone the above example repository, or create a new multiplatform project with about the following submodule configuration (build.gradle.kts):

plugins {
    id("org.jetbrains.kotlin.multiplatform")
    id("com.android.library")
}

kotlin {
    androidTarget()
    jvm()

    applyDefaultHierarchyTemplate()

    sourceSets {
        val jvmAndAndroid by creating {
            dependsOn(commonMain.get())
        }
        androidMain.get().dependsOn(jvmAndAndroid)
        jvmMain.get().dependsOn(jvmAndAndroid)
    }
}

Create a Kotlin source code file in the shared source set (composeApp/src/jvmAndAndroid/kotlin/org/example/dokka/Types.jvmAndAndroid.kt):

package org.example.dokka

import java.io.File

typealias File = File

Run ./gradlew dokkaGfm --stacktrace. It will fail with the following stacktrace:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':composeApp:dokkaGfm'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:130)
        at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:128)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:116)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314)
        at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:463)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:380)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
Caused by: java.lang.AssertionError: Recursion detected in a lazy value under LockBasedStorageManager@61bed5ef (Dokka)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.getDefaultType(LazyTypeAliasDescriptor.kt:57)
        at org.jetbrains.kotlin.types.KotlinTypeFactory.simpleType(KotlinTypeFactory.kt:85)
        at org.jetbrains.kotlin.types.KotlinTypeFactory.simpleType$default(KotlinTypeFactory.kt:77)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveTypeForTypeAlias(TypeResolver.kt:727)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveTypeForClassifier(TypeResolver.kt:583)
        at org.jetbrains.kotlin.resolve.TypeResolver$resolveTypeElement$1.visitUserType(TypeResolver.kt:278)
        at org.jetbrains.kotlin.psi.KtVisitorVoid.visitUserType(KtVisitorVoid.java:937)
        at org.jetbrains.kotlin.psi.KtVisitorVoid.visitUserType(KtVisitorVoid.java:21)
        at org.jetbrains.kotlin.psi.KtUserType.accept(KtUserType.java:42)
        at org.jetbrains.kotlin.psi.KtElementImplStub.accept(KtElementImplStub.java:49)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveTypeElement(TypeResolver.kt:257)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolvePossiblyBareType(TypeResolver.kt:136)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveType(TypeResolver.kt:126)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveAbbreviatedType(TypeResolver.kt:104)
        at org.jetbrains.kotlin.resolve.DescriptorResolver.lambda$resolveTypeAliasDescriptor$2(DescriptorResolver.java:788)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.getUnderlyingType(LazyTypeAliasDescriptor.kt:54)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.computeClassDescriptor(LazyTypeAliasDescriptor.kt:74)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.access$computeClassDescriptor(LazyTypeAliasDescriptor.kt:34)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor$initialize$2.invoke(LazyTypeAliasDescriptor.kt:70)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor$initialize$2.invoke(LazyTypeAliasDescriptor.kt:70)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.getClassDescriptor(LazyTypeAliasDescriptor.kt:56)
        at org.jetbrains.kotlin.descriptors.impl.AbstractTypeAliasDescriptor.computeDefaultType(AbstractTypeAliasDescriptor.kt:98)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.access$computeDefaultType(LazyTypeAliasDescriptor.kt:34)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor$initialize$1.invoke(LazyTypeAliasDescriptor.kt:69)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor$initialize$1.invoke(LazyTypeAliasDescriptor.kt:69)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor.getDefaultType(LazyTypeAliasDescriptor.kt:57)
        at org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DokkaDescriptorVisitor$visitTypeAliasDescriptor$2$1.invokeSuspend(DefaultDescriptorToDocumentableTranslator.kt:844)
        at org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DokkaDescriptorVisitor$visitTypeAliasDescriptor$2$1.invoke(DefaultDescriptorToDocumentableTranslator.kt)
        at org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DokkaDescriptorVisitor$visitTypeAliasDescriptor$2$1.invoke(DefaultDescriptorToDocumentableTranslator.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78)
        at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
        at org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DokkaDescriptorVisitor.visitTypeAliasDescriptor(DefaultDescriptorToDocumentableTranslator.kt:842)
        at org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DokkaDescriptorVisitor.access$visitTypeAliasDescriptor(DefaultDescriptorToDocumentableTranslator.kt:161)
        at org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DokkaDescriptorVisitor$visitTypealiases$2$invokeSuspend$$inlined$parallelMap$1$1.invokeSuspend(parallelCollectionOperations.kt:28)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)

Workaround: if we replace the typealias line to typealias File = java.io.File, then the build will succeed.

Installation

  • Operating system: Linux
  • Build tool: Gradle v8.7
  • Dokka version: 1.9.20
  • Kotlin version: 1.9.23

illarionov avatar Apr 14 '24 16:04 illarionov

Related issues: https://github.com/Kotlin/dokka/issues/3317 https://github.com/Kotlin/dokka/issues/3513

Thank you for the reproducer.


The problem is that the Dokka Gradle Plugin wrongly(?) defines jvmAndAndroid as a common platform here. That means that:

import java.io.File
typealias File = File

java.io.File is unresolved since JDK is only available for a JVM platform. In K1, it causes a recursion (AssertionError that fails a Dokka run). In K2, it just leads to an unresolved type.

vmishenev avatar Apr 18 '24 14:04 vmishenev

An intermediate solution: do not fail the build to at least let the users build documentation, even if the reference is lost.

Overall, to address the issue properly, we need to investigate how this case should be handled, what the expected behaviour is from Kotlin's perspective, whether such setups are even allowed.

IgnatBeresnev avatar Apr 22 '24 08:04 IgnatBeresnev