JVM: use metadata version 1.9 for .kotlin_module if LV=2.0
See the comment in the code for more info. No proper test added because the compiler test infrastructure lacks the ability to run old compiler versions, however I've verified manually that the change fixes the issue. #KT-62531 Fixed
This commit is contained in:
committed by
Space Team
parent
d5540ff035
commit
9fd1445631
@@ -29,9 +29,12 @@ import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassFileFactoryFinalizerExtension;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.config.JvmAnalysisFlags;
|
||||
import org.jetbrains.kotlin.config.LanguageVersion;
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleMappingUtilKt;
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf;
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion;
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf;
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion;
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping;
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMappingKt;
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts;
|
||||
@@ -144,7 +147,7 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
if (state.getLanguageVersionSettings().getFlag(JvmAnalysisFlags.getStrictMetadataVersionSemantics())) {
|
||||
flags |= ModuleMapping.STRICT_METADATA_VERSION_SEMANTICS_FLAG;
|
||||
}
|
||||
return ModuleMappingKt.serializeToByteArray(moduleProto, state.getConfig().getMetadataVersion(), flags);
|
||||
return ModuleMappingKt.serializeToByteArray(moduleProto, getMetadataVersionToUseForModuleMapping(), flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,6 +157,31 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private BinaryVersion getMetadataVersionToUseForModuleMapping() {
|
||||
BinaryVersion version = state.getConfig().getMetadataVersion();
|
||||
if (version.getMajor() == LanguageVersion.KOTLIN_2_0.getMajor() &&
|
||||
version.getMinor() == LanguageVersion.KOTLIN_2_0.getMinor()) {
|
||||
// If language version is >= 2.0, we're using metadata version 1.9.*. This is needed because before Kotlin 1.8.20-RC, there was
|
||||
// a bug in determining whether module metadata is written in the pre-1.4 format, or in the 1.4+ format with an extra integer
|
||||
// for module-wide flags (see https://github.com/jetbrains/kotlin/commit/25c600c556a5).
|
||||
//
|
||||
// Normally it should not be possible to suffer from it because we have only one version forward compatibility on JVM. However,
|
||||
// with `-Xskip-metadata-version-check`, which is used in Gradle, pre-1.8.20-RC Kotlin compilers were trying to read the 2.0
|
||||
// module metadata in the wrong format and failed with an exception: KT-62531.
|
||||
//
|
||||
// Since module metadata is not supposed to have any changes in 2.0, we're using the metadata version 1.9 as a workaround. This
|
||||
// way, it's still written in the 1.4+ format, and old compilers will correctly understand that it's written in the 1.4+ format.
|
||||
//
|
||||
// Patch version does not affect anything, so we can use any number, for example 9999 to make it more recognizable that it's
|
||||
// not a real Kotlin version, and rather a substitute for the 2.0 metadata version.
|
||||
//
|
||||
// This workaround can be removed once we no longer support language version 2.0.
|
||||
return new JvmMetadataVersion(1, 9, 9999);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<OutputFile> asList() {
|
||||
|
||||
+6
-2
@@ -387,8 +387,12 @@ abstract class AbstractCompileKotlinAgainstCustomBinariesTest : AbstractKotlinCo
|
||||
val moduleFile = File(tmpdir.absolutePath, "META-INF/main.kotlin_module").readBytes()
|
||||
val versionNumber = ModuleMapping.readVersionNumber(DataInputStream(ByteArrayInputStream(moduleFile)))!!
|
||||
val moduleVersion = JvmMetadataVersion(*versionNumber)
|
||||
assertEquals("Actual version: $moduleVersion", expectedMajor, moduleVersion.major)
|
||||
assertEquals("Actual version: $moduleVersion", expectedMinor, moduleVersion.minor)
|
||||
if (languageVersion == LanguageVersion.KOTLIN_2_0) {
|
||||
assertEquals("Actual version: $moduleVersion", JvmMetadataVersion(1, 9, 9999), moduleVersion)
|
||||
} else {
|
||||
assertEquals("Actual version: $moduleVersion", expectedMajor, moduleVersion.major)
|
||||
assertEquals("Actual version: $moduleVersion", expectedMinor, moduleVersion.minor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user