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
@@ -4,6 +4,8 @@
- kotlinx-metadata-jvm can no longer be used on JVM 1.6, and now requires JVM 1.8 or later.
- Add `Flag.Type.IS_DEFINITELY_NON_NULL`.
- Add `KmClass.contextReceiverTypes`, `KmFunction.contextReceiverTypes`, `KmProperty.contextReceiverTypes`
- The API is experimental and requires `@ExperimentalContextReceivers` on the usages.
## 0.4.2
@@ -222,7 +222,7 @@ open class JvmPropertyExtensionVisitor @JvmOverloads constructor(
/**
* Visits the JVM signature of a synthetic method which is generated when a delegated property's delegate object is
* optimized out, e.g. because it is constant; in that case, a copy of that object can be obtained on demand by calling
* this method. It takes up to two arguments - the property's receivers.
* this method. It takes the property's receivers as arguments.
*
* Example: `JvmMethodSignature("getX$delegate", "(LMyClass;)LMyDelegate;")`
*
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata
@RequiresOptIn(
"The API uses experimental feature \"context receivers\" (see KEEP-259) and may be changed or removed in any future release."
)
annotation class ExperimentalContextReceivers
@@ -46,6 +46,7 @@ class ReadContext(
}
}
@OptIn(ExperimentalContextReceivers::class)
fun ProtoBuf.Class.accept(
v: KmClassVisitor,
strings: NameResolver,
@@ -100,6 +101,10 @@ fun ProtoBuf.Class.accept(
v.visitInlineClassUnderlyingType(underlyingType.typeFlags)?.let { underlyingType.accept(it, c) }
}
for (contextReceiverType in contextReceiverTypes(c.types)) {
v.visitContextReceiverType(contextReceiverType.typeFlags)?.let { contextReceiverType.accept(it, c) }
}
for (versionRequirement in versionRequirementList) {
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(versionRequirement, it, c) }
}
@@ -214,6 +219,7 @@ private fun ProtoBuf.Constructor.accept(v: KmConstructorVisitor, c: ReadContext)
v.visitEnd()
}
@OptIn(ExperimentalContextReceivers::class)
private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList)
@@ -225,6 +231,10 @@ private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
v.visitReceiverParameterType(receiverType.typeFlags)?.let { receiverType.accept(it, c) }
}
for (contextReceiverType in contextReceiverTypes(c.types)) {
v.visitContextReceiverType(contextReceiverType.typeFlags)?.let { contextReceiverType.accept(it, c) }
}
for (parameter in valueParameterList) {
v.visitValueParameter(parameter.flags, c[parameter.name])?.let { parameter.accept(it, c) }
}
@@ -248,6 +258,7 @@ private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
v.visitEnd()
}
@OptIn(ExperimentalContextReceivers::class)
fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList)
@@ -259,6 +270,10 @@ fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
v.visitReceiverParameterType(receiverType.typeFlags)?.let { receiverType.accept(it, c) }
}
for (contextReceiverType in contextReceiverTypes(c.types)) {
v.visitContextReceiverType(contextReceiverType.typeFlags)?.let { contextReceiverType.accept(it, c) }
}
if (hasSetterValueParameter()) {
val parameter = setterValueParameter
v.visitSetterParameter(parameter.flags, c[parameter.name])?.let { parameter.accept(it, c) }
@@ -158,6 +158,10 @@ private fun writeFunction(c: WriteContext, flags: Flags, name: String, output: (
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? =
writeType(c, flags) { t.receiverType = it.build() }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
writeType(c, flags) { t.addContextReceiverType(it) }
override fun visitValueParameter(flags: Flags, name: String): KmValueParameterVisitor? =
writeValueParameter(c, flags, name) { t.addValueParameter(it) }
@@ -195,6 +199,10 @@ fun writeProperty(
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? =
writeType(c, flags) { t.receiverType = it.build() }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
writeType(c, flags) { t.addContextReceiverType(it) }
override fun visitSetterParameter(flags: Flags, name: String): KmValueParameterVisitor? =
writeValueParameter(c, flags, name) { t.setterValueParameter = it.build() }
@@ -464,6 +472,10 @@ open class ClassWriter(stringTable: StringTable, contextExtensions: List<WriteCo
override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor? =
writeType(c, flags) { t.inlineClassUnderlyingType = it.build() }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
writeType(c, flags) { t.addContextReceiverType(it) }
override fun visitVersionRequirement(): KmVersionRequirementVisitor? =
writeVersionRequirement(c) { t.addVersionRequirement(it) }
@@ -103,6 +103,12 @@ class KmClass : KmClassVisitor(), KmDeclarationContainer {
*/
var inlineClassUnderlyingType: KmType? = null
/**
* Types of context receivers of the class.
*/
@ExperimentalContextReceivers
val contextReceiverTypes: MutableList<KmType> = ArrayList(0)
/**
* Version requirements on this class.
*/
@@ -157,6 +163,10 @@ class KmClass : KmClassVisitor(), KmDeclarationContainer {
override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor =
KmType(flags).also { inlineClassUnderlyingType = it }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
KmType(flags).addTo(contextReceiverTypes)
override fun visitVersionRequirement(): KmVersionRequirementVisitor =
KmVersionRequirement().addTo(versionRequirements)
@@ -168,6 +178,7 @@ class KmClass : KmClassVisitor(), KmDeclarationContainer {
*
* @param visitor the visitor which will visit data in this class
*/
@OptIn(ExperimentalContextReceivers::class)
fun accept(visitor: KmClassVisitor) {
visitor.visit(flags, name)
typeParameters.forEach { visitor.visitTypeParameter(it.flags, it.name, it.id, it.variance)?.let(it::accept) }
@@ -182,6 +193,7 @@ class KmClass : KmClassVisitor(), KmDeclarationContainer {
sealedSubclasses.forEach(visitor::visitSealedSubclass)
inlineClassUnderlyingPropertyName?.let(visitor::visitInlineClassUnderlyingPropertyName)
inlineClassUnderlyingType?.let { visitor.visitInlineClassUnderlyingType(it.flags)?.let(it::accept) }
contextReceiverTypes.forEach { visitor.visitContextReceiverType(it.flags)?.let(it::accept) }
versionRequirements.forEach { visitor.visitVersionRequirement()?.let(it::accept) }
extensions.forEach { visitor.visitExtensions(it.type)?.let(it::accept) }
visitor.visitEnd()
@@ -360,6 +372,12 @@ class KmFunction(
*/
var receiverParameterType: KmType? = null
/**
* Types of context receivers of the function.
*/
@ExperimentalContextReceivers
val contextReceiverTypes: MutableList<KmType> = ArrayList(0)
/**
* Value parameters of the function.
*/
@@ -389,6 +407,10 @@ class KmFunction(
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor =
KmType(flags).also { receiverParameterType = it }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
KmType(flags).addTo(contextReceiverTypes)
override fun visitValueParameter(flags: Flags, name: String): KmValueParameterVisitor =
KmValueParameter(flags, name).addTo(valueParameters)
@@ -409,9 +431,11 @@ class KmFunction(
*
* @param visitor the visitor which will visit data in this function
*/
@OptIn(ExperimentalContextReceivers::class)
fun accept(visitor: KmFunctionVisitor) {
typeParameters.forEach { visitor.visitTypeParameter(it.flags, it.name, it.id, it.variance)?.let(it::accept) }
receiverParameterType?.let { visitor.visitReceiverParameterType(it.flags)?.let(it::accept) }
contextReceiverTypes.forEach { visitor.visitContextReceiverType(it.flags)?.let(it::accept) }
valueParameters.forEach { visitor.visitValueParameter(it.flags, it.name)?.let(it::accept) }
visitor.visitReturnType(returnType.flags)?.let(returnType::accept)
versionRequirements.forEach { visitor.visitVersionRequirement()?.let(it::accept) }
@@ -447,6 +471,12 @@ class KmProperty(
*/
var receiverParameterType: KmType? = null
/**
* Types of context receivers of the property.
*/
@ExperimentalContextReceivers
val contextReceiverTypes: MutableList<KmType> = ArrayList(0)
/**
* Value parameter of the setter of this property, if this is a `var` property.
*/
@@ -471,6 +501,10 @@ class KmProperty(
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor =
KmType(flags).also { receiverParameterType = it }
@ExperimentalContextReceivers
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor =
KmType(flags).addTo(contextReceiverTypes)
override fun visitSetterParameter(flags: Flags, name: String): KmValueParameterVisitor =
KmValueParameter(flags, name).also { setterParameter = it }
@@ -488,9 +522,11 @@ class KmProperty(
*
* @param visitor the visitor which will visit data in this property
*/
@OptIn(ExperimentalContextReceivers::class)
fun accept(visitor: KmPropertyVisitor) {
typeParameters.forEach { visitor.visitTypeParameter(it.flags, it.name, it.id, it.variance)?.let(it::accept) }
receiverParameterType?.let { visitor.visitReceiverParameterType(it.flags)?.let(it::accept) }
contextReceiverTypes.forEach { visitor.visitContextReceiverType(it.flags)?.let(it::accept) }
setterParameter?.let { visitor.visitSetterParameter(it.flags, it.name)?.let(it::accept) }
visitor.visitReturnType(returnType.flags)?.let(returnType::accept)
versionRequirements.forEach { visitor.visitVersionRequirement()?.let(it::accept) }
@@ -149,6 +149,15 @@ abstract class KmClassVisitor @JvmOverloads constructor(delegate: KmClassVisitor
open fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor? =
delegate?.visitInlineClassUnderlyingType(flags)
/**
* Visits the type of a context receiver of the class.
*
* @param flags type flags, consisting of [Flag.Type] flags
*/
@ExperimentalContextReceivers
open fun visitContextReceiverType(flags: Flags): KmTypeVisitor? =
delegate?.visitContextReceiverType(flags)
/**
* Visits the version requirement on this class.
*/
@@ -319,6 +328,15 @@ abstract class KmFunctionVisitor @JvmOverloads constructor(private val delegate:
open fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? =
delegate?.visitReceiverParameterType(flags)
/**
* Visits the type of a context receiver of the function.
*
* @param flags type flags, consisting of [Flag.Type] flags
*/
@ExperimentalContextReceivers
open fun visitContextReceiverType(flags: Flags): KmTypeVisitor? =
delegate?.visitContextReceiverType(flags)
/**
* Visits a value parameter of the function.
*
@@ -391,6 +409,15 @@ abstract class KmPropertyVisitor @JvmOverloads constructor(private val delegate:
open fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? =
delegate?.visitReceiverParameterType(flags)
/**
* Visits the type of a context receiver of the property.
*
* @param flags type flags, consisting of [Flag.Type] flags
*/
@ExperimentalContextReceivers
open fun visitContextReceiverType(flags: Flags): KmTypeVisitor? =
delegate?.visitContextReceiverType(flags)
/**
* Visits a value parameter of the setter of this property, if this is a `var` property.
*