diff --git a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt index d52b209566c..4e4294720fe 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt @@ -96,7 +96,7 @@ fun JavaClassDescriptor.convertToProto(): SerializedJavaClassWithSource { val extension = JavaClassesSerializerExtension() val classProto = try { - DescriptorSerializer.create(this, extension).classProto(this).build() + DescriptorSerializer.create(this, extension, null).classProto(this).build() } catch (e: Exception) { throw IllegalStateException( "Error during writing proto for descriptor: ${DescriptorRenderer.DEBUG_TEXT.render(this)}\n" + diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index ebf7cc3e7b3..321f7f41bd8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.binding.MutableClosure; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; +import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; @@ -30,8 +31,11 @@ import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.lexer.KtTokens; +import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.load.kotlin.TypeMappingMode; +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; +import org.jetbrains.kotlin.metadata.ProtoBuf; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; @@ -52,6 +56,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; +import org.jetbrains.kotlin.serialization.DescriptorSerializer; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.org.objectweb.asm.FieldVisitor; import org.jetbrains.org.objectweb.asm.Label; @@ -97,6 +102,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private final List> additionalTasks = new ArrayList<>(); + private final DescriptorSerializer serializer; + public ImplementationBodyCodegen( @NotNull KtPureClassOrObject aClass, @NotNull ClassContext context, @@ -108,7 +115,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { super(aClass, context, v, state, parentCodegen); this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor)); this.isLocal = isLocal; - delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); + this.delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); + + JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state); + this.serializer = DescriptorSerializer.create( + descriptor, extension, + parentCodegen instanceof ImplementationBodyCodegen + ? ((ImplementationBodyCodegen) parentCodegen).serializer + : DescriptorSerializer.createTopLevel(extension) + ); } @Override @@ -282,7 +297,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { @Override protected void generateKotlinMetadataAnnotation() { - generateKotlinClassMetadataAnnotation(descriptor, false); + ProtoBuf.Class classProto = serializer.classProto(descriptor).build(); + + WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, 0, av -> { + writeAnnotationData(av, serializer, classProto); + return Unit.INSTANCE; + }); } private void writeEnclosingMethod() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index 92e8c387338..30220e7d486 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.PsiElement; -import kotlin.Unit; import kotlin.jvm.functions.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,7 +18,6 @@ import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper; import org.jetbrains.kotlin.codegen.inline.NameGenerator; import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages; import org.jetbrains.kotlin.codegen.inline.SourceMapper; -import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; @@ -29,9 +27,6 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.load.java.JavaVisibilities; import org.jetbrains.kotlin.load.java.JvmAbi; -import org.jetbrains.kotlin.load.java.JvmAnnotationNames; -import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; -import org.jetbrains.kotlin.metadata.ProtoBuf; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.SpecialNames; import org.jetbrains.kotlin.psi.*; @@ -45,7 +40,6 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt; -import org.jetbrains.kotlin.serialization.DescriptorSerializer; import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.storage.NotNullLazyValue; import org.jetbrains.kotlin.types.ErrorUtils; @@ -62,7 +56,8 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import static org.jetbrains.kotlin.codegen.AsmUtil.*; +import static org.jetbrains.kotlin.codegen.AsmUtil.calculateInnerClassAccessFlags; +import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getInlineName; import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; @@ -914,20 +909,6 @@ public abstract class MemberCodegen { - writeAnnotationData(av, serializer, classProto); - return Unit.INSTANCE; - }); - } - public void generateAssertField() { if (jvmAssertFieldGenerated) return; AssertCodegenUtilKt.generateAssertionsDisabledFieldInitialization(this); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt index 8eff84767d4..2021873743e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt @@ -6,25 +6,31 @@ package org.jetbrains.kotlin.codegen import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.codegen.AsmUtil.writeAnnotationData import org.jetbrains.kotlin.codegen.context.CodegenContext import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.context.ScriptContext +import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.load.java.JvmAnnotationNames +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.descriptorUtil.* +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin -import org.jetbrains.kotlin.resolve.jvm.diagnostics.* +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN +import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin +import org.jetbrains.kotlin.serialization.DescriptorSerializer +import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter -import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN -import org.jetbrains.org.objectweb.asm.Opcodes.* - class ScriptCodegen private constructor( private val scriptDeclaration: KtScript, state: GenerationState, @@ -64,7 +70,11 @@ class ScriptCodegen private constructor( override fun generateSyntheticPartsAfterBody() {} override fun generateKotlinMetadataAnnotation() { - generateKotlinClassMetadataAnnotation(scriptDescriptor, true) + val serializer = DescriptorSerializer.create(scriptDescriptor, JvmSerializerExtension(v.serializationBindings, state), null) + val classProto = serializer.classProto(scriptDescriptor).build() + writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, JvmAnnotationNames.METADATA_SCRIPT_FLAG) { av -> + writeAnnotationData(av, serializer, classProto) + } } private fun genConstructor( diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt index 2f8e8d393e7..8c9b986e058 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt @@ -151,29 +151,29 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) { private val extension = createSerializerExtension() fun run() { - serializeClasses(classes) - serializeMembers(members) + val serializer = DescriptorSerializer.createTopLevel(extension) + serializeClasses(classes, serializer) + serializeMembers(members, serializer) serializeStringTable() serializeBuiltInsFile() } - private fun serializeClass(classDescriptor: ClassDescriptor) { - val classProto = DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build() - proto.addClass_(classProto) - - serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)) - } - - private fun serializeClasses(classes: Collection) { + private fun serializeClasses(classes: Collection, parentSerializer: DescriptorSerializer) { for (descriptor in DescriptorSerializer.sort(classes)) { - if (descriptor is ClassDescriptor && descriptor.kind != ClassKind.ENUM_ENTRY) { - serializeClass(descriptor) - } + if (descriptor !is ClassDescriptor || descriptor.kind == ClassKind.ENUM_ENTRY) continue + + val serializer = DescriptorSerializer.create(descriptor, extension, parentSerializer) + serializeClasses( + descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS), + serializer + ) + + proto.addClass_(serializer.classProto(descriptor).build()) } } - private fun serializeMembers(members: Collection) { - proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(packageFqName, members).build() + private fun serializeMembers(members: Collection, serializer: DescriptorSerializer) { + proto.`package` = serializer.packagePartProto(packageFqName, members).build() } private fun serializeStringTable() { diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index b650cc3782a..4161a21c0d7 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTabl import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils.* +import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry import org.jetbrains.kotlin.resolve.MemberComparator import org.jetbrains.kotlin.resolve.RequireKotlinNames import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithAnyExpectedDefault @@ -709,10 +709,14 @@ class DescriptorSerializer private constructor( } @JvmStatic - fun create(descriptor: ClassDescriptor, extension: SerializerExtension): DescriptorSerializer { + fun create( + descriptor: ClassDescriptor, + extension: SerializerExtension, + parentSerializer: DescriptorSerializer? + ): DescriptorSerializer { val container = descriptor.containingDeclaration - val parentSerializer = if (container is ClassDescriptor) - create(container, extension) + val parent = if (container is ClassDescriptor) + parentSerializer ?: create(container, extension, null) else createTopLevel(extension) @@ -720,12 +724,12 @@ class DescriptorSerializer private constructor( // serializing outer classes before nested classes. // Otherwise our interner can get wrong ids because we may serialize classes in any order. val serializer = DescriptorSerializer( - descriptor, - Interner(parentSerializer.typeParameters), - parentSerializer.extension, - MutableTypeTable(), - MutableVersionRequirementTable(), - serializeTypeTableToFunction = false + descriptor, + Interner(parent.typeParameters), + extension, + MutableTypeTable(), + if (container is ClassDescriptor) parent.versionRequirementTable else MutableVersionRequirementTable(), + serializeTypeTableToFunction = false ) for (typeParameter in descriptor.declaredTypeParameters) { serializer.typeParameters.intern(typeParameter) diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt index 43531f93874..0767434d743 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt @@ -3,9 +3,7 @@ suspend fun callRelease() { C().dummy() - // TODO: This should be error WithNested.Nested().dummy() - // TODO: This should be error WithInner().Inner().dummy() -} \ No newline at end of file +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/output.txt index 266e4a2ae79..b3403fe1706 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/output.txt @@ -4,4 +4,10 @@ compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExp compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt:4:9: error: 'dummy(): String' is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2 C().dummy() ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt:6:25: error: 'dummy(): String' is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2 + WithNested.Nested().dummy() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt:8:25: error: 'dummy(): String' is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2 + WithInner().Inner().dummy() + ^ COMPILATION_ERROR diff --git a/compiler/testData/versionRequirement/nestedClassMembers.kt b/compiler/testData/versionRequirement/nestedClassMembers.kt new file mode 100644 index 00000000000..0190c78cfa4 --- /dev/null +++ b/compiler/testData/versionRequirement/nestedClassMembers.kt @@ -0,0 +1,30 @@ +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +package test + +import kotlin.internal.RequireKotlin + +class Outer { + inner class Inner { + @RequireKotlin("1.1") + inner class Deep @RequireKotlin("1.1") constructor() { + @RequireKotlin("1.1") + fun f() {} + + @RequireKotlin("1.1") + val x = "" + + suspend fun s() {} + } + } + + class Nested { + @RequireKotlin("1.1") + fun g() {} + } + + @RequireKotlin("1.1") + companion object +} + +@RequireKotlin("1.1") +fun topLevel() {} diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/VersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt similarity index 63% rename from compiler/tests/org/jetbrains/kotlin/serialization/VersionRequirementTest.kt rename to compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt index ee1095d6423..7a66b3352e7 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/VersionRequirementTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt @@ -5,29 +5,22 @@ 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.config.LanguageVersion +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl 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.metadata.deserialization.VersionRequirement import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor -import org.jetbrains.kotlin.test.ConfigurationKind -import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.TestCaseWithTmpdir -import org.jetbrains.kotlin.test.TestJdkKind import java.io.File -class VersionRequirementTest : TestCaseWithTmpdir() { +abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() { fun doTest( expectedVersionRequirement: VersionRequirement.Version, expectedLevel: DeprecationLevel, @@ -37,47 +30,23 @@ class VersionRequirementTest : TestCaseWithTmpdir() { customLanguageVersion: LanguageVersion = LanguageVersionSettingsImpl.DEFAULT.languageVersion, fqNames: List ) { - LoadDescriptorUtil.compileKotlinToDirAndGetModule( - 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( - customLanguageVersion, - ApiVersion.createByLanguageVersion(customLanguageVersion), - mapOf(AnalysisFlag.jvmDefaultMode to JvmDefaultMode.ENABLE), - emptyMap() - ) - }, - EnvironmentConfigFiles.JVM_CONFIG_FILES - ) - ) + compileFiles(listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, customLanguageVersion) + val module = loadModule(tmpdir) - val (_, module) = JvmResolveUtil.analyze( - KotlinCoreEnvironment.createForTests( - testRootDisposable, - KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir), - EnvironmentConfigFiles.JVM_CONFIG_FILES - ) - ) + for (fqName in fqNames) { + val descriptor = module.findUnambiguousDescriptorByFqName(fqName) - fun check(descriptor: DeclarationDescriptor) { val requirement = when (descriptor) { is DeserializedMemberDescriptor -> descriptor.versionRequirement is DeserializedClassDescriptor -> descriptor.versionRequirement else -> throw AssertionError("Unknown descriptor: $descriptor") } ?: throw AssertionError("No VersionRequirement for $descriptor") - assertEquals(expectedVersionRequirement, requirement.version) - assertEquals(expectedLevel, requirement.level) - assertEquals(expectedMessage, requirement.message) - assertEquals(expectedVersionKind, requirement.kind) - assertEquals(expectedErrorCode, requirement.errorCode) - } - - for (fqName in fqNames) { - check(module.findUnambiguousDescriptorByFqName(fqName)) + assertEquals("Incorrect version for $fqName", expectedVersionRequirement, requirement.version) + assertEquals("Incorrect level for $fqName", expectedLevel, requirement.level) + assertEquals("Incorrect message for $fqName", expectedMessage, requirement.message) + assertEquals("Incorrect versionKind for $fqName", expectedVersionKind, requirement.kind) + assertEquals("Incorrect errorCode for $fqName", expectedErrorCode, requirement.errorCode) } } @@ -102,9 +71,13 @@ class VersionRequirementTest : TestCaseWithTmpdir() { return descriptor } + protected abstract fun compileFiles(files: List, outputDirectory: File, languageVersion: LanguageVersion) + + protected abstract fun loadModule(directory: File): ModuleDescriptor + fun testSuspendFun() { doTest( - VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null, + VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, fqNames = listOf( "test.topLevel", "test.Foo.member", @@ -118,7 +91,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() { ) doTest( - VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null, + VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, customLanguageVersion = LanguageVersion.KOTLIN_1_3, fqNames = listOf( "test.topLevel", @@ -135,7 +108,8 @@ class VersionRequirementTest : TestCaseWithTmpdir() { fun testLanguageVersionViaAnnotation() { doTest( - VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", LANGUAGE_VERSION, 42, + VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", + ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, 42, fqNames = listOf( "test.Klass", "test.Konstructor.", @@ -148,7 +122,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() { fun testApiVersionViaAnnotation() { doTest( - VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", API_VERSION, 42, + VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.API_VERSION, 42, fqNames = listOf( "test.Klass", "test.Konstructor.", @@ -161,7 +135,8 @@ class VersionRequirementTest : TestCaseWithTmpdir() { fun testCompilerVersionViaAnnotation() { doTest( - VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", COMPILER_VERSION, 42, + VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", + ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, 42, fqNames = listOf( "test.Klass", "test.Konstructor.", @@ -174,25 +149,24 @@ class VersionRequirementTest : TestCaseWithTmpdir() { fun testPatchVersion() { doTest( - VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null, LANGUAGE_VERSION, null, + VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null, + ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, fqNames = listOf("test.Klass") ) } - fun testJvmDefault() { + fun testNestedClassMembers() { doTest( - VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, + VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, fqNames = listOf( - "test.Base", - "test.Derived" + "test.Outer.Inner.Deep", + "test.Outer.Inner.Deep.", + "test.Outer.Inner.Deep.f", + "test.Outer.Inner.Deep.x", + "test.Outer.Inner.Deep.s", + "test.Outer.Nested.g", + "test.Outer.Companion" ) ) } - - fun testJvmFieldInInterfaceCompanion() { - doTest( - VersionRequirement.Version(1, 2, 70), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, - fqNames = listOf("test.Base.Companion.foo") - ) - } } diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt new file mode 100644 index 00000000000..d5f5ccea127 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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.ModuleDescriptor +import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION +import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement +import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TestJdkKind +import java.io.File + +class JvmVersionRequirementTest : AbstractVersionRequirementTest() { + override fun compileFiles(files: List, outputDirectory: File, languageVersion: LanguageVersion) { + LoadDescriptorUtil.compileKotlinToDirAndGetModule( + listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), outputDirectory, + KotlinCoreEnvironment.createForTests( + testRootDisposable, + KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, outputDirectory).apply { + put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8) + languageVersionSettings = LanguageVersionSettingsImpl( + languageVersion, + ApiVersion.createByLanguageVersion(languageVersion), + mapOf(AnalysisFlag.jvmDefaultMode to JvmDefaultMode.ENABLE), + emptyMap() + ) + }, + EnvironmentConfigFiles.JVM_CONFIG_FILES + ) + ) + } + + override fun loadModule(directory: File): ModuleDescriptor = JvmResolveUtil.analyze( + KotlinCoreEnvironment.createForTests( + testRootDisposable, + KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir), + EnvironmentConfigFiles.JVM_CONFIG_FILES + ) + ).moduleDescriptor + + fun testJvmDefault() { + doTest( + VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, + fqNames = listOf( + "test.Base", + "test.Derived" + ) + ) + } + + fun testJvmFieldInInterfaceCompanion() { + doTest( + VersionRequirement.Version(1, 2, 70), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, + fqNames = listOf("test.Base.Companion.foo") + ) + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/js/JsVersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/js/JsVersionRequirementTest.kt new file mode 100644 index 00000000000..5ea5d98244b --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/serialization/js/JsVersionRequirementTest.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.serialization.js + +import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAllTo +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.config.ApiVersion +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.MutableModuleContext +import org.jetbrains.kotlin.context.ProjectContext +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.config.JsConfig +import org.jetbrains.kotlin.js.facade.K2JSTranslator +import org.jetbrains.kotlin.js.facade.MainCallParameters +import org.jetbrains.kotlin.js.facade.TranslationResult +import org.jetbrains.kotlin.js.resolve.JsPlatform +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.BindingTraceContext +import org.jetbrains.kotlin.serialization.AbstractVersionRequirementTest +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TestJdkKind +import java.io.File + +class JsVersionRequirementTest : AbstractVersionRequirementTest() { + override fun compileFiles(files: List, outputDirectory: File, languageVersion: LanguageVersion) { + val environment = createEnvironment(languageVersion) + val ktFiles = files.map { file -> KotlinTestUtils.createFile(file.name, file.readText(), environment.project) } + val trace = BindingTraceContext() + val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace( + ktFiles, trace, createModule(environment), environment.configuration + ) + + // There are INVISIBLE_REFERENCE errors on RequireKotlin and K2JSTranslator refuses to translate the code otherwise + trace.clearDiagnostics() + + val result = K2JSTranslator(JsConfig(environment.project, environment.configuration)).translate( + object : JsConfig.Reporter() {}, ktFiles, MainCallParameters.noCall(), analysisResult + ) as TranslationResult.Success + result.getOutputFiles(File(outputDirectory, "lib.js"), null, null).writeAllTo(outputDirectory) + } + + override fun loadModule(directory: File): ModuleDescriptor { + val environment = createEnvironment(extraDependencies = listOf(File(directory, "lib.meta.js"))) + return TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace( + emptyList(), BindingTraceContext(), createModule(environment), environment.configuration + ).moduleDescriptor + } + + private fun createEnvironment( + languageVersion: LanguageVersion? = null, + extraDependencies: List = emptyList() + ): KotlinCoreEnvironment = + KotlinCoreEnvironment.createForTests( + testRootDisposable, + KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK).apply { + put(JSConfigurationKeys.LIBRARIES, extraDependencies.map(File::getPath) + JsConfig.JS_STDLIB) + put(JSConfigurationKeys.META_INFO, true) + + if (languageVersion != null) { + languageVersionSettings = + LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(languageVersion)) + } + }, + EnvironmentConfigFiles.JS_CONFIG_FILES + ) + + private fun createModule(environment: KotlinCoreEnvironment): MutableModuleContext { + val config = JsConfig(environment.project, environment.configuration) + return ContextForNewModule(ProjectContext(environment.project), Name.special(""), JsPlatform.builtIns, null).apply { + setDependencies(listOf(module) + config.moduleDescriptors + module.builtIns.builtInsModule) + } + } +} diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt index fddce0577af..9f7ae0da45a 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt @@ -192,29 +192,24 @@ object KotlinJavascriptSerializationUtil { val classDescriptors = scope.filterIsInstance().sortedBy { it.fqNameSafe.asString() } - fun serializeClasses(descriptors: Collection) { - fun serializeClass(classDescriptor: ClassDescriptor) { - if (skip(classDescriptor)) return - val classProto = - DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build() - ?: error("Class not serialized: $classDescriptor") - builder.addClass_(classProto) - serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors()) - } - + fun serializeClasses(descriptors: Collection, parentSerializer: DescriptorSerializer) { for (descriptor in descriptors) { - if (descriptor is ClassDescriptor) { - serializeClass(descriptor) - } + if (descriptor !is ClassDescriptor || skip(descriptor)) continue + + val serializer = DescriptorSerializer.create(descriptor, extension, parentSerializer) + serializeClasses(descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(), serializer) + val classProto = serializer.classProto(descriptor).build() ?: error("Class not serialized: $descriptor") + builder.addClass_(classProto) } } - serializeClasses(classDescriptors) + val serializer = DescriptorSerializer.createTopLevel(extension) + serializeClasses(classDescriptors, serializer) val stringTable = extension.stringTable val members = scope.filterNot(skip) - builder.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(fqName, members).build() + builder.`package` = serializer.packagePartProto(fqName, members).build() builder.setExtension( JsProtoBuf.packageFragmentFiles,