Support multiple version requirements on single element

This commit is contained in:
Alexander Udalov
2018-07-19 15:11:30 +02:00
parent b7df36643b
commit c011bf61fe
22 changed files with 1681 additions and 601 deletions
@@ -76,9 +76,9 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation()
}
) {
assert(!builder.hasVersionRequirement()) { "VersionRequirement should be empty for $classDescriptor" }
builder.versionRequirement =
writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
builder.addVersionRequirement(
writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
)
}
}
@@ -183,9 +183,9 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
if (descriptor.isJvmFieldPropertyInInterfaceCompanion()) {
proto.setExtension(JvmProtoBuf.flags, JvmFlags.getPropertyFlags(true))
assert(!proto.hasVersionRequirement()) { "VersionRequirement should be empty for $descriptor" }
proto.versionRequirement =
writeVersionRequirement(1, 2, 70, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
proto.addVersionRequirement(
writeVersionRequirement(1, 2, 70, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
)
}
}
@@ -310,7 +310,9 @@ class DeprecationResolver(
result.add(deprecation)
}
getDeprecationByVersionRequirement(target)?.let(result::add)
for (deprecation in getDeprecationByVersionRequirement(target)) {
result.add(deprecation)
}
getDeprecationByCoroutinesVersion(target)?.let(result::add)
}
@@ -356,30 +358,33 @@ class DeprecationResolver(
DeprecatedExperimentalCoroutine(target)
else null
private fun getDeprecationByVersionRequirement(target: DeclarationDescriptor): DeprecatedByVersionRequirement? {
private fun getDeprecationByVersionRequirement(target: DeclarationDescriptor): List<DeprecatedByVersionRequirement> {
fun createVersion(version: String): MavenComparableVersion? = try {
MavenComparableVersion(version)
} catch (e: Exception) {
null
}
val versionRequirement =
(target as? DeserializedMemberDescriptor)?.versionRequirement
?: (target as? DeserializedClassDescriptor)?.versionRequirement
?: return null
val requiredVersion = createVersion(versionRequirement.version.asString())
val currentVersion = when (versionRequirement.kind) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION ->
MavenComparableVersion(languageVersionSettings.languageVersion.versionString)
ProtoBuf.VersionRequirement.VersionKind.API_VERSION ->
languageVersionSettings.apiVersion.version
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION ->
KotlinCompilerVersion.getVersion()?.substringBefore('-')?.let(::createVersion)
else -> null
val versionRequirements =
(target as? DeserializedMemberDescriptor)?.versionRequirements
?: (target as? DeserializedClassDescriptor)?.versionRequirements
?: return emptyList()
return versionRequirements.mapNotNull { versionRequirement ->
val requiredVersion = createVersion(versionRequirement.version.asString())
val currentVersion = when (versionRequirement.kind) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION ->
MavenComparableVersion(languageVersionSettings.languageVersion.versionString)
ProtoBuf.VersionRequirement.VersionKind.API_VERSION ->
languageVersionSettings.apiVersion.version
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION ->
KotlinCompilerVersion.getVersion()?.substringBefore('-')?.let(::createVersion)
else -> null
}
if (currentVersion != null && currentVersion < requiredVersion)
DeprecatedByVersionRequirement(versionRequirement, target)
else
null
}
if (currentVersion != null && currentVersion < requiredVersion) {
return DeprecatedByVersionRequirement(versionRequirement, target)
}
return null
}
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionTy
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
@@ -141,10 +142,7 @@ class DescriptorSerializer private constructor(
builder.typeTable = typeTableProto
}
val requirement = serializeVersionRequirement(classDescriptor)
if (requirement != null) {
builder.versionRequirement = requirement
}
builder.addAllVersionRequirement(serializeVersionRequirements(classDescriptor))
extension.serializeClass(classDescriptor, builder, versionRequirementTable)
@@ -235,11 +233,10 @@ class DescriptorSerializer private constructor(
}
}
val requirement = serializeVersionRequirement(descriptor)
if (requirement != null) {
builder.versionRequirement = requirement
} else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirementDependingOnCoroutinesVersion()
builder.addAllVersionRequirement(serializeVersionRequirements(descriptor))
if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
}
extension.serializeProperty(descriptor, builder, versionRequirementTable)
@@ -305,11 +302,10 @@ class DescriptorSerializer private constructor(
}
}
val requirement = serializeVersionRequirement(descriptor)
if (requirement != null) {
builder.versionRequirement = requirement
} else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirementDependingOnCoroutinesVersion()
builder.addAllVersionRequirement(serializeVersionRequirements(descriptor))
if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
}
contractSerializer.serializeContractOfFunctionIfAny(descriptor, builder, this)
@@ -335,11 +331,10 @@ class DescriptorSerializer private constructor(
builder.addValueParameter(local.valueParameter(valueParameterDescriptor))
}
val requirement = serializeVersionRequirement(descriptor)
if (requirement != null) {
builder.versionRequirement = requirement
} else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.versionRequirement = writeVersionRequirementDependingOnCoroutinesVersion()
builder.addAllVersionRequirement(serializeVersionRequirements(descriptor))
if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
}
extension.serializeConstructor(descriptor, builder)
@@ -392,10 +387,7 @@ class DescriptorSerializer private constructor(
builder.setExpandedType(local.type(expandedType))
}
val requirement = serializeVersionRequirement(descriptor)
if (requirement != null) {
builder.versionRequirement = requirement
}
builder.addAllVersionRequirement(serializeVersionRequirements(descriptor))
for (annotation in descriptor.nonSourceAnnotations) {
builder.addAnnotation(extension.annotationSerializer.serializeAnnotation(annotation))
@@ -633,9 +625,13 @@ class DescriptorSerializer private constructor(
return writeVersionRequirement(major, minor, patch, versionKind, versionRequirementTable)
}
// Returns index into versionRequirementTable, or null if there's no @RequireKotlin on the descriptor
private fun serializeVersionRequirement(descriptor: DeclarationDescriptor): Int? {
val annotation = descriptor.annotations.findAnnotation(RequireKotlinNames.FQ_NAME) ?: return null
// Returns a list of indices into versionRequirementTable, or empty list if there's no @RequireKotlin on the descriptor
private fun serializeVersionRequirements(descriptor: DeclarationDescriptor): List<Int> =
descriptor.annotations
.filter { it.fqName == RequireKotlinNames.FQ_NAME }
.mapNotNull(::serializeVersionRequirementFromRequireKotlin)
private fun serializeVersionRequirementFromRequireKotlin(annotation: AnnotationDescriptor): Int? {
val args = annotation.allValueArguments
val versionString = (args[RequireKotlinNames.VERSION] as? StringValue)?.value ?: return null
@@ -0,0 +1,27 @@
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package a
import kotlin.internal.RequireKotlin as RK
import kotlin.internal.RequireKotlinVersionKind as K
@RK("42.33", message = "This declaration is only supported since Kotlin 42.33")
@RK("40.34", versionKind = K.API_VERSION)
@RK("45.35")
class A
@RK("42.33", message = "This declaration is only supported since Kotlin 42.33")
@RK("40.34", versionKind = K.API_VERSION)
@RK("45.35")
@RK("1.1")
fun f() {}
@RK("42.33", message = "This declaration is only supported since Kotlin 42.33")
@RK("40.34", versionKind = K.API_VERSION)
@RK("45.35")
val p = ""
@RK("42.33", message = "This declaration is only supported since Kotlin 42.33")
@RK("40.34", versionKind = K.API_VERSION)
@RK("45.35")
@RK("1.1")
typealias TA = String
@@ -0,0 +1,37 @@
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:3:13: error: 'A' is only available since Kotlin 42.33 and cannot be used in Kotlin 1.2. This declaration is only supported since Kotlin 42.33
fun test(a: A): TA {
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:3:13: error: 'A' is only available since Kotlin 40.34 and cannot be used in Kotlin 1.2
fun test(a: A): TA {
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:3:13: error: 'A' is only available since Kotlin 45.35 and cannot be used in Kotlin 1.2
fun test(a: A): TA {
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:3:17: error: 'typealias TA = String' is only available since Kotlin 42.33 and cannot be used in Kotlin 1.2. This declaration is only supported since Kotlin 42.33
fun test(a: A): TA {
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:3:17: error: 'typealias TA = String' is only available since Kotlin 40.34 and cannot be used in Kotlin 1.2
fun test(a: A): TA {
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:3:17: error: 'typealias TA = String' is only available since Kotlin 45.35 and cannot be used in Kotlin 1.2
fun test(a: A): TA {
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:4:5: error: 'f(): Unit' is only available since Kotlin 42.33 and cannot be used in Kotlin 1.2. This declaration is only supported since Kotlin 42.33
f()
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:4:5: error: 'f(): Unit' is only available since Kotlin 40.34 and cannot be used in Kotlin 1.2
f()
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:4:5: error: 'f(): Unit' is only available since Kotlin 45.35 and cannot be used in Kotlin 1.2
f()
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:5:12: error: 'p: String' is only available since Kotlin 42.33 and cannot be used in Kotlin 1.2. This declaration is only supported since Kotlin 42.33
return p
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:5:12: error: 'p: String' is only available since Kotlin 40.34 and cannot be used in Kotlin 1.2
return p
^
compiler/testData/compileKotlinAgainstCustomBinaries/requireKotlin/source.kt:5:12: error: 'p: String' is only available since Kotlin 45.35 and cannot be used in Kotlin 1.2
return p
^
COMPILATION_ERROR
@@ -0,0 +1,6 @@
import a.*
fun test(a: A): TA {
f()
return p
}
@@ -296,6 +296,10 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
doTestKotlinLibraryWithWrongMetadataVersionJs("library", "-Xskip-metadata-version-check")
}
fun testRequireKotlin() {
compileKotlin("source.kt", tmpdir, listOf(compileLibrary("library")))
}
fun testRequireKotlinInNestedClasses() {
compileKotlin("source.kt", tmpdir, listOf(compileLibrary("library")))
}
@@ -37,8 +37,8 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
val descriptor = module.findUnambiguousDescriptorByFqName(fqName)
val requirement = when (descriptor) {
is DeserializedMemberDescriptor -> descriptor.versionRequirement
is DeserializedClassDescriptor -> descriptor.versionRequirement
is DeserializedMemberDescriptor -> descriptor.versionRequirements.single()
is DeserializedClassDescriptor -> descriptor.versionRequirements.single()
else -> throw AssertionError("Unknown descriptor: $descriptor")
} ?: throw AssertionError("No VersionRequirement for $descriptor")