kotlinx-metadata: support experimental context receivers

This commit is contained in:
Alexander Udalov
2022-06-14 00:32:38 +02:00
parent 6abf14087c
commit 61652c04e1
11 changed files with 194 additions and 2 deletions
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.kotlinp
import kotlinx.metadata.*
import kotlinx.metadata.jvm.*
import java.util.*
private object SpecialCharacters {
const val TYPE_ALIAS_MARKER = '^'
@@ -18,6 +17,7 @@ private fun visitFunction(settings: KotlinpSettings, sb: StringBuilder, flags: F
val typeParams = mutableListOf<String>()
val params = mutableListOf<String>()
var receiverParameterType: String? = null
val contextReceiverTypes = mutableListOf<String>()
var returnType: String? = null
val versionRequirements = mutableListOf<String>()
var jvmSignature: JvmMemberSignature? = null
@@ -27,6 +27,10 @@ private fun visitFunction(settings: KotlinpSettings, sb: StringBuilder, flags: F
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? =
printType(flags) { receiverParameterType = it }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
printType(flags) { contextReceiverTypes.add(it) }
override fun visitTypeParameter(
flags: Flags, name: String, id: Int, variance: KmVariance
): KmTypeParameterVisitor? =
@@ -68,6 +72,9 @@ private fun visitFunction(settings: KotlinpSettings, sb: StringBuilder, flags: F
if (jvmSignature != null) {
sb.appendLine(" // signature: $jvmSignature")
}
if (contextReceiverTypes.isNotEmpty()) {
sb.appendLine(contextReceiverTypes.joinToString(prefix = " context(", postfix = ")"))
}
sb.append(" ")
sb.appendFlags(flags, FUNCTION_FLAGS_MAP)
sb.append("fun ")
@@ -96,6 +103,7 @@ private fun visitProperty(
object : KmPropertyVisitor() {
val typeParams = mutableListOf<String>()
var receiverParameterType: String? = null
val contextReceiverTypes = mutableListOf<String>()
var returnType: String? = null
var setterParameter: String? = null
val versionRequirements = mutableListOf<String>()
@@ -109,6 +117,10 @@ private fun visitProperty(
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? =
printType(flags) { receiverParameterType = it }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
printType(flags) { contextReceiverTypes.add(it) }
override fun visitTypeParameter(flags: Flags, name: String, id: Int, variance: KmVariance): KmTypeParameterVisitor? =
printTypeParameter(settings, flags, name, id, variance) { typeParams.add(it) }
@@ -169,6 +181,9 @@ private fun visitProperty(
if (isMovedFromInterfaceCompanion) {
sb.appendLine(" // is moved from interface companion")
}
if (contextReceiverTypes.isNotEmpty()) {
sb.appendLine(contextReceiverTypes.joinToString(prefix = " context(", postfix = ")"))
}
sb.append(" ")
sb.appendFlags(flags, PROPERTY_FLAGS_MAP)
sb.append(if (Flag.Property.IS_VAR(flags)) "var " else "val ")
@@ -711,6 +726,7 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab
private var name: ClassName? = null
private val typeParams = mutableListOf<String>()
private val supertypes = mutableListOf<String>()
private val contextReceiverTypes = mutableListOf<String>()
private val versionRequirements = mutableListOf<String>()
private var anonymousObjectOriginName: String? = null
@@ -726,6 +742,9 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab
for (versionRequirement in versionRequirements) {
result.appendLine("// $versionRequirement")
}
if (contextReceiverTypes.isNotEmpty()) {
result.appendLine(contextReceiverTypes.joinToString(prefix = "context(", postfix = ")"))
}
result.appendFlags(flags!!, CLASS_FLAGS_MAP)
result.append(name)
if (typeParams.isNotEmpty()) {
@@ -789,6 +808,10 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab
sb.appendLine(" // underlying type: $it")
}
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
printType(flags) { contextReceiverTypes.add(it) }
override fun visitVersionRequirement(): KmVersionRequirementVisitor? =
printVersionRequirement { versionRequirements.add(it) }
@@ -34,6 +34,11 @@ public class KotlinpTestGenerated extends AbstractKotlinpTest {
runTest("libraries/tools/kotlinp/testData/Annotations.kt");
}
@TestMetadata("ContextReceivers.kt")
public void testContextReceivers() throws Exception {
runTest("libraries/tools/kotlinp/testData/ContextReceivers.kt");
}
@TestMetadata("Contracts.kt")
public void testContracts() throws Exception {
runTest("libraries/tools/kotlinp/testData/Contracts.kt");
+11
View File
@@ -0,0 +1,11 @@
// !LANGUAGE: +ContextReceivers
interface A
interface B
context(A) class C {
context(B) fun f() {}
}
context(A) fun g() {}
context(B) val h: Int get() = 42
+50
View File
@@ -0,0 +1,50 @@
// A.class
// ------------------------------------------
public abstract interface A : kotlin/Any {
// module name: test-module
}
// B.class
// ------------------------------------------
public abstract interface B : kotlin/Any {
// module name: test-module
}
// C.class
// ------------------------------------------
// requires compiler version 1.6.20 (level=ERROR)
context(A)
public final class C : kotlin/Any {
// signature: <init>(LA;)V
public constructor()
// requires compiler version 1.6.20 (level=ERROR)
// signature: f(LB;)V
context(B)
public final fun f(): kotlin/Unit
// module name: test-module
}
// ContextReceiversKt.class
// ------------------------------------------
package {
// requires compiler version 1.6.20 (level=ERROR)
// signature: g(LA;)V
context(A)
public final fun g(): kotlin/Unit
// requires compiler version 1.6.20 (level=ERROR)
// getter: getH(LB;)I
context(B)
public final val h: kotlin/Int
public final /* non-default */ get
}
// META-INF/test-module.kotlin_module
// ------------------------------------------
module {
package <root> {
ContextReceiversKt
}
}