summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Udalov <Alexander.Udalov@jetbrains.com>2018-06-19 15:55:46 +0200
committerAlexander Udalov <Alexander.Udalov@jetbrains.com>2018-06-21 14:29:25 +0200
commita3eb82380d3bc0b59315a6c8fc95e7f6582def4c (patch)
treee33a8601981debb831326b120dea092370510fc4
parentadabcc5c029dc14e2fa1915278e472c86c18118d (diff)
downloadkotlin-a3eb82380d3bc0b59315a6c8fc95e7f6582def4c.tar.gz
Fix serialization of type parameters inner generic class
The call to `createTopLevel` instead of `create` (which creates serializers for outer classes properly, with correct type parameter contexts) caused MetadataSerializer to write type parameter metadata incorrectly. For example, in the following case: class A<E> { inner class B<T, E> { ... } } A's type parameter E would get id 0, and B's type parameters T and E would get ids 0 and 1. This is a problem because ids are supposed to be unique for each class including its outer classes, and deserializer, decompiler and stub builder rely on this assumption. JVM metadata is unaffected because `create` is called correctly there, see MemberCodegen#generateKotlinClassMetadataAnnotation #KT-24944 Fixed
-rw-r--r--compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt2
-rw-r--r--compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt4
-rw-r--r--compiler/testData/multiplatform/innerGenericClass/common.kt9
-rw-r--r--compiler/testData/multiplatform/innerGenericClass/common2.kt11
-rw-r--r--compiler/testData/multiplatform/innerGenericClass/output.txt10
-rw-r--r--compiler/tests/org/jetbrains/kotlin/multiplatform/AbstractMultiPlatformIntegrationTest.kt59
-rw-r--r--compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java18
-rw-r--r--compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt2
-rw-r--r--core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt2
-rw-r--r--js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt12
10 files changed, 95 insertions, 34 deletions
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt
index e276c902b32..8ee354b560b 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt
@@ -158,7 +158,7 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
}
private fun serializeClass(classDescriptor: ClassDescriptor) {
- val classProto = DescriptorSerializer.createTopLevel(extension).classProto(classDescriptor).build()
+ val classProto = DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build()
proto.addClass_(classProto)
serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt
index d3339b2afaa..c117f9998ad 100644
--- a/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt
+++ b/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt
@@ -36,9 +36,9 @@ object KotlinStubVersions {
// BuiltIn stub version should be increased if changes are made to builtIn stub building subsystem (org.jetbrains.kotlin.idea.decompiler.builtIns)
// Increasing this version will lead to reindexing of all builtIn files (see KotlinBuiltInFileType).
- const val BUILTIN_STUB_VERSION = BINARY_STUB_VERSION + 1
+ const val BUILTIN_STUB_VERSION = BINARY_STUB_VERSION + 2
// JS stub version should be increased if changes are made to js stub building subsystem (org.jetbrains.kotlin.idea.decompiler.js)
// Increasing this version will lead to reindexing of js binary files (see KotlinJavaScriptMetaFileType).
- const val JS_STUB_VERSION = BINARY_STUB_VERSION + 1
+ const val JS_STUB_VERSION = BINARY_STUB_VERSION + 2
}
diff --git a/compiler/testData/multiplatform/innerGenericClass/common.kt b/compiler/testData/multiplatform/innerGenericClass/common.kt
new file mode 100644
index 00000000000..e0eb22ced97
--- /dev/null
+++ b/compiler/testData/multiplatform/innerGenericClass/common.kt
@@ -0,0 +1,9 @@
+class A<E> {
+ inner class B<T, E> {
+ fun getAE() = this@A.getAE()
+ fun getBT(): T? = null
+ fun getBE(): E? = null
+ }
+
+ fun getAE(): E? = null
+}
diff --git a/compiler/testData/multiplatform/innerGenericClass/common2.kt b/compiler/testData/multiplatform/innerGenericClass/common2.kt
new file mode 100644
index 00000000000..721c47e019a
--- /dev/null
+++ b/compiler/testData/multiplatform/innerGenericClass/common2.kt
@@ -0,0 +1,11 @@
+fun test(): String {
+ val b = A<String>().B<Int, Double>()
+ val x: String? = b.getAE()
+ val y: Int? = b.getBT()
+ val z: Double? = b.getBE()
+
+ // This line is needed to ensure that B.getAE's return type is not an error type; if it was, this line would compile with no errors
+ b.getAE().unresolved()
+
+ return "$x$y$z"
+}
diff --git a/compiler/testData/multiplatform/innerGenericClass/output.txt b/compiler/testData/multiplatform/innerGenericClass/output.txt
new file mode 100644
index 00000000000..2c52162d1d6
--- /dev/null
+++ b/compiler/testData/multiplatform/innerGenericClass/output.txt
@@ -0,0 +1,10 @@
+-- Common --
+Exit code: OK
+Output:
+
+-- Common (2) --
+Exit code: COMPILATION_ERROR
+Output:
+compiler/testData/multiplatform/innerGenericClass/common2.kt:8:15: error: unresolved reference: unresolved
+ b.getAE().unresolved()
+ ^
diff --git a/compiler/tests/org/jetbrains/kotlin/multiplatform/AbstractMultiPlatformIntegrationTest.kt b/compiler/tests/org/jetbrains/kotlin/multiplatform/AbstractMultiPlatformIntegrationTest.kt
index 14e3123c51a..d7d67777feb 100644
--- a/compiler/tests/org/jetbrains/kotlin/multiplatform/AbstractMultiPlatformIntegrationTest.kt
+++ b/compiler/tests/org/jetbrains/kotlin/multiplatform/AbstractMultiPlatformIntegrationTest.kt
@@ -33,44 +33,57 @@ import java.nio.file.Paths
abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
fun doTest(directoryPath: String) {
val root = File(directoryPath).apply { assert(exists()) }
- val commonSrc = File(root, "common.kt")
- val jsSrc = File(root, "js.kt")
- val jvmSrc = File(root, "jvm.kt")
+ val commonSrc = File(root, "common.kt").apply { assert(exists()) }
+ val jsSrc = File(root, "js.kt").takeIf(File::exists)
+ val jvmSrc = File(root, "jvm.kt").takeIf(File::exists)
// TODO: consider inventing a more clever scheme
- val jvm2Src = File(root, "jvm2.kt")
+ val common2Src = File(root, "common2.kt").takeIf(File::exists)
+ val jvm2Src = File(root, "jvm2.kt").takeIf(File::exists)
val tmpdir = KotlinTestUtils.tmpDir(getTestName(true))
val optionalStdlibCommon =
- if (InTextDirectivesUtils.isDirectiveDefined(commonSrc.readText(), "WITH_RUNTIME"))
- arrayOf("-cp", findStdlibCommon().absolutePath)
- else emptyArray()
+ if (InTextDirectivesUtils.isDirectiveDefined(commonSrc.readText(), "WITH_RUNTIME"))
+ arrayOf("-cp", findStdlibCommon().absolutePath)
+ else emptyArray()
val commonDest = File(tmpdir, "common").absolutePath
- val jvmDest = File(tmpdir, "jvm").absolutePath
- val jsDest = File(File(tmpdir, "js"), "output.js").absolutePath
- val jvm2Dest = File(tmpdir, "jvm2").absolutePath
+ val jvmDest = File(tmpdir, "jvm").absolutePath.takeIf { jvmSrc != null }
+ val jsDest = File(File(tmpdir, "js"), "output.js").absolutePath.takeIf { jsSrc != null }
+ val common2Dest = File(tmpdir, "common2").absolutePath.takeIf { common2Src != null }
+ val jvm2Dest = File(tmpdir, "jvm2").absolutePath.takeIf { jvm2Src != null }
val result = buildString {
appendln("-- Common --")
appendln(K2MetadataCompiler().compile(listOf(commonSrc), "-d", commonDest, *optionalStdlibCommon))
- if (jvmSrc.exists()) {
+ if (jvmSrc != null) {
appendln()
appendln("-- JVM --")
- appendln(K2JVMCompiler().compileBothWays(commonSrc, jvmSrc, "-d", jvmDest))
+ appendln(K2JVMCompiler().compileBothWays(commonSrc, jvmSrc, "-d", jvmDest!!))
}
- if (jsSrc.exists()) {
+ if (jsSrc != null) {
appendln()
appendln("-- JS --")
- appendln(K2JSCompiler().compileBothWays(commonSrc, jsSrc, "-output", jsDest))
+ appendln(K2JSCompiler().compileBothWays(commonSrc, jsSrc, "-output", jsDest!!))
}
- if (jvm2Src.exists()) {
+ if (common2Src != null) {
+ appendln()
+ appendln("-- Common (2) --")
+ appendln(K2MetadataCompiler().compile(listOf(common2Src), "-d", common2Dest!!, "-cp", commonDest, *optionalStdlibCommon))
+ }
+
+ if (jvm2Src != null) {
appendln()
appendln("-- JVM (2) --")
- appendln(K2JVMCompiler().compile(listOf(jvm2Src), "-d", jvm2Dest, "-cp", listOf(commonDest, jvmDest).joinToString(File.pathSeparator)))
+ appendln(
+ K2JVMCompiler().compile(
+ listOf(jvm2Src), "-d", jvm2Dest!!,
+ "-cp", listOfNotNull(commonDest, common2Dest, jvmDest).joinToString(File.pathSeparator)
+ )
+ )
}
}
@@ -89,17 +102,17 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
private fun CLICompiler<*>.compileBothWays(commonSource: File, platformSource: File, vararg mainArguments: String): String {
val configurations = listOf(
- listOf(platformSource, commonSource),
- listOf(commonSource, platformSource)
+ listOf(platformSource, commonSource),
+ listOf(commonSource, platformSource)
)
val (platformFirst, commonFirst) = configurations.map { compile(it, *mainArguments) }
if (platformFirst != commonFirst) {
assertEquals(
- "Compilation results are different when compiling [platform-specific, common] compared to when compiling [common, platform-specific]",
- "// Compiling [platform-specific, common]\n\n$platformFirst",
- "// Compiling [common, platform-specific]\n\n$commonFirst"
+ "Compilation results are different when compiling [platform-specific, common] compared to when compiling [common, platform-specific]",
+ "// Compiling [platform-specific, common]\n\n$platformFirst",
+ "// Compiling [common, platform-specific]\n\n$commonFirst"
)
}
return platformFirst
@@ -107,8 +120,8 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
private fun CLICompiler<*>.compile(sources: List<File>, vararg mainArguments: String): String = buildString {
val (output, exitCode) = AbstractCliTest.executeCompilerGrabOutput(
- this@compile,
- sources.map(File::getAbsolutePath) + listOf("-Xmulti-platform") + mainArguments + loadExtraArguments(sources)
+ this@compile,
+ sources.map(File::getAbsolutePath) + listOf("-Xmulti-platform") + mainArguments + loadExtraArguments(sources)
)
appendln("Exit code: $exitCode")
appendln("Output:")
diff --git a/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java
index 8d9fe94b84a..369ca47b3e7 100644
--- a/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java
@@ -84,6 +84,11 @@ public class MultiPlatformIntegrationTestGenerated extends AbstractMultiPlatform
runTest("compiler/testData/multiplatform/incorrectImplInClass/");
}
+ @TestMetadata("innerGenericClass")
+ public void testInnerGenericClass() throws Exception {
+ runTest("compiler/testData/multiplatform/innerGenericClass/");
+ }
+
@TestMetadata("jsNameClash")
public void testJsNameClash() throws Exception {
runTest("compiler/testData/multiplatform/jsNameClash/");
@@ -530,6 +535,19 @@ public class MultiPlatformIntegrationTestGenerated extends AbstractMultiPlatform
}
}
+ @TestMetadata("compiler/testData/multiplatform/innerGenericClass")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class InnerGenericClass extends AbstractMultiPlatformIntegrationTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInInnerGenericClass() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/multiplatform/innerGenericClass"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
+ }
+ }
+
@TestMetadata("compiler/testData/multiplatform/jsNameClash")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt
index 4917c846b11..745ca4542a4 100644
--- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt
+++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt
@@ -32,7 +32,7 @@ class JsMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
companion object {
@JvmField
- val INSTANCE = JsMetadataVersion(1, 2, 1)
+ val INSTANCE = JsMetadataVersion(1, 2, 2)
@JvmField
val INVALID_VERSION = JsMetadataVersion()
diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt
index c801bc487c4..bd8c9dc1a70 100644
--- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt
+++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt
@@ -29,7 +29,7 @@ class BuiltInsBinaryVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
companion object {
@JvmField
- val INSTANCE = BuiltInsBinaryVersion(1, 0, 2)
+ val INSTANCE = BuiltInsBinaryVersion(1, 0, 3)
@JvmField
val INVALID_VERSION = BuiltInsBinaryVersion()
diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt
index 9511d51cb5c..6a3d48f04a9 100644
--- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt
+++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.serialization.js
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.LanguageVersionSettings
-import org.jetbrains.kotlin.config.isPreRelease
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -197,15 +196,16 @@ object KotlinJavascriptSerializationUtil {
}
val fileRegistry = KotlinFileRegistry()
- val serializerExtension = KotlinJavascriptSerializerExtension(fileRegistry)
- val serializer = DescriptorSerializer.createTopLevel(serializerExtension)
+ val extension = KotlinJavascriptSerializerExtension(fileRegistry)
val classDescriptors = scope.filterIsInstance<ClassDescriptor>().sortedBy { it.fqNameSafe.asString() }
fun serializeClasses(descriptors: Collection<DeclarationDescriptor>) {
fun serializeClass(classDescriptor: ClassDescriptor) {
if (skip(classDescriptor)) return
- val classProto = serializer.classProto(classDescriptor).build() ?: error("Class not serialized: $classDescriptor")
+ val classProto =
+ DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build()
+ ?: error("Class not serialized: $classDescriptor")
builder.addClass_(classProto)
serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors())
}
@@ -219,10 +219,10 @@ object KotlinJavascriptSerializationUtil {
serializeClasses(classDescriptors)
- val stringTable = serializerExtension.stringTable
+ val stringTable = extension.stringTable
val members = scope.filterNot(skip)
- builder.`package` = serializer.packagePartProto(fqName, members).build()
+ builder.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(fqName, members).build()
builder.setExtension(
JsProtoBuf.packageFragmentFiles,