[Commonizer] Provide union of forwardDeclarations as common dependencies

^KT-52050 Verification Pending

The issue described in KT-52050 happened, because forwardDeclarations
were not carried into next commonization steps. For commonization
it is fair to choose the union of all modules forwardDeclarations
as common dependency (instead of a union), since we can assume that
all those forward declarations will be provided.
This commit is contained in:
sebastian.sellmair
2022-04-20 13:45:40 +02:00
committed by Space
parent 99d995a313
commit 204bc4ca95
10 changed files with 67 additions and 44 deletions
@@ -103,6 +103,23 @@ class CommonizeNativeDistributionTest {
) )
} }
@Test
fun `commonize - linux macos - linux macos mingw`() {
val unixTarget = CommonizerTarget(LINUX_X64, MACOS_X64)
val nativeTarget = CommonizerTarget(MINGW_X64, LINUX_X64, MACOS_X64)
CliCommonizer(this::class.java.classLoader).commonizeNativeDistribution(
konanHome = konanHome,
outputTargets = setOf(unixTarget, nativeTarget),
outputDirectory = temporaryOutputDirectory.root,
logLevel = CommonizerLogLevel.Info
)
assertTrue(
resolveCommonizedDirectory(temporaryOutputDirectory.root, nativeTarget).isDirectory,
"Expected directory for $nativeTarget"
)
}
@Test @Test
fun `commonize - no outputTargets specified`() { fun `commonize - no outputTargets specified`() {
CliCommonizer(this::class.java.classLoader).commonizeNativeDistribution( CliCommonizer(this::class.java.classLoader).commonizeNativeDistribution(
@@ -27,20 +27,19 @@ data class CommonizerParameters(
) )
internal fun CommonizerParameters.dependencyClassifiers(target: CommonizerTarget): CirProvidedClassifiers { internal fun CommonizerParameters.dependencyClassifiers(target: CommonizerTarget): CirProvidedClassifiers {
val targetModulesProvider = targetProviders.getOrNull(target)?.modulesProvider
val dependenciesModulesProvider = dependenciesProvider[target] val dependenciesModulesProvider = dependenciesProvider[target]
val providedByTarget = if (targetModulesProvider != null) val exportedForwardDeclarations = target.withAllLeaves()
CirProvidedClassifiersByModules.loadExportedForwardDeclarations(targetModulesProvider) else null .mapNotNull { targetOrLeaf -> targetProviders.getOrNull(targetOrLeaf)?.modulesProvider }
.plus(listOfNotNull(dependenciesModulesProvider))
.let { modulesProviders -> CirProvidedClassifiersByModules.loadExportedForwardDeclarations(modulesProviders) }
val providedByDependencies = if (dependenciesModulesProvider != null) val providedByDependencies = if (dependenciesModulesProvider != null)
CirProvidedClassifiers.of( CirProvidedClassifiersByModules.load(dependenciesModulesProvider)
CirProvidedClassifiersByModules.load(dependenciesModulesProvider), else null
CirProvidedClassifiersByModules.loadExportedForwardDeclarations(dependenciesModulesProvider)
) else null
return CirProvidedClassifiers.of( return CirProvidedClassifiers.of(
*listOfNotNull(CirFictitiousFunctionClassifiers, providedByTarget, providedByDependencies).toTypedArray() *listOfNotNull(CirFictitiousFunctionClassifiers, exportedForwardDeclarations, providedByDependencies).toTypedArray()
) )
} }
@@ -16,7 +16,6 @@ class TargetProvider(
interface ModulesProvider { interface ModulesProvider {
open class ModuleInfo( open class ModuleInfo(
val name: String, val name: String,
val originalLocation: File,
val cInteropAttributes: CInteropModuleAttributes? val cInteropAttributes: CInteropModuleAttributes?
) )
@@ -58,7 +58,6 @@ internal fun commonizeTarget(
targetDependencies = availableTrees.mapValue(CirTreeRoot::dependencies), targetDependencies = availableTrees.mapValue(CirTreeRoot::dependencies),
commonizedNodes = CirCommonizedClassifierNodes.default(), commonizedNodes = CirCommonizedClassifierNodes.default(),
commonDependencies = parameters.dependencyClassifiers(output) commonDependencies = parameters.dependencyClassifiers(output)
) )
val mergedTree = mergeCirTree(parameters.storageManager, classifiers, availableTrees, parameters.settings) val mergedTree = mergeCirTree(parameters.storageManager, classifiers, availableTrees, parameters.settings)
@@ -14,10 +14,9 @@ import java.io.File
internal class DefaultModulesProvider(libraries: Collection<NativeLibrary>) : ModulesProvider { internal class DefaultModulesProvider(libraries: Collection<NativeLibrary>) : ModulesProvider {
internal class NativeModuleInfo( internal class NativeModuleInfo(
name: String, name: String,
originalLocation: File,
val dependencies: Set<String>, val dependencies: Set<String>,
cInteropAttributes: ModulesProvider.CInteropModuleAttributes? cInteropAttributes: ModulesProvider.CInteropModuleAttributes?
) : ModuleInfo(name, originalLocation, cInteropAttributes) ) : ModuleInfo(name, cInteropAttributes)
private val libraryMap: Map<String, NativeLibrary> private val libraryMap: Map<String, NativeLibrary>
private val moduleInfoMap: Map<String, NativeModuleInfo> private val moduleInfoMap: Map<String, NativeModuleInfo>
@@ -30,7 +29,6 @@ internal class DefaultModulesProvider(libraries: Collection<NativeLibrary>) : Mo
val manifestData = library.manifestData val manifestData = library.manifestData
val name = manifestData.uniqueName val name = manifestData.uniqueName
val location = File(library.library.libraryFile.path)
val dependencies = manifestData.dependencies.toSet() val dependencies = manifestData.dependencies.toSet()
val cInteropAttributes = if (manifestData.isInterop) { val cInteropAttributes = if (manifestData.isInterop) {
@@ -39,7 +37,7 @@ internal class DefaultModulesProvider(libraries: Collection<NativeLibrary>) : Mo
} else null } else null
libraryMap.put(name, library)?.let { error("Duplicated libraries: $name") } libraryMap.put(name, library)?.let { error("Duplicated libraries: $name") }
moduleInfoMap[name] = NativeModuleInfo(name, location, dependencies, cInteropAttributes) moduleInfoMap[name] = NativeModuleInfo(name, dependencies, cInteropAttributes)
} }
this.libraryMap = libraryMap this.libraryMap = libraryMap
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
/** A set of classes and type aliases provided by libraries (either the libraries to commonize, or their dependency libraries)/ */ /** A set of classes and type aliases provided by libraries (either the libraries to commonize, or their dependency libraries)/ */
interface CirProvidedClassifiers { sealed interface CirProvidedClassifiers {
fun hasClassifier(classifierId: CirEntityId): Boolean fun hasClassifier(classifierId: CirEntityId): Boolean
fun classifier(classifierId: CirEntityId): CirProvided.Classifier? fun classifier(classifierId: CirEntityId): CirProvided.Classifier?
@@ -24,24 +24,6 @@ interface CirProvidedClassifiers {
override fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId) = emptyList<CirEntityId>() override fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId) = emptyList<CirEntityId>()
} }
private class CompositeClassifiers(val delegates: List<CirProvidedClassifiers>) : CirProvidedClassifiers {
override fun hasClassifier(classifierId: CirEntityId) = delegates.any { it.hasClassifier(classifierId) }
override fun classifier(classifierId: CirEntityId): CirProvided.Classifier? {
var fallbackReturn: CirProvided.Classifier? = null
for (delegate in delegates) {
delegate.classifier(classifierId)?.let { classifier ->
if (classifier !== FALLBACK_FORWARD_DECLARATION_CLASS) return classifier
else fallbackReturn = classifier
}
}
return fallbackReturn
}
override fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId): List<CirEntityId> {
return delegates.flatMap { it.findTypeAliasesWithUnderlyingType(underlyingClassifier) }
}
}
companion object { companion object {
internal val FALLBACK_FORWARD_DECLARATION_CLASS = internal val FALLBACK_FORWARD_DECLARATION_CLASS =
CirProvided.RegularClass(emptyList(), emptyList(), Visibilities.Public, ClassKind.CLASS) CirProvided.RegularClass(emptyList(), emptyList(), Visibilities.Public, ClassKind.CLASS)
@@ -68,3 +50,30 @@ interface CirProvidedClassifiers {
} }
} }
internal operator fun CirProvidedClassifiers.plus(other: CirProvidedClassifiers): CirProvidedClassifiers {
return when {
this is CompositeClassifiers && other is CompositeClassifiers -> CompositeClassifiers(this.delegates + other.delegates)
this is CompositeClassifiers -> CompositeClassifiers(this.delegates + other)
other is CompositeClassifiers -> CompositeClassifiers(listOf(this) + other.delegates)
else -> CompositeClassifiers(listOf(this, other))
}
}
private class CompositeClassifiers(val delegates: List<CirProvidedClassifiers>) : CirProvidedClassifiers {
override fun hasClassifier(classifierId: CirEntityId) = delegates.any { it.hasClassifier(classifierId) }
override fun classifier(classifierId: CirEntityId): CirProvided.Classifier? {
var fallbackReturn: CirProvided.Classifier? = null
for (delegate in delegates) {
delegate.classifier(classifierId)?.let { classifier ->
if (classifier !== CirProvidedClassifiers.FALLBACK_FORWARD_DECLARATION_CLASS) return classifier
else fallbackReturn = classifier
}
}
return fallbackReturn
}
override fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId): List<CirEntityId> {
return delegates.flatMap { it.findTypeAliasesWithUnderlyingType(underlyingClassifier) }
}
}
@@ -68,10 +68,15 @@ internal class CirProvidedClassifiersByModules internal constructor(
return CirProvidedClassifiersByModules(false, classifiers) return CirProvidedClassifiersByModules(false, classifiers)
} }
fun loadExportedForwardDeclarations(modulesProvider: ModulesProvider): CirProvidedClassifiers { /**
* Will load *all* forward declarations provided by all modules into a flat [CirProvidedClassifiers].
* Note: This builds a union *not an intersection* of forward declarations.
*/
fun loadExportedForwardDeclarations(modulesProviders: List<ModulesProvider>): CirProvidedClassifiers {
val classifiers = THashMap<CirEntityId, CirProvided.Classifier>() val classifiers = THashMap<CirEntityId, CirProvided.Classifier>()
modulesProvider.moduleInfos.mapNotNull { moduleInfo -> moduleInfo.cInteropAttributes } modulesProviders.flatMap { moduleProvider -> moduleProvider.moduleInfos }
.mapNotNull { moduleInfo -> moduleInfo.cInteropAttributes }
.forEach { attrs -> readExportedForwardDeclarations(attrs, classifiers::set) } .forEach { attrs -> readExportedForwardDeclarations(attrs, classifiers::set) }
if (classifiers.isEmpty) return CirProvidedClassifiers.EMPTY if (classifiers.isEmpty) return CirProvidedClassifiers.EMPTY
@@ -5,26 +5,23 @@
package org.jetbrains.kotlin.commonizer.mergedtree package org.jetbrains.kotlin.commonizer.mergedtree
import org.jetbrains.kotlin.commonizer.cir.CirClassRecursionMarker
import org.jetbrains.kotlin.commonizer.cir.CirDeclaration
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasRecursionMarker
import org.jetbrains.kotlin.commonizer.core.* import org.jetbrains.kotlin.commonizer.core.*
import org.jetbrains.kotlin.commonizer.CommonizerSettings import org.jetbrains.kotlin.commonizer.CommonizerSettings
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.utils.CommonizedGroup import org.jetbrains.kotlin.commonizer.utils.CommonizedGroup
import org.jetbrains.kotlin.storage.NullableLazyValue import org.jetbrains.kotlin.storage.NullableLazyValue
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
internal fun buildRootNode( internal fun buildRootNode(
storageManager: StorageManager, storageManager: StorageManager,
dependencies: CirProvidedClassifiers, commonDependencies: CirProvidedClassifiers,
size: Int size: Int
): CirRootNode = buildNode( ): CirRootNode = buildNode(
storageManager = storageManager, storageManager = storageManager,
size = size, size = size,
nodeRelationship = null, nodeRelationship = null,
commonizerProducer = ::RootCommonizer, commonizerProducer = ::RootCommonizer,
nodeProducer = { targetDeclarations, commonDeclaration -> CirRootNode(dependencies, targetDeclarations, commonDeclaration) } nodeProducer = { targetDeclarations, commonDeclaration -> CirRootNode(commonDependencies, targetDeclarations, commonDeclaration) }
) )
internal fun buildModuleNode( internal fun buildModuleNode(
@@ -103,7 +103,7 @@ fun InlineSourceBuilder.createCirTreeRootFromSourceCode(@Language("kotlin") sour
fun InlineSourceBuilder.createCirProvidedClassifiers(module: InlineSourceBuilder.Module): CirProvidedClassifiers { fun InlineSourceBuilder.createCirProvidedClassifiers(module: InlineSourceBuilder.Module): CirProvidedClassifiers {
val modulesProvider = object : ModulesProvider { val modulesProvider = object : ModulesProvider {
override val moduleInfos: Collection<ModulesProvider.ModuleInfo> = listOf( override val moduleInfos: Collection<ModulesProvider.ModuleInfo> = listOf(
ModulesProvider.ModuleInfo(name = "CirProvidedForTest", originalLocation = File("."), cInteropAttributes = null) ModulesProvider.ModuleInfo(name = "CirProvidedForTest", cInteropAttributes = null)
) )
override fun loadModuleMetadata(name: String): SerializedMetadata { override fun loadModuleMetadata(name: String): SerializedMetadata {
@@ -122,4 +122,4 @@ fun InlineSourceBuilder.createCirProvidedClassifiers(builder: InlineSourceBuilde
@InlineSourceBuilder.ModuleBuilderDsl @InlineSourceBuilder.ModuleBuilderDsl
fun InlineSourceBuilder.createCirProvidedClassifiersFromSourceCode(@Language("kotlin") sourceCode: String): CirProvidedClassifiers { fun InlineSourceBuilder.createCirProvidedClassifiersFromSourceCode(@Language("kotlin") sourceCode: String): CirProvidedClassifiers {
return createCirProvidedClassifiers(createModule { source(sourceCode) }) return createCirProvidedClassifiers(createModule { source(sourceCode) })
} }
@@ -98,7 +98,7 @@ internal class MockModulesProvider private constructor(
return SERIALIZER.serializeModule(module) return SERIALIZER.serializeModule(module)
} }
private fun fakeModuleInfo(name: String) = ModuleInfo(name, File("/tmp/commonizer/mocks/$name"), null) private fun fakeModuleInfo(name: String) = ModuleInfo(name, null)
companion object { companion object {
@JvmName("createByModuleNames") @JvmName("createByModuleNames")