[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`.
This commit is contained in:
+3
-4
@@ -9,11 +9,10 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
|
|||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
interface IrInterpreterChecker : IrElementVisitor<Boolean, IrInterpreterCheckerData> {
|
interface IrInterpreterChecker : IrElementVisitor<Boolean, IrInterpreterCheckerData>
|
||||||
val mode: EvaluationMode
|
|
||||||
}
|
|
||||||
|
|
||||||
class IrInterpreterCheckerData(
|
class IrInterpreterCheckerData(
|
||||||
|
val mode: EvaluationMode,
|
||||||
val irBuiltIns: IrBuiltIns,
|
val irBuiltIns: IrBuiltIns,
|
||||||
val interpreterConfiguration: IrInterpreterConfiguration
|
val interpreterConfiguration: IrInterpreterConfiguration,
|
||||||
)
|
)
|
||||||
+19
-21
@@ -17,9 +17,7 @@ import org.jetbrains.kotlin.ir.util.constructors
|
|||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
|
|
||||||
class IrInterpreterCommonChecker(
|
class IrInterpreterCommonChecker : IrInterpreterChecker {
|
||||||
override val mode: EvaluationMode
|
|
||||||
) : IrInterpreterChecker {
|
|
||||||
private val visitedStack = mutableListOf<IrElement>()
|
private val visitedStack = mutableListOf<IrElement>()
|
||||||
|
|
||||||
private inline fun IrElement.asVisited(crossinline block: () -> Boolean): Boolean {
|
private inline fun IrElement.asVisited(crossinline block: () -> Boolean): Boolean {
|
||||||
@@ -42,14 +40,14 @@ class IrInterpreterCommonChecker(
|
|||||||
private fun visitConstructor(expression: IrFunctionAccessExpression, data: IrInterpreterCheckerData): Boolean {
|
private fun visitConstructor(expression: IrFunctionAccessExpression, data: IrInterpreterCheckerData): Boolean {
|
||||||
val constructor = expression.symbol.owner
|
val constructor = expression.symbol.owner
|
||||||
|
|
||||||
if (!mode.canEvaluateFunction(constructor)) return false
|
if (!data.mode.canEvaluateFunction(constructor)) return false
|
||||||
if (!visitValueArguments(expression, data)) return false
|
if (!visitValueArguments(expression, data)) return false
|
||||||
return visitBodyIfNeeded(constructor, data) &&
|
return visitBodyIfNeeded(constructor, data) &&
|
||||||
constructor.parentAsClass.declarations.filterIsInstance<IrAnonymousInitializer>().all { it.accept(this, data) }
|
constructor.parentAsClass.declarations.filterIsInstance<IrAnonymousInitializer>().all { it.accept(this, data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun visitBodyIfNeeded(irFunction: IrFunction, data: IrInterpreterCheckerData): Boolean {
|
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 }
|
return irFunction.asVisited { irFunction.body?.accept(this@IrInterpreterCommonChecker, data) ?: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,10 +56,10 @@ class IrInterpreterCommonChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean {
|
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
|
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)
|
// 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
|
// 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 {
|
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.
|
// `IrReturnableBlock` will be created from IrCall after inline. We should do basically the same check as for IrCall.
|
||||||
if (expression is IrReturnableBlock) {
|
if (expression is IrReturnableBlock) {
|
||||||
@@ -113,7 +111,7 @@ class IrInterpreterCommonChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitComposite(expression: IrComposite, data: IrInterpreterCheckerData): Boolean {
|
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)
|
return visitStatements(expression.statements, data)
|
||||||
}
|
}
|
||||||
@@ -125,7 +123,7 @@ class IrInterpreterCommonChecker(
|
|||||||
override fun visitConst(expression: IrConst<*>, data: IrInterpreterCheckerData): Boolean {
|
override fun visitConst(expression: IrConst<*>, data: IrInterpreterCheckerData): Boolean {
|
||||||
if (expression.type.getUnsignedType() != null) {
|
if (expression.type.getUnsignedType() != null) {
|
||||||
val constructor = expression.type.classOrNull?.owner?.constructors?.singleOrNull() ?: return false
|
val constructor = expression.type.classOrNull?.owner?.constructors?.singleOrNull() ?: return false
|
||||||
return mode.canEvaluateFunction(constructor)
|
return data.mode.canEvaluateFunction(constructor)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -146,7 +144,7 @@ class IrInterpreterCommonChecker(
|
|||||||
.filterIsInstance<IrSimpleFunction>()
|
.filterIsInstance<IrSimpleFunction>()
|
||||||
.single { it.name.asString() == "toString" && it.valueParameters.isEmpty() && it.extensionReceiverParameter == null }
|
.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)
|
else -> arg.accept(this, data)
|
||||||
@@ -160,7 +158,7 @@ class IrInterpreterCommonChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetEnumValue(expression: IrGetEnumValue, data: IrInterpreterCheckerData): Boolean {
|
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) }"
|
// we want to avoid recursion in cases like "enum class E(val srt: String) { OK(OK.name) }"
|
||||||
if (visitedStack.contains(expression)) return true
|
if (visitedStack.contains(expression)) return true
|
||||||
@@ -242,20 +240,20 @@ class IrInterpreterCommonChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference, data: IrInterpreterCheckerData): Boolean {
|
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 owner = expression.symbol.owner
|
||||||
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true
|
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true
|
||||||
val extensionReceiverComputable = expression.extensionReceiver?.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)
|
val bodyComputable = visitBodyIfNeeded(owner, data)
|
||||||
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
|
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionExpression(expression: IrFunctionExpression, data: IrInterpreterCheckerData): Boolean {
|
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
|
val body = expression.function.body ?: return false
|
||||||
return expression.function.asVisited { body.accept(this, data) }
|
return expression.function.asVisited { body.accept(this, data) }
|
||||||
@@ -275,7 +273,7 @@ class IrInterpreterCommonChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: IrInterpreterCheckerData): Boolean {
|
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) }
|
return expression.branches.all { it.accept(this, data) }
|
||||||
}
|
}
|
||||||
@@ -297,7 +295,7 @@ class IrInterpreterCommonChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTry(aTry: IrTry, data: IrInterpreterCheckerData): Boolean {
|
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.tryResult.accept(this, data)) return false
|
||||||
if (aTry.finallyExpression != null && aTry.finallyExpression?.accept(this, data) == false) 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 {
|
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)
|
return expression.value.accept(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitPropertyReference(expression: IrPropertyReference, data: IrInterpreterCheckerData): Boolean {
|
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 dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true
|
||||||
val extensionReceiverComputable = expression.extensionReceiver?.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
|
return dispatchReceiverComputable && extensionReceiverComputable && getterIsComputable
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClassReference(expression: IrClassReference, data: IrInterpreterCheckerData): Boolean {
|
override fun visitClassReference(expression: IrClassReference, data: IrInterpreterCheckerData): Boolean {
|
||||||
return mode.canEvaluateClassReference(expression)
|
return data.mode.canEvaluateClassReference(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-4
@@ -16,14 +16,12 @@ import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||||
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
||||||
|
|
||||||
class IrInterpreterNameChecker(
|
class IrInterpreterNameChecker : IrInterpreterChecker {
|
||||||
override val mode: EvaluationMode,
|
|
||||||
) : IrInterpreterChecker {
|
|
||||||
override fun visitElement(element: IrElement, data: IrInterpreterCheckerData) = false
|
override fun visitElement(element: IrElement, data: IrInterpreterCheckerData) = false
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean {
|
override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean {
|
||||||
val owner = expression.symbol.owner
|
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()
|
return expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName()
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -8,8 +8,10 @@ package org.jetbrains.kotlin.ir.interpreter.preprocessor
|
|||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCallableReference
|
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.expressions.impl.IrCompositeImpl
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterNameChecker.Companion.isKCallableNameCall
|
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`.
|
// 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.
|
// 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
|
// receiver is needed for bound callable reference
|
||||||
val receiver = callableReference.dispatchReceiver ?: callableReference.extensionReceiver ?: return expression
|
val receiver = callableReference.dispatchReceiver ?: callableReference.extensionReceiver ?: return expression
|
||||||
|
|
||||||
callableReference.dispatchReceiver = null
|
callableReference.dispatchReceiver = null
|
||||||
callableReference.extensionReceiver = null
|
callableReference.extensionReceiver = null
|
||||||
|
if (receiver is IrGetValue && receiver.symbol.owner.name == SpecialNames.THIS) return expression
|
||||||
|
|
||||||
return IrCompositeImpl(
|
return IrCompositeImpl(
|
||||||
expression.startOffset, expression.endOffset, expression.type, origin = null, statements = listOf(receiver, expression)
|
expression.startOffset, expression.endOffset, expression.type, origin = null, statements = listOf(receiver, expression)
|
||||||
|
|||||||
+3
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.expressions.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
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.isPrimitiveArray
|
||||||
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -22,11 +23,12 @@ internal abstract class IrConstAnnotationTransformer(
|
|||||||
interpreter: IrInterpreter,
|
interpreter: IrInterpreter,
|
||||||
irFile: IrFile,
|
irFile: IrFile,
|
||||||
mode: EvaluationMode,
|
mode: EvaluationMode,
|
||||||
|
checker: IrInterpreterChecker,
|
||||||
evaluatedConstTracker: EvaluatedConstTracker?,
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
suppressExceptions: Boolean,
|
suppressExceptions: Boolean,
|
||||||
) : IrConstTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions) {
|
) : IrConstTransformer(interpreter, irFile, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions) {
|
||||||
protected fun transformAnnotations(annotationContainer: IrAnnotationContainer) {
|
protected fun transformAnnotations(annotationContainer: IrAnnotationContainer) {
|
||||||
annotationContainer.annotations.forEach { annotation ->
|
annotationContainer.annotations.forEach { annotation ->
|
||||||
transformAnnotation(annotation)
|
transformAnnotation(annotation)
|
||||||
|
|||||||
+3
-2
@@ -13,20 +13,21 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrErrorExpression
|
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.IrInterpreter
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker
|
||||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||||
|
|
||||||
internal class IrConstDeclarationAnnotationTransformer(
|
internal class IrConstDeclarationAnnotationTransformer(
|
||||||
interpreter: IrInterpreter,
|
interpreter: IrInterpreter,
|
||||||
irFile: IrFile,
|
irFile: IrFile,
|
||||||
mode: EvaluationMode,
|
mode: EvaluationMode,
|
||||||
|
checker: IrInterpreterChecker,
|
||||||
evaluatedConstTracker: EvaluatedConstTracker?,
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
suppressExceptions: Boolean,
|
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 {
|
override fun visitFile(declaration: IrFile, data: Nothing?): IrFile {
|
||||||
transformAnnotations(declaration)
|
transformAnnotations(declaration)
|
||||||
return super.visitFile(declaration, data)
|
return super.visitFile(declaration, data)
|
||||||
|
|||||||
+11
-5
@@ -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.expressions.impl.IrStringConcatenationImpl
|
||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker
|
||||||
import org.jetbrains.kotlin.ir.interpreter.createGetField
|
import org.jetbrains.kotlin.ir.interpreter.createGetField
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -23,11 +24,12 @@ internal class IrConstExpressionTransformer(
|
|||||||
interpreter: IrInterpreter,
|
interpreter: IrInterpreter,
|
||||||
irFile: IrFile,
|
irFile: IrFile,
|
||||||
mode: EvaluationMode,
|
mode: EvaluationMode,
|
||||||
|
checker: IrInterpreterChecker,
|
||||||
evaluatedConstTracker: EvaluatedConstTracker?,
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
suppressExceptions: Boolean,
|
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 {
|
override fun visitCall(expression: IrCall, data: Nothing?): IrElement {
|
||||||
if (expression.canBeInterpreted()) {
|
if (expression.canBeInterpreted()) {
|
||||||
return expression.interpret(failAsError = false)
|
return expression.interpret(failAsError = false)
|
||||||
@@ -55,27 +57,31 @@ internal class IrConstExpressionTransformer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = false)
|
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
|
// here `StringBuilder`'s list is used to optimize memory, everything works without it
|
||||||
val folded = mutableListOf<IrExpression>()
|
val folded = mutableListOf<IrExpression>()
|
||||||
val buildersList = mutableListOf<StringBuilder>()
|
val buildersList = mutableListOf<StringBuilder>()
|
||||||
for (next in expression.arguments) {
|
for (next in transformed.arguments) {
|
||||||
val last = folded.lastOrNull()
|
val last = folded.lastOrNull()
|
||||||
when {
|
when {
|
||||||
!next.wrapInStringConcat().canBeInterpreted() -> {
|
!next.wrapInStringConcat().canBeInterpreted() -> {
|
||||||
folded += next
|
folded += next
|
||||||
buildersList.add(StringBuilder())
|
buildersList.add(StringBuilder(next.getConstStringOrEmpty()))
|
||||||
}
|
}
|
||||||
last == null || !last.wrapInStringConcat().canBeInterpreted() -> {
|
last == null || !last.wrapInStringConcat().canBeInterpreted() -> {
|
||||||
val result = next.wrapInToStringConcatAndInterpret()
|
val result = next.wrapInToStringConcatAndInterpret()
|
||||||
folded += result
|
folded += result
|
||||||
buildersList.add(StringBuilder((result as? IrConst<*>)?.value?.toString() ?: ""))
|
buildersList.add(StringBuilder(result.getConstStringOrEmpty()))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val nextAsConst = next.wrapInToStringConcatAndInterpret()
|
val nextAsConst = next.wrapInToStringConcatAndInterpret()
|
||||||
if (nextAsConst !is IrConst<*>) {
|
if (nextAsConst !is IrConst<*>) {
|
||||||
folded += next
|
folded += next
|
||||||
buildersList.add(StringBuilder())
|
buildersList.add(StringBuilder(next.getConstStringOrEmpty()))
|
||||||
} else {
|
} else {
|
||||||
folded[folded.size - 1] = IrConstImpl.string(
|
folded[folded.size - 1] = IrConstImpl.string(
|
||||||
// Inlined strings may have `last.startOffset > next.endOffset`
|
// Inlined strings may have `last.startOffset > next.endOffset`
|
||||||
|
|||||||
+24
-25
@@ -16,18 +16,13 @@ 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.interpreter.IrInterpreter
|
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.checker.EvaluationMode
|
import org.jetbrains.kotlin.ir.interpreter.checker.*
|
||||||
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.preprocessor.IrInterpreterKCallableNamePreprocessor
|
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor
|
||||||
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterPreprocessorData
|
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterPreprocessorData
|
||||||
import org.jetbrains.kotlin.ir.interpreter.toConstantValue
|
import org.jetbrains.kotlin.ir.interpreter.toConstantValue
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
|
|
||||||
private val preprocessors = setOf(IrInterpreterKCallableNamePreprocessor())
|
|
||||||
|
|
||||||
fun IrFile.transformConst(
|
fun IrFile.transformConst(
|
||||||
interpreter: IrInterpreter,
|
interpreter: IrInterpreter,
|
||||||
mode: EvaluationMode,
|
mode: EvaluationMode,
|
||||||
@@ -36,22 +31,30 @@ fun IrFile.transformConst(
|
|||||||
onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
|
||||||
suppressExceptions: Boolean = false,
|
suppressExceptions: Boolean = false,
|
||||||
) {
|
) {
|
||||||
val preprocessedFile = preprocessors.fold(this) { acc, preprocessor ->
|
val preprocessors = setOf(IrInterpreterKCallableNamePreprocessor())
|
||||||
preprocessor.preprocess(acc, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns))
|
val preprocessedFile = preprocessors.fold(this) { file, preprocessor ->
|
||||||
|
preprocessor.preprocess(file, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns))
|
||||||
}
|
}
|
||||||
|
|
||||||
val irConstExpressionTransformer = IrConstExpressionTransformer(
|
val checkers = setOf(
|
||||||
interpreter, preprocessedFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
IrInterpreterNameChecker(),
|
||||||
|
IrInterpreterCommonChecker(),
|
||||||
)
|
)
|
||||||
val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer(
|
|
||||||
interpreter, preprocessedFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
checkers.fold(preprocessedFile) { file, checker ->
|
||||||
)
|
val irConstExpressionTransformer = IrConstExpressionTransformer(
|
||||||
val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer(
|
interpreter, file, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
||||||
interpreter, preprocessedFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
)
|
||||||
)
|
val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer(
|
||||||
preprocessedFile.transform(irConstExpressionTransformer, null)
|
interpreter, file, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions
|
||||||
preprocessedFile.transform(irConstDeclarationAnnotationTransformer, null)
|
)
|
||||||
preprocessedFile.transform(irConstTypeAnnotationTransformer, null)
|
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`
|
// 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,
|
protected val interpreter: IrInterpreter,
|
||||||
private val irFile: IrFile,
|
private val irFile: IrFile,
|
||||||
private val mode: EvaluationMode,
|
private val mode: EvaluationMode,
|
||||||
|
private val checker: IrInterpreterChecker,
|
||||||
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,
|
private val suppressExceptions: Boolean,
|
||||||
) : IrElementTransformer<Nothing?> {
|
) : IrElementTransformer<Nothing?> {
|
||||||
private val checkers = setOf(
|
|
||||||
IrInterpreterCommonChecker(mode),
|
|
||||||
IrInterpreterNameChecker(mode)
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun IrExpression.warningIfError(original: IrExpression): IrExpression {
|
private fun IrExpression.warningIfError(original: IrExpression): IrExpression {
|
||||||
if (this is IrErrorExpression) {
|
if (this is IrErrorExpression) {
|
||||||
onWarning(irFile, original, this)
|
onWarning(irFile, original, this)
|
||||||
@@ -94,7 +93,7 @@ internal abstract class IrConstTransformer(
|
|||||||
configuration: IrInterpreterConfiguration = interpreter.environment.configuration
|
configuration: IrInterpreterConfiguration = interpreter.environment.configuration
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return try {
|
return try {
|
||||||
checkers.any { this.accept(it, IrInterpreterCheckerData(interpreter.irBuiltIns, configuration)) }
|
this.accept(checker, IrInterpreterCheckerData(mode, interpreter.irBuiltIns, configuration))
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (suppressExceptions) {
|
if (suppressExceptions) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
+8
-4
@@ -7,22 +7,26 @@ package org.jetbrains.kotlin.ir.interpreter.transformer
|
|||||||
|
|
||||||
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.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.IrErrorExpression
|
||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
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
|
import org.jetbrains.kotlin.ir.visitors.IrTypeTransformerVoid
|
||||||
|
|
||||||
internal class IrConstTypeAnnotationTransformer(
|
internal class IrConstTypeAnnotationTransformer(
|
||||||
interpreter: IrInterpreter,
|
interpreter: IrInterpreter,
|
||||||
irFile: IrFile,
|
irFile: IrFile,
|
||||||
mode: EvaluationMode,
|
mode: EvaluationMode,
|
||||||
|
checker: IrInterpreterChecker,
|
||||||
evaluatedConstTracker: EvaluatedConstTracker?,
|
evaluatedConstTracker: EvaluatedConstTracker?,
|
||||||
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||||
suppressExceptions: Boolean,
|
suppressExceptions: Boolean,
|
||||||
) : IrConstAnnotationTransformer(interpreter, irFile, mode, evaluatedConstTracker, onWarning, onError, suppressExceptions),
|
) : IrConstAnnotationTransformer(interpreter, irFile, mode, checker, evaluatedConstTracker, onWarning, onError, suppressExceptions),
|
||||||
IrTypeTransformerVoid<Nothing?> {
|
IrTypeTransformerVoid<Nothing?> {
|
||||||
|
|
||||||
override fun <Type : IrType?> transformType(container: IrElement, type: Type, data: Nothing?): Type {
|
override fun <Type : IrType?> transformType(container: IrElement, type: Type, data: Nothing?): Type {
|
||||||
|
|||||||
Vendored
+3
@@ -24,9 +24,12 @@ class A {
|
|||||||
|
|
||||||
val temp = A()
|
val temp = A()
|
||||||
val g = temp::b.<!EVALUATED("b")!>name<!>
|
val g = temp::b.<!EVALUATED("b")!>name<!>
|
||||||
|
val insideStringConcat = "${temp::b.<!EVALUATED("b")!>name<!>}"
|
||||||
|
|
||||||
val complexExpression1 = A()::a.<!EVALUATED("a")!>name<!> + A()::b.<!EVALUATED("b")!>name<!>
|
val complexExpression1 = A()::a.<!EVALUATED("a")!>name<!> + A()::b.<!EVALUATED("b")!>name<!>
|
||||||
val complexExpression2 = A::a.<!EVALUATED("a")!>name<!> <!EVALUATED("ab")!>+ A::b.<!EVALUATED("b")!>name<!><!>
|
val complexExpression2 = A::a.<!EVALUATED("a")!>name<!> <!EVALUATED("ab")!>+ A::b.<!EVALUATED("b")!>name<!><!>
|
||||||
|
|
||||||
|
var recursive = ::test.<!EVALUATED("test")!>name<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getA(): A = A()
|
fun getA(): A = A()
|
||||||
|
|||||||
Reference in New Issue
Block a user