[Commonizer] Fallback for const val properties with different values

This commit is contained in:
Dmitriy Dolovov
2020-06-16 11:58:32 +07:00
parent ee455abe52
commit af1dd6251e
6 changed files with 71 additions and 27 deletions
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue
interface CirProperty : CirFunctionOrProperty, CirLiftedUpDeclaration { interface CirProperty : CirFunctionOrProperty, CirLiftedUpDeclaration {
val isVar: Boolean val isVar: Boolean
val isLateInit: Boolean val isLateInit: Boolean
val isConst: Boolean var isConst: Boolean
val isDelegate: Boolean val isDelegate: Boolean
val getter: CirPropertyGetter? val getter: CirPropertyGetter?
val setter: CirPropertySetter? val setter: CirPropertySetter?
@@ -25,7 +25,7 @@ data class CirPropertyImpl(
override val kind: CallableMemberDescriptor.Kind, override val kind: CallableMemberDescriptor.Kind,
override val isVar: Boolean, override val isVar: Boolean,
override val isLateInit: Boolean, override val isLateInit: Boolean,
override val isConst: Boolean, override var isConst: Boolean,
override val isDelegate: Boolean, override val isDelegate: Boolean,
override val getter: CirPropertyGetter?, override val getter: CirPropertyGetter?,
override val setter: CirPropertySetter?, override val setter: CirPropertySetter?,
@@ -8,17 +8,25 @@ package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirProperty import org.jetbrains.kotlin.descriptors.commonizer.cir.CirProperty
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirPropertyFactory import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirPropertyFactory
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirPropertyGetterFactory import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirPropertyGetterFactory
import org.jetbrains.kotlin.descriptors.commonizer.core.PropertyCommonizer.ConstCommonizationState.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirClassifiersCache import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirClassifiersCache
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValue
class PropertyCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropertyCommonizer<CirProperty>(cache) { class PropertyCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropertyCommonizer<CirProperty>(cache) {
private val setter = PropertySetterCommonizer() private val setter = PropertySetterCommonizer()
private var isExternal = true private var isExternal = true
private var constCompileTimeInitializer: ConstantValue<*>? = null private lateinit var constCommonizationState: ConstCommonizationState
override fun commonizationResult(): CirProperty { override fun commonizationResult(): CirProperty {
val setter = setter.result val setter = setter.result
val constCompileTimeInitializer = constCompileTimeInitializer
val constCommonizationState = constCommonizationState
val constCompileTimeInitializer = (constCommonizationState as? ConstSameValue)?.compileTimeInitializer
if (constCommonizationState is ConstMultipleValues) {
// fix all commonized properties to make then non-const
constCommonizationState.properties.forEach { it.isConst = false }
}
return CirPropertyFactory.create( return CirPropertyFactory.create(
annotations = emptyList(), annotations = emptyList(),
@@ -46,8 +54,10 @@ class PropertyCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropert
override fun initialize(first: CirProperty) { override fun initialize(first: CirProperty) {
super.initialize(first) super.initialize(first)
if (first.isConst) { constCommonizationState = if (first.isConst) {
constCompileTimeInitializer = first.compileTimeInitializer first.compileTimeInitializer?.let(::ConstSameValue) ?: NonConst
} else {
NonConst
} }
} }
@@ -57,16 +67,28 @@ class PropertyCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropert
return false return false
} }
val constCompileTimeInitializer = constCompileTimeInitializer val constCommonizationState = constCommonizationState
if (next.isConst) { if (next.isConst) {
// const properties should be lifted up // const properties should be lifted up
// otherwise commonization should fail: expect property can't be const because expect can't have initializer // otherwise commonization should fail: expect property can't be const because expect can't have initializer
when (constCommonizationState) {
NonConst -> {
// previous property was not constant
return false
}
is Const -> {
// previous property was constant
constCommonizationState.properties += next
if (constCompileTimeInitializer == null || constCompileTimeInitializer != next.compileTimeInitializer) { if (constCommonizationState is ConstSameValue) {
// previous property was not constant or const properties have different constants if (constCommonizationState.compileTimeInitializer != next.compileTimeInitializer) {
return false // const properties have different constants
this.constCommonizationState = ConstMultipleValues(constCommonizationState)
}
}
}
} }
} else if (constCompileTimeInitializer != null) { } else if (constCommonizationState != NonConst) {
// previous property was constant but this one is not // previous property was constant but this one is not
return false return false
} }
@@ -80,4 +102,18 @@ class PropertyCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropert
return result return result
} }
private sealed class ConstCommonizationState {
object NonConst : ConstCommonizationState()
abstract class Const : ConstCommonizationState() {
val properties: MutableList<CirProperty> = mutableListOf()
}
class ConstSameValue(val compileTimeInitializer: ConstantValue<*>) : Const()
class ConstMultipleValues(previous: ConstSameValue) : Const() {
init {
properties += previous.properties
}
}
}
} }
@@ -2,10 +2,18 @@ const val property1 = 42
expect val property4: Int expect val property4: Int
const val property5: Byte = 42 const val property5: Byte = 42
expect val property6: Byte
const val property7: Short = 42 const val property7: Short = 42
expect val property8: Short
const val property9: Long = 42 const val property9: Long = 42
expect val property10: Long
const val property11: Double = 4.2 const val property11: Double = 4.2
expect val property12: Double
const val property13: Float = 4.2f const val property13: Float = 4.2f
expect val property14: Float
const val property15 = true const val property15 = true
expect val property16: Boolean
const val property17 = "42" const val property17 = "42"
expect val property18: String
const val property19: Char = 42.toChar() const val property19: Char = 42.toChar()
expect val property20: Char
@@ -2,14 +2,14 @@ const val property2 = 42
val property3 = 42 // intentionally left as non-const val property3 = 42 // intentionally left as non-const
actual val property4 = 42 actual val property4 = 42
const val property6: Byte = 42 actual val property6: Byte = 42
const val property8: Short = 42 actual val property8: Short = 42
const val property10: Long = 42 actual val property10: Long = 42
const val property12: Double = 4.2 actual val property12: Double = 4.2
const val property14: Float = 4.2f actual val property14: Float = 4.2f
const val property16 = true actual val property16 = true
const val property18 = "42" actual val property18 = "42"
const val property20: Char = 42.toChar() actual val property20: Char = 42.toChar()
const val property21: Byte = 42 const val property21: Byte = 42
const val property22: Short = 42 const val property22: Short = 42
@@ -2,14 +2,14 @@ val property2 = 42 // intentionally left as non-const
const val property3 = 42 const val property3 = 42
actual val property4 = 42 actual val property4 = 42
const val property6: Byte = 142 actual val property6: Byte = 142
const val property8: Short = 142 actual val property8: Short = 142
const val property10: Long = 142 actual val property10: Long = 142
const val property12: Double = 14.2 actual val property12: Double = 14.2
const val property14: Float = 14.2f actual val property14: Float = 14.2f
const val property16 = false actual val property16 = false
const val property18 = "142" actual val property18 = "142"
const val property20: Char = 142.toChar() actual val property20: Char = 142.toChar()
const val property21: Char = 42.toChar() const val property21: Char = 42.toChar()
const val property22: Byte = 42 const val property22: Byte = 42