Fix version requirement serialization for nested classes

Use the version requierement table of the outer DescriptorSerializer
instance when serializing metadata for a class. Pass parent serializer
to DescriptorSerializer.create to make sure the correct table is used.
Serialize nested classes before the outer class in JS and common code,
to make sure requirements are not lost. Also, split
VersionRequirementTest to JVM and JS

 #KT-25120 In Progress
This commit is contained in:
Alexander Udalov
2018-07-09 20:23:21 +02:00
parent a61de052c7
commit 1e9694f1db
13 changed files with 312 additions and 134 deletions
@@ -96,7 +96,7 @@ fun JavaClassDescriptor.convertToProto(): SerializedJavaClassWithSource {
val extension = JavaClassesSerializerExtension() val extension = JavaClassesSerializerExtension()
val classProto = try { val classProto = try {
DescriptorSerializer.create(this, extension).classProto(this).build() DescriptorSerializer.create(this, extension, null).classProto(this).build()
} catch (e: Exception) { } catch (e: Exception) {
throw IllegalStateException( throw IllegalStateException(
"Error during writing proto for descriptor: ${DescriptorRenderer.DEBUG_TEXT.render(this)}\n" + "Error during writing proto for descriptor: ${DescriptorRenderer.DEBUG_TEXT.render(this)}\n" +
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.binding.MutableClosure; import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; 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.BothSignatureWriter;
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
import org.jetbrains.kotlin.codegen.state.GenerationState; 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.descriptors.*;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens; 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.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode; 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.ClassId;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name; 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.ExtensionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.FieldVisitor; import org.jetbrains.org.objectweb.asm.FieldVisitor;
import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.Label;
@@ -97,6 +102,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks = new ArrayList<>(); private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks = new ArrayList<>();
private final DescriptorSerializer serializer;
public ImplementationBodyCodegen( public ImplementationBodyCodegen(
@NotNull KtPureClassOrObject aClass, @NotNull KtPureClassOrObject aClass,
@NotNull ClassContext context, @NotNull ClassContext context,
@@ -108,7 +115,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
super(aClass, context, v, state, parentCodegen); super(aClass, context, v, state, parentCodegen);
this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor)); this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor));
this.isLocal = isLocal; 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 @Override
@@ -282,7 +297,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override @Override
protected void generateKotlinMetadataAnnotation() { 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() { private void writeEnclosingMethod() {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen;
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import kotlin.Unit;
import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; 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.NameGenerator;
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages; import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages;
import org.jetbrains.kotlin.codegen.inline.SourceMapper; 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.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.*; 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.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.load.java.JavaVisibilities; import org.jetbrains.kotlin.load.java.JavaVisibilities;
import org.jetbrains.kotlin.load.java.JvmAbi; 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.Name;
import org.jetbrains.kotlin.name.SpecialNames; import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.psi.*; 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.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt; import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.storage.NotNullLazyValue; import org.jetbrains.kotlin.storage.NotNullLazyValue;
import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.ErrorUtils;
@@ -62,7 +56,8 @@ import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; 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.JvmCodegenUtil.isNonDefaultInterfaceMember;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getInlineName; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getInlineName;
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
@@ -914,20 +909,6 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
return StackValue.onStack(callableMethod.getReturnType()); return StackValue.onStack(callableMethod.getReturnType());
} }
protected void generateKotlinClassMetadataAnnotation(@NotNull ClassDescriptor descriptor, boolean isScript) {
DescriptorSerializer serializer =
DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), state));
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
int flags = isScript ? JvmAnnotationNames.METADATA_SCRIPT_FLAG : 0;
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, flags, av -> {
writeAnnotationData(av, serializer, classProto);
return Unit.INSTANCE;
});
}
public void generateAssertField() { public void generateAssertField() {
if (jvmAssertFieldGenerated) return; if (jvmAssertFieldGenerated) return;
AssertCodegenUtilKt.generateAssertionsDisabledFieldInitialization(this); AssertCodegenUtilKt.generateAssertionsDisabledFieldInitialization(this);
@@ -6,25 +6,31 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import com.intellij.psi.PsiElement 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.CodegenContext
import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.context.ScriptContext 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.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ScriptDescriptor 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.psi.*
import org.jetbrains.kotlin.resolve.BindingContext 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
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin 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.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter 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( class ScriptCodegen private constructor(
private val scriptDeclaration: KtScript, private val scriptDeclaration: KtScript,
state: GenerationState, state: GenerationState,
@@ -64,7 +70,11 @@ class ScriptCodegen private constructor(
override fun generateSyntheticPartsAfterBody() {} override fun generateSyntheticPartsAfterBody() {}
override fun generateKotlinMetadataAnnotation() { 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( private fun genConstructor(
@@ -151,29 +151,29 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
private val extension = createSerializerExtension() private val extension = createSerializerExtension()
fun run() { fun run() {
serializeClasses(classes) val serializer = DescriptorSerializer.createTopLevel(extension)
serializeMembers(members) serializeClasses(classes, serializer)
serializeMembers(members, serializer)
serializeStringTable() serializeStringTable()
serializeBuiltInsFile() serializeBuiltInsFile()
} }
private fun serializeClass(classDescriptor: ClassDescriptor) { private fun serializeClasses(classes: Collection<DeclarationDescriptor>, parentSerializer: DescriptorSerializer) {
val classProto = DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build()
proto.addClass_(classProto)
serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
}
private fun serializeClasses(classes: Collection<DeclarationDescriptor>) {
for (descriptor in DescriptorSerializer.sort(classes)) { for (descriptor in DescriptorSerializer.sort(classes)) {
if (descriptor is ClassDescriptor && descriptor.kind != ClassKind.ENUM_ENTRY) { if (descriptor !is ClassDescriptor || descriptor.kind == ClassKind.ENUM_ENTRY) continue
serializeClass(descriptor)
} 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<DeclarationDescriptor>) { private fun serializeMembers(members: Collection<DeclarationDescriptor>, serializer: DescriptorSerializer) {
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(packageFqName, members).build() proto.`package` = serializer.packagePartProto(packageFqName, members).build()
} }
private fun serializeStringTable() { private fun serializeStringTable() {
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTabl
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils 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.MemberComparator
import org.jetbrains.kotlin.resolve.RequireKotlinNames import org.jetbrains.kotlin.resolve.RequireKotlinNames
import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithAnyExpectedDefault import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithAnyExpectedDefault
@@ -709,10 +709,14 @@ class DescriptorSerializer private constructor(
} }
@JvmStatic @JvmStatic
fun create(descriptor: ClassDescriptor, extension: SerializerExtension): DescriptorSerializer { fun create(
descriptor: ClassDescriptor,
extension: SerializerExtension,
parentSerializer: DescriptorSerializer?
): DescriptorSerializer {
val container = descriptor.containingDeclaration val container = descriptor.containingDeclaration
val parentSerializer = if (container is ClassDescriptor) val parent = if (container is ClassDescriptor)
create(container, extension) parentSerializer ?: create(container, extension, null)
else else
createTopLevel(extension) createTopLevel(extension)
@@ -720,12 +724,12 @@ class DescriptorSerializer private constructor(
// serializing outer classes before nested classes. // serializing outer classes before nested classes.
// Otherwise our interner can get wrong ids because we may serialize classes in any order. // Otherwise our interner can get wrong ids because we may serialize classes in any order.
val serializer = DescriptorSerializer( val serializer = DescriptorSerializer(
descriptor, descriptor,
Interner(parentSerializer.typeParameters), Interner(parent.typeParameters),
parentSerializer.extension, extension,
MutableTypeTable(), MutableTypeTable(),
MutableVersionRequirementTable(), if (container is ClassDescriptor) parent.versionRequirementTable else MutableVersionRequirementTable(),
serializeTypeTableToFunction = false serializeTypeTableToFunction = false
) )
for (typeParameter in descriptor.declaredTypeParameters) { for (typeParameter in descriptor.declaredTypeParameters) {
serializer.typeParameters.intern(typeParameter) serializer.typeParameters.intern(typeParameter)
@@ -3,9 +3,7 @@ suspend fun callRelease() {
C().dummy() C().dummy()
// TODO: This should be error
WithNested.Nested().dummy() WithNested.Nested().dummy()
// TODO: This should be error
WithInner().Inner().dummy() WithInner().Inner().dummy()
} }
@@ -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 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() 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 COMPILATION_ERROR
@@ -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() {}
@@ -5,29 +5,22 @@
package org.jetbrains.kotlin.serialization package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
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.metadata.ProtoBuf 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.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor 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.TestCaseWithTmpdir
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File import java.io.File
class VersionRequirementTest : TestCaseWithTmpdir() { abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
fun doTest( fun doTest(
expectedVersionRequirement: VersionRequirement.Version, expectedVersionRequirement: VersionRequirement.Version,
expectedLevel: DeprecationLevel, expectedLevel: DeprecationLevel,
@@ -37,47 +30,23 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
customLanguageVersion: LanguageVersion = LanguageVersionSettingsImpl.DEFAULT.languageVersion, customLanguageVersion: LanguageVersion = LanguageVersionSettingsImpl.DEFAULT.languageVersion,
fqNames: List<String> fqNames: List<String>
) { ) {
LoadDescriptorUtil.compileKotlinToDirAndGetModule( compileFiles(listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, customLanguageVersion)
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, val module = loadModule(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
)
)
val (_, module) = JvmResolveUtil.analyze( for (fqName in fqNames) {
KotlinCoreEnvironment.createForTests( val descriptor = module.findUnambiguousDescriptorByFqName(fqName)
testRootDisposable,
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir),
EnvironmentConfigFiles.JVM_CONFIG_FILES
)
)
fun check(descriptor: DeclarationDescriptor) {
val requirement = when (descriptor) { val requirement = when (descriptor) {
is DeserializedMemberDescriptor -> descriptor.versionRequirement is DeserializedMemberDescriptor -> descriptor.versionRequirement
is DeserializedClassDescriptor -> descriptor.versionRequirement is DeserializedClassDescriptor -> descriptor.versionRequirement
else -> throw AssertionError("Unknown descriptor: $descriptor") else -> throw AssertionError("Unknown descriptor: $descriptor")
} ?: throw AssertionError("No VersionRequirement for $descriptor") } ?: throw AssertionError("No VersionRequirement for $descriptor")
assertEquals(expectedVersionRequirement, requirement.version) assertEquals("Incorrect version for $fqName", expectedVersionRequirement, requirement.version)
assertEquals(expectedLevel, requirement.level) assertEquals("Incorrect level for $fqName", expectedLevel, requirement.level)
assertEquals(expectedMessage, requirement.message) assertEquals("Incorrect message for $fqName", expectedMessage, requirement.message)
assertEquals(expectedVersionKind, requirement.kind) assertEquals("Incorrect versionKind for $fqName", expectedVersionKind, requirement.kind)
assertEquals(expectedErrorCode, requirement.errorCode) assertEquals("Incorrect errorCode for $fqName", expectedErrorCode, requirement.errorCode)
}
for (fqName in fqNames) {
check(module.findUnambiguousDescriptorByFqName(fqName))
} }
} }
@@ -102,9 +71,13 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
return descriptor return descriptor
} }
protected abstract fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion)
protected abstract fun loadModule(directory: File): ModuleDescriptor
fun testSuspendFun() { fun testSuspendFun() {
doTest( 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( fqNames = listOf(
"test.topLevel", "test.topLevel",
"test.Foo.member", "test.Foo.member",
@@ -118,7 +91,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
) )
doTest( 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, customLanguageVersion = LanguageVersion.KOTLIN_1_3,
fqNames = listOf( fqNames = listOf(
"test.topLevel", "test.topLevel",
@@ -135,7 +108,8 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
fun testLanguageVersionViaAnnotation() { fun testLanguageVersionViaAnnotation() {
doTest( 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( fqNames = listOf(
"test.Klass", "test.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
@@ -148,7 +122,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
fun testApiVersionViaAnnotation() { fun testApiVersionViaAnnotation() {
doTest( 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( fqNames = listOf(
"test.Klass", "test.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
@@ -161,7 +135,8 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
fun testCompilerVersionViaAnnotation() { fun testCompilerVersionViaAnnotation() {
doTest( 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( fqNames = listOf(
"test.Klass", "test.Klass",
"test.Konstructor.<init>", "test.Konstructor.<init>",
@@ -174,25 +149,24 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
fun testPatchVersion() { fun testPatchVersion() {
doTest( 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") fqNames = listOf("test.Klass")
) )
} }
fun testJvmDefault() { fun testNestedClassMembers() {
doTest( 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( fqNames = listOf(
"test.Base", "test.Outer.Inner.Deep",
"test.Derived" "test.Outer.Inner.Deep.<init>",
"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")
)
}
} }
@@ -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<File>, 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")
)
}
}
@@ -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<File>, 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<File> = 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("<test>"), JsPlatform.builtIns, null).apply {
setDependencies(listOf(module) + config.moduleDescriptors + module.builtIns.builtInsModule)
}
}
}
@@ -192,29 +192,24 @@ object KotlinJavascriptSerializationUtil {
val classDescriptors = scope.filterIsInstance<ClassDescriptor>().sortedBy { it.fqNameSafe.asString() } val classDescriptors = scope.filterIsInstance<ClassDescriptor>().sortedBy { it.fqNameSafe.asString() }
fun serializeClasses(descriptors: Collection<DeclarationDescriptor>) { fun serializeClasses(descriptors: Collection<DeclarationDescriptor>, parentSerializer: DescriptorSerializer) {
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())
}
for (descriptor in descriptors) { for (descriptor in descriptors) {
if (descriptor is ClassDescriptor) { if (descriptor !is ClassDescriptor || skip(descriptor)) continue
serializeClass(descriptor)
} 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 stringTable = extension.stringTable
val members = scope.filterNot(skip) val members = scope.filterNot(skip)
builder.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(fqName, members).build() builder.`package` = serializer.packagePartProto(fqName, members).build()
builder.setExtension( builder.setExtension(
JsProtoBuf.packageFragmentFiles, JsProtoBuf.packageFragmentFiles,