[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.IrCatchImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
|
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.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
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
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,21 +34,20 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
|||||||
* is converted into
|
* is converted into
|
||||||
*
|
*
|
||||||
* try {}
|
* try {}
|
||||||
* catch (ex: Ex = LCA(Ex1, Ex2, Ex3)) {
|
* catch ($p: dynamic) {
|
||||||
* when (ex) {
|
* when ($p) {
|
||||||
* ex is Ex1 -> catch1((Ex1)ex)
|
* ex is Ex1 -> catch1((Ex1)$p)
|
||||||
* ex is Ex2 -> catch2((Ex2)ex)
|
* ex is Ex2 -> catch2((Ex2)$p)
|
||||||
* ex is Ex3 -> catch3((Ex3)ex)
|
* ex is Ex3 -> catch3((Ex3)$p)
|
||||||
* else throw ex [ | catch_dynamic(ex) ]
|
* else throw $p [ | catch_dynamic($p) ]
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* finally {}
|
* finally {}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
class MultipleCatchesLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
||||||
val litTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
private val litTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||||
val unitType = context.irBuiltIns.unitType
|
private val nothingType = context.irBuiltIns.nothingType
|
||||||
val nothingType = context.irBuiltIns.nothingType
|
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||||
@@ -65,23 +60,21 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
|||||||
override fun visitTry(aTry: IrTry, data: IrDeclarationParent): IrExpression {
|
override fun visitTry(aTry: IrTry, data: IrDeclarationParent): IrExpression {
|
||||||
aTry.transformChildren(this, data)
|
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(context.dynamicType, data, "\$p")
|
||||||
|
|
||||||
val pendingExceptionDeclaration = JsIrBuilder.buildVar(commonType, data, "\$p")
|
|
||||||
val pendingException = { JsIrBuilder.buildGetValue(pendingExceptionDeclaration.symbol) }
|
val pendingException = { JsIrBuilder.buildGetValue(pendingExceptionDeclaration.symbol) }
|
||||||
|
|
||||||
val branches = mutableListOf<IrBranch>()
|
val branches = mutableListOf<IrBranch>()
|
||||||
|
var isCaughtDynamic = false
|
||||||
|
|
||||||
for (catch in aTry.catches) {
|
for (catch in aTry.catches) {
|
||||||
assert(!catch.catchParameter.isVar) { "caught exception parameter has to be immutable" }
|
assert(!catch.catchParameter.isVar) { "caught exception parameter has to be immutable" }
|
||||||
val type = catch.catchParameter.type
|
val type = catch.catchParameter.type
|
||||||
|
|
||||||
val typeSymbol = type.classifierOrNull
|
|
||||||
val castedPendingException = {
|
val castedPendingException = {
|
||||||
if (type !is IrDynamicType)
|
if (type !is IrDynamicType)
|
||||||
buildImplicitCast(pendingException(), type, typeSymbol!!)
|
buildImplicitCast(pendingException(), type)
|
||||||
else
|
else
|
||||||
pendingException()
|
pendingException()
|
||||||
}
|
}
|
||||||
@@ -96,15 +89,15 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
|||||||
|
|
||||||
if (type is IrDynamicType) {
|
if (type is IrDynamicType) {
|
||||||
branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody)
|
branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody)
|
||||||
|
isCaughtDynamic = true
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
val typeCheck = buildIsCheck(pendingException(), type, typeSymbol!!)
|
val typeCheck = buildIsCheck(pendingException(), type)
|
||||||
branches += IrBranchImpl(catch.startOffset, catch.endOffset, typeCheck, catchBody)
|
branches += IrBranchImpl(catch.startOffset, catch.endOffset, typeCheck, catchBody)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isCaughtDynamic) {
|
||||||
if (commonType !is IrDynamicType) {
|
|
||||||
val throwStatement = JsIrBuilder.buildThrow(nothingType, pendingException())
|
val throwStatement = JsIrBuilder.buildThrow(nothingType, pendingException())
|
||||||
branches += IrElseBranchImpl(litTrue, JsIrBuilder.buildBlock(nothingType, listOf(throwStatement)))
|
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) }
|
return aTry.run { IrTryImpl(startOffset, endOffset, type, tryResult, listOf(newCatch), finallyExpression) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildIsCheck(value: IrExpression, toType: IrType, toTypeSymbol: IrClassifierSymbol) =
|
private fun buildIsCheck(value: IrExpression, toType: IrType) =
|
||||||
JsIrBuilder.buildTypeOperator(context.irBuiltIns.booleanType, IrTypeOperator.INSTANCEOF, value, toType, toTypeSymbol)
|
JsIrBuilder.buildTypeOperator(context.irBuiltIns.booleanType, IrTypeOperator.INSTANCEOF, value, toType)
|
||||||
|
|
||||||
private fun buildImplicitCast(value: IrExpression, toType: IrType, toTypeSymbol: IrClassifierSymbol) =
|
private fun buildImplicitCast(value: IrExpression, toType: IrType) =
|
||||||
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType, toTypeSymbol)
|
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType)
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, irFile)
|
}, irFile)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user