[IR] Separate IrConstTransformer into two distinct classes
The first one `IrConstExpressionTransformer` is responsible for transforming ordinary expressions and the second one `IrConstAnnotationTransformer` is responsible for annotations. #KT-57812
This commit is contained in:
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
|||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.IrConstTransformer
|
import org.jetbrains.kotlin.ir.interpreter.checker.transformConst
|
||||||
import org.jetbrains.kotlin.ir.util.KotlinMangler
|
import org.jetbrains.kotlin.ir.util.KotlinMangler
|
||||||
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
|
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
@@ -431,12 +431,7 @@ class Fir2IrConverter(
|
|||||||
val interpreter = IrInterpreter(IrInterpreterEnvironment(irModuleFragment.irBuiltins, configuration))
|
val interpreter = IrInterpreter(IrInterpreterEnvironment(irModuleFragment.irBuiltins, configuration))
|
||||||
val mode = if (intrinsicConstEvaluation) EvaluationMode.ONLY_INTRINSIC_CONST else EvaluationMode.ONLY_BUILTINS
|
val mode = if (intrinsicConstEvaluation) EvaluationMode.ONLY_INTRINSIC_CONST else EvaluationMode.ONLY_BUILTINS
|
||||||
irModuleFragment.files.forEach {
|
irModuleFragment.files.forEach {
|
||||||
val transformer = IrConstTransformer(
|
it.transformConst(interpreter, mode = mode, evaluatedConstTracker = fir2IrConfiguration.evaluatedConstTracker)
|
||||||
interpreter, it,
|
|
||||||
mode = mode,
|
|
||||||
evaluatedConstTracker = fir2IrConfiguration.evaluatedConstTracker
|
|
||||||
)
|
|
||||||
it.transformChildren(transformer, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-7
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
|||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.IrConstTransformer
|
import org.jetbrains.kotlin.ir.interpreter.checker.transformConst
|
||||||
|
|
||||||
class ConstEvaluationLowering(
|
class ConstEvaluationLowering(
|
||||||
val context: CommonBackendContext,
|
val context: CommonBackendContext,
|
||||||
@@ -28,13 +28,9 @@ class ConstEvaluationLowering(
|
|||||||
private val evaluatedConstTracker = context.configuration[CommonConfigurationKeys.EVALUATED_CONST_TRACKER]
|
private val evaluatedConstTracker = context.configuration[CommonConfigurationKeys.EVALUATED_CONST_TRACKER]
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
val transformer = IrConstTransformer(
|
irFile.transformConst(
|
||||||
interpreter, irFile,
|
interpreter, mode = EvaluationMode.ONLY_INTRINSIC_CONST, evaluatedConstTracker, onWarning, onError, suppressErrors
|
||||||
mode = EvaluationMode.ONLY_INTRINSIC_CONST,
|
|
||||||
evaluatedConstTracker,
|
|
||||||
onWarning, onError, suppressErrors
|
|
||||||
)
|
)
|
||||||
irFile.transformChildren(transformer, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.interpreter.checker
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.isPrimitiveArray
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
|
||||||
|
internal class IrConstAnnotationTransformer(
|
||||||
|
interpreter: IrInterpreter,
|
||||||
|
irFile: IrFile,
|
||||||
|
mode: EvaluationMode,
|
||||||
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
|
suppressExceptions: Boolean,
|
||||||
|
) : IrConstTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions) {
|
||||||
|
override fun visitField(declaration: IrField): IrStatement {
|
||||||
|
transformAnnotations(declaration)
|
||||||
|
return super.visitField(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
||||||
|
transformAnnotations(declaration)
|
||||||
|
return super.visitDeclaration(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun transformAnnotations(annotationContainer: IrAnnotationContainer) {
|
||||||
|
annotationContainer.annotations.forEach { annotation ->
|
||||||
|
transformAnnotation(annotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun transformAnnotation(annotation: IrConstructorCall) {
|
||||||
|
for (i in 0 until annotation.valueArgumentsCount) {
|
||||||
|
val arg = annotation.getValueArgument(i) ?: continue
|
||||||
|
when (arg) {
|
||||||
|
is IrVararg -> annotation.putValueArgument(i, arg.transformVarArg())
|
||||||
|
else -> annotation.putValueArgument(i, arg.transformSingleArg(annotation.symbol.owner.valueParameters[i].type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrVararg.transformVarArg(): IrVararg {
|
||||||
|
if (elements.isEmpty()) return this
|
||||||
|
val newIrVararg = IrVarargImpl(this.startOffset, this.endOffset, this.type, this.varargElementType)
|
||||||
|
for (element in this.elements) {
|
||||||
|
when (val arg = (element as? IrSpreadElement)?.expression ?: element) {
|
||||||
|
is IrVararg -> arg.transformVarArg().elements.forEach { newIrVararg.addElement(it) }
|
||||||
|
is IrExpression -> newIrVararg.addElement(arg.transformSingleArg(this.varargElementType))
|
||||||
|
else -> newIrVararg.addElement(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newIrVararg
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.transformSingleArg(expectedType: IrType): IrExpression {
|
||||||
|
if (this.canBeInterpreted(configuration = interpreter.environment.configuration.copy(treatFloatInSpecialWay = false))) {
|
||||||
|
return this.interpret(failAsError = true).convertToConstIfPossible(expectedType)
|
||||||
|
} else if (this is IrConstructorCall) {
|
||||||
|
transformAnnotation(this)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.convertToConstIfPossible(type: IrType): IrExpression {
|
||||||
|
return when {
|
||||||
|
this !is IrConst<*> || type is IrErrorType -> this
|
||||||
|
type.isArray() -> this.convertToConstIfPossible((type as IrSimpleType).arguments.single().typeOrNull!!)
|
||||||
|
type.isPrimitiveArray() -> this.convertToConstIfPossible(this.type)
|
||||||
|
else -> this.value.toIrConst(type, this.startOffset, this.endOffset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.interpreter.checker
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
internal class IrConstExpressionTransformer(
|
||||||
|
interpreter: IrInterpreter,
|
||||||
|
irFile: IrFile,
|
||||||
|
mode: EvaluationMode,
|
||||||
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
|
suppressExceptions: Boolean,
|
||||||
|
) : IrConstTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions) {
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
if (expression.canBeInterpreted()) {
|
||||||
|
return expression.interpret(failAsError = false)
|
||||||
|
}
|
||||||
|
return super.visitCall(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField): IrStatement {
|
||||||
|
val initializer = declaration.initializer
|
||||||
|
val expression = initializer?.expression ?: return declaration
|
||||||
|
val isConst = declaration.correspondingPropertySymbol?.owner?.isConst == true
|
||||||
|
if (!isConst) return super.visitField(declaration)
|
||||||
|
|
||||||
|
if (expression.canBeInterpreted(declaration, interpreter.environment.configuration.copy(treatFloatInSpecialWay = false))) {
|
||||||
|
initializer.expression = expression.interpret(failAsError = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitField(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
|
||||||
|
fun IrExpression.wrapInStringConcat(): IrExpression = IrStringConcatenationImpl(
|
||||||
|
this.startOffset, this.endOffset, expression.type, listOf(this@wrapInStringConcat)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = false)
|
||||||
|
|
||||||
|
// here `StringBuilder`'s list is used to optimize memory, everything works without it
|
||||||
|
val folded = mutableListOf<IrExpression>()
|
||||||
|
val buildersList = mutableListOf<StringBuilder>()
|
||||||
|
for (next in expression.arguments) {
|
||||||
|
val last = folded.lastOrNull()
|
||||||
|
when {
|
||||||
|
!next.wrapInStringConcat().canBeInterpreted() -> {
|
||||||
|
folded += next
|
||||||
|
buildersList.add(StringBuilder())
|
||||||
|
}
|
||||||
|
last == null || !last.wrapInStringConcat().canBeInterpreted() -> {
|
||||||
|
val result = next.wrapInToStringConcatAndInterpret()
|
||||||
|
folded += result
|
||||||
|
buildersList.add(StringBuilder((result as? IrConst<*>)?.value?.toString() ?: ""))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val nextAsConst = next.wrapInToStringConcatAndInterpret()
|
||||||
|
if (nextAsConst !is IrConst<*>) {
|
||||||
|
folded += next
|
||||||
|
buildersList.add(StringBuilder())
|
||||||
|
} else {
|
||||||
|
folded[folded.size - 1] = IrConstImpl.string(
|
||||||
|
// Inlined strings may have `last.startOffset > next.endOffset`
|
||||||
|
min(last.startOffset, next.startOffset), max(last.endOffset, next.endOffset), expression.type, ""
|
||||||
|
)
|
||||||
|
buildersList.last().append(nextAsConst.value.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val foldedConst = folded.singleOrNull() as? IrConst<*>
|
||||||
|
if (foldedConst != null) {
|
||||||
|
return IrConstImpl.string(expression.startOffset, expression.endOffset, expression.type, buildersList.single().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
folded.zip(buildersList).forEach {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
(it.first as? IrConst<String>)?.value = it.second.toString()
|
||||||
|
}
|
||||||
|
return IrStringConcatenationImpl(expression.startOffset, expression.endOffset, expression.type, folded)
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
-142
@@ -8,29 +8,45 @@ package org.jetbrains.kotlin.ir.interpreter.checker
|
|||||||
import org.jetbrains.kotlin.constant.ErrorValue
|
import org.jetbrains.kotlin.constant.ErrorValue
|
||||||
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.name
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrErrorExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
||||||
import org.jetbrains.kotlin.ir.interpreter.*
|
import org.jetbrains.kotlin.ir.interpreter.toConstantValue
|
||||||
import org.jetbrains.kotlin.ir.interpreter.isPrimitiveArray
|
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
class IrConstTransformer(
|
fun IrFile.transformConst(
|
||||||
private val interpreter: IrInterpreter,
|
interpreter: IrInterpreter,
|
||||||
|
mode: EvaluationMode,
|
||||||
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
|
||||||
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
|
||||||
|
suppressExceptions: Boolean = false,
|
||||||
|
) {
|
||||||
|
val irConstExpressionTransformer = IrConstExpressionTransformer(
|
||||||
|
interpreter, this, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
||||||
|
)
|
||||||
|
val irConstAnnotationTransformer = IrConstAnnotationTransformer(
|
||||||
|
interpreter, this, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
||||||
|
)
|
||||||
|
this.transform(irConstExpressionTransformer, null)
|
||||||
|
this.transform(irConstAnnotationTransformer, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class IrConstTransformer(
|
||||||
|
protected val interpreter: IrInterpreter,
|
||||||
private val irFile: IrFile,
|
private val irFile: IrFile,
|
||||||
private val mode: EvaluationMode,
|
private val mode: EvaluationMode,
|
||||||
private val evaluatedConstTracker: EvaluatedConstTracker? = null,
|
private val evaluatedConstTracker: EvaluatedConstTracker? = null,
|
||||||
private val onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
|
private val onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
private val onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
|
private val onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
private val suppressExceptions: Boolean = false,
|
private val suppressExceptions: Boolean,
|
||||||
) : IrElementTransformerVoid() {
|
) : IrElementTransformerVoid() {
|
||||||
private fun IrExpression.warningIfError(original: IrExpression): IrExpression {
|
private fun IrExpression.warningIfError(original: IrExpression): IrExpression {
|
||||||
if (this is IrErrorExpression) {
|
if (this is IrErrorExpression) {
|
||||||
@@ -52,7 +68,7 @@ class IrConstTransformer(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrExpression.canBeInterpreted(
|
protected fun IrExpression.canBeInterpreted(
|
||||||
containingDeclaration: IrElement? = null,
|
containingDeclaration: IrElement? = null,
|
||||||
configuration: IrInterpreterConfiguration = interpreter.environment.configuration
|
configuration: IrInterpreterConfiguration = interpreter.environment.configuration
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -66,7 +82,7 @@ class IrConstTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrExpression.interpret(failAsError: Boolean): IrExpression {
|
protected fun IrExpression.interpret(failAsError: Boolean): IrExpression {
|
||||||
val result = try {
|
val result = try {
|
||||||
interpreter.interpret(this, irFile)
|
interpreter.interpret(this, irFile)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
@@ -83,128 +99,4 @@ class IrConstTransformer(
|
|||||||
)
|
)
|
||||||
return if (failAsError) result.reportIfError(this) else result.warningIfError(this)
|
return if (failAsError) result.reportIfError(this) else result.warningIfError(this)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
|
||||||
if (expression.canBeInterpreted()) {
|
|
||||||
return expression.interpret(failAsError = false)
|
|
||||||
}
|
|
||||||
return super.visitCall(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitField(declaration: IrField): IrStatement {
|
|
||||||
transformAnnotations(declaration)
|
|
||||||
|
|
||||||
val initializer = declaration.initializer
|
|
||||||
val expression = initializer?.expression ?: return declaration
|
|
||||||
val isConst = declaration.correspondingPropertySymbol?.owner?.isConst == true
|
|
||||||
if (!isConst) return super.visitField(declaration)
|
|
||||||
|
|
||||||
if (expression.canBeInterpreted(declaration, interpreter.environment.configuration.copy(treatFloatInSpecialWay = false))) {
|
|
||||||
initializer.expression = expression.interpret(failAsError = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.visitField(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
|
|
||||||
fun IrExpression.wrapInStringConcat(): IrExpression = IrStringConcatenationImpl(
|
|
||||||
this.startOffset, this.endOffset, expression.type, listOf(this@wrapInStringConcat)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = false)
|
|
||||||
|
|
||||||
// here `StringBuilder`'s list is used to optimize memory, everything works without it
|
|
||||||
val folded = mutableListOf<IrExpression>()
|
|
||||||
val buildersList = mutableListOf<StringBuilder>()
|
|
||||||
for (next in expression.arguments) {
|
|
||||||
val last = folded.lastOrNull()
|
|
||||||
when {
|
|
||||||
!next.wrapInStringConcat().canBeInterpreted() -> {
|
|
||||||
folded += next
|
|
||||||
buildersList.add(StringBuilder())
|
|
||||||
}
|
|
||||||
last == null || !last.wrapInStringConcat().canBeInterpreted() -> {
|
|
||||||
val result = next.wrapInToStringConcatAndInterpret()
|
|
||||||
folded += result
|
|
||||||
buildersList.add(StringBuilder((result as? IrConst<*>)?.value?.toString() ?: ""))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val nextAsConst = next.wrapInToStringConcatAndInterpret()
|
|
||||||
if (nextAsConst !is IrConst<*>) {
|
|
||||||
folded += next
|
|
||||||
buildersList.add(StringBuilder())
|
|
||||||
} else {
|
|
||||||
folded[folded.size - 1] = IrConstImpl.string(
|
|
||||||
// Inlined strings may have `last.startOffset > next.endOffset`
|
|
||||||
min(last.startOffset, next.startOffset), max(last.endOffset, next.endOffset), expression.type, ""
|
|
||||||
)
|
|
||||||
buildersList.last().append(nextAsConst.value.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val foldedConst = folded.singleOrNull() as? IrConst<*>
|
|
||||||
if (foldedConst != null) {
|
|
||||||
return IrConstImpl.string(expression.startOffset, expression.endOffset, expression.type, buildersList.single().toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
folded.zip(buildersList).forEach {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
(it.first as? IrConst<String>)?.value = it.second.toString()
|
|
||||||
}
|
|
||||||
return IrStringConcatenationImpl(expression.startOffset, expression.endOffset, expression.type, folded)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
|
||||||
transformAnnotations(declaration)
|
|
||||||
return super.visitDeclaration(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun transformAnnotations(annotationContainer: IrAnnotationContainer) {
|
|
||||||
annotationContainer.annotations.forEach { annotation ->
|
|
||||||
transformAnnotation(annotation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun transformAnnotation(annotation: IrConstructorCall) {
|
|
||||||
for (i in 0 until annotation.valueArgumentsCount) {
|
|
||||||
val arg = annotation.getValueArgument(i) ?: continue
|
|
||||||
when (arg) {
|
|
||||||
is IrVararg -> annotation.putValueArgument(i, arg.transformVarArg())
|
|
||||||
else -> annotation.putValueArgument(i, arg.transformSingleArg(annotation.symbol.owner.valueParameters[i].type))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrVararg.transformVarArg(): IrVararg {
|
|
||||||
if (elements.isEmpty()) return this
|
|
||||||
val newIrVararg = IrVarargImpl(this.startOffset, this.endOffset, this.type, this.varargElementType)
|
|
||||||
for (element in this.elements) {
|
|
||||||
when (val arg = (element as? IrSpreadElement)?.expression ?: element) {
|
|
||||||
is IrVararg -> arg.transformVarArg().elements.forEach { newIrVararg.addElement(it) }
|
|
||||||
is IrExpression -> newIrVararg.addElement(arg.transformSingleArg(this.varargElementType))
|
|
||||||
else -> newIrVararg.addElement(arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newIrVararg
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrExpression.transformSingleArg(expectedType: IrType): IrExpression {
|
|
||||||
if (this.canBeInterpreted(configuration = interpreter.environment.configuration.copy(treatFloatInSpecialWay = false))) {
|
|
||||||
return this.interpret(failAsError = true).convertToConstIfPossible(expectedType)
|
|
||||||
} else if (this is IrConstructorCall) {
|
|
||||||
transformAnnotation(this)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrExpression.convertToConstIfPossible(type: IrType): IrExpression {
|
|
||||||
return when {
|
|
||||||
this !is IrConst<*> || type is IrErrorType -> this
|
|
||||||
type.isArray() -> this.convertToConstIfPossible((type as IrSimpleType).arguments.single().typeOrNull!!)
|
|
||||||
type.isPrimitiveArray() -> this.convertToConstIfPossible(this.type)
|
|
||||||
else -> this.value.toIrConst(type, this.startOffset, this.endOffset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user