[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:
Marco Pennekamp
2022-12-20 18:41:23 +01:00
committed by teamcity
parent 1803bd36cc
commit d6cb75ca91
15 changed files with 126 additions and 36 deletions
@@ -25,7 +25,7 @@ public sealed interface KtModule {
* A list of Regular dependencies. Regular dependency allows the current module to see symbols from the dependent module. In the case
* of a source set, it can be either the source set it depends on, a library, or an SDK.
*
* The dependencies list is non-transitive and should not include the current module.
* The dependencies list is non-transitive and does not include the current module.
*/
public val directRegularDependencies: List<KtModule>
@@ -35,14 +35,22 @@ public sealed interface KtModule {
* A `dependsOn` dependency expresses that the current module can provide `actual` declarations for `expect` declarations from the
* dependent module, as well as see internal symbols of the dependent module.
*
* `dependsOn` dependencies are transitive, but the list is not a transitive closure. The list should not include the current module.
* `dependsOn` dependencies are transitive, but the list is not a transitive closure. The list does not include the current module.
*/
public val directDependsOnDependencies: List<KtModule>
/**
* A list of [directDependsOnDependencies] and all of their parents (directly and indirectly), sorted topologically with the nearest
* dependencies first in the list. The list does not include the current module.
*
* @see computeTransitiveDependsOnDependencies
*/
public val transitiveDependsOnDependencies: List<KtModule>
/**
* A list of Friend dependencies. Friend dependencies express that the current module may see internal symbols of the dependent module.
*
* The dependencies list is non-transitive and should not include the current module.
* The dependencies list is non-transitive and does not include the current module.
*/
public val directFriendDependencies: List<KtModule>
@@ -159,6 +167,7 @@ public class KtBuiltinsModule(
) : KtBinaryModule {
override val directRegularDependencies: List<KtModule> get() = emptyList()
override val directDependsOnDependencies: List<KtModule> get() = emptyList()
override val transitiveDependsOnDependencies: List<KtModule> get() = emptyList()
override val directFriendDependencies: List<KtModule> get() = emptyList()
override val contentScope: GlobalSearchScope get() = GlobalSearchScope.EMPTY_SCOPE
override fun getBinaryRoots(): Collection<Path> = emptyList()
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.analysis.project.structure
import org.jetbrains.kotlin.utils.topologicalSort
/**
* A list of all modules that the current module can depend on with regular dependency.
*
@@ -51,4 +53,14 @@ public fun KtModule.allDirectDependencies(): Sequence<KtModule> =
* @see KtModule.directFriendDependencies
*/
public inline fun <reified M : KtModule> KtModule.allDirectDependenciesOfType(): Sequence<M> =
allDirectDependencies().filterIsInstance<M>()
allDirectDependencies().filterIsInstance<M>()
/**
* Computes the transitive `dependsOn` dependencies of [directDependsOnDependencies]. [computeTransitiveDependsOnDependencies] is the
* default computation strategy to provide [KtModule.transitiveDependsOnDependencies].
*
* The algorithm is a depth-first search-based topological sort. `dependsOn` dependencies cannot be cyclical and thus form a DAG, which
* allows the application of a topological sort.
*/
public fun computeTransitiveDependsOnDependencies(directDependsOnDependencies: List<KtModule>): List<KtModule> =
topologicalSort(directDependsOnDependencies) { this.directDependsOnDependencies }