[LL FIR] KT-55329 Support transitive dependsOn dependencies in LL FIR
- In contrast to other kinds of dependencies, `dependsOn` dependencies must be followed transitively. - Add `transitiveDependsOnDependencies` to `KtModule`. These dependencies are calculated lazily with a topological sort. They are added to the dependency provider when it's built in `LLFirSessionFactory`. ^KT-55329 fixed
This commit is contained in:
committed by
teamcity
parent
1803bd36cc
commit
d6cb75ca91
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.utils
|
||||
|
||||
/**
|
||||
* Sorts [nodes] topologically collecting direct edges via [dependencies]. [nodes] and [dependencies] must form a directed, acyclic graph.
|
||||
* [topologicalSort] will throw an [IllegalStateException] if it encounters a cycle.
|
||||
*
|
||||
* The algorithm is based on depth-first search, starting in order from each node in [nodes]. Kahn's algorithm is harder to apply to the
|
||||
* ad-hoc dependency structure because it's not easily apparent whether a node has no other incoming edges.
|
||||
*
|
||||
* For example, consider the following structure: `C -> A, C -> B, B -> A`. The resulting order should be `[C, B, A]`. However, `A` is
|
||||
* first in the list of dependencies of `C`. Without a way to find the incoming edge from `B` to `A` while processing `C -> A`, a naive
|
||||
* implementation of Kahn's algorithm might order `A` before `B`.
|
||||
*/
|
||||
fun <A> topologicalSort(nodes: Iterable<A>, dependencies: A.() -> Iterable<A>): List<A> {
|
||||
val visiting = mutableSetOf<A>()
|
||||
val visited = mutableSetOf<A>()
|
||||
|
||||
fun visit(node: A) {
|
||||
if (node in visited) return
|
||||
if (node in visiting) throw IllegalStateException("Cannot compute a topological sort: The node $node is in a cycle.")
|
||||
|
||||
// Keeping track of the nodes that are being visited allows the algorithm to throw an exception in case of a cycle. The input should
|
||||
// never be cyclic, but this approach gives some additional safety in case of bugs.
|
||||
visiting.add(node)
|
||||
node.dependencies().forEach(::visit)
|
||||
visiting.remove(node)
|
||||
|
||||
visited.add(node)
|
||||
}
|
||||
|
||||
nodes.forEach(::visit)
|
||||
|
||||
// The paper algorithm inserts nodes at the head of the result list. Because our `visited` set remembers elements in their order of
|
||||
// insertion, the result needs to be reversed.
|
||||
return visited.toMutableList().apply { reverse() }
|
||||
}
|
||||
Reference in New Issue
Block a user