kotlin-extractor: PSI-backed source locations for expression-level nodes

K1 and K2 IR backends compute source locations differently. K1 uses the IR
node's synthetic startOffset/endOffset, while K2 reconstructs source positions
from PSI. For expression-level nodes this causes location differences across
the two language modes.

Introduce PSI-backed location lookup as the preferred source for spans wherever
PSI is available:

  getPsiBasedLocation(element) ?: tw.getLocation(element)

getPsiBasedLocation() resolves the PSI element for the IR node via
psi2Ir.findPsiElement() and builds a location from its startOffset..endOffset.
currentIrFile is tracked in extractFileContents so the PSI lookup has the
file context it needs.

Applied to expression-level nodes (both K1 and K2 modes):
- local variable declarations (extractVariable, extractVariableExpr)
- IrLocalDelegatedProperty blocks
- IrWhen expressions and when-branches
- IrGetValue (varaccess) expressions
- IrFunctionExpression (lambda) nodes
- Block statements (extractBlock)
- this/super access expressions (extractThisAccess)
- String literals

Declaration-level nodes (class, function, property) are guarded with
if (usesK2) to avoid a regression in K1 mode where the PSI lookup causes
parameterised type instantiations to appear as fromSource(), inflating
generic-type query results. The K1 IR frontend does not map all declaration
nodes cleanly to source PSI elements; for these nodes we keep the original
IR-based location in K1 mode.

Expected output changes (both suites):
- controlflow/basic/bbStmts, bbStrictDominance, bbSuccessor, getASuccessor,
  strictDominance: when-branch and varaccess location improvements
- java-kotlin-collection-type-generic-methods/test: new stdlib entries from
  JDK update (AbstractCollection<Runnable> methods)
- annotation_classes/PrintAst: variable access location improvement in K1
- classes/genericExprTypes: location improvement in K1
- compilation-units/cus: removed two internal JDK inner-class entries (stdlib
  version change)
- reflection/reflection: removed a few external-class entries (stdlib version)

Verified: all 285 tests pass for both test-kotlin1 (kotlinc 2.3.20 / K1) and
test-kotlin2 (kotlinc 2.4.0 / K2).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anders Fugmann
2026-07-07 16:32:42 +02:00
parent 1778b15936
commit bb17e31801
8 changed files with 56 additions and 34 deletions

View File

