[IR] Forbid unconditional interpretation of IrGetObjectValue

Earlier we always allowed to interpret `IrGetObjectValue` because
this value is used in const val getter. But now we do a special
check for such getter avoiding visit of `IrGetObjectValue` node.

#KT-59775 Fixed
This commit is contained in:
Ivan Kylchik
2023-07-04 11:21:15 +02:00
committed by Space Team
parent 04f16d75d2
commit d557bcaba4
9 changed files with 98 additions and 13 deletions
@@ -305,11 +305,16 @@ internal fun IrClass.getSingleAbstractMethod(): IrFunction {
}
internal fun IrExpression?.isAccessToNotNullableObject(): Boolean {
if (this !is IrGetValue) return false
val owner = this.symbol.owner
val expectedClass = this.type.classOrNull?.owner
if (expectedClass == null || !expectedClass.isObject || this.type.isNullable()) return false
return owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER || owner.name.asString() == "<this>"
return when (this) {
is IrGetObjectValue -> !this.type.isNullable()
is IrGetValue -> {
val owner = this.symbol.owner
val expectedClass = this.type.classOrNull?.owner
if (expectedClass == null || !expectedClass.isObject || this.type.isNullable()) return false
owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER || owner.name.asString() == "<this>"
}
else -> false
}
}
internal fun IrFunction.isAccessorOfPropertyWithBackingField(): Boolean {
@@ -58,17 +58,18 @@ class IrInterpreterCommonChecker : IrInterpreterChecker {
}
override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean {
val owner = expression.symbol.owner
if (expression.dispatchReceiver.isAccessToNotNullableObject() && expression.isGetterToConstVal()) {
return visitBodyIfNeeded(owner, data)
}
if (!data.mode.canEvaluateExpression(expression)) return false
val owner = expression.symbol.owner
if (!data.mode.canEvaluateFunction(owner)) return false
if (expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName()) return true
if (expression.dispatchReceiver.isAccessToNotNullableObject()) {
return expression.isGetterToConstVal()
}
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, data) ?: true
if (!visitValueArguments(expression, data)) return false
@@ -146,8 +147,7 @@ class IrInterpreterCommonChecker : IrInterpreterChecker {
}
override fun visitGetObjectValue(expression: IrGetObjectValue, data: IrInterpreterCheckerData): Boolean {
// to get object value we need nothing, but it will contain only fields with compile time annotation
return true
return data.mode.canEvaluateExpression(expression)
}
override fun visitGetEnumValue(expression: IrGetEnumValue, data: IrInterpreterCheckerData): Boolean {
@@ -185,7 +185,7 @@ class IrInterpreterCommonChecker : IrInterpreterChecker {
expression.receiver == null -> property?.isConst == true && owner.initializer?.accept(this, data) == true
owner.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && property?.isConst == true -> {
val receiverComputable = (expression.receiver?.accept(this, data) ?: true)
|| expression.isAccessToNotNullableObject()
|| expression.receiver.isAccessToNotNullableObject()
val initializerComputable = owner.initializer?.accept(this, data) ?: false
receiverComputable && initializerComputable
}