[JS IR BE] Refact MultipleCatchLowering

- catch dynamic type instead of common super type over all catch blocks
This commit is contained in:
Roman Artemev
2019-07-09 11:25:45 +03:00
committed by romanart
parent 1605dc3251
commit 131158df65
@@ -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)
} }