This commit is contained in:
Dmitry Petrov
2016-08-24 19:08:12 +03:00
committed by Dmitry Petrov
parent ebd8f1266d
commit 17758d8c00
12 changed files with 285 additions and 8 deletions
@@ -19,9 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.expressions.IrDummyExpression
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
@@ -77,6 +75,14 @@ fun Generator.getReturnType(key: KtExpression): KotlinType? {
return getReturnType(key.statements.last())
}
if (key is KtConstantExpression) {
return getInferredTypeWithSmartcasts(key)
}
if (key is KtStringTemplateExpression) {
return context.builtIns.stringType
}
throw AssertionError("Unexpected expression: $key")
}
@@ -294,6 +294,9 @@ class StatementGenerator(
override fun visitContinueExpression(expression: KtContinueExpression, data: Nothing?): IrStatement =
LoopExpressionGenerator(this).generateContinue(expression)
override fun visitTryExpression(expression: KtTryExpression, data: Nothing?): IrStatement =
TryCatchExpressionGenerator(this).generateTryCatch(expression)
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTryCatchImpl
import org.jetbrains.kotlin.psi.KtTryExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
class TryCatchExpressionGenerator(val statementGenerator: StatementGenerator) : GeneratorWithScope {
override val scope: Scope get() = statementGenerator.scope
override val context: GeneratorContext get() = statementGenerator.context
fun generateTryCatch(ktTry: KtTryExpression): IrExpression {
val resultType = getInferredTypeWithSmartcasts(ktTry)
val irTryCatch = IrTryCatchImpl(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)
}
irTryCatch.finallyExpression = ktTry.finallyBlock?.let{ statementGenerator.generateExpression(it.finalExpression) }
return irTryCatch
}
}
@@ -103,6 +103,17 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementVisitor<Unit,
expression.value.replaceWithCast(builtIns.throwable.defaultType)
}
override fun visitTryCatch(tryCatch: IrTryCatch, data: Nothing?) {
tryCatch.acceptChildren(this, null)
val resultType = tryCatch.type
tryCatch.tryResult.replaceWithCast(resultType)
for (catchClauseIndex in tryCatch.catchClauseIndices) {
tryCatch.getNthCatchResult(catchClauseIndex)!!.replaceWithCast(resultType)
}
}
private fun IrExpression.replaceWithCast(expectedType: KotlinType?) {
replaceWith { it.wrapWithImplicitCast(expectedType) }
}
@@ -30,4 +30,6 @@ const val IF_THEN_SLOT = 1
const val IF_ELSE_SLOT = -1
const val LOOP_BODY_SLOT = -1
const val LOOP_CONDITION_SLOT = -2
const val SETTER_ARGUMENT_INDEX = 0
const val SETTER_ARGUMENT_INDEX = 0
const val TRY_RESULT_SLOT = -1
const val FINALLY_EXPRESSION_SLOT = -2
@@ -0,0 +1,117 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.SmartList
interface IrTryCatch : IrExpression {
var tryResult: IrExpression
val catchClausesCount: Int
fun getNthCatchParameter(n: Int): VariableDescriptor?
fun getNthCatchResult(n: Int): IrExpression?
var finallyExpression : IrExpression?
}
val IrTryCatch.catchClauseIndices: IntRange get() = 0 ..catchClausesCount - 1
class IrTryCatchImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?
) : IrExpressionBase(startOffset, endOffset, type), IrTryCatch {
private var tryResultImpl: IrExpression? = null
override var tryResult: IrExpression
get() = tryResultImpl!!
set(value) {
value.assertDetached()
tryResultImpl?.detach()
tryResultImpl = value
value.setTreeLocation(this, TRY_RESULT_SLOT)
}
private val catchClauseParameters = SmartList<VariableDescriptor>()
private val catchClauseResults = SmartList<IrExpression>()
override val catchClausesCount: Int get() = catchClauseResults.size
fun addCatchClause(parameter: VariableDescriptor, result: IrExpression) {
result.assertDetached()
result.setTreeLocation(this, catchClausesCount)
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 var finallyExpression: IrExpression? = null
set(value) {
value?.assertDetached()
field?.detach()
field = value
value?.setTreeLocation(this, FINALLY_EXPRESSION_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when {
slot == TRY_RESULT_SLOT ->
tryResult
slot >= 0 ->
catchClauseResults.getOrNull(slot)
slot == FINALLY_EXPRESSION_SLOT ->
finallyExpression
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when {
slot == TRY_RESULT_SLOT ->
tryResult = newChild.assertCast()
slot >= 0 ->
putCatchClauseElement(catchClauseResults, newChild, slot)
slot == FINALLY_EXPRESSION_SLOT ->
finallyExpression = newChild.assertCast()
}
}
private inline fun <reified T : IrElement> putCatchClauseElement(list: MutableList<T>, newChild: IrElement, slot: Int) {
list[slot].detach()
list[slot] = newChild.assertCast()
newChild.setTreeLocation(this, slot)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitTryCatch(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
tryResult.accept(visitor, data)
for (index in 0 ..catchClausesCount - 1) {
catchClauseResults[index].accept(visitor, data)
}
finallyExpression?.accept(visitor, data)
}
}
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceLocationManager
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrDoWhileLoop
import org.jetbrains.kotlin.ir.expressions.IrWhen
import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.utils.Printer
@@ -80,6 +77,17 @@ 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}")
}
tryCatch.finallyExpression?.accept(this, "finally")
}
}
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
printer.println(accept(elementRenderer, null).withLabel(label))
indented(body)
@@ -115,6 +115,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitThrow(expression: IrThrow, data: Nothing?): String =
"THROW type=${expression.renderType()}"
override fun visitTryCatch(tryCatch: IrTryCatch, data: Nothing?): String =
"TRY_CATCH type=${tryCatch.renderType()}"
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
"DUMMY ${declaration.descriptor.name}"
@@ -59,6 +59,7 @@ 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 visitBreakContinue(jump: IrBreakContinue, data: D) = visitExpression(jump, data)
fun visitBreak(jump: IrBreak, data: D) = visitBreakContinue(jump, data)
+31
View File
@@ -0,0 +1,31 @@
fun test1() {
try {
println()
}
catch (e: Throwable) {
println()
}
finally {
println()
}
}
fun test2(): Int {
return try {
println()
42
}
catch (e: Throwable) {
println()
24
}
finally {
println()
}
}
fun testImplicitCast(a: Any) {
if (a !is String) return
val t: String = try { a } catch (e: Throwable) { "" }
}
+38
View File
@@ -0,0 +1,38 @@
IrFile /tryCatch.kt
IrFunction public fun test1(): kotlin.Unit
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
TRY_CATCH type=kotlin.Unit
try: BLOCK type=<no-type> hasResult=false operator=null
CALL .println type=kotlin.Unit operator=null
catch e: BLOCK type=<no-type> hasResult=false operator=null
CALL .println type=kotlin.Unit operator=null
finally: BLOCK type=<no-type> hasResult=false operator=null
CALL .println type=kotlin.Unit operator=null
IrFunction public fun test2(): kotlin.Int
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
RETURN type=<no-type>
TRY_CATCH type=kotlin.Int
try: BLOCK type=kotlin.Int hasResult=true operator=null
CALL .println type=kotlin.Unit operator=null
CONST Int type=kotlin.Int value='42'
catch e: BLOCK type=kotlin.Int hasResult=true operator=null
CALL .println type=kotlin.Unit operator=null
CONST Int type=kotlin.Int value='24'
finally: BLOCK type=<no-type> hasResult=false operator=null
CALL .println type=kotlin.Unit operator=null
IrFunction public fun testImplicitCast(/*0*/ a: kotlin.Any): kotlin.Unit
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
WHEN type=kotlin.Unit operator=IF
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
GET_VAR a type=kotlin.Any operator=null
then: RETURN type=<no-type>
VAR val t: kotlin.String
TRY_CATCH type=kotlin.String
try: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
BLOCK type=kotlin.Any hasResult=true operator=null
GET_VAR a type=kotlin.Any operator=null
catch e: BLOCK type=kotlin.String hasResult=true operator=null
CONST String type=kotlin.String value=''
@@ -263,6 +263,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("tryCatch.kt")
public void testTryCatch() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/tryCatch.kt");
doTest(fileName);
}
@TestMetadata("typeOperators.kt")
public void testTypeOperators() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/typeOperators.kt");