[JS IR BE] Fix exceptions

* set message property in the correct way
 * set proper name for each Throwable successor
This commit is contained in:
Roman Artemev
2018-10-23 14:53:41 +03:00
committed by romanart
parent 6a05b1eee5
commit 276000a974
@@ -16,15 +16,15 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.isThrowable
import org.jetbrains.kotlin.ir.util.isThrowableTypeOrSubtype
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
@@ -33,9 +33,11 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
private val nothingNType = context.irBuiltIns.nothingNType
private val nothingType = context.irBuiltIns.nothingType
private val stringType = context.irBuiltIns.stringType
private val booleanType = context.irBuiltIns.booleanType
private val propertyGetter = context.intrinsics.jsGetJSField.symbol
private val propertySetter = context.intrinsics.jsSetJSField.symbol
private val eqeqeqSymbol = context.irBuiltIns.eqeqSymbol
private val messageName = JsIrBuilder.buildString(stringType, "message")
private val causeName = JsIrBuilder.buildString(stringType, "cause")
@@ -71,10 +73,36 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
pendingSuperUsages.clear()
irFile.acceptChildrenVoid(ThrowableAccessorCreationVisitor())
pendingSuperUsages.forEach { it.klass.transformChildren(ThrowableDirectSuccessorTransformer(it), it.klass) }
irFile.transformChildren(ThrowableNameSetterTransformer(), irFile)
irFile.transformChildrenVoid(ThrowablePropertiesUsageTransformer())
irFile.transformChildrenVoid(ThrowableInstanceCreationLowering())
}
inner class ThrowableNameSetterTransformer : IrElementTransformer<IrDeclarationParent> {
override fun visitClass(declaration: IrClass, data: IrDeclarationParent) = super.visitClass(declaration, declaration)
override fun visitConstructor(declaration: IrConstructor, data: IrDeclarationParent): IrStatement {
declaration.transformChildren(this, data)
if (!declaration.isPrimary) return declaration
val klass = data as IrClass
if (klass.defaultType.isThrowableTypeOrSubtype()) {
(declaration.body as? IrBlockBody)?.let {
it.statements += JsIrBuilder.buildCall(propertySetter, unitType).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(klass.thisReceiver!!.symbol))
putValueArgument(1, nameName)
putValueArgument(2, JsIrBuilder.buildString(stringType, klass.name.asString()))
}
}
}
return declaration
}
}
inner class ThrowableInstanceCreationLowering : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
if (expression.symbol.owner !in throwableConstructors) return super.visitCall(expression)
@@ -204,9 +232,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
val klass = successor.klass
val receiver = IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol)
val nameArg = JsIrBuilder.buildString(stringType, klass.name.asString())
val fillStatements = fillThrowableInstance(expression, receiver, messageArg, causeArg, nameArg)
val fillStatements = fillThrowableInstance(expression, receiver, messageArg, causeArg)
return expression.run {
IrCompositeImpl(startOffset, endOffset, type, origin, paramStatements + newDelegation + fillStatements)
@@ -217,8 +243,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
expression: IrFunctionAccessExpression,
receiver: IrExpression,
messageArg: IrExpression,
causeArg: IrExpression,
name: IrExpression
causeArg: IrExpression
): List<IrStatement> {
val setMessage = expression.run {
@@ -229,17 +254,11 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
IrSetFieldImpl(startOffset, endOffset, successor.cause.symbol, receiver, causeArg, unitType)
}
val setName = IrCallImpl(expression.startOffset, expression.endOffset, unitType, propertySetter).apply {
putValueArgument(0, receiver)
putValueArgument(1, nameName)
putValueArgument(2, name)
}
val setStackTrace = IrCallImpl(expression.startOffset, expression.endOffset, unitType, captureStackFunction).apply {
putValueArgument(0, receiver)
}
return listOf(setMessage, setCause, setName, setStackTrace)
return listOf(setMessage, setCause, setStackTrace)
}
private fun extractConstructorParameters(
@@ -255,19 +274,25 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
val cus = expression.getValueArgument(1)!!
val irValM = JsIrBuilder.buildVar(msg.type, parent, initializer = msg)
val irValC = JsIrBuilder.buildVar(cus.type, parent, initializer = cus)
Triple(JsIrBuilder.buildGetValue(irValM.symbol), JsIrBuilder.buildGetValue(irValC.symbol), listOf(irValM, irValC))
val check = JsIrBuilder.buildCall(eqeqeqSymbol, booleanType).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irValM.symbol))
putValueArgument(1, nullValue)
}
val msgElvis = JsIrBuilder.buildIfElse(
stringType.makeNullable(), check,
safeCallToString(irValC), JsIrBuilder.buildGetValue(irValM.symbol)
)
Triple(msgElvis, JsIrBuilder.buildGetValue(irValC.symbol), listOf(irValM, irValC))
}
else -> {
val arg = expression.getValueArgument(0)!!
val irVal = JsIrBuilder.buildVar(arg.type, parent, initializer = arg)
val argValue = JsIrBuilder.buildGetValue(irVal.symbol)
when {
arg.type.makeNotNull().isThrowable() -> {
val messageExpr = JsIrBuilder.buildCall(toString.symbol, stringType).apply {
dispatchReceiver = argValue
}
Triple(messageExpr, argValue, listOf(irVal))
}
arg.type.makeNotNull().isThrowable() -> Triple(safeCallToString(irVal), argValue, listOf(irVal))
else -> Triple(argValue, nullValue, listOf(irVal))
}
}
@@ -275,6 +300,17 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
}
}
private fun safeCallToString(receiver: IrValueDeclaration): IrExpression {
val value = JsIrBuilder.buildGetValue(receiver.symbol)
val check = JsIrBuilder.buildCall(eqeqeqSymbol, booleanType).apply {
putValueArgument(0, value)
putValueArgument(1, JsIrBuilder.buildNull(value.type))
}
val value2 = JsIrBuilder.buildGetValue(receiver.symbol)
val call = JsIrBuilder.buildCall(toString.symbol, stringType).apply { dispatchReceiver = value2 }
return JsIrBuilder.buildIfElse(stringType.makeNullable(), check, JsIrBuilder.buildNull(stringType), call)
}
private fun isDirectChildOfThrowable(irClass: IrClass) = irClass.superTypes.any { it.isThrowable() }
private fun ownPropertyAccessor(irClass: IrClass, irBase: IrFunction) =
irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }