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 ed87b48437d..c4d93403202 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 @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.interpreter.accessesTopLevelOrObjectField import org.jetbrains.kotlin.ir.interpreter.fqName import org.jetbrains.kotlin.ir.interpreter.isAccessToNotNullableObject +import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isEnumName +import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isKCallableNameCall import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.parentAsClass @@ -61,6 +63,8 @@ class IrInterpreterCommonChecker : IrInterpreterChecker { 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() } 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 deleted file mode 100644 index d931588662c..00000000000 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.ir.IrBuiltIns -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrCallableReference -import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue -import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation -import org.jetbrains.kotlin.ir.interpreter.property -import org.jetbrains.kotlin.ir.util.isSubclassOf - -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 (!data.mode.canEvaluateFunction(owner)) return false - - return expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName() - } - - override fun visitStringConcatenation(expression: IrStringConcatenation, data: IrInterpreterCheckerData): Boolean { - val possibleNameCall = expression.arguments.singleOrNull() as? IrCall ?: return false - return possibleNameCall.accept(this, data) - } - - companion object { - fun IrCall.isKCallableNameCall(irBuiltIns: IrBuiltIns): Boolean { - if (this.dispatchReceiver !is IrCallableReference<*>) return false - - val directMember = this.symbol.owner.let { it.property ?: it } - - val irClass = directMember.parent as? IrClass ?: return false - if (!irClass.isSubclassOf(irBuiltIns.kCallableClass.owner)) return false - - val name = when (directMember) { - is IrSimpleFunction -> directMember.name - is IrProperty -> directMember.name - else -> throw AssertionError("Should be IrSimpleFunction or IrProperty, got $directMember") - } - return name.asString() == "name" - } - - private fun IrCall.isEnumName(): Boolean { - val owner = this.symbol.owner - if (owner.extensionReceiverParameter != null || owner.valueParameters.isNotEmpty()) return false - val property = owner.property ?: return false - return this.dispatchReceiver is IrGetEnumValue && property.name.asString() == "name" - } - } -} 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 651a2c45304..876c7977583 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 @@ -5,12 +5,18 @@ package org.jetbrains.kotlin.ir.interpreter.preprocessor +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCallableReference +import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue 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.ir.interpreter.property +import org.jetbrains.kotlin.ir.util.isSubclassOf import org.jetbrains.kotlin.name.SpecialNames // Note: this class still will not allow us to evaluate things like `A()::a.name + `A()::b.name`. @@ -33,4 +39,29 @@ class IrInterpreterKCallableNamePreprocessor : IrInterpreterPreprocessor { expression.startOffset, expression.endOffset, expression.type, origin = null, statements = listOf(receiver, expression) ) } + + companion object { + fun IrCall.isKCallableNameCall(irBuiltIns: IrBuiltIns): Boolean { + if (this.dispatchReceiver !is IrCallableReference<*>) return false + + val directMember = this.symbol.owner.let { it.property ?: it } + + val irClass = directMember.parent as? IrClass ?: return false + if (!irClass.isSubclassOf(irBuiltIns.kCallableClass.owner)) return false + + val name = when (directMember) { + is IrSimpleFunction -> directMember.name + is IrProperty -> directMember.name + else -> throw AssertionError("Should be IrSimpleFunction or IrProperty, got $directMember") + } + return name.asString() == "name" + } + + fun IrCall.isEnumName(): Boolean { + val owner = this.symbol.owner + if (owner.extensionReceiverParameter != null || owner.valueParameters.isNotEmpty()) return false + val property = owner.property ?: return false + return this.dispatchReceiver is IrGetEnumValue && property.name.asString() == "name" + } + } } \ No newline at end of file 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 ee7aa1e9216..9ca4216c3c4 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 @@ -38,25 +38,19 @@ fun IrFile.transformConst( preprocessor.preprocess(file, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns)) } - val checkers = setOf( - IrInterpreterNameChecker(), - IrInterpreterCommonChecker(), + val checker = IrInterpreterCommonChecker() + val irConstExpressionTransformer = IrConstExpressionTransformer( + interpreter, preprocessedFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions ) - - checkers.fold(preprocessedFile) { file, checker -> - val irConstExpressionTransformer = IrConstExpressionTransformer( - interpreter, file, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions - ) - val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer( - interpreter, file, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions - ) - val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer( - interpreter, file, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions - ) - file.transform(irConstExpressionTransformer, null) - file.transform(irConstDeclarationAnnotationTransformer, null) - file.transform(irConstTypeAnnotationTransformer, null) - } + val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer( + interpreter, preprocessedFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions + ) + val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer( + interpreter, preprocessedFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions + ) + preprocessedFile.transform(irConstExpressionTransformer, null) + preprocessedFile.transform(irConstDeclarationAnnotationTransformer, null) + preprocessedFile.transform(irConstTypeAnnotationTransformer, null) } // Note: We are using `IrElementTransformer` here instead of `IrElementTransformerVoid` to avoid conflicts with `IrTypeVisitorVoid` diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt index 41eb7be4069..eed382697a7 100644 --- a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt +++ b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt @@ -15,7 +15,7 @@ const val methodName = A::foo.name const val suspendMethodName = A::bar.name const val className = ::A.")!>name const val topLevelPropName = ::topLevelProp.name -const val nameInComplexExpression = A::OK.name + "!" +const val nameInComplexExpression = A::OK.name + "!" // STOP_EVALUATION_CHECKS fun box(): String { diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt index 261623cb357..f0abd4d85eb 100644 --- a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt +++ b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt @@ -27,7 +27,7 @@ class A { val insideStringConcat = "${temp::b.name}" val complexExpression1 = A()::a.name + A()::b.name - val complexExpression2 = A::a.name + A::b.name + val complexExpression2 = A::a.name + A::b.name var recursive = ::test.name }