-
Notifications
You must be signed in to change notification settings - Fork 0
/
IrTryBuilder.kt
80 lines (67 loc) · 2.99 KB
/
IrTryBuilder.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.rnett.plugin.ir
import org.jetbrains.kotlin.backend.common.lower.irCatch
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.declarations.buildVariable
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrCatch
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTry
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isSubtypeOf
import org.jetbrains.kotlin.name.Name
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
public fun IrBuilderWithScope.irTry(
result: IrExpression,
type: IrType,
catches: List<IrCatch>,
finally: IrExpression? = null,
): IrTry =
IrTryImpl(startOffset, endOffset, type, result, catches, finally)
public fun IrBuilderWithScope.irTry(result: IrExpression, type: IrType = result.type): IrTry =
irTry(result, type, emptyList(), null)
//TODO convert to extensions on IrTry. Needs multiple receivers for builder
public class IrTryBuilder(private val builder: IrBuilderWithScope) {
private val catches = mutableListOf<IrCatch>()
private val caughtTypes = mutableSetOf<IrType>()
private var finallyExpression: IrExpression? = null
@OptIn(ExperimentalContracts::class)
public fun irCatch(throwableType: IrType, body: IrBuilderWithScope.(IrVariable) -> IrExpression) {
contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) }
if (!throwableType.isSubtypeOf(
builder.context.irBuiltIns.throwableType,
builder.context.typeSystem
) && throwableType != builder.context.irBuiltIns.throwableType
)
error("Can only catch types that inherit from kotlin.Throwable")
if (!caughtTypes.add(throwableType))
error("Already caught type $throwableType")
val catchVariable =
buildVariable(
builder.scope.getLocalDeclarationParent(),
builder.startOffset,
builder.endOffset,
IrDeclarationOrigin.CATCH_PARAMETER,
Name.identifier("t_${catches.size}"),
throwableType
)
catches += builder.irCatch(catchVariable, builder.body(catchVariable))
}
public fun irFinally(expression: IrExpression) {
if (finallyExpression != null)
error("finally expression already set")
finallyExpression = expression
}
@PublishedApi
internal fun build(result: IrExpression, type: IrType): IrTry =
builder.irTry(result, type, catches, finallyExpression)
}
public inline fun IrBuilderWithScope.irTry(
result: IrExpression,
type: IrType = result.type,
catches: IrTryBuilder.() -> Unit,
): IrTry =
IrTryBuilder(this).apply(catches).build(result, type)