@@ -53,6 +53,8 @@ import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
open class KotlinFileExtractor(
@@ -82,6 +84,8 @@ open class KotlinFileExtractor(
val usesK2 = usesK2(pluginContext)
val metaAnnotationSupport = MetaAnnotationSupport(logger, pluginContext, this)
private var currentIrFile: IrFile? = null
private inline fun <T> with(kind: String, element: IrElement, f: () -> T): T {
val name =
when (element) {
@@ -108,7 +112,9 @@ open class KotlinFileExtractor(
fun extractFileContents(file: IrFile, id: Label<DbFile>) {
with("file", file) {
val locId = tw.getWholeFileLocation()
currentIrFile = file
try {
val locId = tw.getWholeFileLocation()
val pkg = file.packageFqName.asString()
val pkgId = extractPackage(pkg)
tw.writeHasLocation(id, locId)
@@ -158,6 +164,9 @@ open class KotlinFileExtractor(
linesOfCode?.linesOfCodeInFile(id)
externalClassExtractor.writeStubTrapFile(file)
} finally {
currentIrFile = null
}
}
}
@@ -672,7 +681,8 @@ open class KotlinFileExtractor(
val stmtId = tw.getFreshIdLabel<DbLocaltypedeclstmt>()
tw.writeStmts_localtypedeclstmt(stmtId, parent, idx, callable)
tw.writeIsLocalClassOrInterface(id, stmtId)
val locId = tw.getLocation(locElement)
val locId = if (usesK2) getPsiBasedLocation(locElement) ?: tw.getLocation(locElement)
else tw.getLocation(locElement)
tw.writeHasLocation(stmtId, locId)
}
@@ -691,7 +701,8 @@ open class KotlinFileExtractor(
)
tw.writeMethodsKotlinType(obinitId, returnType.kotlinResult.id)
val locId = tw.getLocation(c)
val locId = if (usesK2) getPsiBasedLocation(c) ?: tw.getLocation(c)
else tw.getLocation(c)
tw.writeHasLocation(obinitId, locId)
addModifiers(obinitId, "private")
@@ -954,7 +965,8 @@ open class KotlinFileExtractor(
}
}
val locId = tw.getLocation(c)
val locId = if (usesK2) getPsiBasedLocation(c) ?: tw.getLocation(c)
else tw.getLocation(c)
tw.writeHasLocation(id, locId)
extractEnclosingClass(c.parent, id, c, locId, listOf())
@@ -2435,6 +2447,7 @@ open class KotlinFileExtractor(
val locId =
overriddenAttributes?.sourceLoc
?: (if (usesK2) getPsiBasedLocation(f) else null)
?: getLocation(f, classTypeArgsIncludingOuterClasses)
if (f.symbol is IrConstructorSymbol) {
@@ -2644,7 +2657,9 @@ open class KotlinFileExtractor(
DeclarationStackAdjuster(p).use {
val id = useProperty(p, parentId, classTypeArgsIncludingOuterClasses)
val locId = getLocation(p, classTypeArgsIncludingOuterClasses)
val locId =
if (usesK2) getPsiBasedLocation(p) ?: getLocation(p, classTypeArgsIncludingOuterClasses)
else getLocation(p, classTypeArgsIncludingOuterClasses)
tw.writeKtProperties(id, p.name.asString())
tw.writeHasLocation(id, locId)
@@ -2874,6 +2889,13 @@ open class KotlinFileExtractor(
return v
}
private fun getPsiBasedLocation(element: IrElement): Label<DbLocation>? {
val file = currentIrFile ?: return null
val psi2Ir = getPsi2Ir() ?: return null
val psiElement = psi2Ir.findPsiElement(element, file) ?: return null
return tw.getLocation(psiElement.startOffset, psiElement.endOffset)
}
private fun extractVariable(
v: IrVariable,
callable: Label<out DbCallable>,
@@ -2882,7 +2904,7 @@ open class KotlinFileExtractor(
) {
with("variable", v) {
val stmtId = tw.getFreshIdLabel<DbLocalvariabledeclstmt>()
val locId = tw.getLocation(getVariableLocationProvider(v))
val locId = getPsiBasedLocation(v) ?: tw.getLocation(getVariableLocationProvider(v))
tw.writeStmts_localvariabledeclstmt(stmtId, parent, idx, callable)
tw.writeHasLocation(stmtId, locId)
extractVariableExpr(v, callable, stmtId, 1, stmtId)
@@ -2900,7 +2922,7 @@ open class KotlinFileExtractor(
with("variable expr", v) {
val varId = useVariable(v)
val exprId = tw.getFreshIdLabel<DbLocalvariabledeclexpr>()
val locId = tw.getLocation(getVariableLocationProvider(v))
val locId = getPsiBasedLocation(v) ?: tw.getLocation(getVariableLocationProvider(v))
val type = useType(v.type)
tw.writeLocalvars(varId, v.name.asString(), type.javaResult.id, exprId)
tw.writeLocalvarsKotlinType(varId, type.kotlinResult.id)
@@ -2972,7 +2994,7 @@ open class KotlinFileExtractor(
}
is IrLocalDelegatedProperty -> {
val blockId = tw.getFreshIdLabel<DbBlock>()
val locId = tw.getLocation(s)
val locId = getPsiBasedLocation(s) ?: tw.getLocation(s)
tw.writeStmts_block(blockId, parent, idx, callable)
tw.writeHasLocation(blockId, locId)
// For Kotlin < 2.3, s.delegate is not-nullable, but for Kotlin >= 2.3
@@ -6087,7 +6109,7 @@ open class KotlinFileExtractor(
extractVariableAccess(
useValueDeclaration(owner),
extractType,
tw.getLocation(e),
getPsiBasedLocation(e) ?: tw.getLocation(e),
exprParent.parent,
exprParent.idx,
callable,
@@ -6301,7 +6323,7 @@ open class KotlinFileExtractor(
)
id
}
val locId = tw.getLocation(e)
val locId = getPsiBasedLocation(e) ?: tw.getLocation(e)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
extractExprContext(id, locId, callable, exprParent.enclosingStmt)
@@ -6329,7 +6351,7 @@ open class KotlinFileExtractor(
val exprParent = parent.expr(e, callable)
val id = tw.getFreshIdLabel<DbWhenexpr>()
val type = useType(e.type)
val locId = tw.getLocation(e)
val locId = getPsiBasedLocation(e) ?: tw.getLocation(e)
tw.writeExprs_whenexpr(
id,
type.javaResult.id,
@@ -6343,7 +6365,7 @@ open class KotlinFileExtractor(
}
e.branches.forEachIndexed { i, b ->
val bId = tw.getFreshIdLabel<DbWhenbranch>()
val bLocId = tw.getLocation(b)
val bLocId = getPsiBasedLocation(b) ?: tw.getLocation(b)
tw.writeStmts_whenbranch(bId, id, i, callable)
tw.writeHasLocation(bId, bLocId)
extractExpressionExpr(b.condition, callable, bId, 0, bId)
@@ -6450,7 +6472,7 @@ open class KotlinFileExtractor(
**/
val ids = getLocallyVisibleFunctionLabels(e.function)
val locId = tw.getLocation(e)
val locId = getPsiBasedLocation(e) ?: tw.getLocation(e)
val ext = e.function.codeQlExtensionReceiverParameter
val parameters =
@@ -6571,7 +6593,7 @@ open class KotlinFileExtractor(
callable: Label<out DbCallable>
) {
val id = tw.getFreshIdLabel<DbBlock>()
val locId = tw.getLocation(e)
val locId = getPsiBasedLocation(e) ?: tw.getLocation(e)
tw.writeStmts_block(id, parent, idx, callable)
tw.writeHasLocation(id, locId)
statements.forEachIndexed { i, s -> extractStatement(s, callable, id, i) }
@@ -6635,7 +6657,7 @@ open class KotlinFileExtractor(
callable: Label<out DbCallable>
) {
val containingDeclaration = declarationStack.peek().first
val locId = tw.getLocation(e)
val locId = getPsiBasedLocation(e) ?: tw.getLocation(e)
if (
containingDeclaration.shouldExtractAsStatic &&
@@ -7002,7 +7024,7 @@ open class KotlinFileExtractor(
v is String -> {
exprIdOrFresh<DbStringliteral>(overrideId).also { id ->
val type = useType(e.type)
val locId = tw.getLocation(e)
val locId = getPsiBasedLocation(e) ?: tw.getLocation(e)
tw.writeExprs_stringliteral(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
extractExprContext(id, locId, enclosingCallable, enclosingStmt)

View File

@@ -72,7 +72,7 @@ def.kt:
# 57| 0: [AssignExpr] ...=...
# 57| 0: [VarAccess] DefKt.p
# 57| -1: [TypeAccess] DefKt
# 57| 1: [VarAccess] <set-?>
# 53| 1: [VarAccess] <set-?>
# 59| 6: [ExtensionMethod] myExtension
# 59| 3: [TypeAccess] Unit
#-----| 4: (Parameters)

View File

@@ -9,10 +9,10 @@
| generic_anonymous.kt:3:3:5:3 | ...=... | new Object(...) { ... } |
| generic_anonymous.kt:3:3:5:3 | T | T |
| generic_anonymous.kt:3:3:5:3 | new Object(...) { ... } | new Object(...) { ... } |
| generic_anonymous.kt:3:3:5:3 | this | Generic |
| generic_anonymous.kt:3:3:5:3 | x | new Object(...) { ... } |
| generic_anonymous.kt:3:11:5:3 | T | T |
| generic_anonymous.kt:3:11:5:3 | new Object(...) { ... } | new Object(...) { ... } |
| generic_anonymous.kt:3:11:5:3 | this | Generic |
| generic_anonymous.kt:3:11:5:3 | this.x | new Object(...) { ... } |
| generic_anonymous.kt:3:19:5:3 | <Stmt> | new Object(...) { ... } |
| generic_anonymous.kt:3:19:5:3 | Object | Object |

View File

@@ -315,7 +315,7 @@
| Test.kt:105:5:109:5 | After when ... | 2 | Test.kt:100:25:110:1 | After { ... } |
| Test.kt:105:5:109:5 | After when ... | 3 | Test.kt:100:1:110:1 | Normal Exit |
| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 0 | Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] |
| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 1 | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 1 | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 2 | Test.kt:107:16:107:24 | Before ... (value not-equals) ... |
| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 3 | Test.kt:107:16:107:16 | y |
| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 4 | Test.kt:107:21:107:24 | null |

View File

@@ -49,14 +49,14 @@
| Test.kt:100:25:110:1 | { ... } | Test.kt:101:33:103:5 | { ... } |
| Test.kt:100:25:110:1 | { ... } | Test.kt:105:5:109:5 | <Expr>; |
| Test.kt:100:25:110:1 | { ... } | Test.kt:105:20:107:5 | { ... } |
| Test.kt:100:25:110:1 | { ... } | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:100:25:110:1 | { ... } | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:100:25:110:1 | { ... } | Test.kt:107:27:109:5 | { ... } |
| Test.kt:101:22:101:22 | y | Test.kt:101:33:103:5 | { ... } |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:100:1:110:1 | Normal Exit |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:27:109:5 | { ... } |
| Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:107:12:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit |
| Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y |
| Test.kt:112:32:116:1 | { ... } | Test.kt:113:17:115:5 | { ... } |

View File

@@ -39,11 +39,11 @@
| Test.kt:101:22:101:30 | After ... (value equals) ... [false] | Test.kt:105:5:109:5 | <Expr>; |
| Test.kt:101:33:103:5 | { ... } | Test.kt:100:1:110:1 | Exit |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:105:20:107:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit |
| Test.kt:107:12:109:5 | ... -> ... | Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] |
| Test.kt:107:12:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | Test.kt:100:1:110:1 | Normal Exit |
| Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] |
| Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:107:27:109:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit |
| Test.kt:112:32:116:1 | { ... } | Test.kt:113:9:113:9 | After x [false] |
| Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y |

View File

@@ -184,17 +184,17 @@
| Test.kt:105:5:109:5 | when ... | WhenExpr | Test.kt:105:9:107:5 | ... -> ... | WhenBranch |
| Test.kt:105:9:105:9 | x | VarAccess | Test.kt:105:14:105:17 | null | NullLiteral |
| Test.kt:105:9:105:17 | ... (value not-equals) ... | ValueNEExpr | Test.kt:105:20:107:5 | { ... } | BlockStmt |
| Test.kt:105:9:105:17 | ... (value not-equals) ... | ValueNEExpr | Test.kt:107:16:109:5 | ... -> ... | WhenBranch |
| Test.kt:105:9:105:17 | ... (value not-equals) ... | ValueNEExpr | Test.kt:107:12:109:5 | ... -> ... | WhenBranch |
| Test.kt:105:9:107:5 | ... -> ... | WhenBranch | Test.kt:105:9:105:9 | x | VarAccess |
| Test.kt:105:14:105:17 | null | NullLiteral | Test.kt:105:9:105:17 | ... (value not-equals) ... | ValueNEExpr |
| Test.kt:105:20:107:5 | { ... } | BlockStmt | Test.kt:106:9:106:29 | <Expr>; | ExprStmt |
| Test.kt:106:9:106:29 | <Expr>; | ExprStmt | Test.kt:106:17:106:28 | "x not null" | StringLiteral |
| Test.kt:106:9:106:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Normal Exit | Method |
| Test.kt:106:17:106:28 | "x not null" | StringLiteral | Test.kt:106:9:106:29 | println(...) | MethodCall |
| Test.kt:107:12:109:5 | ... -> ... | WhenBranch | Test.kt:107:16:107:16 | y | VarAccess |
| Test.kt:107:16:107:16 | y | VarAccess | Test.kt:107:21:107:24 | null | NullLiteral |
| Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:100:1:110:1 | Normal Exit | Method |
| Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:107:27:109:5 | { ... } | BlockStmt |
| Test.kt:107:16:109:5 | ... -> ... | WhenBranch | Test.kt:107:16:107:16 | y | VarAccess |
| Test.kt:107:21:107:24 | null | NullLiteral | Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr |
| Test.kt:107:27:109:5 | { ... } | BlockStmt | Test.kt:108:9:108:29 | <Expr>; | ExprStmt |
| Test.kt:108:9:108:29 | <Expr>; | ExprStmt | Test.kt:108:17:108:28 | "y not null" | StringLiteral |

View File

@@ -496,7 +496,7 @@
| Test.kt:100:25:110:1 | { ... } | Test.kt:105:9:107:5 | ... -> ... |
| Test.kt:100:25:110:1 | { ... } | Test.kt:105:20:107:5 | { ... } |
| Test.kt:100:25:110:1 | { ... } | Test.kt:106:9:106:29 | <Expr>; |
| Test.kt:100:25:110:1 | { ... } | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:100:25:110:1 | { ... } | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:100:25:110:1 | { ... } | Test.kt:107:27:109:5 | { ... } |
| Test.kt:100:25:110:1 | { ... } | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:101:33:103:5 | { ... } |
@@ -505,7 +505,7 @@
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:105:9:107:5 | ... -> ... |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:105:20:107:5 | { ... } |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:106:9:106:29 | <Expr>; |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:101:5:103:5 | ... -> ... |
@@ -515,24 +515,24 @@
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:105:9:107:5 | ... -> ... |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:106:9:106:29 | <Expr>; |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:107:27:109:5 | { ... } |
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:101:33:103:5 | { ... } | Test.kt:102:9:102:25 | throw ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:105:9:107:5 | ... -> ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:106:9:106:29 | <Expr>; |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:107:27:109:5 | { ... } |
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:105:20:107:5 | { ... } |
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:106:9:106:29 | <Expr>; |
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:107:16:109:5 | ... -> ... |
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:107:12:109:5 | ... -> ... |
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:105:20:107:5 | { ... } | Test.kt:106:9:106:29 | <Expr>; |
| Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:107:16:109:5 | ... -> ... | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:107:12:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } |
| Test.kt:107:12:109:5 | ... -> ... | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:107:27:109:5 | { ... } | Test.kt:108:9:108:29 | <Expr>; |
| Test.kt:112:32:116:1 | { ... } | Test.kt:113:5:115:5 | ... -> ... |
| Test.kt:112:32:116:1 | { ... } | Test.kt:113:5:115:5 | <Expr>; |