Add @RequireKotlin(1.2.40) on interface with @JvmDefaults and its subinterfaces

This commit is contained in:
Mikhael Bogdanov
2018-04-04 13:10:04 +02:00
parent be33a9bf3b
commit 4aec9499b5
3 changed files with 62 additions and 20 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface
import org.jetbrains.kotlin.resolve.MemberComparator
import org.jetbrains.kotlin.resolve.RequireKotlinNames
import org.jetbrains.kotlin.resolve.annotations.hasJvmDefaultAnnotation
@@ -142,6 +143,8 @@ class DescriptorSerializer private constructor(
val requirement = serializeVersionRequirement(classDescriptor)
if (requirement != null) {
builder.versionRequirement = requirement
} else {
writeVersionRequirementForJvmDefaultIfNeeded(classDescriptor, builder)
}
val versionRequirementTableProto = versionRequirementTable.serialize()
@@ -239,8 +242,6 @@ class DescriptorSerializer private constructor(
}
else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines)
} else if (descriptor.hasJvmDefaultAnnotation()) {
builder.versionRequirement = writeVersionRequirement(1, 2, 40)
}
extension.serializeProperty(descriptor, builder)
@@ -311,8 +312,6 @@ class DescriptorSerializer private constructor(
builder.versionRequirement = requirement
} else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines)
} else if (descriptor.hasJvmDefaultAnnotation()) {
builder.versionRequirement = writeVersionRequirement(1, 2, 40)
}
contractSerializer.serializeContractOfFunctionIfAny(descriptor, builder, this)
@@ -619,23 +618,36 @@ class DescriptorSerializer private constructor(
return builder
}
private fun writeVersionRequirement(languageFeature: LanguageFeature): Int {
val languageVersion = languageFeature.sinceVersion!!
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
VersionRequirement.Version(languageVersion.major, languageVersion.minor).encode(
writeVersion = { version = it },
writeVersionFull = { versionFull = it }
)
// Interfaces which have @JvmDefault members somewhere in the hierarchy need the compiler 1.2.40+
// so that the generated bridges in subclasses would call the super members correctly
private fun writeVersionRequirementForJvmDefaultIfNeeded(classDescriptor: ClassDescriptor, builder: ProtoBuf.Class.Builder) {
if (
isInterface(classDescriptor) &&
classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any {
it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation()
}
) {
builder.versionRequirement = writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION)
}
return versionRequirementTable[requirement]
}
private fun writeVersionRequirement(major: Int, minor: Int, patch: Int): Int {
private fun writeVersionRequirement(languageFeature: LanguageFeature): Int {
val languageVersion = languageFeature.sinceVersion!!
return writeVersionRequirement(
languageVersion.major, languageVersion.minor, 0,
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION
)
}
private fun writeVersionRequirement(major: Int, minor: Int, patch: Int, versionKind: ProtoBuf.VersionRequirement.VersionKind): Int {
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
VersionRequirement.Version(major, minor, patch).encode(
writeVersion = { version = it },
writeVersionFull = { versionFull = it }
)
if (versionKind != defaultInstanceForType.versionKind) {
this.versionKind = versionKind
}
}
return versionRequirementTable[requirement]
}
+8
View File
@@ -0,0 +1,8 @@
package test
interface Base {
@JvmDefault
fun foo() {}
}
interface Derived : Base
@@ -18,12 +18,14 @@ package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.VersionRequirement.VersionKind.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
@@ -46,8 +48,20 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
vararg fqNames: String
) {
LoadDescriptorUtil.compileKotlinToDirAndGetModule(
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir,
KotlinTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(testRootDisposable)
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir,
KotlinCoreEnvironment.createForTests(
testRootDisposable,
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir).apply {
put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersionSettingsImpl.DEFAULT.languageVersion,
LanguageVersionSettingsImpl.DEFAULT.apiVersion,
mapOf(AnalysisFlag.enableJvmDefault to true),
emptyMap()
)
},
EnvironmentConfigFiles.JVM_CONFIG_FILES
)
)
val (_, module) = JvmResolveUtil.analyze(
@@ -99,7 +113,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
}
fun testSuspendFun() {
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null,
"test.topLevel",
"test.Foo.member",
"test.Foo.<init>",
@@ -112,7 +126,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
}
fun testLanguageVersionViaAnnotation() {
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, 42,
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", LANGUAGE_VERSION, 42,
"test.Klass",
"test.Konstructor.<init>",
"test.Typealias",
@@ -122,7 +136,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
}
fun testApiVersionViaAnnotation() {
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.API_VERSION, 42,
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", API_VERSION, 42,
"test.Klass",
"test.Konstructor.<init>",
"test.Typealias",
@@ -132,7 +146,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
}
fun testCompilerVersionViaAnnotation() {
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, 42,
doTest(VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", COMPILER_VERSION, 42,
"test.Klass",
"test.Konstructor.<init>",
"test.Typealias",
@@ -142,8 +156,16 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
}
fun testPatchVersion() {
doTest(VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
doTest(VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null, LANGUAGE_VERSION, null,
"test.Klass"
)
}
fun testJvmDefault() {
doTest(
VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
"test.Base",
"test.Derived"
)
}
}