'try'
This commit is contained in:
committed by
Dmitry Petrov
parent
ebd8f1266d
commit
17758d8c00
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+51
@@ -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
|
||||
}
|
||||
}
|
||||
+11
@@ -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
@@ -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
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user