Fix requirements

This commit is contained in:
Mikhail Bogdanov
2020-03-27 16:12:12 +01:00
parent c11f38688e
commit 7bcbae9826
6 changed files with 157 additions and 38 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.createFreeFakeLocalPropertyDescriptor
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.* import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -30,6 +31,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi
import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultAnnotation
import org.jetbrains.kotlin.resolve.jvm.annotations.isCompiledToJvmDefaultIfNoAbstract import org.jetbrains.kotlin.resolve.jvm.annotations.isCompiledToJvmDefaultIfNoAbstract
import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.DescriptorSerializer.Companion.writeVersionRequirement import org.jetbrains.kotlin.serialization.DescriptorSerializer.Companion.writeVersionRequirement
@@ -102,15 +104,19 @@ class JvmSerializerExtension @JvmOverloads constructor(
builder: ProtoBuf.Class.Builder, builder: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable versionRequirementTable: MutableVersionRequirementTable
) { ) {
if ( if (isInterface(classDescriptor)) {
isInterface(classDescriptor) && if (jvmDefaultMode == JvmDefaultMode.ENABLE && classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any {
classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any { it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation()
it is CallableMemberDescriptor && it.isCompiledToJvmDefaultIfNoAbstract(jvmDefaultMode) //TODO: new requirements for new option }) {
builder.addVersionRequirement(
writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
)
}
if (jvmDefaultMode == JvmDefaultMode.ALL_INCOMPATIBLE) {
builder.addVersionRequirement(
writeVersionRequirement(1, 4, 0, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
)
} }
) {
builder.addVersionRequirement(
writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
)
} }
} }
@@ -0,0 +1,27 @@
package test
interface Base {
fun foo() {}
}
interface Derived : Base
interface BaseWithProperty {
val prop: String
get() = "123"
}
interface DerivedWithProperty : BaseWithProperty
interface Empty
interface EmptyWithNested {
interface Nested
}
interface WithAbstractDeclaration {
fun foo()
var prop: String
}
interface DerivedFromWithAbstractDeclaration : WithAbstractDeclaration
+27
View File
@@ -0,0 +1,27 @@
package test
interface Base {
fun foo() {}
}
interface Derived : Base
interface BaseWithProperty {
val prop: String
get() = "123"
}
interface DerivedWithProperty : BaseWithProperty
interface Empty
interface EmptyWithNested {
interface Nested
}
interface WithAbstractDeclaration {
fun foo()
var prop: String
}
interface DerivedFromWithAbstractDeclaration : WithAbstractDeclaration
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.serialization package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -28,19 +29,17 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
expectedVersionKind: ProtoBuf.VersionRequirement.VersionKind, expectedVersionKind: ProtoBuf.VersionRequirement.VersionKind,
expectedErrorCode: Int?, expectedErrorCode: Int?,
customLanguageVersion: LanguageVersion = LanguageVersionSettingsImpl.DEFAULT.languageVersion, customLanguageVersion: LanguageVersion = LanguageVersionSettingsImpl.DEFAULT.languageVersion,
fqNames: List<String> analysisFlags: Map<AnalysisFlag<*>, Any?> = emptyMap(),
fqNamesWithRequirements: List<String>,
fqNamesWithoutRequirement: List<String> = emptyList()
) { ) {
compileFiles(listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, customLanguageVersion) compileFiles(listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, customLanguageVersion, analysisFlags)
val module = loadModule(tmpdir) val module = loadModule(tmpdir)
for (fqName in fqNames) { for (fqName in fqNamesWithRequirements) {
val descriptor = module.findUnambiguousDescriptorByFqName(fqName) val descriptor = module.findUnambiguousDescriptorByFqName(fqName)
val requirement = when (descriptor) { val requirement = extractRequirement(descriptor) ?: throw AssertionError("No VersionRequirement for $descriptor")
is DeserializedMemberDescriptor -> descriptor.versionRequirements.singleOrNull()
is DeserializedClassDescriptor -> descriptor.versionRequirements.singleOrNull()
else -> throw AssertionError("Unknown descriptor: $descriptor")
} ?: throw AssertionError("No VersionRequirement for $descriptor")
assertEquals("Incorrect version for $fqName", expectedVersionRequirement, requirement.version) assertEquals("Incorrect version for $fqName", expectedVersionRequirement, requirement.version)
assertEquals("Incorrect level for $fqName", expectedLevel, requirement.level) assertEquals("Incorrect level for $fqName", expectedLevel, requirement.level)
@@ -48,6 +47,21 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
assertEquals("Incorrect versionKind for $fqName", expectedVersionKind, requirement.kind) assertEquals("Incorrect versionKind for $fqName", expectedVersionKind, requirement.kind)
assertEquals("Incorrect errorCode for $fqName", expectedErrorCode, requirement.errorCode) assertEquals("Incorrect errorCode for $fqName", expectedErrorCode, requirement.errorCode)
} }
for (fqName in fqNamesWithoutRequirement) {
val descriptor = module.findUnambiguousDescriptorByFqName(fqName)
val requirenment = extractRequirement(descriptor)
assertNull("Expecting absence of any requirements for $fqName, but `$requirenment`", requirenment)
}
}
private fun extractRequirement(descriptor: DeclarationDescriptor): VersionRequirement? {
return when (descriptor) {
is DeserializedMemberDescriptor -> descriptor.versionRequirements.singleOrNull()
is DeserializedClassDescriptor -> descriptor.versionRequirements.singleOrNull()
else -> throw AssertionError("Unknown descriptor: $descriptor")
}
} }
private fun ModuleDescriptor.findUnambiguousDescriptorByFqName(fqName: String): DeclarationDescriptor { private fun ModuleDescriptor.findUnambiguousDescriptorByFqName(fqName: String): DeclarationDescriptor {
@@ -71,7 +85,12 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
return descriptor return descriptor
} }
protected abstract fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion) protected abstract fun compileFiles(
files: List<File>,
outputDirectory: File,
languageVersion: LanguageVersion,
analysisFlags: Map<AnalysisFlag<*>, Any?>
)
protected abstract fun loadModule(directory: File): ModuleDescriptor protected abstract fun loadModule(directory: File): ModuleDescriptor
@@ -79,7 +98,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
doTest( doTest(
VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
customLanguageVersion = LanguageVersion.KOTLIN_1_3, customLanguageVersion = LanguageVersion.KOTLIN_1_3,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.topLevel", "test.topLevel",
"test.Foo.member", "test.Foo.member",
"test.Foo.<init>", "test.Foo.<init>",
@@ -96,7 +115,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
doTest( doTest(
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message",
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, 42, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, 42,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.Klass", "test.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
"test.Typealias", "test.Typealias",
@@ -109,7 +128,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
fun testApiVersionViaAnnotation() { fun testApiVersionViaAnnotation() {
doTest( doTest(
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.API_VERSION, 42, VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.API_VERSION, 42,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.Klass", "test.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
"test.Typealias", "test.Typealias",
@@ -123,7 +142,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
doTest( doTest(
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message",
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, 42, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, 42,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.Klass", "test.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
"test.Typealias", "test.Typealias",
@@ -137,7 +156,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
doTest( doTest(
VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null, VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null,
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
fqNames = listOf("test.Klass") fqNamesWithRequirements = listOf("test.Klass")
) )
} }
@@ -145,7 +164,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
doTest( doTest(
VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
customLanguageVersion = LanguageVersion.KOTLIN_1_3, customLanguageVersion = LanguageVersion.KOTLIN_1_3,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.Outer.Inner.Deep", "test.Outer.Inner.Deep",
"test.Outer.Inner.Deep.<init>", "test.Outer.Inner.Deep.<init>",
"test.Outer.Inner.Deep.f", "test.Outer.Inner.Deep.f",
@@ -160,7 +179,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
fun testInlineClassesAndRelevantDeclarations() { fun testInlineClassesAndRelevantDeclarations() {
doTest( doTest(
VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.IC", "test.IC",
"test.Ctor.<init>", "test.Ctor.<init>",
"test.simpleFun", "test.simpleFun",
@@ -31,7 +31,12 @@ import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File import java.io.File
class JvmVersionRequirementTest : AbstractVersionRequirementTest() { class JvmVersionRequirementTest : AbstractVersionRequirementTest() {
override fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion) { override fun compileFiles(
files: List<File>,
outputDirectory: File,
languageVersion: LanguageVersion,
analysisFlags: Map<AnalysisFlag<*>, Any?>
) {
LoadDescriptorUtil.compileKotlinToDirAndGetModule( LoadDescriptorUtil.compileKotlinToDirAndGetModule(
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), outputDirectory, listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), outputDirectory,
KotlinCoreEnvironment.createForTests( KotlinCoreEnvironment.createForTests(
@@ -41,10 +46,7 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() {
languageVersionSettings = LanguageVersionSettingsImpl( languageVersionSettings = LanguageVersionSettingsImpl(
languageVersion, languageVersion,
ApiVersion.createByLanguageVersion(languageVersion), ApiVersion.createByLanguageVersion(languageVersion),
mapOf( analysisFlags.toMap() + mapOf(AnalysisFlags.explicitApiVersion to true),
JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ENABLE,
AnalysisFlags.explicitApiVersion to true
),
emptyMap() emptyMap()
) )
}, },
@@ -64,24 +66,60 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() {
fun testJvmDefault() { fun testJvmDefault() {
doTest( doTest(
VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
fqNames = listOf( analysisFlags = mapOf(JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ENABLE),
fqNamesWithRequirements = listOf(
"test.Base", "test.Base",
"test.Derived" "test.Derived"
) )
) )
} }
fun testAllJvmDefault() {
doTest(
VersionRequirement.Version(1, 4, 0), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
analysisFlags = mapOf(JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ALL_INCOMPATIBLE),
fqNamesWithRequirements = listOf(
"test.Base",
"test.Derived",
"test.BaseWithProperty",
"test.DerivedWithProperty",
"test.Empty",
"test.EmptyWithNested",
"test.WithAbstractDeclaration",
"test.DerivedFromWithAbstractDeclaration"
)
)
}
fun testAllCompatibilityJvmDefault() {
doTest(
VersionRequirement.Version(1, 4, 0), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
analysisFlags = mapOf(JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ALL_COMPATIBILITY),
fqNamesWithRequirements = emptyList(),
fqNamesWithoutRequirement = listOf(
"test.Base",
"test.Derived",
"test.BaseWithProperty",
"test.DerivedWithProperty",
"test.Empty",
"test.EmptyWithNested",
"test.WithAbstractDeclaration",
"test.DerivedFromWithAbstractDeclaration"
)
)
}
fun testJvmFieldInInterfaceCompanion() { fun testJvmFieldInInterfaceCompanion() {
doTest( doTest(
VersionRequirement.Version(1, 2, 70), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, VersionRequirement.Version(1, 2, 70), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
fqNames = listOf("test.Base.Companion.foo") fqNamesWithRequirements = listOf("test.Base.Companion.foo")
) )
} }
fun testInlineParameterNullCheck() { fun testInlineParameterNullCheck() {
doTest( doTest(
VersionRequirement.Version(1, 3, 50), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, VersionRequirement.Version(1, 3, 50), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.doRun", "test.doRun",
"test.lambdaVarProperty", "test.lambdaVarProperty",
"test.extensionProperty" "test.extensionProperty"
@@ -94,7 +132,7 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() {
doTest( doTest(
VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null, VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null,
customLanguageVersion = LanguageVersion.KOTLIN_1_2, customLanguageVersion = LanguageVersion.KOTLIN_1_2,
fqNames = listOf( fqNamesWithRequirements = listOf(
"test.topLevel", "test.topLevel",
"test.Foo.member", "test.Foo.member",
"test.Foo.<init>", "test.Foo.<init>",
@@ -8,10 +8,7 @@ package org.jetbrains.kotlin.serialization.js
import org.jetbrains.kotlin.cli.common.output.writeAllTo import org.jetbrains.kotlin.cli.common.output.writeAllTo
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.ApiVersion import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.context.ContextForNewModule import org.jetbrains.kotlin.context.ContextForNewModule
import org.jetbrains.kotlin.context.MutableModuleContext import org.jetbrains.kotlin.context.MutableModuleContext
import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.context.ProjectContext
@@ -33,7 +30,12 @@ import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File import java.io.File
class JsVersionRequirementTest : AbstractVersionRequirementTest() { class JsVersionRequirementTest : AbstractVersionRequirementTest() {
override fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion) { override fun compileFiles(
files: List<File>,
outputDirectory: File,
languageVersion: LanguageVersion,
analysisFlags: Map<AnalysisFlag<*>, Any?>
) {
val environment = createEnvironment(languageVersion) val environment = createEnvironment(languageVersion)
val ktFiles = files.map { file -> KotlinTestUtils.createFile(file.name, file.readText(), environment.project) } val ktFiles = files.map { file -> KotlinTestUtils.createFile(file.name, file.readText(), environment.project) }
val trace = BindingTraceContext() val trace = BindingTraceContext()