Fix metadata deserialization for context receivers with type table

In DeserializedClassDescriptor and MemberDeserializer, only the
`contextReceiverTypeList` field was used, and not
`contextReceiverTypeIdList` which is used when `-Xuse-type-table` is
enabled. The convention is to use a bunch of utilities declared in
`protoTypeTableUtil.kt` which deal with both methods of reading types.
Also, simplify the deserialization code in FIR (which was correct for
some reason).
This commit is contained in:
Alexander Udalov
2022-06-14 00:16:59 +02:00
parent 71f6c0b1b2
commit 08f18c2940
13 changed files with 178 additions and 38 deletions
@@ -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)
@@ -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|
}
@@ -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<FirContextReceiver> = when {
classProto.contextReceiverTypeCount > 0 ->
classProto.contextReceiverTypeList.map(::loadContextReceiverFromType)
classProto.contextReceiverTypeIdCount > 0 ->
classProto.contextReceiverTypeIdList.map(::loadContextReceiverFromTypeId)
else -> emptyList()
}
internal fun createContextReceiversForClass(classProto: ProtoBuf.Class): List<FirContextReceiver> =
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
}
@@ -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
@@ -0,0 +1,16 @@
package test
context(test.B) public val h: kotlin.Int
context(test.B) public fun `<get-h>`(): 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
}
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)),
@@ -146,7 +146,7 @@ class DeserializedClassDescriptor(
override fun getConstructors() = constructors()
override fun getContextReceivers(): List<ReceiverParameterDescriptor> = classProto.contextReceiverTypeList.map {
override fun getContextReceivers(): List<ReceiverParameterDescriptor> = classProto.contextReceiverTypes(c.typeTable).map {
val contextReceiverType = c.typeDeserializer.type(it)
ReceiverParameterDescriptorImpl(
thisAsReceiverParameter,
@@ -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<ProtoBuf.Type> =
contextReceiverTypeList.takeIf(Collection<*>::isNotEmpty) ?: contextReceiverTypeIdList.map { typeTable[it] }
fun ProtoBuf.Function.contextReceiverTypes(typeTable: TypeTable): List<ProtoBuf.Type> =
contextReceiverTypeList.takeIf(Collection<*>::isNotEmpty) ?: contextReceiverTypeIdList.map { typeTable[it] }
fun ProtoBuf.Property.contextReceiverTypes(typeTable: TypeTable): List<ProtoBuf.Type> =
contextReceiverTypeList.takeIf(Collection<*>::isNotEmpty) ?: contextReceiverTypeIdList.map { typeTable[it] }