[Commonizer] Commonize 'val' and 'var' properties

If a setter is not present on all platforms a fallback private setter
shall be emitted.

^KT-47502 Verification Pending
^KT-47691 Verification Pending
This commit is contained in:
sebastian.sellmair
2021-07-12 16:21:43 +02:00
committed by Space
parent c4d90dc744
commit 8bab6c3076
5 changed files with 111 additions and 100 deletions
@@ -34,4 +34,30 @@ open class AssociativeCommonizerAdapter<T : Any>(
_result = commonizer.commonize(currentResult, next) _result = commonizer.commonize(currentResult, next)
return _result != null return _result != null
} }
}
fun <T> AssociativeCommonizer<T?>.asNullableCommonizer(): Commonizer<T?, T?> = NullableAssociativeCommonizerAdapter(this)
open class NullableAssociativeCommonizerAdapter<T>(
private val commonizer: AssociativeCommonizer<T?>
) : Commonizer<T?, T?> {
private var isInitialized = false
private var _result: T? = null
override val result: T?
get() = _result
override fun commonizeWith(next: T?): Boolean {
val currentResult = _result
if (!isInitialized) {
_result = next
isInitialized = true
return true
}
_result = commonizer.commonize(currentResult, next)
return true
}
} }
@@ -10,14 +10,19 @@ import org.jetbrains.kotlin.commonizer.cir.CirProperty
import org.jetbrains.kotlin.commonizer.cir.CirPropertyGetter import org.jetbrains.kotlin.commonizer.cir.CirPropertyGetter
import org.jetbrains.kotlin.commonizer.core.PropertyCommonizer.ConstCommonizationState.* import org.jetbrains.kotlin.commonizer.core.PropertyCommonizer.ConstCommonizationState.*
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
import org.jetbrains.kotlin.descriptors.Modality
class PropertyCommonizer(classifiers: CirKnownClassifiers) : AbstractFunctionOrPropertyCommonizer<CirProperty>(classifiers) { class PropertyCommonizer(classifiers: CirKnownClassifiers) : AbstractFunctionOrPropertyCommonizer<CirProperty>(classifiers) {
private val setter = PropertySetterCommonizer() private val setter = PropertySetterCommonizer.asNullableCommonizer()
private var isExternal = true private var isExternal = true
private lateinit var constCommonizationState: ConstCommonizationState private lateinit var constCommonizationState: ConstCommonizationState
override fun commonizationResult(): CirProperty { override fun commonizationResult(): CirProperty {
val setter = setter.result val modality = modality.result
val setter = setter.result?.takeIf { setter ->
setter !== PropertySetterCommonizer.privateFallbackSetter || modality == Modality.FINAL
}
val constCommonizationState = constCommonizationState val constCommonizationState = constCommonizationState
val constCompileTimeInitializer = (constCommonizationState as? ConstSameValue)?.compileTimeInitializer val constCompileTimeInitializer = (constCommonizationState as? ConstSameValue)?.compileTimeInitializer
@@ -27,7 +32,7 @@ class PropertyCommonizer(classifiers: CirKnownClassifiers) : AbstractFunctionOrP
name = name, name = name,
typeParameters = typeParameters.result, typeParameters = typeParameters.result,
visibility = visibility.result, visibility = visibility.result,
modality = modality.result, modality = modality,
containingClass = null, // does not matter containingClass = null, // does not matter
isExternal = isExternal, isExternal = isExternal,
extensionReceiver = extensionReceiver.result, extensionReceiver = extensionReceiver.result,
@@ -5,12 +5,25 @@
package org.jetbrains.kotlin.commonizer.core package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.cir.CirHasVisibility
import org.jetbrains.kotlin.commonizer.cir.CirPropertySetter import org.jetbrains.kotlin.commonizer.cir.CirPropertySetter
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibilities
class PropertySetterCommonizer : AbstractNullableCommonizer<CirPropertySetter, CirPropertySetter, CirHasVisibility, Visibility>( object PropertySetterCommonizer : AssociativeCommonizer<CirPropertySetter?> {
wrappedCommonizerFactory = { VisibilityCommonizer.equalizing() }, override fun commonize(first: CirPropertySetter?, second: CirPropertySetter?): CirPropertySetter? {
extractor = { it }, if (first == null && second == null) return null
builder = CirPropertySetter::createDefaultNoAnnotations if (first != null && second == null) return privateFallbackSetter
) if (first == null && second != null) return privateFallbackSetter
if (first != null && second != null) {
if (Visibilities.compare(first.visibility, second.visibility) == 0) {
return CirPropertySetter.createDefaultNoAnnotations(first.visibility)
}
return privateFallbackSetter
}
return null
}
val privateFallbackSetter = CirPropertySetter.createDefaultNoAnnotations(Visibilities.Private)
}
@@ -9,8 +9,16 @@ expect var setterWithDelegation1: Int
expect var setterWithDelegation2: Int expect var setterWithDelegation2: Int
expect var defaultSetteCustomVisibility1: Int expect var defaultSetteCustomVisibility1: Int
expect var defaultSetteCustomVisibility2: Int
private set
expect var defaultSetteCustomVisibility3 = 42 expect var defaultSetteCustomVisibility3 = 42
internal set internal set
expect var defaultSetteCustomVisibility4: Int
private set
expect var defaultSetteCustomVisibility5: Int
private set
expect val propertyWithoutSetter: Int expect val propertyWithoutSetter: Int
expect var propertyWithSetter: Int expect var propertyMaybeSetter: Int
private set
expect var propertyWithSetter: Int
@@ -6,101 +6,60 @@
package org.jetbrains.kotlin.commonizer.core package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.cir.CirPropertySetter import org.jetbrains.kotlin.commonizer.cir.CirPropertySetter
import org.jetbrains.kotlin.descriptors.Visibilities.Internal import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibilities.Local
import org.jetbrains.kotlin.descriptors.Visibilities.Private
import org.jetbrains.kotlin.descriptors.Visibilities.Protected
import org.jetbrains.kotlin.descriptors.Visibilities.Public
import org.jetbrains.kotlin.descriptors.Visibility
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertSame
class PropertySetterCommonizerTest : AbstractCommonizerTest<CirPropertySetter?, CirPropertySetter?>() { class PropertySetterCommonizerTest {
@Test @Test
fun missingOnly() = super.doTestSuccess( fun `missing only`() {
expected = null, assertNull(
null, null, null PropertySetterCommonizer.commonize(null, null),
) "Expected no property setting being commonized from nulls"
@Test(expected = IllegalCommonizerStateException::class)
fun missingAndPublic() = doTestFailure(
null, null, null, Public
)
@Test(expected = IllegalCommonizerStateException::class)
fun publicAndMissing() = doTestFailure(
Public, Public, Public, null
)
@Test(expected = IllegalCommonizerStateException::class)
fun protectedAndMissing() = doTestFailure(
Protected, Protected, null
)
@Test(expected = IllegalCommonizerStateException::class)
fun missingAndInternal() = doTestFailure(
null, null, Internal
)
@Test
fun publicOnly() = doTestSuccess(
expected = Public,
Public, Public, Public
)
@Test
fun protectedOnly() = doTestSuccess(
expected = Protected,
Protected, Protected, Protected
)
@Test
fun internalOnly() = doTestSuccess(
expected = Internal,
Internal, Internal, Internal
)
@Test(expected = IllegalCommonizerStateException::class)
fun privateOnly() = doTestFailure(
Private
)
@Test(expected = IllegalCommonizerStateException::class)
fun publicAndProtected() = doTestFailure(
Public, Public, Protected
)
@Test(expected = IllegalCommonizerStateException::class)
fun publicAndInternal() = doTestFailure(
Public, Public, Internal
)
@Test(expected = IllegalCommonizerStateException::class)
fun protectedAndInternal() = doTestFailure(
Protected, Protected, Internal
)
@Test(expected = IllegalCommonizerStateException::class)
fun publicAndPrivate() = doTestFailure(
Public, Public, Private
)
@Test(expected = IllegalCommonizerStateException::class)
fun somethingUnexpected() = doTestFailure(
Public, Local
)
private fun doTestSuccess(expected: Visibility?, vararg variants: Visibility?) =
super.doTestSuccess(
expected = expected?.let { CirPropertySetter.createDefaultNoAnnotations(expected) },
*variants.map { it?.let(CirPropertySetter::createDefaultNoAnnotations) }.toTypedArray()
) )
}
private fun doTestFailure(vararg variants: Visibility?) = @Test
super.doTestFailure( fun `missing and public`() {
*variants.map { it?.let(CirPropertySetter::createDefaultNoAnnotations) }.toTypedArray(), assertSame(
shouldFailOnFirstVariant = false PropertySetterCommonizer.privateFallbackSetter,
PropertySetterCommonizer.commonize(null, CirPropertySetter.createDefaultNoAnnotations(Visibilities.Public))
) )
}
override fun createCommonizer() = PropertySetterCommonizer() @Test
fun `public public`() {
assertEquals(
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Public),
PropertySetterCommonizer.commonize(
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Public),
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Public)
)
)
}
@Test
fun `internal internal`() {
assertEquals(
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Internal),
PropertySetterCommonizer.commonize(
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Internal),
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Internal)
)
)
}
@Test
fun `internal public`() {
assertEquals(
PropertySetterCommonizer.privateFallbackSetter,
PropertySetterCommonizer.commonize(
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Internal),
CirPropertySetter.createDefaultNoAnnotations(Visibilities.Public)
)
)
}
} }