diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt index 5f31d3fe90e..f919b34a63f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt @@ -5,8 +5,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors @@ -24,22 +22,28 @@ object FirCyclicTypeBoundsChecker : FirMemberDeclarationChecker() { val processed = mutableSetOf() val cycles = mutableSetOf() - val graph = declaration.typeParameters.map { param -> + val graph = declaration.typeParameters.associate { param -> param.symbol.name to param.symbol.fir.bounds.flatMap { extractTypeParamNames(it) }.toSet() - }.toMap() + } + val graphFunc = { name: Name -> graph.getOrDefault(name, emptySet()) } + val path = mutableListOf() - declaration.typeParameters.forEach { param -> - if (!processed.contains(param.symbol.name)) { - findCycles( - persistentListOf(), - param.symbol.name, - processed, - mutableSetOf(), - cycles - ) { name -> graph.getOrDefault(name, emptySet()) } + fun findCycles( + node: Name + ) { + if (processed.add(node)) { + path.add(node) + graphFunc(node).forEach { nextNode -> + findCycles(nextNode) + } + path.removeAt(path.size - 1) + } else { + cycles.addAll(path.dropWhile { it != node }) } } + declaration.typeParameters.forEach { param -> findCycles(param.symbol.name) } + if (cycles.isNotEmpty()) { declaration.typeParameters .filter { cycles.contains(it.symbol.name) } @@ -72,24 +76,4 @@ object FirCyclicTypeBoundsChecker : FirMemberDeclarationChecker() { ref.unwrapBound().mapNotNull { extractTypeParamName(it.coneType) }.toSet() private fun extractTypeParamName(type: ConeKotlinType): Name? = type.safeAs()?.lookupTag?.name - - private fun findCycles( - path: PersistentList, - node: Name, - processed: MutableSet, - visited: MutableSet, - cycles: MutableSet, - graph: (Name) -> Set - ) { - processed.add(node) - if (visited.add(node)) { - val newPath = path.add(node) - graph(node).forEach { nextNode -> - findCycles(newPath, nextNode, processed, visited, cycles, graph) - } - } else { - cycles.addAll(path.dropWhile { it != node }) - } - } - }