IrCatch element.

This commit is contained in:
Dmitry Petrov
2016-09-15 14:24:21 +03:00
committed by Dmitry Petrov
parent c02ae4a4a5
commit 90119880c5
11 changed files with 104 additions and 92 deletions
@@ -17,7 +17,8 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrTryCatchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCatchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.psi.KtTryExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
@@ -26,19 +27,18 @@ import org.jetbrains.kotlin.resolve.BindingContext
class TryCatchExpressionGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
fun generateTryCatch(ktTry: KtTryExpression): IrExpression {
val resultType = getInferredTypeWithImplicitCastsOrFail(ktTry)
val irTryCatch = IrTryCatchImpl(ktTry.startOffset, ktTry.endOffset, resultType)
val irTryCatch = IrTryImpl(ktTry.startOffset, ktTry.endOffset, resultType)
irTryCatch.tryResult = statementGenerator.generateExpression(ktTry.tryBlock)
for (ktCatchClause in ktTry.catchClauses) {
val ktCatchParameter = ktCatchClause.catchParameter!!
val ktCatchBody = ktCatchClause.catchBody!!
val catchParameterDescriptor = getOrFail(BindingContext.VALUE_PARAMETER, ktCatchParameter)
val irCatchResult = statementGenerator.generateExpression(ktCatchBody)
irTryCatch.addCatchClause(catchParameterDescriptor, irCatchResult)
val irCatch = IrCatchImpl(ktCatchClause.startOffset, ktCatchClause.endOffset,
catchParameterDescriptor, irCatchResult)
irTryCatch.catches.add(irCatch)
}
irTryCatch.finallyExpression = ktTry.finallyBlock?.let{ statementGenerator.generateExpression(it.finalExpression) }
@@ -43,12 +43,12 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
expression.transformChildren(this, data)
with(expression) {
dispatchReceiver = dispatchReceiver?.wrapWithImplicitCast(descriptor.dispatchReceiverParameter?.type)
extensionReceiver = extensionReceiver?.wrapWithImplicitCast(descriptor.extensionReceiverParameter?.type)
dispatchReceiver = dispatchReceiver?.cast(descriptor.dispatchReceiverParameter?.type)
extensionReceiver = extensionReceiver?.cast(descriptor.extensionReceiverParameter?.type)
for (index in descriptor.valueParameters.indices) {
val argument = getArgument(index) ?: continue
val parameterType = descriptor.valueParameters[index].type
putArgument(index, argument.wrapWithImplicitCast(parameterType))
putArgument(index, argument.cast(parameterType))
}
}
@@ -65,7 +65,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
val lastStatement = expression.statements.last()
if (lastStatement is IrExpression) {
expression.putStatement(expression.statements.lastIndex, lastStatement.wrapWithImplicitCast(type))
expression.putStatement(expression.statements.lastIndex, lastStatement.cast(type))
}
return expression
@@ -74,7 +74,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
override fun visitReturn(expression: IrReturn, data: Nothing?): IrExpression {
expression.transformChildren(this, data)
expression.value = expression.value?.wrapWithImplicitCast(expression.returnTarget.returnType)
expression.value = expression.value?.cast(expression.returnTarget.returnType)
return expression
}
@@ -82,7 +82,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): IrExpression {
expression.transformChildren(this, data)
expression.value = expression.value.wrapWithImplicitCast(expression.descriptor.type)
expression.value = expression.value.cast(expression.descriptor.type)
return expression
}
@@ -90,7 +90,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
override fun visitSetField(expression: IrSetField, data: Nothing?): IrExpression {
expression.transformChildren(this, data)
expression.value = expression.value.wrapWithImplicitCast(expression.descriptor.type)
expression.value = expression.value.cast(expression.descriptor.type)
return expression
}
@@ -98,7 +98,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
override fun visitVariable(declaration: IrVariable, data: Nothing?): IrVariable {
declaration.transformChildren(this, data)
declaration.initializer = declaration.initializer?.wrapWithImplicitCast(declaration.descriptor.type)
declaration.initializer = declaration.initializer?.cast(declaration.descriptor.type)
return declaration
}
@@ -112,11 +112,11 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
val nthCondition = expression.getNthCondition(i)!!
val nthResult = expression.getNthResult(i)!!
expression.putNthCondition(i, nthCondition.wrapWithImplicitCast(builtIns.booleanType))
expression.putNthResult(i, nthResult.wrapWithImplicitCast(resultType))
expression.putNthCondition(i, nthCondition.cast(builtIns.booleanType))
expression.putNthResult(i, nthResult.cast(resultType))
}
expression.elseBranch = expression.elseBranch?.wrapWithImplicitCast(resultType)
expression.elseBranch = expression.elseBranch?.cast(resultType)
return expression
}
@@ -124,7 +124,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
override fun visitLoop(loop: IrLoop, data: Nothing?): IrExpression {
loop.transformChildren(this, data)
loop.condition = loop.condition.wrapWithImplicitCast(builtIns.booleanType)
loop.condition = loop.condition.cast(builtIns.booleanType)
return loop
}
@@ -132,24 +132,23 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
override fun visitThrow(expression: IrThrow, data: Nothing?): IrExpression {
expression.transformChildren(this, data)
expression.value = expression.value.wrapWithImplicitCast(builtIns.throwable.defaultType)
expression.value = expression.value.cast(builtIns.throwable.defaultType)
return expression
}
override fun visitTryCatch(tryCatch: IrTryCatch, data: Nothing?): IrExpression {
tryCatch.transformChildren(this, data)
override fun visitTry(aTry: IrTry, data: Nothing?): IrExpression {
aTry.transformChildren(this, data)
val resultType = tryCatch.type
val resultType = aTry.type
tryCatch.tryResult = tryCatch.tryResult.wrapWithImplicitCast(resultType)
aTry.tryResult = aTry.tryResult.cast(resultType)
for (i in tryCatch.catchClauseIndices) {
val nthCatchResult = tryCatch.getNthCatchResult(i)!!
tryCatch.putNthCatchResult(i, nthCatchResult.wrapWithImplicitCast(resultType))
for (aCatch in aTry.catches) {
aCatch.result = aCatch.result.cast(resultType)
}
return tryCatch
return aTry
}
override fun visitVararg(expression: IrVararg, data: Nothing?): IrExpression {
@@ -158,16 +157,16 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
expression.elements.forEachIndexed { i, element ->
when (element) {
is IrSpreadElement ->
element.expression = element.expression.wrapWithImplicitCast(expression.type)
element.expression = element.expression.cast(expression.type)
is IrExpression ->
expression.putElement(i, element.wrapWithImplicitCast(expression.varargElementType))
expression.putElement(i, element.cast(expression.varargElementType))
}
}
return expression
}
private fun IrExpression.wrapWithImplicitCast(expectedType: KotlinType?): IrExpression {
private fun IrExpression.cast(expectedType: KotlinType?): IrExpression {
if (expectedType == null) return this
if (expectedType.isError) return this
if (KotlinBuiltIns.isUnit(expectedType)) return this // TODO expose coercion to Unit in IR?
@@ -179,7 +178,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementTransformer<No
return IrTypeOperatorCallImpl(
this.startOffset, this.endOffset, nonNullValueType,
IrTypeOperator.IMPLICIT_NOTNULL, nonNullValueType, this
).wrapWithImplicitCast(expectedType)
).cast(expectedType)
}
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType.makeNotNullable(), expectedType)) {
@@ -17,19 +17,21 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
interface IrTryCatch : IrExpression {
interface IrTry : IrExpression {
var tryResult: IrExpression
val catchClausesCount: Int
fun getNthCatchParameter(n: Int): VariableDescriptor?
fun getNthCatchResult(n: Int): IrExpression?
fun putNthCatchParameter(n: Int, variableDescriptor: VariableDescriptor)
fun putNthCatchResult(n: Int, expression: IrExpression)
val catches: List<IrCatch>
var finallyExpression : IrExpression?
}
val IrTryCatch.catchClauseIndices: IntRange get() = 0 ..catchClausesCount - 1
interface IrCatch : IrElement {
val parameter: VariableDescriptor
var result: IrExpression
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrCatch =
super.transform(transformer, data) as IrCatch
}
@@ -17,57 +17,54 @@
package org.jetbrains.kotlin.ir.expressions.impl
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.expressions.IrCatch
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTryCatch
import org.jetbrains.kotlin.ir.expressions.IrTry
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.SmartList
class IrTryCatchImpl(startOffset: Int, endOffset: Int, type: KotlinType) :
IrExpressionBase(startOffset, endOffset, type), IrTryCatch {
class IrTryImpl(startOffset: Int, endOffset: Int, type: KotlinType) :
IrExpressionBase(startOffset, endOffset, type), IrTry {
override lateinit var tryResult: IrExpression
private val catchClauseParameters = SmartList<VariableDescriptor>()
private val catchClauseResults = SmartList<IrExpression>()
override val catchClausesCount: Int get() = catchClauseResults.size
fun addCatchClause(parameter: VariableDescriptor, result: IrExpression) {
catchClauseParameters.add(parameter)
catchClauseResults.add(result)
}
override fun getNthCatchParameter(n: Int): VariableDescriptor? =
catchClauseParameters.getOrNull(n)
override fun getNthCatchResult(n: Int): IrExpression? =
catchClauseResults.getOrNull(n)
override fun putNthCatchParameter(n: Int, variableDescriptor: VariableDescriptor) {
catchClauseParameters[n] = variableDescriptor
}
override fun putNthCatchResult(n: Int, expression: IrExpression) {
catchClauseResults[n] = expression
}
override val catches: MutableList<IrCatch> = SmartList()
override var finallyExpression: IrExpression? = null
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitTryCatch(this, data)
return visitor.visitTry(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
tryResult.accept(visitor, data)
catchClauseResults.forEach { it.accept(visitor, data) }
catches.forEach { it.accept(visitor, data) }
finallyExpression?.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
tryResult = tryResult.transform(transformer, data)
catchClauseResults.forEachIndexed { i, irExpression ->
catchClauseResults[i] = irExpression.transform(transformer, data)
catches.forEachIndexed { i, irCatch ->
catches[i] = irCatch.transform(transformer, data)
}
}
}
class IrCatchImpl(startOffset: Int, endOffset: Int,
override val parameter: VariableDescriptor,
override var result: IrExpression
) : IrCatch, IrElementBase(startOffset, endOffset) {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitCatch(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
result.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
result = result.transform(transformer, data)
}
}
@@ -142,14 +142,13 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
}
}
override fun visitTryCatch(tryCatch: IrTryCatch, data: String) {
tryCatch.dumpLabeledElementWith(data) {
tryCatch.tryResult.accept(this, "try")
for (i in 0 .. tryCatch.catchClausesCount - 1) {
val catchClauseParameter = tryCatch.getNthCatchParameter(i)!!
tryCatch.getNthCatchResult(i)!!.accept(this, "catch ${catchClauseParameter.name}")
override fun visitTry(aTry: IrTry, data: String) {
aTry.dumpLabeledElementWith(data) {
aTry.tryResult.accept(this, "try")
for (aCatch in aTry.catches) {
aCatch.accept(this, "")
}
tryCatch.finallyExpression?.accept(this, "finally")
aTry.finallyExpression?.accept(this, "finally")
}
}
@@ -179,8 +179,11 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitGetClass(expression: IrGetClass, data: Nothing?): String =
"GET_CLASS type=${expression.type.render()}"
override fun visitTryCatch(tryCatch: IrTryCatch, data: Nothing?): String =
"TRY_CATCH type=${tryCatch.type.render()}"
override fun visitTry(aTry: IrTry, data: Nothing?): String =
"TRY type=${aTry.type.render()}"
override fun visitCatch(aCatch: IrCatch, data: Nothing?): String =
"CATCH parameter=${aCatch.parameter.ref()}"
override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String =
"ERROR_DECL ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.ref()}"
@@ -104,7 +104,12 @@ interface IrElementTransformer<in D> : IrElementVisitor<IrElement, D> {
override fun visitLoop(loop: IrLoop, data: D) = visitExpression(loop, data)
override fun visitWhileLoop(loop: IrWhileLoop, data: D) = visitLoop(loop, data)
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: D) = visitLoop(loop, data)
override fun visitTryCatch(tryCatch: IrTryCatch, data: D) = visitExpression(tryCatch, data)
override fun visitTry(aTry: IrTry, data: D) = visitExpression(aTry, data)
override fun visitCatch(aCatch: IrCatch, data: D): IrCatch {
aCatch.transformChildren(this, data)
return aCatch
}
override fun visitBreakContinue(jump: IrBreakContinue, data: D) = visitExpression(jump, data)
override fun visitBreak(jump: IrBreak, data: D) = visitBreakContinue(jump, data)
@@ -81,7 +81,8 @@ interface IrElementVisitor<out R, in D> {
fun visitLoop(loop: IrLoop, data: D) = visitExpression(loop, data)
fun visitWhileLoop(loop: IrWhileLoop, data: D) = visitLoop(loop, data)
fun visitDoWhileLoop(loop: IrDoWhileLoop, data: D) = visitLoop(loop, data)
fun visitTryCatch(tryCatch: IrTryCatch, data: D) = visitExpression(tryCatch, data)
fun visitTry(aTry: IrTry, data: D) = visitExpression(aTry, data)
fun visitCatch(aCatch: IrCatch, data: D) = visitElement(aCatch, data)
fun visitBreakContinue(jump: IrBreakContinue, data: D) = visitExpression(jump, data)
fun visitBreak(jump: IrBreak, data: D) = visitBreakContinue(jump, data)
@@ -174,8 +174,11 @@ interface IrElementVisitorVoid : IrElementVisitor<Unit, Nothing?> {
fun visitDoWhileLoop(loop: IrDoWhileLoop) = visitLoop(loop)
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?) = visitDoWhileLoop(loop)
fun visitTryCatch(tryCatch: IrTryCatch) = visitExpression(tryCatch)
override fun visitTryCatch(tryCatch: IrTryCatch, data: Nothing?) = visitTryCatch(tryCatch)
fun visitTry(aTry: IrTry) = visitExpression(aTry)
override fun visitTry(aTry: IrTry, data: Nothing?) = visitTry(aTry)
fun visitCatch(aCatch: IrCatch) = visitElement(aCatch)
override fun visitCatch(aCatch: IrCatch, data: Nothing?) = visitCatch(aCatch)
fun visitBreakContinue(jump: IrBreakContinue) = visitExpression(jump)
override fun visitBreakContinue(jump: IrBreakContinue, data: Nothing?) = visitBreakContinue(jump)
+9 -7
View File
@@ -1,22 +1,24 @@
FILE /tryCatch.kt
FUN public fun test1(): kotlin.Unit
BLOCK_BODY
TRY_CATCH type=kotlin.Unit
TRY type=kotlin.Unit
try: BLOCK type=kotlin.Unit origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
catch e: BLOCK type=kotlin.Unit origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
CATCH parameter=e: Throwable
BLOCK type=kotlin.Unit origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
finally: BLOCK type=kotlin.Unit origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
FUN public fun test2(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='test2(): Int'
TRY_CATCH type=kotlin.Int
TRY type=kotlin.Int
try: BLOCK type=kotlin.Int origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
CONST Int type=kotlin.Int value='42'
catch e: BLOCK type=kotlin.Int origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
CONST Int type=kotlin.Int value='24'
CATCH parameter=e: Throwable
BLOCK type=kotlin.Int origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
CONST Int type=kotlin.Int value='24'
finally: BLOCK type=kotlin.Unit origin=null
CALL 'println(): Unit' type=kotlin.Unit origin=null
@@ -6,9 +6,10 @@ FILE /tryCatchWithImplicitCast.kt
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
then: RETURN type=kotlin.Nothing from='testImplicitCast(Any): Unit'
VAR val t: kotlin.String
TRY_CATCH type=kotlin.String
TRY type=kotlin.String
try: BLOCK type=kotlin.String origin=null
TYPE_OP origin=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
catch e: BLOCK type=kotlin.String origin=null
CONST String type=kotlin.String value=''
CATCH parameter=e: Throwable
BLOCK type=kotlin.String origin=null
CONST String type=kotlin.String value=''