[JS IR BE] Refact MultipleCatchLowering
- catch dynamic type instead of common super type over all catch blocks
This commit is contained in:
+20
-44
@@ -17,12 +17,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCatchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
/**
|
||||
@@ -38,21 +34,20 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
* is converted into
|
||||
*
|
||||
* try {}
|
||||
* catch (ex: Ex = LCA(Ex1, Ex2, Ex3)) {
|
||||
* when (ex) {
|
||||
* ex is Ex1 -> catch1((Ex1)ex)
|
||||
* ex is Ex2 -> catch2((Ex2)ex)
|
||||
* ex is Ex3 -> catch3((Ex3)ex)
|
||||
* else throw ex [ | catch_dynamic(ex) ]
|
||||
* catch ($p: dynamic) {
|
||||
* when ($p) {
|
||||
* ex is Ex1 -> catch1((Ex1)$p)
|
||||
* ex is Ex2 -> catch2((Ex2)$p)
|
||||
* ex is Ex3 -> catch3((Ex3)$p)
|
||||
* else throw $p [ | catch_dynamic($p) ]
|
||||
* }
|
||||
* }
|
||||
* finally {}
|
||||
*/
|
||||
|
||||
class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val litTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
val unitType = context.irBuiltIns.unitType
|
||||
val nothingType = context.irBuiltIns.nothingType
|
||||
class MultipleCatchesLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val litTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val nothingType = context.irBuiltIns.nothingType
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||
@@ -65,23 +60,21 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
||||
override fun visitTry(aTry: IrTry, data: IrDeclarationParent): IrExpression {
|
||||
aTry.transformChildren(this, data)
|
||||
|
||||
if (aTry.catches.isEmpty()) return aTry.apply { assert(finallyExpression != null) }
|
||||
if (aTry.catches.isEmpty()) return aTry.also { assert(it.finallyExpression != null) }
|
||||
|
||||
val commonType = mergeTypes(aTry.catches.map { it.catchParameter.type })
|
||||
|
||||
val pendingExceptionDeclaration = JsIrBuilder.buildVar(commonType, data, "\$p")
|
||||
val pendingExceptionDeclaration = JsIrBuilder.buildVar(context.dynamicType, data, "\$p")
|
||||
val pendingException = { JsIrBuilder.buildGetValue(pendingExceptionDeclaration.symbol) }
|
||||
|
||||
val branches = mutableListOf<IrBranch>()
|
||||
var isCaughtDynamic = false
|
||||
|
||||
for (catch in aTry.catches) {
|
||||
assert(!catch.catchParameter.isVar) { "caught exception parameter has to be immutable" }
|
||||
val type = catch.catchParameter.type
|
||||
|
||||
val typeSymbol = type.classifierOrNull
|
||||
val castedPendingException = {
|
||||
if (type !is IrDynamicType)
|
||||
buildImplicitCast(pendingException(), type, typeSymbol!!)
|
||||
buildImplicitCast(pendingException(), type)
|
||||
else
|
||||
pendingException()
|
||||
}
|
||||
@@ -96,15 +89,15 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
||||
|
||||
if (type is IrDynamicType) {
|
||||
branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody)
|
||||
isCaughtDynamic = true
|
||||
break
|
||||
} else {
|
||||
val typeCheck = buildIsCheck(pendingException(), type, typeSymbol!!)
|
||||
val typeCheck = buildIsCheck(pendingException(), type)
|
||||
branches += IrBranchImpl(catch.startOffset, catch.endOffset, typeCheck, catchBody)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (commonType !is IrDynamicType) {
|
||||
if (!isCaughtDynamic) {
|
||||
val throwStatement = JsIrBuilder.buildThrow(nothingType, pendingException())
|
||||
branches += IrElseBranchImpl(litTrue, JsIrBuilder.buildBlock(nothingType, listOf(throwStatement)))
|
||||
}
|
||||
@@ -118,28 +111,11 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
||||
return aTry.run { IrTryImpl(startOffset, endOffset, type, tryResult, listOf(newCatch), finallyExpression) }
|
||||
}
|
||||
|
||||
private fun buildIsCheck(value: IrExpression, toType: IrType, toTypeSymbol: IrClassifierSymbol) =
|
||||
JsIrBuilder.buildTypeOperator(context.irBuiltIns.booleanType, IrTypeOperator.INSTANCEOF, value, toType, toTypeSymbol)
|
||||
private fun buildIsCheck(value: IrExpression, toType: IrType) =
|
||||
JsIrBuilder.buildTypeOperator(context.irBuiltIns.booleanType, IrTypeOperator.INSTANCEOF, value, toType)
|
||||
|
||||
private fun buildImplicitCast(value: IrExpression, toType: IrType, toTypeSymbol: IrClassifierSymbol) =
|
||||
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType, toTypeSymbol)
|
||||
|
||||
private fun mergeTypes(types: List<IrType>): IrType {
|
||||
|
||||
return types.firstOrNull { it is IrDynamicType } ?: run {
|
||||
|
||||
val superClassifier =
|
||||
types.map { (it as IrSimpleType).classifier }.commonSuperclass().also {
|
||||
assert(it.isSubtypeOfClass(context.irBuiltIns.throwableClass))
|
||||
}
|
||||
|
||||
val typeArguments = if (superClassifier is IrClassSymbol) {
|
||||
superClassifier.owner.typeParameters.map { IrStarProjectionImpl }
|
||||
} else emptyList<IrTypeArgument>()
|
||||
|
||||
return IrSimpleTypeImpl(superClassifier, false, typeArguments, emptyList())
|
||||
}
|
||||
}
|
||||
private fun buildImplicitCast(value: IrExpression, toType: IrType) =
|
||||
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType)
|
||||
|
||||
}, irFile)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user