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.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry 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.MemberComparator
import org.jetbrains.kotlin.resolve.RequireKotlinNames import org.jetbrains.kotlin.resolve.RequireKotlinNames
import org.jetbrains.kotlin.resolve.annotations.hasJvmDefaultAnnotation import org.jetbrains.kotlin.resolve.annotations.hasJvmDefaultAnnotation
@@ -142,6 +143,8 @@ class DescriptorSerializer private constructor(
val requirement = serializeVersionRequirement(classDescriptor) val requirement = serializeVersionRequirement(classDescriptor)
if (requirement != null) { if (requirement != null) {
builder.versionRequirement = requirement builder.versionRequirement = requirement
} else {
writeVersionRequirementForJvmDefaultIfNeeded(classDescriptor, builder)
} }
val versionRequirementTableProto = versionRequirementTable.serialize() val versionRequirementTableProto = versionRequirementTable.serialize()
@@ -239,8 +242,6 @@ class DescriptorSerializer private constructor(
} }
else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines) builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines)
} else if (descriptor.hasJvmDefaultAnnotation()) {
builder.versionRequirement = writeVersionRequirement(1, 2, 40)
} }
extension.serializeProperty(descriptor, builder) extension.serializeProperty(descriptor, builder)
@@ -311,8 +312,6 @@ class DescriptorSerializer private constructor(
builder.versionRequirement = requirement builder.versionRequirement = requirement
} else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { } else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines) builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines)
} else if (descriptor.hasJvmDefaultAnnotation()) {
builder.versionRequirement = writeVersionRequirement(1, 2, 40)
} }
contractSerializer.serializeContractOfFunctionIfAny(descriptor, builder, this) contractSerializer.serializeContractOfFunctionIfAny(descriptor, builder, this)
@@ -619,23 +618,36 @@ class DescriptorSerializer private constructor(
return builder return builder
} }
private fun writeVersionRequirement(languageFeature: LanguageFeature): Int { // Interfaces which have @JvmDefault members somewhere in the hierarchy need the compiler 1.2.40+
val languageVersion = languageFeature.sinceVersion!! // so that the generated bridges in subclasses would call the super members correctly
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply { private fun writeVersionRequirementForJvmDefaultIfNeeded(classDescriptor: ClassDescriptor, builder: ProtoBuf.Class.Builder) {
VersionRequirement.Version(languageVersion.major, languageVersion.minor).encode( if (
writeVersion = { version = it }, isInterface(classDescriptor) &&
writeVersionFull = { versionFull = it } 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 { val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
VersionRequirement.Version(major, minor, patch).encode( VersionRequirement.Version(major, minor, patch).encode(
writeVersion = { version = it }, writeVersion = { version = it },
writeVersionFull = { versionFull = it } writeVersionFull = { versionFull = it }
) )
if (versionKind != defaultInstanceForType.versionKind) {
this.versionKind = versionKind
}
} }
return versionRequirementTable[requirement] 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.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.VersionRequirement.VersionKind.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
@@ -46,8 +48,20 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
vararg fqNames: String vararg fqNames: String
) { ) {
LoadDescriptorUtil.compileKotlinToDirAndGetModule( LoadDescriptorUtil.compileKotlinToDirAndGetModule(
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir,
KotlinTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(testRootDisposable) 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( val (_, module) = JvmResolveUtil.analyze(
@@ -99,7 +113,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
} }
fun testSuspendFun() { 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.topLevel",
"test.Foo.member", "test.Foo.member",
"test.Foo.<init>", "test.Foo.<init>",
@@ -112,7 +126,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
} }
fun testLanguageVersionViaAnnotation() { 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.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
"test.Typealias", "test.Typealias",
@@ -122,7 +136,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
} }
fun testApiVersionViaAnnotation() { 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.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
"test.Typealias", "test.Typealias",
@@ -132,7 +146,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
} }
fun testCompilerVersionViaAnnotation() { 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.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
"test.Typealias", "test.Typealias",
@@ -142,8 +156,16 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
} }
fun testPatchVersion() { 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" "test.Klass"
) )
} }
fun testJvmDefault() {
doTest(
VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
"test.Base",
"test.Derived"
)
}
} }