[Commonizer] Implement associative commonization

^KT-47301 Verification Pending
This commit is contained in:
sebastian.sellmair
2021-06-11 15:19:35 +02:00
committed by Space
parent 5fdbcb3dd1
commit 42f60d981f
58 changed files with 957 additions and 1091 deletions
@@ -9,27 +9,22 @@ import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
import org.jetbrains.kotlin.commonizer.mergedtree.CirFictitiousFunctionClassifiers
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
import org.jetbrains.kotlin.commonizer.stats.StatsCollector
import org.jetbrains.kotlin.commonizer.utils.ProgressLogger
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.util.Logger
data class CommonizerParameters(
val outputTarget: SharedCommonizerTarget,
val outputTargets: Set<SharedCommonizerTarget>,
val manifestProvider: TargetDependent<NativeManifestDataProvider>,
val dependenciesProvider: TargetDependent<ModulesProvider?>,
val targetProviders: TargetDependent<TargetProvider?>,
val resultsConsumer: ResultsConsumer,
val storageManager: StorageManager = LockBasedStorageManager.NO_LOCKS,
val statsCollector: StatsCollector? = null,
val logger: ProgressLogger? = null,
val logger: Logger? = null,
)
internal fun CommonizerParameters.dependencyClassifiers(target: CommonizerTarget): CirProvidedClassifiers {
val modules = outputTarget.withAllAncestors()
.sortedBy { it.level }
.filter { it == target || it isAncestorOf target }
.mapNotNull { compatibleTarget -> dependenciesProvider[compatibleTarget] }
return modules.fold<ModulesProvider, CirProvidedClassifiers>(CirFictitiousFunctionClassifiers) { classifiers, module ->
CirProvidedClassifiers.of(classifiers, CirProvidedClassifiers.by(module))
}
val modulesProvider = dependenciesProvider[target]
return CirProvidedClassifiers.of(CirFictitiousFunctionClassifiers, CirProvidedClassifiers.by(modulesProvider))
}
internal fun CommonizerParameters.with(logger: ProgressLogger?) = copy(logger = logger)
@@ -0,0 +1,143 @@
/*
* Copyright 2010-2021 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.commonizer
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
import org.jetbrains.kotlin.commonizer.tree.assembleCirTree
import org.jetbrains.kotlin.storage.NullableLazyValue
import org.jetbrains.kotlin.storage.StorageManager
private typealias OutputCommonizerTarget = SharedCommonizerTarget
private typealias InputCommonizerTarget = CommonizerTarget
internal fun CommonizerQueue(parameters: CommonizerParameters): CommonizerQueue {
return CommonizerQueue(
storageManager = parameters.storageManager,
outputTargets = parameters.outputTargets,
deserializers = parameters.targetProviders.mapTargets { target ->
CommonizerQueue.Deserializer { deserializeTarget(parameters, target) }
},
commonizer = { inputs, output -> commonizeTarget(parameters, inputs, output) },
serializer = { declarations, outputTarget -> serializeTarget(parameters, declarations, outputTarget) },
inputTargetsSelector = DefaultInputTargetsSelector
)
}
internal class CommonizerQueue(
private val storageManager: StorageManager,
private val outputTargets: Set<OutputCommonizerTarget>,
private val deserializers: TargetDependent<Deserializer>,
private val commonizer: Commonizer,
private val serializer: Serializer,
private val inputTargetsSelector: InputTargetsSelector
) {
fun interface Deserializer {
operator fun invoke(): CirTreeRoot?
}
fun interface Commonizer {
operator fun invoke(inputs: TargetDependent<CirTreeRoot?>, output: SharedCommonizerTarget): CirRootNode?
}
fun interface Serializer {
operator fun invoke(declarations: CirRootNode, outputTarget: OutputCommonizerTarget)
}
/**
* Targets that can just be deserialized and do not need to be commonized.
* All leaf targets are expected to be provided.
* Previously commonized targets can also be provided
*/
private val deserializedTargets: MutableMap<InputCommonizerTarget, NullableLazyValue<CirTreeRoot>> =
deserializers.toMap().mapValuesTo(mutableMapOf()) { (_, deserializer) ->
storageManager.createNullableLazyValue { deserializer() }
}
/**
* Targets that created using commonization.
* The roots are lazy and will be removed as no further pending target requires it's input
*/
private val commonizedTargets: MutableMap<OutputCommonizerTarget, NullableLazyValue<CirTreeRoot>> = mutableMapOf()
/**
* Represents dependency relationships between input and output targets.
* Dependencies will be removed if the target was commonized.
*/
private val targetDependencies: MutableMap<OutputCommonizerTarget, Set<InputCommonizerTarget>> = mutableMapOf()
val retainedDeserializedTargets: Set<InputCommonizerTarget> get() = deserializedTargets.keys
val retainedCommonizedTargets: Set<OutputCommonizerTarget> get() = commonizedTargets.keys
val retainedTargetDependencies: Map<OutputCommonizerTarget, Set<InputCommonizerTarget>> get() = targetDependencies.toMap()
val pendingOutputTargets: Set<CommonizerTarget> get() = targetDependencies.keys
/**
* Runs all tasks/targets in this queue
*/
fun invokeAll() {
outputTargets.forEach { outputTarget -> invokeTarget(outputTarget) }
assert(deserializedTargets.isEmpty()) { "Expected 'deserializedTargets' to be empty. Found ${deserializedTargets.keys}" }
assert(commonizedTargets.isEmpty()) { "Expected 'commonizedTargets' to be empty. Found ${commonizedTargets.keys}" }
assert(targetDependencies.isEmpty()) { "Expected 'targetDependencies' to be empty. Found $targetDependencies" }
}
fun invokeTarget(outputTarget: OutputCommonizerTarget) {
commonizedTargets[outputTarget]?.invoke()
}
private fun enqueue(outputTarget: OutputCommonizerTarget) {
registerTargetDependencies(outputTarget)
commonizedTargets[outputTarget] = storageManager.createNullableLazyValue {
commonize(outputTarget)
}
}
private fun commonize(target: SharedCommonizerTarget): CirTreeRoot? {
val inputTargets = targetDependencies.getValue(target)
val inputDeclarations = EagerTargetDependent(inputTargets) { inputTarget ->
(deserializedTargets[inputTarget] ?: commonizedTargets[inputTarget]
?: throw IllegalStateException("Missing inputTarget $inputTarget")).invoke()
}
return commonizer(inputDeclarations, target)
.also { removeTargetDependencies(target) }
?.also { commonizedDeclarations -> serializer(commonizedDeclarations, target) }
?.assembleCirTree()
}
private fun registerTargetDependencies(outputTarget: OutputCommonizerTarget) {
targetDependencies[outputTarget] = inputTargetsSelector(outputTargets + deserializers.targets, outputTarget)
}
private fun removeTargetDependencies(target: OutputCommonizerTarget) {
targetDependencies.remove(target) ?: return
val referencedDependencyTargets = targetDependencies.values.flatten().toSet()
// Release all commonized targets that are not pending anymore (are already invoked)
// and that are not listed as input target dependency for any further commonization
// Release all commonized targets that no one intends to use any further.
commonizedTargets.keys
.filter { it !in referencedDependencyTargets && it !in pendingOutputTargets }
.forEach(commonizedTargets::remove)
// Release all deserialized targets that are not referenced as any further dependency anymore.
// Release all deserialized targets that no one intends to use any further
deserializedTargets.keys
.filter { it !in referencedDependencyTargets }
.forEach(deserializedTargets::remove)
}
init {
outputTargets.forEach(this::enqueue)
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2021 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.commonizer
import org.jetbrains.kotlin.commonizer.utils.isProperSubsetOf
import org.jetbrains.kotlin.commonizer.utils.isSubsetOf
internal fun interface InputTargetsSelector {
operator fun invoke(inputTargets: Set<CommonizerTarget>, outputTarget: SharedCommonizerTarget): Set<CommonizerTarget>
}
internal operator fun InputTargetsSelector.invoke(
parameters: CommonizerParameters,
outputTarget: SharedCommonizerTarget
): Set<CommonizerTarget> {
return invoke(parameters.outputTargets + parameters.targetProviders.targets, outputTarget)
}
internal object DefaultInputTargetsSelector : InputTargetsSelector {
override fun invoke(inputTargets: Set<CommonizerTarget>, outputTarget: SharedCommonizerTarget): Set<CommonizerTarget> {
val subsetInputTargets = inputTargets
.filter { inputTarget -> inputTarget != outputTarget && inputTarget.allLeaves() isSubsetOf outputTarget.allLeaves() }
.sortedBy { it.allLeaves().size }
val disjointSubsetInputTargets = subsetInputTargets
.filter { inputTarget ->
subsetInputTargets.none { potentialSuperSet -> inputTarget.allLeaves() isProperSubsetOf potentialSuperSet.allLeaves() }
}
return outputTarget.allLeaves().fold(setOf()) { selectedInputTargets, outputLeafTarget ->
if (outputLeafTarget in selectedInputTargets.allLeaves()) return@fold selectedInputTargets
selectedInputTargets + (disjointSubsetInputTargets.firstOrNull { inputTarget -> outputLeafTarget in inputTarget.allLeaves() }
?: failedSelectingInputTargets(inputTargets, outputTarget))
}
}
}
private fun failedSelectingInputTargets(inputTargets: Set<CommonizerTarget>, outputTarget: SharedCommonizerTarget): Nothing {
throw IllegalArgumentException(
"Failed selecting input targets for $outputTarget\n" +
"inputTargets=$inputTargets\n" +
"missing leaf targets: ${outputTarget.allLeaves() - inputTargets.allLeaves()}"
)
}
@@ -8,16 +8,16 @@ package org.jetbrains.kotlin.commonizer.cli
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
import org.jetbrains.kotlin.commonizer.parseCommonizerTarget
internal object OutputCommonizerTargetOptionType : OptionType<SharedCommonizerTarget>(
alias = "output-commonizer-target",
description = "Shared commonizer target representing the commonized output hierarchy",
mandatory = false
internal object OutputCommonizerTargetsOptionType : OptionType<Set<SharedCommonizerTarget>>(
alias = "output-targets",
description = "Shared commonizer target representing the commonized output hierarchy", // TODO NOW
mandatory = true
) {
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<SharedCommonizerTarget> {
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<Set<SharedCommonizerTarget>> {
return try {
Option(this, parseCommonizerTarget(rawValue) as SharedCommonizerTarget)
Option(this, rawValue.split(";").map(::parseCommonizerTarget).map { it as SharedCommonizerTarget }.toSet())
} catch (t: Throwable) {
onError("Failed parsing output-commonizer-target ($rawValue): ${t.message}")
onError("Failed parsing output-target ($rawValue): ${t.message}")
}
}
}
@@ -18,7 +18,7 @@ internal enum class TaskType(
NativeDistributionOptionType,
OutputOptionType,
NativeTargetsOptionType,
OutputCommonizerTargetOptionType,
OutputCommonizerTargetsOptionType,
BooleanOptionType(
"copy-stdlib",
"Boolean (default false);\nwhether to copy Kotlin/Native endorsed libraries to the destination",
@@ -52,7 +52,7 @@ internal enum class TaskType(
OutputOptionType,
InputLibrariesOptionType,
DependencyLibrariesOptionType,
OutputCommonizerTargetOptionType,
OutputCommonizerTargetsOptionType,
LogLevelOptionType
),
::NativeKlibCommonize
@@ -3,18 +3,19 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("DuplicatedCode")
package org.jetbrains.kotlin.commonizer.cli
import org.jetbrains.kotlin.commonizer.*
import org.jetbrains.kotlin.commonizer.konan.*
import org.jetbrains.kotlin.commonizer.konan.LibraryCommonizer
import org.jetbrains.kotlin.commonizer.konan.ModuleSerializer
import org.jetbrains.kotlin.commonizer.repository.*
import org.jetbrains.kotlin.commonizer.stats.FileStatsOutput
import org.jetbrains.kotlin.commonizer.stats.StatsCollector
import org.jetbrains.kotlin.commonizer.stats.StatsType
import org.jetbrains.kotlin.commonizer.utils.ProgressLogger
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
internal class NativeDistributionListTargets(options: Collection<Option<*>>) : Task(options) {
@@ -48,35 +49,31 @@ internal class NativeKlibCommonize(options: Collection<Option<*>>) : Task(option
val destination = getMandatory<File, OutputOptionType>()
val targetLibraries = getMandatory<List<File>, InputLibrariesOptionType>()
val dependencyLibraries = getOptional<List<CommonizerDependency>, DependencyLibrariesOptionType>().orEmpty()
val outputCommonizerTarget = compatGetOutputTarget()
val outputTargets = getMandatory<Set<SharedCommonizerTarget>, OutputCommonizerTargetsOptionType>()
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
val logLevel = getOptional<CommonizerLogLevel, LogLevelOptionType>() ?: CommonizerLogLevel.Quiet
val konanTargets = outputCommonizerTarget.konanTargets
val konanTargets = outputTargets.konanTargets
val commonizerTargets = konanTargets.map(::CommonizerTarget)
val logger = ProgressLogger(CliLoggerAdapter(logLevel, 2))
val logger = CliLoggerAdapter(logLevel, 2)
val libraryLoader = DefaultNativeLibraryLoader(logger)
val statsCollector = StatsCollector(statsType, commonizerTargets)
val repository = FilesRepository(targetLibraries.toSet(), libraryLoader)
val resultsConsumer = buildResultsConsumer {
this add ModuleSerializer(destination, HierarchicalCommonizerOutputLayout)
this add CopyUnconsumedModulesAsIsConsumer(
repository, destination, commonizerTargets.toSet(), NativeDistributionCommonizerOutputLayout
)
this add LoggingResultsConsumer(outputCommonizerTarget)
this add ModuleSerializer(destination)
}
LibraryCommonizer(
outputTarget = outputCommonizerTarget,
outputTargets = outputTargets,
repository = repository,
dependencies = StdlibRepository(distribution, libraryLoader) +
CommonizerDependencyRepository(dependencyLibraries.toSet(), libraryLoader),
resultsConsumer = resultsConsumer,
statsCollector = statsCollector,
progressLogger = logger
logger = logger
).run()
statsCollector?.writeTo(FileStatsOutput(destination, statsType.name.lowercase()))
@@ -90,40 +87,30 @@ internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Tas
val distribution = KonanDistribution(getMandatory<File, NativeDistributionOptionType>())
val destination = getMandatory<File, OutputOptionType>()
val outputTarget = compatGetOutputTarget()
val outputLayout = if (getOptional<SharedCommonizerTarget, OutputCommonizerTargetOptionType>() != null)
HierarchicalCommonizerOutputLayout
else NativeDistributionCommonizerOutputLayout
val outputTargets = getMandatory<Set<SharedCommonizerTarget>, OutputCommonizerTargetsOptionType>()
val copyStdlib = getOptional<Boolean, BooleanOptionType> { it == "copy-stdlib" } ?: false
val copyEndorsedLibs = getOptional<Boolean, BooleanOptionType> { it == "copy-endorsed-libs" } ?: false
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
val logLevel = getOptional<CommonizerLogLevel, LogLevelOptionType>() ?: CommonizerLogLevel.Quiet
val logger = ProgressLogger(CliLoggerAdapter(logLevel, 2))
val logger = CliLoggerAdapter(logLevel, 2)
val libraryLoader = DefaultNativeLibraryLoader(logger)
val repository = KonanDistributionRepository(distribution, outputTarget.konanTargets, libraryLoader)
val statsCollector = StatsCollector(statsType, outputTarget.withAllAncestors().toList())
val repository = KonanDistributionRepository(distribution, outputTargets.konanTargets, libraryLoader)
val statsCollector = StatsCollector(statsType, outputTargets.allLeaves().toList())
val resultsConsumer = buildResultsConsumer {
this add ModuleSerializer(destination, outputLayout)
this add CopyUnconsumedModulesAsIsConsumer(repository, destination, outputTarget.allLeaves(), outputLayout)
if (copyStdlib) this add CopyStdlibResultsConsumer(distribution, destination)
if (copyEndorsedLibs) this add CopyEndorsedLibrairesResultsConsumer(distribution, destination)
this add LoggingResultsConsumer(outputTarget)
this add ModuleSerializer(destination)
}
val descriptionSuffix = estimateLibrariesCount(repository, outputTarget.allLeaves()).let { " ($it items)" }
logger.log("${logPrefix}Preparing commonized Kotlin/Native libraries for $outputTarget$descriptionSuffix")
val descriptionSuffix = estimateLibrariesCount(repository, outputTargets.allLeaves()).let { " ($it items)" }
logger.log("${logPrefix}Preparing commonized Kotlin/Native libraries for ${outputTargets.allLeaves()}$descriptionSuffix")
LibraryCommonizer(
outputTarget = outputTarget,
outputTargets = outputTargets,
repository = repository,
dependencies = StdlibRepository(distribution, libraryLoader),
resultsConsumer = resultsConsumer,
statsCollector = statsCollector,
progressLogger = logger
logger = logger
).run()
statsCollector?.writeTo(FileStatsOutput(destination, statsType.name.lowercase()))
@@ -136,10 +123,4 @@ internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Tas
}
}
private fun Task.compatGetOutputTarget(): SharedCommonizerTarget {
getOptional<SharedCommonizerTarget, OutputCommonizerTargetOptionType>()?.let { return it }
val konanTargets = getOptional<List<KonanTarget>, NativeTargetsOptionType>() ?: throw IllegalArgumentException(
"Missing ${OutputCommonizerTargetOptionType.alias} or deprecated ${NativeTargetsOptionType.alias} option was specified"
)
return SharedCommonizerTarget(konanTargets)
}
@@ -9,7 +9,7 @@ package org.jetbrains.kotlin.commonizer
* @return Set of module names that is available across all children targets
*/
internal fun CommonizerParameters.commonModuleNames(target: CommonizerTarget): Set<String> {
val supportedTargets = target.withAllAncestors().mapNotNull(targetProviders::getOrNull)
val supportedTargets = target.withAllLeaves().mapNotNull(targetProviders::getOrNull)
if (supportedTargets.isEmpty()) return emptySet() // Nothing to do
val allModuleNames: List<Set<String>> = supportedTargets.toList().map { targetProvider ->
@@ -23,8 +23,8 @@ internal fun CommonizerParameters.commonModuleNames(target: CommonizerTarget): S
* @return Set of module names that this [targetProvider] shares with *at least* one other target
*/
internal fun CommonizerParameters.commonModuleNames(targetProvider: TargetProvider): Set<String> {
return outputTarget.withAllAncestors()
.filter { target -> target isAncestorOf targetProvider.target }
return outputTargets
.filter { target -> (target.allLeaves() intersect targetProvider.target.allLeaves()).isNotEmpty() }
.map { target -> commonModuleNames(target) }
.fold(emptySet()) { acc, names -> acc + names }
}
@@ -6,22 +6,24 @@
package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.LeafCommonizerTarget
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
import org.jetbrains.kotlin.commonizer.allLeaves
import org.jetbrains.kotlin.commonizer.cir.CirRoot
class RootCommonizer : AbstractStandardCommonizer<CirRoot, CirRoot>() {
private val targets = mutableSetOf<CommonizerTarget>()
private val targets = mutableSetOf<LeafCommonizerTarget>()
override fun commonizationResult() = CirRoot.create(
target = SharedCommonizerTarget(targets)
)
override fun initialize(first: CirRoot) {
targets += first.target
targets += first.target.allLeaves()
}
override fun doCommonizeWith(next: CirRoot): Boolean {
targets += next.target
targets += next.target.allLeaves()
return true
}
}
@@ -6,126 +6,79 @@
package org.jetbrains.kotlin.commonizer
import kotlinx.metadata.klib.ChunkedKlibModuleFragmentWriteStrategy
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult.Missing
import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
import org.jetbrains.kotlin.commonizer.core.CommonizationVisitor
import org.jetbrains.kotlin.commonizer.mergedtree.CirCommonizedClassifierNodes
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.indexOfCommon
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.targetIndices
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer.serializeSingleTarget
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer
import org.jetbrains.kotlin.commonizer.transformer.Checked.Companion.invoke
import org.jetbrains.kotlin.commonizer.transformer.InlineTypeAliasCirNodeTransformer
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
import org.jetbrains.kotlin.commonizer.tree.assembleCirTree
import org.jetbrains.kotlin.commonizer.tree.deserializeCirTree
import org.jetbrains.kotlin.commonizer.tree.defaultCirTreeRootDeserializer
import org.jetbrains.kotlin.commonizer.tree.mergeCirTree
import org.jetbrains.kotlin.commonizer.utils.progress
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
fun runCommonization(parameters: CommonizerParameters) {
if (!parameters.containsCommonModuleNames()) {
parameters.resultsConsumer.allConsumed(parameters, Status.NOTHING_TO_DO)
return
}
val storageManager = LockBasedStorageManager("Declarations commonization")
commonize(parameters, storageManager, parameters.outputTarget)
CommonizerQueue(parameters).invokeAll()
parameters.resultsConsumer.allConsumed(parameters, Status.DONE)
}
private fun commonize(
parameters: CommonizerParameters,
storageManager: StorageManager,
target: SharedCommonizerTarget,
): CirRootNode? {
val cirTrees = getCirTree(parameters, storageManager, target)
parameters.logProgress("Built declaration tree for $target")
// build merged tree:
val classifiers = CirKnownClassifiers(
commonizedNodes = CirCommonizedClassifierNodes.default(),
commonDependencies = parameters.dependencyClassifiers(target)
)
val mergedTree = merge(storageManager, classifiers, cirTrees) ?: return null
InlineTypeAliasCirNodeTransformer(storageManager, classifiers).invoke(mergedTree)
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
parameters.logProgress("Commonized declarations for $target")
serialize(parameters, mergedTree, target)
return mergedTree
}
private fun getCirTree(
parameters: CommonizerParameters, storageManager: StorageManager, target: SharedCommonizerTarget
): TargetDependent<CirTreeRoot?> {
return EagerTargetDependent(target.targets) { childTarget ->
when (childTarget) {
is LeafCommonizerTarget -> deserialize(parameters, childTarget)
is SharedCommonizerTarget -> commonize(parameters.fork(), storageManager, childTarget)?.assembleCirTree().also {
parameters.logProgress("Commonized target $childTarget")
}
}
internal fun deserializeTarget(parameters: CommonizerParameters, target: TargetProvider): CirTreeRoot {
return parameters.logger.progress(target.target, "Deserialized declarations") {
defaultCirTreeRootDeserializer(parameters, target)
}
}
private fun deserialize(parameters: CommonizerParameters, target: CommonizerTarget): CirTreeRoot? {
internal fun deserializeTarget(parameters: CommonizerParameters, target: CommonizerTarget): CirTreeRoot? {
val targetProvider = parameters.targetProviders[target] ?: return null
return deserializeCirTree(parameters, targetProvider)
return deserializeTarget(parameters, targetProvider)
}
private fun merge(
storageManager: StorageManager, classifiers: CirKnownClassifiers, cirTrees: TargetDependent<CirTreeRoot?>,
internal fun commonizeTarget(
parameters: CommonizerParameters,
inputs: TargetDependent<CirTreeRoot?>,
output: CommonizerTarget
): CirRootNode? {
val availableTrees = cirTrees.filterNonNull()
/* Nothing to merge */
if (availableTrees.size == 0) return null
parameters.logger.progress(output, "Commonized declarations from ${inputs.targets}") {
val availableTrees = inputs.filterNonNull()
/* Nothing to merge */
if (availableTrees.size == 0) return null
return mergeCirTree(storageManager, classifiers, availableTrees)
}
val classifiers = CirKnownClassifiers(
commonizedNodes = CirCommonizedClassifierNodes.default(),
commonDependencies = parameters.dependencyClassifiers(output)
)
private fun serialize(parameters: CommonizerParameters, mergedTree: CirRootNode, commonTarget: CommonizerTarget) {
for (targetIndex in mergedTree.targetIndices) {
val target = mergedTree.targetDeclarations[targetIndex]?.target ?: continue
serializeMissingModules(parameters, target)
if (target is LeafCommonizerTarget) {
serialize(parameters, mergedTree, target, targetIndex)
}
val mergedTree = mergeCirTree(parameters.storageManager, classifiers, availableTrees)
InlineTypeAliasCirNodeTransformer(parameters.storageManager, classifiers).invoke(mergedTree)
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
return mergedTree
}
serialize(parameters, mergedTree, commonTarget, mergedTree.indexOfCommon)
}
private fun serialize(parameters: CommonizerParameters, mergedTree: CirRootNode, target: CommonizerTarget, targetIndex: Int) {
serializeSingleTarget(mergedTree, targetIndex, parameters.statsCollector) { metadataModule ->
internal fun serializeTarget(
parameters: CommonizerParameters,
commonized: CirRootNode,
outputTarget: SharedCommonizerTarget
): Unit = parameters.logger.progress(outputTarget, "Serialized target") {
CirTreeSerializer.serializeSingleTarget(commonized, commonized.indexOfCommon, parameters.statsCollector) { metadataModule ->
val libraryName = metadataModule.name
val serializedMetadata = with(metadataModule.write(KLIB_FRAGMENT_WRITE_STRATEGY)) {
val serializedMetadata = with(metadataModule.write(ChunkedKlibModuleFragmentWriteStrategy())) {
SerializedMetadata(header, fragments, fragmentNames)
}
val manifestData = parameters.manifestProvider[target].buildManifest(libraryName)
parameters.resultsConsumer.consume(parameters, target, ModuleResult.Commonized(libraryName, serializedMetadata, manifestData))
val manifestData = parameters.manifestProvider[outputTarget].buildManifest(libraryName)
parameters.resultsConsumer.consume(
parameters, outputTarget,
ResultsConsumer.ModuleResult.Commonized(libraryName, serializedMetadata, manifestData)
)
}
parameters.resultsConsumer.targetConsumed(parameters, target)
parameters.resultsConsumer.targetConsumed(parameters, outputTarget)
}
private fun serializeMissingModules(parameters: CommonizerParameters, requestedTarget: CommonizerTarget) {
val targetProvider = parameters.targetProviders.getOrNull(requestedTarget) ?: return
val commonModuleNames = parameters.commonModuleNames(targetProvider)
targetProvider.modulesProvider.loadModuleInfos()
.filter { it.name !in commonModuleNames }
.forEach { missingModule ->
parameters.resultsConsumer.consume(parameters, requestedTarget, Missing(missingModule.originalLocation))
}
}
private fun CommonizerParameters.fork(): CommonizerParameters = with(logger?.fork())
private fun CommonizerParameters.logProgress(message: String) = logger?.progress(message)
private val KLIB_FRAGMENT_WRITE_STRATEGY = ChunkedKlibModuleFragmentWriteStrategy()
@@ -1,60 +0,0 @@
/*
* Copyright 2010-2021 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.commonizer.konan
import org.jetbrains.kotlin.commonizer.CommonizerParameters
import org.jetbrains.kotlin.commonizer.KonanDistribution
import org.jetbrains.kotlin.commonizer.ResultsConsumer
import org.jetbrains.kotlin.commonizer.klibDir
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import java.io.File
internal fun CopyStdlibResultsConsumer(
konanDistribution: KonanDistribution,
destination: File
): ResultsConsumer {
return CopyLibrariesFromKonanDistributionResultsConsumer(
konanDistribution,
destination,
invokeWhenCopied = { logger?.progress("Copied standard library") },
copyFileIf = { file -> file.endsWith(KONAN_STDLIB_NAME) }
)
}
internal fun CopyEndorsedLibrairesResultsConsumer(
konanDistribution: KonanDistribution,
destination: File,
): ResultsConsumer {
return CopyLibrariesFromKonanDistributionResultsConsumer(
konanDistribution,
destination,
invokeWhenCopied = { logger?.progress("Copied endorsed libraries") },
copyFileIf = { file -> !file.endsWith(KONAN_STDLIB_NAME) }
)
}
private class CopyLibrariesFromKonanDistributionResultsConsumer(
private val konanDistribution: KonanDistribution,
private val destination: File,
private val invokeWhenCopied: CommonizerParameters.() -> Unit = {},
private val copyFileIf: (File) -> Boolean = { true }
) : ResultsConsumer {
override fun allConsumed(parameters: CommonizerParameters, status: ResultsConsumer.Status) {
konanDistribution.klibDir
.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
.listFiles().orEmpty()
.filter { it.isDirectory }
.filterNot(copyFileIf)
.forEach { libraryOrigin ->
val libraryDestination = destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).resolve(libraryOrigin.name)
libraryOrigin.copyRecursively(libraryDestination)
}
parameters.invokeWhenCopied()
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2010-2021 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.commonizer.konan
import org.jetbrains.kotlin.commonizer.*
import org.jetbrains.kotlin.commonizer.repository.Repository
import java.io.File
internal class CopyUnconsumedModulesAsIsConsumer(
private val repository: Repository,
private val destination: File,
private val targets: Set<LeafCommonizerTarget>,
private val outputLayout: CommonizerOutputLayout,
) : ResultsConsumer {
private val consumedTargets = mutableSetOf<LeafCommonizerTarget>()
override fun targetConsumed(parameters: CommonizerParameters, target: CommonizerTarget) {
if (target is LeafCommonizerTarget) {
consumedTargets += target
}
}
override fun allConsumed(parameters: CommonizerParameters, status: ResultsConsumer.Status) {
when (status) {
ResultsConsumer.Status.NOTHING_TO_DO -> targets.forEach { target -> copyTargetAsIs(parameters, target) }
ResultsConsumer.Status.DONE -> targets.minus(consumedTargets).forEach { target -> copyTargetAsIs(parameters, target) }
}
}
private fun copyTargetAsIs(parameters: CommonizerParameters, target: LeafCommonizerTarget) {
val libraries = repository.getLibraries(target)
val librariesDestination = outputLayout.getTargetDirectory(destination, target)
librariesDestination.mkdirs() // always create an empty directory even if there is nothing to copy
libraries.map { it.library.libraryFile.absolutePath }.map(::File).forEach { libraryFile ->
libraryFile.copyRecursively(destination.resolve(libraryFile.name))
}
parameters.logger?.progress("Copied ${libraries.size} libraries for ${target.prettyName}")
}
}
@@ -8,55 +8,61 @@ package org.jetbrains.kotlin.commonizer.konan
import org.jetbrains.kotlin.commonizer.*
import org.jetbrains.kotlin.commonizer.repository.Repository
import org.jetbrains.kotlin.commonizer.stats.StatsCollector
import org.jetbrains.kotlin.commonizer.utils.ProgressLogger
import org.jetbrains.kotlin.commonizer.utils.progress
import org.jetbrains.kotlin.util.Logger
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
internal class LibraryCommonizer internal constructor(
private val outputTarget: SharedCommonizerTarget,
private val outputTargets: Set<SharedCommonizerTarget>,
private val repository: Repository,
private val dependencies: Repository,
private val resultsConsumer: ResultsConsumer,
private val statsCollector: StatsCollector?,
private val progressLogger: ProgressLogger
private val logger: Logger
) {
fun run() {
checkPreconditions()
val allLibraries = loadLibraries()
commonizeAndSaveResults(allLibraries)
progressLogger.logTotal()
logger.progress("Commonized all targets") {
checkPreconditions()
val allLibraries = loadLibraries()
commonizeAndSaveResults(allLibraries)
}
}
private fun loadLibraries(): TargetDependent<NativeLibrariesToCommonize?> {
val libraries = EagerTargetDependent(outputTarget.allLeaves()) { target ->
repository.getLibraries(target).toList().ifNotEmpty { NativeLibrariesToCommonize(target, this) }
}
return logger.progress("Resolved all libraries for commonization") {
val libraries = EagerTargetDependent(outputTargets.allLeaves()) { target ->
repository.getLibraries(target).toList().ifNotEmpty { NativeLibrariesToCommonize(target, this) }
}
libraries.forEachWithTarget { target, librariesOrNull ->
if (librariesOrNull == null)
progressLogger.warning(
"No libraries found for target ${target.prettyName}. This target will be excluded from commonization."
)
libraries.forEachWithTarget { target, librariesOrNull ->
if (librariesOrNull == null)
logger.warning(
"No libraries found for target ${target}. This target will be excluded from commonization."
)
}
libraries
}
progressLogger.progress("Resolved libraries to be commonized")
return libraries
}
private fun commonizeAndSaveResults(libraries: TargetDependent<NativeLibrariesToCommonize?>) {
val parameters = CommonizerParameters(
outputTarget = outputTarget,
targetProviders = libraries.map { target, targetLibraries -> createTargetProvider(target, targetLibraries) },
manifestProvider = createManifestProvider(libraries),
dependenciesProvider = createDependenciesProvider(),
resultsConsumer = resultsConsumer,
statsCollector = statsCollector,
logger = progressLogger
runCommonization(
CommonizerParameters(
outputTargets = outputTargets,
targetProviders = libraries.map { target, targetLibraries -> createTargetProvider(target, targetLibraries) },
manifestProvider = createManifestProvider(libraries),
dependenciesProvider = createDependenciesProvider(),
resultsConsumer = resultsConsumer,
statsCollector = statsCollector,
logger = logger
)
)
runCommonization(parameters)
}
private fun createTargetProvider(target: CommonizerTarget, libraries: NativeLibrariesToCommonize?): TargetProvider? {
private fun createTargetProvider(
target: CommonizerTarget,
libraries: NativeLibrariesToCommonize?
): TargetProvider? {
if (libraries == null) return null
return TargetProvider(
target = target,
@@ -65,7 +71,7 @@ internal class LibraryCommonizer internal constructor(
}
private fun createDependenciesProvider(): TargetDependent<ModulesProvider?> {
return TargetDependent(outputTarget.withAllAncestors()) { target ->
return TargetDependent(outputTargets + outputTargets.allLeaves()) { target ->
DefaultModulesProvider.create(dependencies.getLibraries(target))
}
}
@@ -73,7 +79,7 @@ internal class LibraryCommonizer internal constructor(
private fun createManifestProvider(
libraries: TargetDependent<NativeLibrariesToCommonize?>
): TargetDependent<NativeManifestDataProvider> {
return TargetDependent(outputTarget.withAllAncestors()) { target ->
return TargetDependent(outputTargets) { target ->
when (target) {
is LeafCommonizerTarget -> libraries[target] ?: error("Can't provide manifest for missing target $target")
is SharedCommonizerTarget -> NativeManifestDataProvider(
@@ -84,9 +90,11 @@ internal class LibraryCommonizer internal constructor(
}
private fun checkPreconditions() {
/* TODO
when (outputTarget.allLeaves().size) {
0 -> progressLogger.fatal("No targets specified")
1 -> progressLogger.fatal("Too few targets specified: $outputTarget")
}
*/
}
}
@@ -1,16 +0,0 @@
/*
* Copyright 2010-2021 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.commonizer.konan
import org.jetbrains.kotlin.commonizer.*
internal class LoggingResultsConsumer(
private val outputCommonizerTarget: SharedCommonizerTarget
) : ResultsConsumer {
override fun targetConsumed(parameters: CommonizerParameters, target: CommonizerTarget) {
parameters.logger?.progress("Written libraries for ${outputCommonizerTarget.prettyName(target)}")
}
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.commonizer.konan
import org.jetbrains.kotlin.commonizer.CommonizerOutputLayout
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout
import org.jetbrains.kotlin.commonizer.CommonizerParameters
import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.ResultsConsumer
@@ -18,10 +18,9 @@ import java.io.File
internal class ModuleSerializer(
private val destination: File,
private val outputLayout: CommonizerOutputLayout,
) : ResultsConsumer {
override fun consume(parameters: CommonizerParameters, target: CommonizerTarget, moduleResult: ResultsConsumer.ModuleResult) {
val librariesDestination = outputLayout.getTargetDirectory(destination, target)
val librariesDestination = CommonizerOutputFileLayout.getCommonizedDirectory(destination, target)
when (moduleResult) {
is ResultsConsumer.ModuleResult.Commonized -> {
val libraryDestination = librariesDestination.resolve(moduleResult.fileSystemCompatibleLibraryName)
@@ -5,8 +5,11 @@
package org.jetbrains.kotlin.commonizer.repository
import org.jetbrains.kotlin.commonizer.*
import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.KonanDistribution
import org.jetbrains.kotlin.commonizer.NativeLibraryLoader
import org.jetbrains.kotlin.commonizer.konan.NativeLibrary
import org.jetbrains.kotlin.commonizer.stdlib
internal class StdlibRepository(
private val konanDistribution: KonanDistribution,
@@ -18,6 +21,6 @@ internal class StdlibRepository(
}
override fun getLibraries(target: CommonizerTarget): Set<NativeLibrary> {
return if (target is SharedCommonizerTarget) setOf(stdlib) else emptySet()
return setOf(stdlib)
}
}
@@ -6,8 +6,10 @@
package org.jetbrains.kotlin.commonizer.tree
import org.jetbrains.kotlin.commonizer.CommonizerParameters
import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.TargetProvider
import org.jetbrains.kotlin.commonizer.tree.deserializer.*
import org.jetbrains.kotlin.commonizer.utils.progress
internal val defaultCirTreeModuleDeserializer = CirTreeModuleDeserializer(
packageDeserializer = CirTreePackageDeserializer(
@@ -25,8 +27,3 @@ internal val defaultCirTreeModuleDeserializer = CirTreeModuleDeserializer(
internal val defaultCirTreeRootDeserializer = RootCirTreeDeserializer(
defaultCirTreeModuleDeserializer
)
internal fun deserializeCirTree(parameters: CommonizerParameters, target: TargetProvider): CirTreeRoot {
return defaultCirTreeRootDeserializer(parameters, target)
}
@@ -5,36 +5,25 @@
package org.jetbrains.kotlin.commonizer.utils
import org.jetbrains.kotlin.commonizer.cli.CliLoggerAdapter
import org.jetbrains.kotlin.commonizer.CommonizerLogLevel
import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.util.Logger
class ProgressLogger(
private val wrapped: Logger = CliLoggerAdapter(CommonizerLogLevel.Info, 0),
private val indent: Int = 0,
) : Logger by wrapped {
private val clockMark = ResettableClockMark()
private var finished = false
private const val ansiReset = "\u001B[0m"
private const val ansiTimeColor = "\u001B[36m"
private const val ansiTargetColor = "\u001B[32m"
private val prefix = " ".repeat(indent) + " * "
init {
clockMark.reset()
require(indent >= 0) { "Required indent >= 1" }
}
fun progress(message: String) {
check(!finished)
wrapped.log("$prefix$message in ${clockMark.elapsedSinceLast()}")
}
fun logTotal() {
check(!finished)
wrapped.log("TOTAL: ${clockMark.elapsedSinceStart()}")
finished = true
}
fun fork(): ProgressLogger {
return ProgressLogger(this, indent + 1)
internal inline fun <T> Logger?.progress(message: String, action: () -> T): T {
val clock = ResettableClockMark()
clock.reset()
try {
return action()
} finally {
this?.log("$message ${ansiTimeColor}in ${clock.elapsedSinceLast()}$ansiReset")
}
}
internal inline fun <T> Logger?.progress(
target: CommonizerTarget, message: String, action: () -> T
): T {
return progress("[$ansiTargetColor$target$ansiReset]: $message", action)
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 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.commonizer.utils
infix fun <T> Set<T>.isSubsetOf(other: Set<T>): Boolean {
if (this === other) return true
return other.containsAll(this)
}
infix fun <T> Set<T>.isProperSubsetOf(other: Set<T>): Boolean {
if (this == other) return false
return other.containsAll(this)
}
@@ -84,17 +84,6 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
(results.modulesByTargets.getValue(sharedTarget).single() as ModuleResult.Commonized).metadata
assertModulesAreEqual(sharedModuleAsExpected, sharedModuleByCommonizer, sharedTarget)
val leafTargets: Set<LeafCommonizerTarget> = analyzedModules.leafTargets
assertEquals(leafTargets, results.leafTargets)
for (leafTarget in leafTargets) {
val leafTargetModuleAsExpected: SerializedMetadata = analyzedModules.commonizedModules.getValue(leafTarget)
val leafTargetModuleByCommonizer: SerializedMetadata =
(results.modulesByTargets.getValue(leafTarget).single() as ModuleResult.Commonized).metadata
assertModulesAreEqual(leafTargetModuleAsExpected, leafTargetModuleByCommonizer, leafTarget)
}
}
}
@@ -208,9 +197,14 @@ private class AnalyzedModules(
resultsConsumer: ResultsConsumer,
manifestDataProvider: (CommonizerTarget) -> NativeManifestDataProvider = { MockNativeManifestDataProvider(it) }
) = CommonizerParameters(
outputTarget = SharedCommonizerTarget(leafTargets.toSet()),
manifestProvider = TargetDependent(sharedTarget.withAllAncestors(), manifestDataProvider),
dependenciesProvider = TargetDependent(sharedTarget.withAllAncestors()) { dependencyModules[it]?.let(MockModulesProvider::create) },
outputTargets = setOf(SharedCommonizerTarget(leafTargets.toSet())),
manifestProvider = TargetDependent(sharedTarget.withAllLeaves(), manifestDataProvider),
dependenciesProvider = TargetDependent(sharedTarget.withAllLeaves()) { target ->
dependencyModules
.filter { (registeredTarget, _) -> target in registeredTarget.withAllLeaves() }
.values.flatten()
.let(MockModulesProvider::create)
},
targetProviders = TargetDependent(leafTargets) { leafTarget ->
TargetProvider(
target = leafTarget,
@@ -25,7 +25,7 @@ data class HierarchicalCommonizationResult(
abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizerTestCase() {
data class Parameters(
val outputTarget: SharedCommonizerTarget,
val outputTargets: Set<SharedCommonizerTarget>,
val dependencies: TargetDependent<List<InlineSourceBuilder.Module>>,
val targets: List<Target>
)
@@ -41,7 +41,7 @@ abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizer
@InlineSourcesCommonizationTestDsl
class ParametersBuilder(private val parentInlineSourceBuilder: InlineSourceBuilder) {
private var outputTarget: SharedCommonizerTarget? = null
private var outputTargets: MutableSet<SharedCommonizerTarget>? = null
private val dependencies: MutableMap<CommonizerTarget, MutableList<InlineSourceBuilder.Module>> = LinkedHashMap()
@@ -52,8 +52,12 @@ abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizer
@InlineSourcesCommonizationTestDsl
fun outputTarget(target: String) {
outputTarget = parseCommonizerTarget(target) as SharedCommonizerTarget
fun outputTarget(vararg targets: String) {
val outputTargets = outputTargets ?: mutableSetOf()
targets.forEach { target ->
outputTargets += parseCommonizerTarget(target) as SharedCommonizerTarget
}
this.outputTargets = outputTargets
}
@InlineSourcesCommonizationTestDsl
@@ -67,18 +71,20 @@ abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizer
}
@InlineSourcesCommonizationTestDsl
fun registerDependency(target: CommonizerTarget, builder: InlineSourceBuilder.ModuleBuilder.() -> Unit) {
val dependenciesList = dependencies.getOrPut(target) { mutableListOf() }
val dependency = inlineSourceBuilderFactory[target].createModule {
builder()
name = "${target.prettyName}-dependency-${dependenciesList.size}-$name"
fun registerDependency(vararg targets: CommonizerTarget, builder: InlineSourceBuilder.ModuleBuilder.() -> Unit) {
targets.forEach { target ->
val dependenciesList = dependencies.getOrPut(target) { mutableListOf() }
val dependency = inlineSourceBuilderFactory[target].createModule {
builder()
name = "$target-dependency-${dependenciesList.size}-$name"
}
dependenciesList.add(dependency)
}
dependenciesList.add(dependency)
}
@InlineSourcesCommonizationTestDsl
fun registerDependency(target: String, builder: InlineSourceBuilder.ModuleBuilder.() -> Unit) {
registerDependency(parseCommonizerTarget(target), builder)
fun registerDependency(vararg targets: String, builder: InlineSourceBuilder.ModuleBuilder.() -> Unit) {
registerDependency(targets = targets.map(::parseCommonizerTarget).toTypedArray(), builder)
}
@InlineSourcesCommonizationTestDsl
@@ -96,7 +102,7 @@ abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizer
}
fun build(): Parameters = Parameters(
outputTarget = outputTarget ?: SharedCommonizerTarget(targets.map { it.target }.toSet()),
outputTargets = outputTargets ?: setOf(SharedCommonizerTarget(targets.map { it.target }.allLeaves())),
dependencies = dependencies.toTargetDependent(),
targets = targets.toList()
)
@@ -111,7 +117,7 @@ abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizer
override fun createModule(builder: InlineSourceBuilder.ModuleBuilder.() -> Unit): InlineSourceBuilder.Module {
return inlineSourceBuilder.createModule {
dependencies.toMap()
.filterKeys { dependencyTarget -> dependencyTarget.isEqualOrAncestorOf(target) }.values.flatten()
.filterKeys { dependencyTarget -> target in dependencyTarget.withAllLeaves() }.values.flatten()
.forEach { dependencyModule -> dependency(dependencyModule) }
builder()
}
@@ -155,16 +161,16 @@ abstract class AbstractInlineSourcesCommonizationTest : KtInlineSourceCommonizer
manifestDataProvider: (CommonizerTarget) -> NativeManifestDataProvider = { MockNativeManifestDataProvider(it) }
): CommonizerParameters {
return CommonizerParameters(
outputTarget = outputTarget,
manifestProvider = TargetDependent(outputTarget.withAllAncestors(), manifestDataProvider),
dependenciesProvider = TargetDependent(outputTarget.withAllAncestors()) { target ->
outputTargets = outputTargets,
manifestProvider = TargetDependent(outputTargets, manifestDataProvider),
dependenciesProvider = TargetDependent(outputTargets.withAllLeaves()) { target ->
val explicitDependencies = dependencies.getOrNull(target).orEmpty().map { module -> createModuleDescriptor(module) }
val implicitDependencies = listOfNotNull(if (target == outputTarget) DefaultBuiltIns.Instance.builtInsModule else null)
val implicitDependencies = listOfNotNull(DefaultBuiltIns.Instance.builtInsModule)
val dependencies = explicitDependencies + implicitDependencies
if (dependencies.isEmpty()) null
else MockModulesProvider.create(dependencies)
},
targetProviders = TargetDependent(outputTarget.allLeaves()) { commonizerTarget ->
targetProviders = TargetDependent(outputTargets.allLeaves()) { commonizerTarget ->
val target = targets.singleOrNull { it.target == commonizerTarget } ?: return@TargetDependent null
TargetProvider(
target = commonizerTarget,
@@ -70,12 +70,12 @@ class CommonizerFacadeTest {
manifestDataProvider: (CommonizerTarget) -> NativeManifestDataProvider = { MockNativeManifestDataProvider(it) }
): CommonizerParameters {
val targetDependentModuleNames = mapKeys { (targetName, _) -> LeafCommonizerTarget(targetName) }.toTargetDependent()
val sharedTarget = SharedCommonizerTarget(targetDependentModuleNames.targets.toSet())
val sharedTarget = SharedCommonizerTarget(targetDependentModuleNames.targets.allLeaves())
return CommonizerParameters(
outputTarget = sharedTarget,
dependenciesProvider = TargetDependent(sharedTarget.withAllAncestors()) { null },
manifestProvider = TargetDependent(sharedTarget.withAllAncestors(), manifestDataProvider),
outputTargets = setOf(sharedTarget),
dependenciesProvider = TargetDependent(sharedTarget.withAllLeaves()) { null },
manifestProvider = TargetDependent(sharedTarget.withAllLeaves(), manifestDataProvider),
targetProviders = targetDependentModuleNames.map { target, moduleNames ->
TargetProvider(
target = target,
@@ -0,0 +1,136 @@
/*
* Copyright 2010-2021 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.commonizer
import org.jetbrains.kotlin.commonizer.cir.CirRoot
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
import org.jetbrains.kotlin.commonizer.utils.CommonizedGroup
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.junit.Test
import kotlin.test.assertEquals
class CommonizerQueueTest {
@Test
fun `test retained targets`() {
val queue = CommonizerQueue(
storageManager = LockBasedStorageManager.NO_LOCKS,
outputTargets = setOf("(a, b)", "(a, b, c)").map(::parseCommonizerTarget).map { it as SharedCommonizerTarget }.toSet(),
deserializers = EagerTargetDependent(
setOf("a", "b", "c").map(::parseCommonizerTarget)
) { CommonizerQueue.Deserializer { null } },
commonizer = { _, _ -> null },
serializer = { _, _ -> },
inputTargetsSelector = DefaultInputTargetsSelector
)
assertEquals(
setOf("a", "b", "c"), queue.retainedDeserializedTargets.map { it.identityString }.toSet(),
"Expected all targets a, b, c to be retained in the beginning"
)
assertEquals(
setOf("(a, b)", "(a, b, c)"), queue.retainedCommonizedTargets.map { it.identityString }.toSet(),
"Expected all output targets to be retained in the beginning"
)
assertEquals(
setOf("(a, b)", "(a, b, c)"), queue.retainedTargetDependencies.keys.map { it.identityString }.toSet(),
"Expected all output targets to declare its dependencies"
)
queue.invokeTarget(parseCommonizerTarget("(a, b)") as SharedCommonizerTarget)
assertEquals(
setOf("c"), queue.retainedDeserializedTargets.map { it.identityString }.toSet(),
"Expected only target 'c' to be retained after commonizing (a, b)"
)
assertEquals(
setOf("(a, b)", "(a, b, c)"), queue.retainedCommonizedTargets.map { it.identityString }.toSet(),
"Expected all output targets to be retained after commonizing (a, b)"
)
assertEquals(
setOf("(a, b, c)"), queue.retainedTargetDependencies.keys.map { it.identityString }.toSet(),
"Expected remaining targets to declare its dependencies"
)
assertEquals(queue.pendingOutputTargets, queue.retainedTargetDependencies.keys)
queue.invokeTarget(parseCommonizerTarget("(a, b, c)") as SharedCommonizerTarget)
assertEquals(
emptySet(), queue.retainedDeserializedTargets,
"Expected no retained deserialized targets"
)
assertEquals(
emptySet(), queue.retainedCommonizedTargets,
"Expected no retained commonized targets"
)
assertEquals(
emptySet(), queue.retainedTargetDependencies.keys,
"Expected no retained target dependencies"
)
assertEquals(queue.pendingOutputTargets, queue.retainedTargetDependencies.keys)
queue.invokeAll()
}
@Test
fun `test commonizer being called`() {
data class CommonizerInvocation(val inputs: TargetDependent<CirTreeRoot?>, val output: SharedCommonizerTarget)
val commonizerInvocations = mutableListOf<CommonizerInvocation>()
val storageManager = LockBasedStorageManager.NO_LOCKS
val providedTargets = setOf("a", "b", "c").map(::parseCommonizerTarget).toSet()
val abOutputTarget = parseCommonizerTarget("(a, b)") as SharedCommonizerTarget
val abcOutputTarget = parseCommonizerTarget("(a, b, c)") as SharedCommonizerTarget
val outputTargets = setOf(abOutputTarget, abcOutputTarget)
val queue = CommonizerQueue(
storageManager = storageManager,
outputTargets = outputTargets,
deserializers = EagerTargetDependent(providedTargets) { CommonizerQueue.Deserializer { null } },
commonizer = { inputs, output ->
commonizerInvocations.add(CommonizerInvocation(inputs, output))
CirRootNode(CommonizedGroup(0), storageManager.createNullableLazyValue { CirRoot.create(output) })
},
serializer = { _, _ -> },
inputTargetsSelector = DefaultInputTargetsSelector
)
queue.invokeAll()
assertEquals(
2, commonizerInvocations.size,
"Expected 2 commonizer invocations"
)
assertEquals(
outputTargets, commonizerInvocations.map { it.output }.toSet(),
"Expected specified output targets to be invoked"
)
val abInvocation = commonizerInvocations.single { it.output == abOutputTarget }
assertEquals(
DefaultInputTargetsSelector(providedTargets + outputTargets, abOutputTarget),
abInvocation.inputs.targets.toSet(),
"Expected commonizer being invoked with selected targets for abInvocation"
)
val abcInvocation = commonizerInvocations.single { it.output == abcOutputTarget }
assertEquals(
DefaultInputTargetsSelector(providedTargets + outputTargets, abcOutputTarget),
abcInvocation.inputs.targets.toSet(),
"Expected commonizer being invoked with selected targets for abcInvocation"
)
}
}
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2021 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.commonizer
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue
class DefaultInputTargetsSelectorTest {
@Test
fun `missing leaf targets`() {
val inputTargets = setOf(LeafCommonizerTarget("a"), LeafCommonizerTarget("b"))
val exception = assertFailsWith<IllegalArgumentException> {
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b, c)") as SharedCommonizerTarget)
}
assertTrue(
exception.message.orEmpty().contains(inputTargets.toString()),
"Expected error message to contain all input targets. Found ${exception.message}"
)
assertTrue(
exception.message.orEmpty().contains(parseCommonizerTarget("(a, b, c)").toString()),
"Expected error message to contain output target. Found ${exception.message}"
)
}
@Test
fun `sample 0`() {
val inputTargets = setOf(
LeafCommonizerTarget("a"),
LeafCommonizerTarget("b"),
LeafCommonizerTarget("c"),
LeafCommonizerTarget("d"),
SharedCommonizerTarget(LeafCommonizerTarget("c"), LeafCommonizerTarget("d"))
)
assertEquals(
setOf(LeafCommonizerTarget("a"), LeafCommonizerTarget("b")),
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b)") as SharedCommonizerTarget)
)
assertEquals(
setOf(LeafCommonizerTarget("a"), LeafCommonizerTarget("b"), LeafCommonizerTarget("c")),
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b, c)") as SharedCommonizerTarget)
)
assertEquals(
setOf(LeafCommonizerTarget("a"), LeafCommonizerTarget("b"), parseCommonizerTarget("(c, d)")),
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b, c, d)") as SharedCommonizerTarget)
)
}
@Test
fun `sample 1`() {
val inputTargets = setOf(
parseCommonizerTarget("(a, b)"),
parseCommonizerTarget("(a, b, c)"),
parseCommonizerTarget("(a, b, c, d)"),
parseCommonizerTarget("(c, d)"),
parseCommonizerTarget("(c, d, e)"),
parseCommonizerTarget("f")
)
assertEquals(
setOf("(a, b, c, d)", "f").map(::parseCommonizerTarget).toSet(),
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b, c, d, f)") as SharedCommonizerTarget)
)
assertEquals(
setOf("(a, b, c, d)", "(c, d, e)").map(::parseCommonizerTarget).toSet(),
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b, c, d, e)") as SharedCommonizerTarget)
)
assertEquals(
setOf("(a, b, c, d)", "(c, d, e)", "f").map(::parseCommonizerTarget).toSet(),
DefaultInputTargetsSelector(inputTargets, parseCommonizerTarget("(a, b, c, d, e, f)") as SharedCommonizerTarget)
)
}
@Test
fun `empty outputTarget`() {
assertEquals(
emptySet(),
DefaultInputTargetsSelector(emptySet(), parseCommonizerTarget("()") as SharedCommonizerTarget)
)
}
@Test
fun `single leaf outputTarget`() {
assertEquals(
setOf(LeafCommonizerTarget("a")),
DefaultInputTargetsSelector(setOf(LeafCommonizerTarget("a")), parseCommonizerTarget("(a)") as SharedCommonizerTarget)
)
}
@Test
fun `exact output available`() {
assertEquals(
setOf(parseCommonizerTarget("(a, b)"), parseCommonizerTarget("(c, d)")),
DefaultInputTargetsSelector(
setOf("a", "b", "c", "d", "(a, b)", "(c, d)", "(a, b, c, d)").map(::parseCommonizerTarget).toSet(),
parseCommonizerTarget("(a, b, c, d)") as SharedCommonizerTarget
)
)
}
}
@@ -41,24 +41,6 @@ class FunctionReturnTypeCommonizationTest : AbstractInlineSourcesCommonizationTe
result.assertCommonized(
"(a,b)", ""
)
result.assertCommonized(
"a", """
class A {
class B
}
fun x(): A.B = TODO()
"""
)
result.assertCommonized(
"b", """
interface A {
class B
}
fun x(): A.B = TODO()
"""
)
}
@@ -98,23 +80,5 @@ class FunctionReturnTypeCommonizationTest : AbstractInlineSourcesCommonizationTe
expect fun x(): A.B
"""
)
result.assertCommonized(
"a", """
interface A {
class B
}
fun x(): A.B = TODO()
"""
)
result.assertCommonized(
"b", """
interface A {
class B
}
fun x(): A.B = TODO()
"""
)
}
}
@@ -18,13 +18,11 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
}
result.assertCommonized("(a, b)", "expect class X")
result.assertCommonized("a", "typealias X = Int")
result.assertCommonized("b", "class X")
}
fun `test commonization of typeAlias and class hierarchically`() {
val result = commonize {
outputTarget("((a, b), (c, d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
simpleSingleSourceTarget("a", "typealias X = Int")
simpleSingleSourceTarget("b", "typealias X = Long")
simpleSingleSourceTarget("c", "class X")
@@ -12,7 +12,7 @@ class HierarchicalClassCommonizationTest : AbstractInlineSourcesCommonizationTes
fun `test simple class`() {
val result = commonize {
outputTarget("((a,b), (c,d), e)")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)", "(a, b, c, d, e)")
simpleSingleSourceTarget("a", "class X")
simpleSingleSourceTarget("b", "class X")
simpleSingleSourceTarget("c", "class X")
@@ -20,12 +20,6 @@ class HierarchicalClassCommonizationTest : AbstractInlineSourcesCommonizationTes
simpleSingleSourceTarget("e", "class X")
}
result.assertCommonized("a", "class X")
result.assertCommonized("b", "class X")
result.assertCommonized("c", "class X")
result.assertCommonized("d", "class X")
result.assertCommonized("e", "class X")
result.assertCommonized("(a,b)", "expect class X expect constructor()")
result.assertCommonized("(c,d)", "expect class X expect constructor()")
result.assertCommonized("(a,b)", "expect class X expect constructor()")
@@ -34,7 +28,7 @@ class HierarchicalClassCommonizationTest : AbstractInlineSourcesCommonizationTes
fun `test sample class`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
simpleSingleSourceTarget(
"a", """
class X {
@@ -76,46 +70,6 @@ class HierarchicalClassCommonizationTest : AbstractInlineSourcesCommonizationTes
)
}
result.assertCommonized(
"a", """
class X {
val a: Int = 42
val ab: Int = 42
val abcd: Int = 42
}
"""
)
result.assertCommonized(
"b", """
class X {
val b: Int = 42
val ab: Int = 42
val abcd: Int = 42
}
"""
)
result.assertCommonized(
"c", """
class X {
val c: Int = 42
val cd: Int = 42
val abcd: Int = 42
}
"""
)
result.assertCommonized(
"d", """
class X {
val d: Int = 42
val cd: Int = 42
val abcd: Int = 42
}
"""
)
result.assertCommonized(
"(a,b)", """
expect class X expect constructor() {
@@ -12,7 +12,7 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
fun `test simple function 1`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
outputTarget("(a,b)", "(c,d)", "(a, b, c, d)")
simpleSingleSourceTarget("a", "fun x(): Int = 42")
simpleSingleSourceTarget("b", "fun x(): Int = 42")
simpleSingleSourceTarget("c", "fun x(): Int = 42")
@@ -22,15 +22,11 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
result.assertCommonized("((a,b), (c,d))", "expect fun x(): Int")
result.assertCommonized("(a,b)", "expect fun x(): Int")
result.assertCommonized("(c,d)", "expect fun x(): Int")
result.assertCommonized("a", "actual fun x(): Int = 42")
result.assertCommonized("b", "actual fun x(): Int = 42")
result.assertCommonized("c", "actual fun x(): Int = 42")
result.assertCommonized("d", "actual fun x(): Int = 42")
}
fun `test simple function 2`() {
val result = commonize {
outputTarget("((a,b), c)")
outputTarget("(a, b)", "(a, b, c)")
simpleSingleSourceTarget("a", "fun x(): Int = 42")
simpleSingleSourceTarget("b", "fun x(): Int = 42")
simpleSingleSourceTarget("c", "fun x(): Int = 42")
@@ -38,14 +34,11 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
result.assertCommonized("((a,b), c)", "expect fun x(): Int")
result.assertCommonized("(a,b)", "expect fun x(): Int")
result.assertCommonized("a", "fun x(): Int = 42")
result.assertCommonized("b", "fun x(): Int = 42")
result.assertCommonized("c", "fun x(): Int = 42")
}
fun `test function with returnType`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
simpleSingleSourceTarget(
"a", """
interface ABCD
@@ -73,34 +66,6 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
)
}
result.assertCommonized(
"a", """
interface ABCD
fun x(): ABCD = TODO()
"""
)
result.assertCommonized(
"b", """
interface ABCD
fun x(): ABCD = TODO()
"""
)
result.assertCommonized(
"c", """
interface ABCD
fun x(): ABCD = TODO()
"""
)
result.assertCommonized(
"d", """
interface ABCD
fun x(): ABCD = TODO()
"""
)
result.assertCommonized(
"(a, b)", """
expect interface ABCD
@@ -125,18 +90,14 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
fun `test function with returnType from dependency 1`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
registerDependency("((a,b), (c,d))") { source("interface ABCD") }
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
registerDependency("a", "b", "c", "d", "(a, b)", "(c, d)", "(a, b, c, d)") { source("interface ABCD") }
simpleSingleSourceTarget("a", "fun x(): ABCD = TODO()")
simpleSingleSourceTarget("b", "fun x(): ABCD = TODO()")
simpleSingleSourceTarget("c", "fun x(): ABCD = TODO()")
simpleSingleSourceTarget("d", "fun x(): ABCD = TODO()")
}
result.assertCommonized("a", "fun x(): ABCD")
result.assertCommonized("b", "fun x(): ABCD")
result.assertCommonized("c", "fun x(): ABCD")
result.assertCommonized("d", "fun x(): ABCD")
result.assertCommonized("(c, d)", "expect fun x(): ABCD")
result.assertCommonized("(a, b)", "expect fun x(): ABCD")
result.assertCommonized("((a,b), (c,d))", "expect fun x(): ABCD")
@@ -144,8 +105,9 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
fun `test function with returnType from dependency 2`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
registerDependency("(a,b)") { source("interface ABCD") }
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
registerDependency("a", "b", "c", "d") { source("interface ABCD") }
registerDependency("(a, b)") { source("interface ABCD") }
registerDependency("(c,d)") { source("interface ABCD") }
simpleSingleSourceTarget("a", "fun x(): ABCD = TODO()")
simpleSingleSourceTarget("b", "fun x(): ABCD = TODO()")
@@ -153,28 +115,23 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
simpleSingleSourceTarget("d", "fun x(): ABCD = TODO()")
}
result.assertCommonized("a", "fun x(): ABCD")
result.assertCommonized("b", "fun x(): ABCD")
result.assertCommonized("c", "fun x(): ABCD")
result.assertCommonized("d", "fun x(): ABCD")
result.assertCommonized("(c, d)", "expect fun x(): ABCD")
result.assertCommonized("(a, b)", "expect fun x(): ABCD")
// ABCD is not given as dependency on (a, b, c, d) -> can't be commonized
result.assertCommonized("((a,b), (c,d))", "")
}
fun `test function with returnType from dependency 3`() {
val result = commonize {
outputTarget("((a,b), c)")
registerDependency("((a,b), c)") { source("interface ABCD") }
registerDependency("(a,b)") { source("interface ABCD") }
outputTarget("(a, b)", "(a, b, c)")
registerDependency("(a, b, c)") { source("interface ABCD") }
registerDependency("a", "b", "c", "(a, b)") { source("interface ABCD") }
simpleSingleSourceTarget("a", "fun x(): ABCD = TODO()")
simpleSingleSourceTarget("b", "fun x(): ABCD = TODO()")
simpleSingleSourceTarget("c", "fun x(): ABCD = TODO()")
}
result.assertCommonized("a", "fun x(): ABCD")
result.assertCommonized("b", "fun x(): ABCD")
result.assertCommonized("c", "fun x(): ABCD")
result.assertCommonized("(a, b)", "expect fun x(): ABCD")
result.assertCommonized("((a,b), c)", "expect fun x(): ABCD")
}
@@ -17,7 +17,7 @@ class HierarchicalModuleCommonizationTest : AbstractInlineSourcesCommonizationTe
fun `test common modules hierarchically`() {
val result = commonize {
outputTarget("((a, b), c)")
outputTarget("(a, b)", "(a, b, c)")
target("a") {
module {
@@ -67,20 +67,20 @@ class HierarchicalModuleCommonizationTest : AbstractInlineSourcesCommonizationTe
}
result.assertCommonized("((a, b), c)") {
result.assertCommonized("(a, b, c)") {
name = "foo"
source("expect val foo: Int")
}
assertEquals(
1, result.results[parseCommonizerTarget("((a, b), c)")].orEmpty().size,
1, result.results[parseCommonizerTarget("(a, b, c)")].orEmpty().size,
"Expected only a single module"
)
}
fun `test module commonization with empty root not sharing any module`() {
val result = commonize {
outputTarget("((a, b), c)")
outputTarget("(a, b)", "(a, b, c)")
target("a") {
module {
@@ -110,14 +110,14 @@ class HierarchicalModuleCommonizationTest : AbstractInlineSourcesCommonizationTe
}
assertTrue(
result.results[parseCommonizerTarget("((a, b), c)")].orEmpty().isEmpty(),
"Expected empty result for ((a, b), c)"
result.results[parseCommonizerTarget("(a, b, c)")].orEmpty().isEmpty(),
"Expected empty result for (a, b, c)"
)
}
fun `test no common modules`() {
val result = commonize(Status.NOTHING_TO_DO) {
outputTarget("((a, b), c)")
outputTarget("(a, b)", "(a, b, c)")
target("a") {
module {
@@ -146,7 +146,7 @@ class HierarchicalModuleCommonizationTest : AbstractInlineSourcesCommonizationTe
fun `test propagation`() {
val result = commonize {
outputTarget("(((a, b), c), d)")
outputTarget("(a, b)", "(a, b, c)", "(a, b, c, d)")
target("a") {
module {
@@ -170,12 +170,12 @@ class HierarchicalModuleCommonizationTest : AbstractInlineSourcesCommonizationTe
}
}
result.assertCommonized("((a, b), c)") {
result.assertCommonized("(a, b, c)") {
name = "foo"
source("expect val foo: Int")
}
result.assertCommonized("(((a, b), c), d)") {
result.assertCommonized("(a, b, c, d)") {
name = "foo"
source("expect val foo: Int")
}
@@ -212,36 +212,9 @@ class HierarchicalModuleCommonizationTest : AbstractInlineSourcesCommonizationTe
assertEquals(1, result.results[parseCommonizerTarget("(a, b)")]?.size, "Expected only one commonized module")
result.assertCommonized("(a, b)") {
name = "shared"
source("expect class Shared expect constructor()")
}
result.assertCommonized("a") {
name = "shared"
source("class Shared constructor()")
}
result.assertCommonized("b") {
name = "shared"
source("class Shared constructor()")
}
val targetAResults = result.results[parseCommonizerTarget("a")].orEmpty()
assertEquals(2, targetAResults.size, "Expected 'Missing' and 'Commonized' results for target a")
val targetAMissingModule = kotlin.test.assertNotNull(
targetAResults.filterIsInstance<Missing>().singleOrNull(),
"Expected 'Missing' result for target a"
)
assertEquals("onlyInA", targetAMissingModule.libraryName)
val targetBResults = result.results[parseCommonizerTarget("b")].orEmpty()
assertEquals(2, targetBResults.size, "Expected 'Missing' and 'Commonized' results for target b")
val targetBMissingModule = kotlin.test.assertNotNull(
targetBResults.filterIsInstance<Missing>().singleOrNull(),
"Expected 'Missing' result for target b"
)
assertEquals("onlyInB", targetBMissingModule.libraryName)
}
}
@@ -12,7 +12,7 @@ class HierarchicalPackageCommonizationTest : AbstractInlineSourcesCommonizationT
fun `test package with dummy`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
target("a") {
module {
@@ -107,90 +107,6 @@ class HierarchicalPackageCommonizationTest : AbstractInlineSourcesCommonizationT
}
}
result.assertCommonized("a") {
source(
"""
package pkg.abcd
val dummy = "me"
""", "abcd.kt"
)
source(
"""
package pkg.ab
val dummy = "me"
""", "ab.kt"
)
source(
"""
package pkg.a
val dummy = "me"
""", "a.kt"
)
}
result.assertCommonized("b") {
source(
"""
package pkg.abcd
val dummy = "me"
""", "abcd.kt"
)
source(
"""
package pkg.ab
val dummy = "me"
""", "ab.kt"
)
source(
"""
package pkg.b
val dummy = "me"
""", "b.kt"
)
}
result.assertCommonized("c") {
source(
"""
package pkg.abcd
val dummy = "me"
""", "abcd.kt"
)
source(
"""
package pkg.cd
val dummy = "me"
""", "cd.kt"
)
source(
"""
package pkg.c
val dummy = "me"
""", "c.kt"
)
}
result.assertCommonized("d") {
source(
"""
package pkg.abcd
val dummy = "me"
""", "abcd.kt"
)
source(
"""
package pkg.cd
val dummy = "me"
""", "cd.kt"
)
source(
"""
package pkg.d
val dummy = "me"
""", "d.kt"
)
}
result.assertCommonized("(a,b)") {
source(
"""
@@ -12,7 +12,7 @@ class HierarchicalPropertyCommonizationTest : AbstractInlineSourcesCommonization
fun `test simple property`() {
val result = commonize {
outputTarget("((a, b), (c, d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
simpleSingleSourceTarget("a", "val x: Int = 42")
simpleSingleSourceTarget("b", "val x: Int = 42")
simpleSingleSourceTarget("c", "val x: Int = 42")
@@ -22,10 +22,6 @@ class HierarchicalPropertyCommonizationTest : AbstractInlineSourcesCommonization
result.assertCommonized("((a,b), (c,d))", "expect val x: Int")
result.assertCommonized("(a, b)", "expect val x: Int")
result.assertCommonized("(c, d)", "expect val x: Int")
result.assertCommonized("a", "val x: Int = 42")
result.assertCommonized("b", "val x: Int = 42")
result.assertCommonized("c", "val x: Int = 42")
result.assertCommonized("d", "val x: Int = 42")
}
fun `test same typeAliased property`() {
@@ -12,7 +12,7 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio
fun `test simple type alias`() {
val result = commonize {
outputTarget("((a,b), (c,d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
simpleSingleSourceTarget("a", "typealias X = Int")
simpleSingleSourceTarget("b", "typealias X = Int")
simpleSingleSourceTarget("c", "typealias X = Int")
@@ -22,12 +22,6 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio
result.assertCommonized("((a,b), (c,d))", "typealias X = Int")
result.assertCommonized("(a,b)", "typealias X = Int")
result.assertCommonized("(c, d)", "typealias X = Int")
/* Special case: For now, leaves should depend on commonized platform libraries */
result.assertCommonized("a", "")
result.assertCommonized("b", "")
result.assertCommonized("c", "")
result.assertCommonized("d", "")
}
/**
@@ -50,7 +44,7 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio
fun `test typealias to different classes`() {
val result = commonize {
outputTarget("(((a,b), (c,d)), (e,f))")
outputTarget("(a, b)", "(c, d)", "(e, f)", "(a, b, c, d)", "(a, b, c, d, e, f)")
simpleSingleSourceTarget(
"a", """
class AB
@@ -79,13 +73,6 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio
simpleSingleSourceTarget("f", """class x""")
}
result.assertCommonized("a", """class AB""")
result.assertCommonized("b", """class AB""")
result.assertCommonized("c", """class CD""")
result.assertCommonized("d", """class CD""")
result.assertCommonized("e", """class x""")
result.assertCommonized("f", """class x""")
result.assertCommonized(
"(a,b)", """
expect class AB expect constructor()
@@ -111,7 +98,7 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio
"(e,f)", """expect class x expect constructor()"""
)
result.assertCommonized("((a,b), (c,d))", """expect class x expect constructor()""")
result.assertCommonized("(((a,b), (c,d)), (e,f))", """expect class x expect constructor()""")
result.assertCommonized("(a, b, c, d)", """expect class x expect constructor()""")
result.assertCommonized("(a, b, c, d, e, f)", """expect class x expect constructor()""")
}
}
@@ -21,11 +21,10 @@ class SingleTargetPropagationTest : AbstractInlineSourcesCommonizationTest() {
@Test
fun `test single native target in hierarchy`() {
val result = commonize {
outputTarget("((a, b), (c, d))")
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
simpleSingleSourceTarget("a", """class A""")
}
result.assertCommonized("a", "class A")
result.assertCommonized("(a,b)", "expect class A expect constructor()")
result.assertCommonized("((a, b), (c, d))", "expect class A expect constructor()")
}