From 70560fc3eb04fc79a677f1b6702340f1c21c1d4d Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Fri, 28 Apr 2023 14:28:50 +0200 Subject: [PATCH] [IR] Handle each interpreter checker one by one This wy we can interpret all expressions like `A::a.name` at first and after that evaluate all complex expressions like `A::a.name + A::b.name`. --- .../checker/IrInterpreterChecker.kt | 7 ++- .../checker/IrInterpreterCommonChecker.kt | 40 +++++++-------- .../checker/IrInterpreterNameChecker.kt | 6 +-- .../IrInterpreterKCallableNamePreprocessor.kt | 4 ++ .../IrConstAnnotationTransformer.kt | 4 +- ...IrConstDeclarationAnnotationTransformer.kt | 5 +- .../IrConstExpressionTransformer.kt | 16 ++++-- .../transformer/IrConstTransformer.kt | 49 +++++++++---------- .../IrConstTypeAnnotationTransformer.kt | 12 +++-- .../kCallableNameWithSideEffect.kt | 3 ++ 10 files changed, 80 insertions(+), 66 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterChecker.kt index 4f158c7904d..3ba4ab0b813 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterChecker.kt @@ -9,11 +9,10 @@ import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration import org.jetbrains.kotlin.ir.visitors.IrElementVisitor -interface IrInterpreterChecker : IrElementVisitor { - val mode: EvaluationMode -} +interface IrInterpreterChecker : IrElementVisitor class IrInterpreterCheckerData( + val mode: EvaluationMode, val irBuiltIns: IrBuiltIns, - val interpreterConfiguration: IrInterpreterConfiguration + val interpreterConfiguration: IrInterpreterConfiguration, ) \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt index 919b483bbda..ffe6c9df9a7 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt @@ -17,9 +17,7 @@ import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.statements -class IrInterpreterCommonChecker( - override val mode: EvaluationMode -) : IrInterpreterChecker { +class IrInterpreterCommonChecker : IrInterpreterChecker { private val visitedStack = mutableListOf() private inline fun IrElement.asVisited(crossinline block: () -> Boolean): Boolean { @@ -42,14 +40,14 @@ class IrInterpreterCommonChecker( private fun visitConstructor(expression: IrFunctionAccessExpression, data: IrInterpreterCheckerData): Boolean { val constructor = expression.symbol.owner - if (!mode.canEvaluateFunction(constructor)) return false + if (!data.mode.canEvaluateFunction(constructor)) return false if (!visitValueArguments(expression, data)) return false return visitBodyIfNeeded(constructor, data) && constructor.parentAsClass.declarations.filterIsInstance().all { it.accept(this, data) } } private fun visitBodyIfNeeded(irFunction: IrFunction, data: IrInterpreterCheckerData): Boolean { - if (!mode.mustCheckBodyOf(irFunction)) return true + if (!data.mode.mustCheckBodyOf(irFunction)) return true return irFunction.asVisited { irFunction.body?.accept(this@IrInterpreterCommonChecker, data) ?: true } } @@ -58,10 +56,10 @@ class IrInterpreterCommonChecker( } override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateExpression(expression)) return false + if (!data.mode.canEvaluateExpression(expression)) return false val owner = expression.symbol.owner - if (!mode.canEvaluateFunction(owner)) return false + if (!data.mode.canEvaluateFunction(owner)) return false // We disable `toFloat` folding on K/JS till `toFloat` is fixed (KT-35422) // This check must be placed here instead of CallInterceptor because we still @@ -101,7 +99,7 @@ class IrInterpreterCommonChecker( } override fun visitBlock(expression: IrBlock, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateBlock(expression)) return false + if (!data.mode.canEvaluateBlock(expression)) return false // `IrReturnableBlock` will be created from IrCall after inline. We should do basically the same check as for IrCall. if (expression is IrReturnableBlock) { @@ -113,7 +111,7 @@ class IrInterpreterCommonChecker( } override fun visitComposite(expression: IrComposite, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateComposite(expression)) return false + if (!data.mode.canEvaluateComposite(expression)) return false return visitStatements(expression.statements, data) } @@ -125,7 +123,7 @@ class IrInterpreterCommonChecker( override fun visitConst(expression: IrConst<*>, data: IrInterpreterCheckerData): Boolean { if (expression.type.getUnsignedType() != null) { val constructor = expression.type.classOrNull?.owner?.constructors?.singleOrNull() ?: return false - return mode.canEvaluateFunction(constructor) + return data.mode.canEvaluateFunction(constructor) } return true } @@ -146,7 +144,7 @@ class IrInterpreterCommonChecker( .filterIsInstance() .single { it.name.asString() == "toString" && it.valueParameters.isEmpty() && it.extensionReceiverParameter == null } - mode.canEvaluateFunction(toString) && visitBodyIfNeeded(toString, data) + data.mode.canEvaluateFunction(toString) && visitBodyIfNeeded(toString, data) } else -> arg.accept(this, data) @@ -160,7 +158,7 @@ class IrInterpreterCommonChecker( } override fun visitGetEnumValue(expression: IrGetEnumValue, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateEnumValue(expression)) return false + if (!data.mode.canEvaluateEnumValue(expression)) return false // we want to avoid recursion in cases like "enum class E(val srt: String) { OK(OK.name) }" if (visitedStack.contains(expression)) return true @@ -242,20 +240,20 @@ class IrInterpreterCommonChecker( } override fun visitFunctionReference(expression: IrFunctionReference, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateCallableReference(expression)) return false + if (!data.mode.canEvaluateCallableReference(expression)) return false val owner = expression.symbol.owner val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true val extensionReceiverComputable = expression.extensionReceiver?.accept(this, data) ?: true - if (!mode.canEvaluateFunction(owner)) return false + if (!data.mode.canEvaluateFunction(owner)) return false val bodyComputable = visitBodyIfNeeded(owner, data) return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable } override fun visitFunctionExpression(expression: IrFunctionExpression, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateFunctionExpression(expression)) return false + if (!data.mode.canEvaluateFunctionExpression(expression)) return false val body = expression.function.body ?: return false return expression.function.asVisited { body.accept(this, data) } @@ -275,7 +273,7 @@ class IrInterpreterCommonChecker( } override fun visitWhen(expression: IrWhen, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateExpression(expression)) return false + if (!data.mode.canEvaluateExpression(expression)) return false return expression.branches.all { it.accept(this, data) } } @@ -297,7 +295,7 @@ class IrInterpreterCommonChecker( } override fun visitTry(aTry: IrTry, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateExpression(aTry)) return false + if (!data.mode.canEvaluateExpression(aTry)) return false if (!aTry.tryResult.accept(this, data)) return false if (aTry.finallyExpression != null && aTry.finallyExpression?.accept(this, data) == false) return false @@ -314,22 +312,22 @@ class IrInterpreterCommonChecker( } override fun visitThrow(expression: IrThrow, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateExpression(expression)) return false + if (!data.mode.canEvaluateExpression(expression)) return false return expression.value.accept(this, data) } override fun visitPropertyReference(expression: IrPropertyReference, data: IrInterpreterCheckerData): Boolean { - if (!mode.canEvaluateCallableReference(expression)) return false + if (!data.mode.canEvaluateCallableReference(expression)) return false val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true val extensionReceiverComputable = expression.extensionReceiver?.accept(this, data) ?: true - val getterIsComputable = expression.getter?.let { mode.canEvaluateFunction(it.owner) } ?: true + val getterIsComputable = expression.getter?.let { data.mode.canEvaluateFunction(it.owner) } ?: true return dispatchReceiverComputable && extensionReceiverComputable && getterIsComputable } override fun visitClassReference(expression: IrClassReference, data: IrInterpreterCheckerData): Boolean { - return mode.canEvaluateClassReference(expression) + return data.mode.canEvaluateClassReference(expression) } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt index 0b067cb5807..4ba1c92f2aa 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt @@ -16,14 +16,12 @@ import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation import org.jetbrains.kotlin.ir.util.isSubclassOf -class IrInterpreterNameChecker( - override val mode: EvaluationMode, -) : IrInterpreterChecker { +class IrInterpreterNameChecker : IrInterpreterChecker { override fun visitElement(element: IrElement, data: IrInterpreterCheckerData) = false override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean { val owner = expression.symbol.owner - if (!mode.canEvaluateFunction(owner)) return false + if (!data.mode.canEvaluateFunction(owner)) return false return expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName() } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt index cd9536dd10c..651a2c45304 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt @@ -8,8 +8,10 @@ package org.jetbrains.kotlin.ir.interpreter.preprocessor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCallableReference +import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterNameChecker.Companion.isKCallableNameCall +import org.jetbrains.kotlin.name.SpecialNames // Note: this class still will not allow us to evaluate things like `A()::a.name + `A()::b.name`. // This code will be optimized but not completely turned into "ab" result. @@ -22,8 +24,10 @@ class IrInterpreterKCallableNamePreprocessor : IrInterpreterPreprocessor { // receiver is needed for bound callable reference val receiver = callableReference.dispatchReceiver ?: callableReference.extensionReceiver ?: return expression + callableReference.dispatchReceiver = null callableReference.extensionReceiver = null + if (receiver is IrGetValue && receiver.symbol.owner.name == SpecialNames.THIS) return expression return IrCompositeImpl( expression.startOffset, expression.endOffset, expression.type, origin = null, statements = listOf(receiver, expression) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstAnnotationTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstAnnotationTransformer.kt index edd3f314dc0..c49e24f908f 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstAnnotationTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstAnnotationTransformer.kt @@ -14,6 +14,7 @@ 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.checker.EvaluationMode +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker import org.jetbrains.kotlin.ir.interpreter.isPrimitiveArray import org.jetbrains.kotlin.ir.interpreter.toIrConst import org.jetbrains.kotlin.ir.types.* @@ -22,11 +23,12 @@ internal abstract class IrConstAnnotationTransformer( interpreter: IrInterpreter, irFile: IrFile, mode: EvaluationMode, + checker: IrInterpreterChecker, evaluatedConstTracker: EvaluatedConstTracker?, onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit, onError: (IrFile, IrElement, IrErrorExpression) -> Unit, suppressExceptions: Boolean, -) : IrConstTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions) { +) : IrConstTransformer(interpreter, irFile, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions) { protected fun transformAnnotations(annotationContainer: IrAnnotationContainer) { annotationContainer.annotations.forEach { annotation -> transformAnnotation(annotation) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstDeclarationAnnotationTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstDeclarationAnnotationTransformer.kt index bf902bbaa24..fced3dbec0a 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstDeclarationAnnotationTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstDeclarationAnnotationTransformer.kt @@ -13,20 +13,21 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrErrorExpression -import org.jetbrains.kotlin.ir.expressions.IrVararg import org.jetbrains.kotlin.ir.interpreter.IrInterpreter import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker import org.jetbrains.kotlin.ir.util.primaryConstructor internal class IrConstDeclarationAnnotationTransformer( interpreter: IrInterpreter, irFile: IrFile, mode: EvaluationMode, + checker: IrInterpreterChecker, evaluatedConstTracker: EvaluatedConstTracker?, onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit, onError: (IrFile, IrElement, IrErrorExpression) -> Unit, suppressExceptions: Boolean, -) : IrConstAnnotationTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions) { +) : IrConstAnnotationTransformer(interpreter, irFile, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions) { override fun visitFile(declaration: IrFile, data: Nothing?): IrFile { transformAnnotations(declaration) return super.visitFile(declaration, data) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstExpressionTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstExpressionTransformer.kt index 9c490b42f72..156eb41c027 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstExpressionTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstExpressionTransformer.kt @@ -15,6 +15,7 @@ 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.interpreter.checker.EvaluationMode +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker import org.jetbrains.kotlin.ir.interpreter.createGetField import kotlin.math.max import kotlin.math.min @@ -23,11 +24,12 @@ internal class IrConstExpressionTransformer( interpreter: IrInterpreter, irFile: IrFile, mode: EvaluationMode, + checker: IrInterpreterChecker, evaluatedConstTracker: EvaluatedConstTracker?, onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit, onError: (IrFile, IrElement, IrErrorExpression) -> Unit, suppressExceptions: Boolean, -) : IrConstTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions) { +) : IrConstTransformer(interpreter, irFile, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions) { override fun visitCall(expression: IrCall, data: Nothing?): IrElement { if (expression.canBeInterpreted()) { return expression.interpret(failAsError = false) @@ -55,27 +57,31 @@ internal class IrConstExpressionTransformer( ) fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = false) + fun IrExpression.getConstStringOrEmpty(): String = if (this is IrConst<*>) value.toString() else "" + // If we have some complex expression in arguments (like some `IrComposite`) we will skip it, + // but we must visit this argument in order to apply all possible optimizations. + val transformed = super.visitStringConcatenation(expression, data) as? IrStringConcatenation ?: return expression // here `StringBuilder`'s list is used to optimize memory, everything works without it val folded = mutableListOf() val buildersList = mutableListOf() - for (next in expression.arguments) { + for (next in transformed.arguments) { val last = folded.lastOrNull() when { !next.wrapInStringConcat().canBeInterpreted() -> { folded += next - buildersList.add(StringBuilder()) + buildersList.add(StringBuilder(next.getConstStringOrEmpty())) } last == null || !last.wrapInStringConcat().canBeInterpreted() -> { val result = next.wrapInToStringConcatAndInterpret() folded += result - buildersList.add(StringBuilder((result as? IrConst<*>)?.value?.toString() ?: "")) + buildersList.add(StringBuilder(result.getConstStringOrEmpty())) } else -> { val nextAsConst = next.wrapInToStringConcatAndInterpret() if (nextAsConst !is IrConst<*>) { folded += next - buildersList.add(StringBuilder()) + buildersList.add(StringBuilder(next.getConstStringOrEmpty())) } else { folded[folded.size - 1] = IrConstImpl.string( // Inlined strings may have `last.startOffset > next.endOffset` diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt index 7433894e5bc..67df88c1f70 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt @@ -16,18 +16,13 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.interpreter.IrInterpreter import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration -import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode -import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterCheckerData -import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterCommonChecker -import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterNameChecker +import org.jetbrains.kotlin.ir.interpreter.checker.* import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterPreprocessorData import org.jetbrains.kotlin.ir.interpreter.toConstantValue import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.visitors.IrElementTransformer -private val preprocessors = setOf(IrInterpreterKCallableNamePreprocessor()) - fun IrFile.transformConst( interpreter: IrInterpreter, mode: EvaluationMode, @@ -36,22 +31,30 @@ fun IrFile.transformConst( onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> }, suppressExceptions: Boolean = false, ) { - val preprocessedFile = preprocessors.fold(this) { acc, preprocessor -> - preprocessor.preprocess(acc, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns)) + val preprocessors = setOf(IrInterpreterKCallableNamePreprocessor()) + val preprocessedFile = preprocessors.fold(this) { file, preprocessor -> + preprocessor.preprocess(file, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns)) } - val irConstExpressionTransformer = IrConstExpressionTransformer( - interpreter, preprocessedFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions + val checkers = setOf( + IrInterpreterNameChecker(), + IrInterpreterCommonChecker(), ) - val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer( - interpreter, preprocessedFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions - ) - val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer( - interpreter, preprocessedFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions - ) - preprocessedFile.transform(irConstExpressionTransformer, null) - preprocessedFile.transform(irConstDeclarationAnnotationTransformer, null) - preprocessedFile.transform(irConstTypeAnnotationTransformer, null) + + checkers.fold(preprocessedFile) { file, checker -> + val irConstExpressionTransformer = IrConstExpressionTransformer( + interpreter, file, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions + ) + val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer( + interpreter, file, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions + ) + val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer( + interpreter, file, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions + ) + file.transform(irConstExpressionTransformer, null) + file.transform(irConstDeclarationAnnotationTransformer, null) + file.transform(irConstTypeAnnotationTransformer, null) + } } // Note: We are using `IrElementTransformer` here instead of `IrElementTransformerVoid` to avoid conflicts with `IrTypeVisitorVoid` @@ -60,16 +63,12 @@ internal abstract class IrConstTransformer( protected val interpreter: IrInterpreter, private val irFile: IrFile, private val mode: EvaluationMode, + private val checker: IrInterpreterChecker, private val evaluatedConstTracker: EvaluatedConstTracker? = null, private val onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit, private val onError: (IrFile, IrElement, IrErrorExpression) -> Unit, private val suppressExceptions: Boolean, ) : IrElementTransformer { - private val checkers = setOf( - IrInterpreterCommonChecker(mode), - IrInterpreterNameChecker(mode) - ) - private fun IrExpression.warningIfError(original: IrExpression): IrExpression { if (this is IrErrorExpression) { onWarning(irFile, original, this) @@ -94,7 +93,7 @@ internal abstract class IrConstTransformer( configuration: IrInterpreterConfiguration = interpreter.environment.configuration ): Boolean { return try { - checkers.any { this.accept(it, IrInterpreterCheckerData(interpreter.irBuiltIns, configuration)) } + this.accept(checker, IrInterpreterCheckerData(mode, interpreter.irBuiltIns, configuration)) } catch (e: Throwable) { if (suppressExceptions) { return false diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTypeAnnotationTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTypeAnnotationTransformer.kt index a89b69d3cb5..76eabc300e7 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTypeAnnotationTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTypeAnnotationTransformer.kt @@ -7,22 +7,26 @@ package org.jetbrains.kotlin.ir.interpreter.transformer import org.jetbrains.kotlin.constant.EvaluatedConstTracker import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.expressions.IrErrorExpression import org.jetbrains.kotlin.ir.interpreter.IrInterpreter import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode -import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.typeOrNull import org.jetbrains.kotlin.ir.visitors.IrTypeTransformerVoid internal class IrConstTypeAnnotationTransformer( interpreter: IrInterpreter, irFile: IrFile, mode: EvaluationMode, + checker: IrInterpreterChecker, evaluatedConstTracker: EvaluatedConstTracker?, onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit, onError: (IrFile, IrElement, IrErrorExpression) -> Unit, suppressExceptions: Boolean, -) : IrConstAnnotationTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions), +) : IrConstAnnotationTransformer(interpreter, irFile, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions), IrTypeTransformerVoid { override fun transformType(container: IrElement, type: Type, data: Nothing?): Type { diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt index fe84c33dc6d..261623cb357 100644 --- a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt +++ b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt @@ -24,9 +24,12 @@ class A { val temp = A() val g = temp::b.name + val insideStringConcat = "${temp::b.name}" val complexExpression1 = A()::a.name + A()::b.name val complexExpression2 = A::a.name + A::b.name + + var recursive = ::test.name } fun getA(): A = A()