Atomicfu plugin (JS IR): fix for private delegated properties

Fixes https://github.com/Kotlin/kotlinx-atomicfu/issues/260
This commit is contained in:
mvicsokolova
2022-11-03 14:40:21 +00:00
committed by Space Team
parent 92ec8e6a3e
commit 5708b2229a
2 changed files with 38 additions and 28 deletions
@@ -125,13 +125,13 @@ class AtomicfuJsIrTransformer(private val context: IrPluginContext) {
// fun <get-a>() = a$delegate.value -> _a.value
// fun <set-a>(value: Int) = { a$delegate.value = value } -> { _a.value = value }
val originalField = initializer.getBackingField()
declaration.transform(DelegatePropertyTransformer(originalField, initializer.dispatchReceiver, false), null)
declaration.transform(DelegatePropertyTransformer(originalField), null)
}
initializer.isAtomicFactory() -> {
// var a by atomic(77) -> var a: Int = 77
it.expression = initializer.eraseAtomicFactory()
?: error("Atomic factory was expected but found ${initializer.render()}")
declaration.transform(DelegatePropertyTransformer(delegateBackingField, initializer.dispatchReceiver, true), null)
declaration.transform(DelegatePropertyTransformer(delegateBackingField), null)
}
else -> error("Unexpected initializer of the delegated property: $initializer")
}
@@ -275,9 +275,7 @@ class AtomicfuJsIrTransformer(private val context: IrPluginContext) {
}
private inner class DelegatePropertyTransformer(
val originalField: IrField,
val receiver: IrExpression?,
val isInitializedWithAtomicFactory: Boolean
val originalField: IrField
): IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
// Accessors of the delegated property have following signatures:
@@ -291,11 +289,14 @@ class AtomicfuJsIrTransformer(private val context: IrPluginContext) {
val type = originalField.type.atomicToValueType()
val isSetter = name == SET_VALUE
val runtimeFunction = getRuntimeFunctionSymbol(name, type)
val dispatchReceiver = if (isInitializedWithAtomicFactory) {
val thisRef = expression.getValueArgument(0)!!
if (thisRef.isConstNull()) null else thisRef
} else {
receiver
// val _a = atomic(77)
// var a: Int by _a
// This is the delegate getValue operator of property `a`, which should be transformed to getting the value of the original atomic `_a`
// operator fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>) {
// return thisRef._a
// }
val dispatchReceiver = expression.getValueArgument(0)?.let {
if (it.isConstNull()) null else it
}
val fieldAccessors = listOf(
context.buildFieldAccessor(originalField, dispatchReceiver, false),
@@ -7,37 +7,47 @@ var topLevelInt: Int by _topLevelInt
private var topLevelVolatile by atomic(56)
class DelegatedProperties {
// Delegated properties should be declared in the same scope as the original atomic values
private val _a = atomic(42)
var a: Int by _a
private var privateA: Int by _a
private val _l = atomic(55555555555)
var l: Long by _l
private var l: Long by _l
private val _b = atomic(false)
var b: Boolean by _b
private var b: Boolean by _b
private val _ref = atomic(A(B(77)))
var ref: A by _ref
private var ref: A by _ref
var vInt by atomic(77)
private var vInt by atomic(77)
var vLong by atomic(777777777)
private var vLong by atomic(777777777)
var vBoolean by atomic(false)
private var vBoolean by atomic(false)
var vRef by atomic(A(B(77)))
private var vRef by atomic(A(B(77)))
class A (val b: B)
class B (val n: Int)
fun testDelegatedAtomicInt() {
assertEquals(42, a)
assertEquals(42, privateA)
_a.compareAndSet(42, 56)
assertEquals(56, a)
assertEquals(56, privateA)
a = 77
_a.compareAndSet(77, 66)
privateA = 88
_a.compareAndSet(88, 66)
assertEquals(66, _a.value)
assertEquals(66, a)
assertEquals(66, privateA)
val aValue = a + privateA
assertEquals(132, aValue)
}
fun testDelegatedAtomicLong() {
@@ -95,25 +105,23 @@ class DelegatedProperties {
}
inner class D {
var b: Int by _a
var c by atomic("aaa")
}
fun testScopedDelegatedProperties() {
fun testScopedVolatileProperties() {
val clazz = D()
clazz.b = 42
_a.compareAndSet(42, 56)
assertEquals(56, clazz.b)
clazz.b = 77
_a.compareAndSet(77, 66)
assertEquals(66, _a.value)
assertEquals(66, clazz.b)
assertEquals("aaa", clazz.c)
clazz.c = "bbb"
assertEquals("bbb", clazz.c)
}
fun testDelegatedVariablesFlow() {
_a.lazySet(55)
assertEquals(55, _a.value)
assertEquals(55, a)
var aValue = a
}
fun test() {
testDelegatedAtomicInt()
testDelegatedAtomicLong()
@@ -123,7 +131,8 @@ class DelegatedProperties {
testVolatileBoolean()
testVolatileLong()
testVolatileRef()
testScopedDelegatedProperties()
testScopedVolatileProperties()
testDelegatedVariablesFlow()
}
}