JS: several bugfixes in incremental compilation

1. Fix exported packages sometimes being mixed up
2. Fix metadata losing package fragments sometimes
3. Don't serialize empty packages to .meta.js
4. Preserve order of package fragments in .meta.js
5. In IC tests, compare textual representation of metadata rather
   than binary representation
This commit is contained in:
Alexey Andreev
2017-10-19 12:19:34 +03:00
parent 2fbecfdd9c
commit e1f8bac4d5
7 changed files with 84 additions and 17 deletions
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.DataOutputStream
import java.util.*
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
@@ -109,7 +108,7 @@ object KotlinJavascriptSerializationUtil {
for (fqName in getPackagesFqNames(module)) {
val fragment = serializePackageFragment(bindingContext, module, fqName)
if (fragment.hasPackage() || fragment.class_Count > 0) {
if (!fragment.isEmpty()) {
builder.addPackageFragment(fragment)
}
}
@@ -212,13 +211,11 @@ object KotlinJavascriptSerializationUtil {
module: ModuleDescriptor,
languageVersionSettings: LanguageVersionSettings
): Map<String, ByteArray> {
val contentMap = hashMapOf<String, ByteArray>()
val contentMap = mutableMapOf<String, ByteArray>()
for (fqName in getPackagesFqNames(module)) {
val part = serializePackageFragment(bindingContext, module, fqName)
if (part.class_Count == 0 && part.`package`.let { packageProto ->
packageProto.functionCount == 0 && packageProto.propertyCount == 0 && packageProto.typeAliasCount == 0
}) continue
if (part.isEmpty()) continue
val stream = ByteArrayOutputStream()
with(DataOutputStream(stream)) {
@@ -236,6 +233,9 @@ object KotlinJavascriptSerializationUtil {
return contentMap
}
private fun ProtoBuf.PackageFragment.isEmpty(): Boolean =
class_Count == 0 && `package`.let { it.functionCount == 0 && it.propertyCount == 0 && it.typeAliasCount == 0 }
fun serializeHeader(packageFqName: FqName?, languageVersionSettings: LanguageVersionSettings): JsProtoBuf.Header {
val header = JsProtoBuf.Header.newBuilder()
@@ -253,7 +253,7 @@ object KotlinJavascriptSerializationUtil {
}
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
return HashSet<FqName>().apply {
return mutableSetOf<FqName>().apply {
getSubPackagesFqNames(module.getPackage(FqName.ROOT), this)
add(FqName.ROOT)
}
@@ -17,13 +17,12 @@
package org.jetbrains.kotlin.serialization.js
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.NotFoundClasses
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.PackageFragmentProviderImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.parentOrNull
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.storage.StorageManager
@@ -36,12 +35,26 @@ fun createKotlinJavascriptPackageFragmentProvider(
configuration: DeserializationConfiguration,
lookupTracker: LookupTracker
): PackageFragmentProvider {
val packageFragments = packageFragmentProtos.mapNotNull { proto ->
val packageFragments: MutableList<PackageFragmentDescriptor> = packageFragmentProtos.mapNotNullTo(mutableListOf()) { proto ->
proto.fqName?.let { fqName ->
KotlinJavascriptPackageFragment(fqName, storageManager, module, proto, header, configuration)
}
}
// Generate empty PackageFragmentDescriptor instances for packages that aren't mentioned in compilation units directly.
// For example, if there's `package foo.bar` directive, we'll get only PackageFragmentDescriptor for `foo.bar`, but
// none for `foo`. Various descriptor/scope code relies on presence of such package fragments, and currently we
// don't know if it's possible to fix this.
// TODO: think about fixing issues in descriptors/scopes
val packageFqNames = packageFragmentProtos.mapNotNullTo(mutableSetOf()) { it.fqName }
for (packageFqName in packageFqNames.mapNotNull { it.parentOrNull() }) {
var ancestorFqName = packageFqName
while (!ancestorFqName.isRoot && packageFqNames.add(ancestorFqName)) {
packageFragments += EmptyPackageFragmentDescriptor(module, ancestorFqName)
ancestorFqName = ancestorFqName.parent()
}
}
val provider = PackageFragmentProviderImpl(packageFragments)
val notFoundClasses = NotFoundClasses(storageManager, module)
@@ -63,7 +76,7 @@ fun createKotlinJavascriptPackageFragmentProvider(
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent
)
for (packageFragment in packageFragments) {
for (packageFragment in packageFragments.filterIsInstance<KotlinJavascriptPackageFragment>()) {
packageFragment.components = components
}