[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.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.*
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.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNotNull 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.isThrowable
import org.jetbrains.kotlin.ir.util.isThrowableTypeOrSubtype
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -33,9 +33,11 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
private val nothingNType = context.irBuiltIns.nothingNType private val nothingNType = context.irBuiltIns.nothingNType
private val nothingType = context.irBuiltIns.nothingType private val nothingType = context.irBuiltIns.nothingType
private val stringType = context.irBuiltIns.stringType private val stringType = context.irBuiltIns.stringType
private val booleanType = context.irBuiltIns.booleanType
private val propertyGetter = context.intrinsics.jsGetJSField.symbol private val propertyGetter = context.intrinsics.jsGetJSField.symbol
private val propertySetter = context.intrinsics.jsSetJSField.symbol private val propertySetter = context.intrinsics.jsSetJSField.symbol
private val eqeqeqSymbol = context.irBuiltIns.eqeqSymbol
private val messageName = JsIrBuilder.buildString(stringType, "message") private val messageName = JsIrBuilder.buildString(stringType, "message")
private val causeName = JsIrBuilder.buildString(stringType, "cause") private val causeName = JsIrBuilder.buildString(stringType, "cause")
@@ -71,10 +73,36 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
pendingSuperUsages.clear() pendingSuperUsages.clear()
irFile.acceptChildrenVoid(ThrowableAccessorCreationVisitor()) irFile.acceptChildrenVoid(ThrowableAccessorCreationVisitor())
pendingSuperUsages.forEach { it.klass.transformChildren(ThrowableDirectSuccessorTransformer(it), it.klass) } pendingSuperUsages.forEach { it.klass.transformChildren(ThrowableDirectSuccessorTransformer(it), it.klass) }
irFile.transformChildren(ThrowableNameSetterTransformer(), irFile)
irFile.transformChildrenVoid(ThrowablePropertiesUsageTransformer()) irFile.transformChildrenVoid(ThrowablePropertiesUsageTransformer())
irFile.transformChildrenVoid(ThrowableInstanceCreationLowering()) 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() { inner class ThrowableInstanceCreationLowering : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
if (expression.symbol.owner !in throwableConstructors) return super.visitCall(expression) if (expression.symbol.owner !in throwableConstructors) return super.visitCall(expression)
@@ -204,9 +232,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
val klass = successor.klass val klass = successor.klass
val receiver = IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol) 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)
val fillStatements = fillThrowableInstance(expression, receiver, messageArg, causeArg, nameArg)
return expression.run { return expression.run {
IrCompositeImpl(startOffset, endOffset, type, origin, paramStatements + newDelegation + fillStatements) IrCompositeImpl(startOffset, endOffset, type, origin, paramStatements + newDelegation + fillStatements)
@@ -217,8 +243,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
expression: IrFunctionAccessExpression, expression: IrFunctionAccessExpression,
receiver: IrExpression, receiver: IrExpression,
messageArg: IrExpression, messageArg: IrExpression,
causeArg: IrExpression, causeArg: IrExpression
name: IrExpression
): List<IrStatement> { ): List<IrStatement> {
val setMessage = expression.run { val setMessage = expression.run {
@@ -229,17 +254,11 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
IrSetFieldImpl(startOffset, endOffset, successor.cause.symbol, receiver, causeArg, unitType) 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 { val setStackTrace = IrCallImpl(expression.startOffset, expression.endOffset, unitType, captureStackFunction).apply {
putValueArgument(0, receiver) putValueArgument(0, receiver)
} }
return listOf(setMessage, setCause, setName, setStackTrace) return listOf(setMessage, setCause, setStackTrace)
} }
private fun extractConstructorParameters( private fun extractConstructorParameters(
@@ -255,19 +274,25 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
val cus = expression.getValueArgument(1)!! val cus = expression.getValueArgument(1)!!
val irValM = JsIrBuilder.buildVar(msg.type, parent, initializer = msg) val irValM = JsIrBuilder.buildVar(msg.type, parent, initializer = msg)
val irValC = JsIrBuilder.buildVar(cus.type, parent, initializer = cus) 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 -> { else -> {
val arg = expression.getValueArgument(0)!! val arg = expression.getValueArgument(0)!!
val irVal = JsIrBuilder.buildVar(arg.type, parent, initializer = arg) val irVal = JsIrBuilder.buildVar(arg.type, parent, initializer = arg)
val argValue = JsIrBuilder.buildGetValue(irVal.symbol) val argValue = JsIrBuilder.buildGetValue(irVal.symbol)
when { when {
arg.type.makeNotNull().isThrowable() -> { arg.type.makeNotNull().isThrowable() -> Triple(safeCallToString(irVal), argValue, listOf(irVal))
val messageExpr = JsIrBuilder.buildCall(toString.symbol, stringType).apply {
dispatchReceiver = argValue
}
Triple(messageExpr, argValue, listOf(irVal))
}
else -> Triple(argValue, nullValue, 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 isDirectChildOfThrowable(irClass: IrClass) = irClass.superTypes.any { it.isThrowable() }
private fun ownPropertyAccessor(irClass: IrClass, irBase: IrFunction) = private fun ownPropertyAccessor(irClass: IrClass, irBase: IrFunction) =
irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter } irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }