diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/js/AtomicfuJsIrTransformer.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/js/AtomicfuJsIrTransformer.kt index 7bc4858af16..9620caa1edc 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/js/AtomicfuJsIrTransformer.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/js/AtomicfuJsIrTransformer.kt @@ -125,13 +125,13 @@ class AtomicfuJsIrTransformer(private val context: IrPluginContext) { // fun () = a$delegate.value -> _a.value // fun (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), diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/DelegatedPropertiesTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/box/DelegatedPropertiesTest.kt index af7b28cbddb..10d72ca08ee 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/DelegatedPropertiesTest.kt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/DelegatedPropertiesTest.kt @@ -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() } }