diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java index cb2be00ecdf..c67ca1e466a 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java @@ -996,6 +996,24 @@ public class FirLoadCompiledKotlinGenerated extends AbstractFirLoadCompiledKotli } } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractFirLoadCompiledKotlin { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("SimpleContextReceivers.kt") + public void testSimpleContextReceivers() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt"); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/analysis-tests/testData/loadCompiledKotlin/contextReceivers/SimpleContextReceivers.txt b/compiler/fir/analysis-tests/testData/loadCompiledKotlin/contextReceivers/SimpleContextReceivers.txt new file mode 100644 index 00000000000..4cad40f786d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/loadCompiledKotlin/contextReceivers/SimpleContextReceivers.txt @@ -0,0 +1,21 @@ +context(R|test/A|) +public final fun g(): R|kotlin/Unit| + +context(R|test/B|) +public final val h: R|kotlin/Int| + public get(): R|kotlin/Int| + +public abstract interface A : R|kotlin/Any| { +} + +public abstract interface B : R|kotlin/Any| { +} + +context(R|test/A|) +public final class C : R|kotlin/Any| { + context(R|test/B|) + public final fun f(): R|kotlin/Unit| + + public constructor(): R|test/C| + +} diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt index 767e2abae3e..00f97966b93 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt @@ -423,43 +423,24 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) { this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver) deprecation = annotations.getDeprecationInfosFromAnnotations(c.session.languageVersionSettings.apiVersion, false) - contextReceivers.addAll( - when { - proto.contextReceiverTypeCount > 0 -> - proto.contextReceiverTypeList.map(::loadContextReceiverFromType) - proto.contextReceiverTypeIdCount > 0 -> - proto.contextReceiverTypeIdList.map(::loadContextReceiverFromTypeId) - else -> emptyList() - } - ) - + proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver) }.apply { versionRequirementsTable = c.versionRequirementTable } } - fun loadContextReceiverFromType(proto: ProtoBuf.Type): FirContextReceiver = - loadContextReceiverFromTypeRef(proto.toTypeRef(c)) - - fun loadContextReceiverFromTypeId(id: Int): FirContextReceiver = loadContextReceiverFromType(c.typeTable[id]) - - private fun loadContextReceiverFromTypeRef(typeRef: FirTypeRef): FirContextReceiver = - buildContextReceiver { + private fun loadContextReceiver(proto: ProtoBuf.Type): FirContextReceiver { + val typeRef = proto.toTypeRef(c) + return buildContextReceiver { val type = typeRef.coneType this.labelNameFromTypeRef = (type as? ConeLookupTagBasedType)?.lookupTag?.name this.typeRef = typeRef } - - fun createContextReceiversForClass( - classProto: ProtoBuf.Class, - ): List = when { - classProto.contextReceiverTypeCount > 0 -> - classProto.contextReceiverTypeList.map(::loadContextReceiverFromType) - classProto.contextReceiverTypeIdCount > 0 -> - classProto.contextReceiverTypeIdList.map(::loadContextReceiverFromTypeId) - else -> emptyList() } + internal fun createContextReceiversForClass(classProto: ProtoBuf.Class): List = + classProto.contextReceiverTypes(c.typeTable).map(::loadContextReceiver) + fun loadFunction( proto: ProtoBuf.Function, classProto: ProtoBuf.Class? = null, @@ -521,15 +502,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) { deprecation = annotations.getDeprecationInfosFromAnnotations(c.session.languageVersionSettings.apiVersion, false) this.containerSource = c.containerSource - contextReceivers.addAll( - when { - proto.contextReceiverTypeCount > 0 -> - proto.contextReceiverTypeList.map(::loadContextReceiverFromType) - proto.contextReceiverTypeIdCount > 0 -> - proto.contextReceiverTypeIdList.map(::loadContextReceiverFromTypeId) - else -> emptyList() - } - ) + proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver) }.apply { versionRequirementsTable = c.versionRequirementTable } diff --git a/compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt b/compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt new file mode 100644 index 00000000000..0a651006ce2 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt @@ -0,0 +1,13 @@ +// !LANGUAGE: +ContextReceivers + +package test + +interface A +interface B + +context(A) class C { + context(B) fun f() {} +} + +context(A) fun g() {} +context(B) val h: Int get() = 42 diff --git a/compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.txt b/compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.txt new file mode 100644 index 00000000000..e82b1ef557c --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.txt @@ -0,0 +1,16 @@ +package test + +context(test.B) public val h: kotlin.Int + context(test.B) public fun ``(): kotlin.Int +context(test.A) public fun g(): kotlin.Unit + +public interface A { +} + +public interface B { +} + +context(test.A) public final class C { + /*primary*/ public constructor C() + context(test.B) public final fun f(): kotlin.Unit +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index 1d909b24fa5..6760076a4e5 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -2674,6 +2674,24 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { } } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractLoadJavaTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestCompiledKotlin, this, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("SimpleContextReceivers.kt") + public void testSimpleContextReceivers() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt"); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java index 19c32986e01..09c9c1cee95 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java @@ -996,6 +996,24 @@ public class LoadKotlinWithTypeTableTestGenerated extends AbstractLoadKotlinWith } } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractLoadKotlinWithTypeTableTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("SimpleContextReceivers.kt") + public void testSimpleContextReceivers() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt"); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java index c7dd0eb931f..62cfc0429e5 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java @@ -2675,6 +2675,24 @@ public class IrLoadJavaTestGenerated extends AbstractIrLoadJavaTest { } } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractIrLoadJavaTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestCompiledKotlin, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("SimpleContextReceivers.kt") + public void testSimpleContextReceivers() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt"); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java index ca1e5b6ec37..d69248e8773 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java @@ -2674,6 +2674,24 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT } } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractLoadJavaUsingJavacTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestCompiledKotlin, this, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("SimpleContextReceivers.kt") + public void testSimpleContextReceivers() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt"); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java b/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java index d53ff04d4bf..adbd383ba8f 100644 --- a/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java +++ b/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java @@ -998,6 +998,24 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD } } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractJvmRuntimeDescriptorLoaderTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("SimpleContextReceivers.kt") + public void testSimpleContextReceivers() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/contextReceivers/SimpleContextReceivers.kt"); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlin/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt index 614a0f1c056..2bba9f9b2e4 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt @@ -60,7 +60,7 @@ class MemberDeserializer(private val c: DeserializationContext) { proto.receiverType(c.typeTable)?.let(local.typeDeserializer::type)?.let { receiverType -> DescriptorFactory.createExtensionReceiverParameterForCallable(property, receiverType, receiverAnnotations) }, - proto.contextReceiverTypeList.map { it.toContextReceiver(local, property) } + proto.contextReceiverTypes(c.typeTable).map { it.toContextReceiver(local, property) } ) // Per documentation on Property.getter_flags in metadata.proto, if an accessor flags field is absent, its value should be computed @@ -212,7 +212,7 @@ class MemberDeserializer(private val c: DeserializationContext) { DescriptorFactory.createExtensionReceiverParameterForCallable(function, receiverType, receiverAnnotations) }, getDispatchReceiverParameter(), - proto.contextReceiverTypeList.mapNotNull { it.toContextReceiver(local, function) }, + proto.contextReceiverTypes(c.typeTable).mapNotNull { it.toContextReceiver(local, function) }, local.typeDeserializer.ownTypeParameters, local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION), local.typeDeserializer.type(proto.returnType(c.typeTable)), diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt index 35f01da232b..5a5f00088ab 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt @@ -146,7 +146,7 @@ class DeserializedClassDescriptor( override fun getConstructors() = constructors() - override fun getContextReceivers(): List = classProto.contextReceiverTypeList.map { + override fun getContextReceivers(): List = classProto.contextReceiverTypes(c.typeTable).map { val contextReceiverType = c.typeDeserializer.type(it) ReceiverParameterDescriptorImpl( thisAsReceiverParameter, diff --git a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt index a693fc81a0d..45c6925bf38 100644 --- a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt +++ b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt @@ -113,3 +113,12 @@ fun ProtoBuf.Expression.isInstanceType(typeTable: TypeTable): ProtoBuf.Type? = w hasIsInstanceTypeId() -> typeTable[isInstanceTypeId] else -> null } + +fun ProtoBuf.Class.contextReceiverTypes(typeTable: TypeTable): List = + contextReceiverTypeList.takeIf(Collection<*>::isNotEmpty) ?: contextReceiverTypeIdList.map { typeTable[it] } + +fun ProtoBuf.Function.contextReceiverTypes(typeTable: TypeTable): List = + contextReceiverTypeList.takeIf(Collection<*>::isNotEmpty) ?: contextReceiverTypeIdList.map { typeTable[it] } + +fun ProtoBuf.Property.contextReceiverTypes(typeTable: TypeTable): List = + contextReceiverTypeList.takeIf(Collection<*>::isNotEmpty) ?: contextReceiverTypeIdList.map { typeTable[it] }