Implement more precise control flow in ir interpreter
"More precise" in terms of the number of passing tests. In this case ControlStructures test block was used.
This commit is contained in:
committed by
TeamCityServer
parent
c3ad319c13
commit
fe99b235d3
+17
-10
@@ -496,13 +496,9 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
||||
return executionResult
|
||||
}
|
||||
|
||||
private fun interpretBlock(block: IrBlock): ExecutionResult {
|
||||
return stack.newFrame(asSubFrame = true) { interpretStatements(block.statements) }
|
||||
}
|
||||
|
||||
private fun interpretBody(body: IrBody): ExecutionResult {
|
||||
private fun List<IrStatement>.withUnitIfNoResult(): ExecutionResult {
|
||||
return stack.newFrame(asSubFrame = true) {
|
||||
val executionResult = interpretStatements(body.statements).check { return@newFrame it }
|
||||
val executionResult = interpretStatements(this).check { return@newFrame it }
|
||||
when {
|
||||
!stack.hasReturnValue() -> getOrCreateObjectValue(irBuiltIns.unitClass.owner)
|
||||
else -> executionResult
|
||||
@@ -510,6 +506,14 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
||||
}
|
||||
}
|
||||
|
||||
private fun interpretBlock(block: IrBlock): ExecutionResult {
|
||||
return block.statements.withUnitIfNoResult()
|
||||
}
|
||||
|
||||
private fun interpretBody(body: IrBody): ExecutionResult {
|
||||
return body.statements.withUnitIfNoResult()
|
||||
}
|
||||
|
||||
private fun interpretReturn(expression: IrReturn): ExecutionResult {
|
||||
expression.value.interpret().check { return it }
|
||||
return Return.addOwnerInfo(expression.returnTargetSymbol.owner)
|
||||
@@ -528,7 +532,7 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
||||
do {
|
||||
// pool from body must be seen to condition expression, so must create temp frame here
|
||||
stack.newFrame(asSubFrame = true) {
|
||||
expression.body?.interpret()?.check { return@newFrame it }
|
||||
expression.body?.interpret()?.check(ReturnLabel.REGULAR, ReturnLabel.CONTINUE) { return@newFrame it }
|
||||
expression.condition.interpret().check { return@newFrame it }
|
||||
Next
|
||||
}.check { return it }
|
||||
@@ -705,8 +709,10 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
||||
val typeOperand = if (isReified) (stack.getVariable(typeClassifier).state as KTypeState).irType else expression.typeOperand
|
||||
|
||||
when (expression.operator) {
|
||||
// coercion to unit means that return value isn't used
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> stack.popReturnValue()
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
||||
stack.popReturnValue()
|
||||
getOrCreateObjectValue(irBuiltIns.unitClass.owner).check { return it }
|
||||
}
|
||||
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
||||
if (!isErased && !stack.peekReturnValue().isSubtypeOf(typeOperand)) {
|
||||
val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
|
||||
@@ -802,7 +808,8 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
||||
}
|
||||
return Exception
|
||||
} finally {
|
||||
expression.finallyExpression?.takeIf { (it as? IrBlock)?.statements?.isEmpty() != true }?.interpret()?.check { return it }
|
||||
expression.finallyExpression?.interpret()
|
||||
?.let { if (it.returnLabel == ReturnLabel.REGULAR) stack.popReturnValue() else return it }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@ import org.jetbrains.kotlin.ir.interpreter.state.Primitive
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
||||
import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.throwAsUserException
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
@@ -38,11 +35,15 @@ open class ExecutionResult(val returnLabel: ReturnLabel, private val owner: IrEl
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.BREAK_LOOP -> when (irElement) {
|
||||
is IrWhileLoop -> if (owner == irElement) Next else this
|
||||
is IrWhileLoop, is IrDoWhileLoop -> if (owner == irElement) Next else this
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.CONTINUE -> when (irElement) {
|
||||
is IrWhileLoop -> if (owner == irElement) irElement.interpret() else this
|
||||
is IrDoWhileLoop -> {
|
||||
if (owner != irElement) return this
|
||||
error("Continue must be handled inside DoWhile interpreter function")
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.EXCEPTION -> Exception
|
||||
@@ -55,8 +56,10 @@ open class ExecutionResult(val returnLabel: ReturnLabel, private val owner: IrEl
|
||||
}
|
||||
}
|
||||
|
||||
inline fun ExecutionResult.check(toCheckLabel: ReturnLabel = ReturnLabel.REGULAR, returnBlock: (ExecutionResult) -> Unit): ExecutionResult {
|
||||
if (this.returnLabel != toCheckLabel) returnBlock(this)
|
||||
inline fun ExecutionResult.check(
|
||||
vararg toCheckLabel: ReturnLabel = arrayOf(ReturnLabel.REGULAR), returnBlock: (ExecutionResult) -> Unit
|
||||
): ExecutionResult {
|
||||
if (this.returnLabel !in toCheckLabel) returnBlock(this)
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ internal class ExceptionState private constructor(
|
||||
}
|
||||
|
||||
constructor(common: Common, stackTrace: List<String>) : this(common.irClass, common.fields, stackTrace) {
|
||||
(common.superWrapperClass?.value as? Throwable)?.let { setMessage(it.message) }
|
||||
setUpCauseIfNeeded(common.superWrapperClass)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user