Introduce new ir nodes for constant values

This commit is contained in:
Pavel Kunyavskiy
2021-07-12 14:44:57 +03:00
committed by Space
parent 0764cef82f
commit bf3c343ced
10 changed files with 277 additions and 0 deletions
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.IrType
abstract class IrConstantValue : IrExpression() {
abstract fun contentEquals(other: IrConstantValue) : Boolean
abstract fun contentHashCode(): Int
}
abstract class IrConstantPrimitive : IrConstantValue() {
abstract var value: IrConst<*>
}
abstract class IrConstantObject : IrConstantValue() {
abstract val constructor: IrConstructorSymbol
abstract val valueArguments: List<IrConstantValue>
abstract val typeArguments: List<IrType>
abstract fun putArgument(index: Int, value: IrConstantValue)
}
abstract class IrConstantArray : IrConstantValue() {
abstract val elements: List<IrConstantValue>
abstract fun putElement(index: Int, value: IrConstantValue)
}
@@ -0,0 +1,131 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.expressions.impl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.transformInPlace
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.utils.SmartList
class IrConstantPrimitiveImpl(
override val startOffset: Int,
override val endOffset: Int,
override var value: IrConst<*>,
) : IrConstantPrimitive() {
override fun contentEquals(other: IrConstantValue) =
other is IrConstantPrimitive &&
value.type == other.value.type &&
value.kind == other.value.kind &&
value.value == other.value
override fun contentHashCode() =
(value.type.hashCode() * 31 + value.kind.hashCode()) * 31 + value.value.hashCode()
override var type = value.type
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
value.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
value = value.transform(transformer, data) as IrConst<*>
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitConstantPrimitive(this, data)
}
}
class IrConstantObjectImpl constructor(
override val startOffset: Int,
override val endOffset: Int,
override val constructor: IrConstructorSymbol,
initArguments: List<IrConstantValue>,
override val typeArguments: List<IrType>,
override var type: IrType = constructor.owner.constructedClassType,
) : IrConstantObject() {
override val valueArguments = SmartList(initArguments)
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitConstantObject(this, data)
}
override fun putArgument(index: Int, value: IrConstantValue) {
valueArguments[index] = value
}
override fun contentEquals(other: IrConstantValue): Boolean =
other is IrConstantObject &&
other.type == type &&
other.constructor == constructor &&
valueArguments.size == other.valueArguments.size &&
typeArguments.size == other.typeArguments.size &&
valueArguments.indices.all { index -> valueArguments[index].contentEquals(other.valueArguments[index]) } &&
typeArguments.indices.all { index -> typeArguments[index] == other.typeArguments[index] }
override fun contentHashCode(): Int {
var res = type.hashCode() * 31 + constructor.hashCode()
for (value in valueArguments) {
res = res * 31 + value.contentHashCode()
}
for (value in typeArguments) {
res = res * 31 + value.hashCode()
}
return res
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
valueArguments.forEach { value -> value.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
valueArguments.transformInPlace { it.transform(transformer, data) }
}
}
class IrConstantArrayImpl(
override val startOffset: Int,
override val endOffset: Int,
override var type: IrType,
initElements: List<IrConstantValue>,
) : IrConstantArray() {
override val elements = SmartList(initElements)
override fun putElement(index: Int, value: IrConstantValue) {
elements[index] = value
}
override fun contentEquals(other: IrConstantValue): Boolean =
other is IrConstantArray &&
other.type == type &&
elements.size == other.elements.size &&
elements.indices.all { elements[it].contentEquals(other.elements[it]) }
override fun contentHashCode(): Int {
var res = type.hashCode()
for (value in elements) {
res = res * 31 + value.contentHashCode()
}
return res
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitConstantArray(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
elements.forEach { value -> value.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
elements.transformInPlace { value -> value.transform(transformer, data) }
}
}
@@ -410,6 +410,28 @@ open class DeepCopyIrTreeWithSymbols(
override fun <T> visitConst(expression: IrConst<T>): IrConst<T> =
expression.shallowCopy().copyAttributes(expression)
override fun visitConstantObject(expression: IrConstantObject): IrConstantValue =
IrConstantObjectImpl(
expression.startOffset, expression.endOffset,
symbolRemapper.getReferencedConstructor(expression.constructor),
expression.valueArguments.transform(),
expression.typeArguments.map { it.remapType() },
expression.type.remapType()
).copyAttributes(expression)
override fun visitConstantPrimitive(expression: IrConstantPrimitive): IrConstantValue =
IrConstantPrimitiveImpl(
expression.startOffset, expression.endOffset,
expression.value.transform()
).copyAttributes(expression)
override fun visitConstantArray(expression: IrConstantArray): IrConstantValue =
IrConstantArrayImpl(
expression.startOffset, expression.endOffset,
expression.type.remapType(),
expression.elements.transform(),
).copyAttributes(expression)
override fun visitVararg(expression: IrVararg): IrVararg =
IrVarargImpl(
expression.startOffset, expression.endOffset,
@@ -344,6 +344,22 @@ class DumpIrTreeVisitor(
}
}
override fun visitConstantArray(expression: IrConstantArray, data: String) {
expression.dumpLabeledElementWith(data) {
for ((i, value) in expression.elements.withIndex()) {
value.accept(this, i.toString())
}
}
}
override fun visitConstantObject(expression: IrConstantObject, data: String) {
expression.dumpLabeledElementWith(data) {
for ((index, argument) in expression.valueArguments.withIndex()) {
argument.accept(this, expression.constructor.owner.valueParameters[index].name.toString())
}
}
}
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
printer.println(accept(elementRenderer, null).withLabel(label))
indented(body)
@@ -727,6 +727,16 @@ class RenderIrElementVisitor(private val normalizeNames: Boolean = false, privat
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String =
"ERROR_CALL '${expression.description}' type=${expression.type.render()}"
override fun visitConstantArray(expression: IrConstantArray, data: Nothing?): String =
"CONSTANT_ARRAY type=${expression.type.render()}"
override fun visitConstantObject(expression: IrConstantObject, data: Nothing?): String =
"CONSTANT_OBJECT type=${expression.type.render()} constructor=${expression.constructor.renderReference()}"
override fun visitConstantPrimitive(expression: IrConstantPrimitive, data: Nothing?): String =
"CONSTANT_PRIMITIVE type=${expression.type.render()}"
private val descriptorRendererForErrorDeclarations = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES
}
@@ -81,6 +81,14 @@ interface IrElementTransformer<in D> : IrElementVisitor<IrElement, D> {
override fun <T> visitConst(expression: IrConst<T>, data: D) = visitExpression(expression, data)
override fun visitVararg(expression: IrVararg, data: D) = visitExpression(expression, data)
override fun visitConstantValue(expression: IrConstantValue, data: D) : IrConstantValue {
expression.transformChildren(this, data)
return expression
}
override fun visitConstantObject(expression: IrConstantObject, data: D) = visitConstantValue(expression, data)
override fun visitConstantPrimitive(expression: IrConstantPrimitive, data: D) = visitConstantValue(expression, data)
override fun visitConstantArray(expression: IrConstantArray, data: D) = visitConstantValue(expression, data)
override fun visitSpreadElement(spread: IrSpreadElement, data: D): IrSpreadElement {
spread.transformChildren(this, data)
@@ -137,6 +137,22 @@ abstract class IrElementTransformerVoid : IrElementTransformer<Nothing?> {
open fun <T> visitConst(expression: IrConst<T>) = visitExpression(expression)
final override fun <T> visitConst(expression: IrConst<T>, data: Nothing?) = visitConst(expression)
open fun visitConstantValue(expression: IrConstantValue) : IrConstantValue {
expression.transformChildren(this, null)
return expression
}
final override fun visitConstantValue(expression: IrConstantValue, data: Nothing?) = visitConstantValue(expression)
open fun visitConstantObject(expression: IrConstantObject) = visitConstantValue(expression)
final override fun visitConstantObject(expression: IrConstantObject, data: Nothing?) = visitConstantObject(expression)
open fun visitConstantPrimitive(expression: IrConstantPrimitive) = visitConstantValue(expression)
final override fun visitConstantPrimitive(expression: IrConstantPrimitive, data: Nothing?) = visitConstantPrimitive(expression)
open fun visitConstantArray(expression: IrConstantArray) = visitConstantValue(expression)
final override fun visitConstantArray(expression: IrConstantArray, data: Nothing?) = visitConstantArray(expression)
open fun visitVararg(expression: IrVararg) = visitExpression(expression)
final override fun visitVararg(expression: IrVararg, data: Nothing?) = visitVararg(expression)
@@ -53,6 +53,10 @@ interface IrElementVisitor<out R, in D> {
fun visitExpression(expression: IrExpression, data: D) = visitElement(expression, data)
fun <T> visitConst(expression: IrConst<T>, data: D) = visitExpression(expression, data)
fun visitConstantValue(expression: IrConstantValue, data: D) = visitExpression(expression, data)
fun visitConstantObject(expression: IrConstantObject, data: D) = visitConstantValue(expression, data)
fun visitConstantPrimitive(expression: IrConstantPrimitive, data: D) = visitConstantValue(expression, data)
fun visitConstantArray(expression: IrConstantArray, data: D) = visitConstantValue(expression, data)
fun visitVararg(expression: IrVararg, data: D) = visitExpression(expression, data)
fun visitSpreadElement(spread: IrSpreadElement, data: D) = visitElement(spread, data)
@@ -107,6 +107,18 @@ interface IrElementVisitorVoid : IrElementVisitor<Unit, Nothing?> {
fun <T> visitConst(expression: IrConst<T>) = visitExpression(expression)
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?) = visitConst(expression)
fun visitConstantValue(expression: IrConstantValue) = visitExpression(expression)
override fun visitConstantValue(expression: IrConstantValue, data: Nothing?) = visitConstantValue(expression)
fun visitConstantObject(expression: IrConstantObject) = visitConstantValue(expression)
override fun visitConstantObject(expression: IrConstantObject, data: Nothing?) = visitConstantObject(expression)
fun visitConstantPrimitive(expression: IrConstantPrimitive) = visitConstantValue(expression)
override fun visitConstantPrimitive(expression: IrConstantPrimitive, data: Nothing?) = visitConstantPrimitive(expression)
fun visitConstantArray(expression: IrConstantArray) = visitConstantValue(expression)
override fun visitConstantArray(expression: IrConstantArray, data: Nothing?) = visitConstantArray(expression)
fun visitVararg(expression: IrVararg) = visitExpression(expression)
override fun visitVararg(expression: IrVararg, data: Nothing?) = visitVararg(expression)
@@ -16,9 +16,13 @@ import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isBoxedArray
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import java.lang.IllegalStateException
/**
@@ -269,6 +273,30 @@ internal abstract class AbstractValueUsageTransformer(
return declaration
}
override fun visitConstantArray(expression: IrConstantArray): IrConstantValue {
expression.transformChildrenVoid(this)
val elementType = if (expression.type.isBoxedArray)
irBuiltIns.anyNType
else
irBuiltIns.primitiveArrayElementTypes[expression.type.getClass()?.symbol]
?: throw IllegalStateException("Unexpected array type ${expression.type.render()}")
expression.elements.forEachIndexed { index, it ->
expression.putElement(index, it.useAs(elementType) as IrConstantValue)
}
return expression
}
override fun visitConstantObject(expression: IrConstantObject): IrConstantValue {
expression.transformChildrenVoid(this)
expression.valueArguments.forEachIndexed { index, arg ->
expression.putArgument(index, arg.useAsArgument(expression.constructor.owner.valueParameters[index]) as IrConstantValue)
}
return expression
}
// TODO: IrStringConcatenation, IrEnumEntry?
}