[FIR] Capture receiver for pre/postfix dec/increment of qualified access

This prevents double-evaluation of the receiver expression, which may
have side-effects. E.g.: a.b++
This commit is contained in:
Mark Punzalan
2020-09-17 22:42:43 -07:00
committed by Mikhail Glukhikh
parent 393189db8d
commit f55ff8eb1b
13 changed files with 278 additions and 117 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.TokenType
import com.intellij.psi.tree.IElementType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
@@ -81,13 +82,25 @@ open class BaseConverter(
return this.getChildNodesByType(type).firstOrNull()
}
override val LighterASTNode?.receiverExpression: LighterASTNode?
get() {
var candidate: LighterASTNode? = null
this?.forEachChildren {
when (it.tokenType) {
DOT, SAFE_ACCESS -> return if (candidate?.elementType != TokenType.ERROR_ELEMENT) candidate else null
else -> candidate = it
}
}
return null
}
override val LighterASTNode?.selectorExpression: LighterASTNode?
get() {
var isSelector = false
this?.forEachChildren {
when (it.tokenType) {
DOT, SAFE_ACCESS -> isSelector = true
else -> if (isSelector) return it
else -> if (isSelector) return if (it.elementType != TokenType.ERROR_ELEMENT) it else null
}
}
return null
@@ -122,6 +122,9 @@ class RawFirBuilder(
return (this as KtAnnotatedExpression).baseExpression
}
override val PsiElement?.receiverExpression: PsiElement?
get() = (this as? KtQualifiedExpression)?.receiverExpression
override val PsiElement?.selectorExpression: PsiElement?
get() = (this as? KtQualifiedExpression)?.selectorExpression
@@ -8,14 +8,12 @@ FILE: unary.kt
}
lval x2: <implicit> = {
lval <unary>: <implicit> = x#
x# = R|<local>/<unary>|.inc#()
x# = x#.inc#()
x#
}
lval x3: <implicit> = {
lval <unary>: <implicit> = x#
x# = R|<local>/<unary>|.dec#()
x# = x#.dec#()
x#
}
@@ -43,15 +41,16 @@ FILE: unary.kt
}
public? final? fun test2(x: X): R|kotlin/Unit| {
lval x1: <implicit> = {
lval <unary>: <implicit> = x#.i#
x#.i# = R|<local>/<unary>|.inc#()
lval <receiver>: <implicit> = x#
lval <unary>: <implicit> = R|<local>/<receiver>|.i#
R|<local>/<receiver>|.i# = R|<local>/<unary>|.inc#()
R|<local>/<unary>|
}
lval x2: <implicit> = {
lval <unary>: <implicit> = x#.i#
lval <unary-result>: <implicit> = R|<local>/<unary>|.inc#()
x#.i# = R|<local>/<unary-result>|
lval <receiver>: <implicit> = x#
lval <unary-result>: <implicit> = R|<local>/<receiver>|.i#.inc#()
R|<local>/<receiver>|.i# = R|<local>/<unary-result>|
R|<local>/<unary-result>|
}
@@ -64,8 +63,7 @@ FILE: unary.kt
}
lval x2: <implicit> = {
lval <unary>: <implicit> = arr#.get#(IntegerLiteral(1))
lval <unary-result>: <implicit> = R|<local>/<unary>|.inc#()
lval <unary-result>: <implicit> = arr#.get#(IntegerLiteral(1)).inc#()
arr#.set#(IntegerLiteral(1), R|<local>/<unary-result>|)
R|<local>/<unary-result>|
}
@@ -88,8 +86,7 @@ FILE: unary.kt
}
lval x2: <implicit> = {
lval <unary>: <implicit> = y#.arr#.get#(IntegerLiteral(1))
lval <unary-result>: <implicit> = R|<local>/<unary>|.inc#()
lval <unary-result>: <implicit> = y#.arr#.get#(IntegerLiteral(1)).inc#()
y#.arr#.set#(IntegerLiteral(1), R|<local>/<unary-result>|)
R|<local>/<unary-result>|
}
@@ -19,10 +19,12 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.builder.*
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.lexer.KtTokens.CLOSING_QUOTE
@@ -50,6 +52,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
abstract fun T.getExpressionInParentheses(): T?
abstract fun T.getAnnotatedExpression(): T?
abstract fun T.getChildNodeByType(type: IElementType): T?
abstract val T?.receiverExpression: T?
abstract val T?.selectorExpression: T?
/**** Class name utils ****/
@@ -383,14 +386,17 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
*
* result:
* {
* val <unary> = argument
* argument = <unary>.inc()
* ^argument
* val <unary-result> = argument.inc()
* argument = <unary-result>
* ^<unary-result>
* }
*
*/
// TODO: Refactor, support receiver capturing in case of a.b
// TODO:
// 1. Support receiver capturing for `array.b++` (elementType == ARRAY_ACCESS_EXPRESSION).
// 2. Support receiver capturing for `a?.b++` (elementType == SAFE_ACCESS_EXPRESSION).
// 3. Add box test cases for #1 and #2 where receiver expression has side effects.
fun generateIncrementOrDecrementBlock(
baseExpression: T,
operationReference: T?,
@@ -405,31 +411,67 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
diagnostic = ConeSimpleDiagnostic("Inc/dec without operand", DiagnosticKind.Syntax)
}
}
if (argument.elementType == PARENTHESIZED) {
return generateIncrementOrDecrementBlock(
baseExpression,
operationReference,
argument.getExpressionInParentheses(),
callName,
prefix,
convert
)
}
if (argument.elementType == DOT_QUALIFIED_EXPRESSION) {
return generateIncrementOrDecrementBlockForQualifiedAccess(
baseExpression,
operationReference,
argument,
callName,
prefix,
convert
)
}
return buildBlock {
val baseSource = baseExpression?.toFirSourceElement()
val desugaredSource = baseSource?.fakeElement(FirFakeSourceElementKind.DesugaredIncrementOrDecrement)
source = desugaredSource
val tempName = Name.special("<unary>")
val temporaryVariable = generateTemporaryVariable(
// initialValueVar is only used for postfix increment/decrement (stores the argument value before increment/decrement).
val initialValueVar = generateTemporaryVariable(
this@BaseFirBuilder.baseSession,
desugaredSource,
tempName,
Name.special("<unary>"),
argument.convert()
)
statements += temporaryVariable
val resultName = Name.special("<unary-result>")
// resultInitializer is the expression for `argument.inc()`
val resultInitializer = buildFunctionCall {
source = desugaredSource
calleeReference = buildSimpleNamedReference {
source = operationReference?.toFirSourceElement()
name = callName
}
explicitReceiver = generateResolvedAccessExpression(desugaredSource, temporaryVariable)
explicitReceiver = if (prefix) {
argument.convert()
} else {
generateResolvedAccessExpression(desugaredSource, initialValueVar)
}
}
val resultVar = generateTemporaryVariable(this@BaseFirBuilder.baseSession, desugaredSource, resultName, resultInitializer)
// resultVar is only used for prefix increment/decrement.
val resultVar = generateTemporaryVariable(
this@BaseFirBuilder.baseSession,
desugaredSource,
Name.special("<unary-result>"),
resultInitializer
)
val assignment = argument.generateAssignment(
desugaredSource,
argument,
null,
if (prefix && argument.elementType != REFERENCE_EXPRESSION)
generateResolvedAccessExpression(source, resultVar)
else
@@ -455,8 +497,127 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
statements += generateAccessExpression(desugaredSource, argument.getReferencedNameAsName())
}
} else {
statements += initialValueVar
appendAssignment()
statements += generateResolvedAccessExpression(desugaredSource, temporaryVariable)
statements += generateResolvedAccessExpression(desugaredSource, initialValueVar)
}
}
}
/**
* given:
* a.b++
*
* result:
* {
* val <receiver> = a
* val <unary> = <receiver>.b
* <receiver>.b = <unary>.inc()
* ^<unary>
* }
*
* given:
* ++a.b
*
* result:
* {
* val <receiver> = a
* val <unary-result> = <receiver>.b.inc()
* <receiver>.b = <unary-result>
* ^<unary-result>
* }
*
*/
private fun generateIncrementOrDecrementBlockForQualifiedAccess(
baseExpression: T,
operationReference: T?,
argument: T,
callName: Name,
prefix: Boolean,
convert: T.() -> FirExpression
): FirExpression {
return buildBlock {
val baseSource = baseExpression?.toFirSourceElement()
val desugaredSource = baseSource?.fakeElement(FirFakeSourceElementKind.DesugaredIncrementOrDecrement)
source = desugaredSource
val argumentReceiver = argument.receiverExpression
val argumentSelector = argument.selectorExpression
val argumentReceiverVariable = generateTemporaryVariable(
this@BaseFirBuilder.baseSession,
argumentReceiver?.toFirSourceElement(),
Name.special("<receiver>"),
argumentReceiver?.convert() ?: buildErrorExpression {
source = argument.toFirSourceElement()
diagnostic = ConeSimpleDiagnostic("Qualified expression without receiver", DiagnosticKind.Syntax)
}
).also { statements += it }
val firArgument = generateResolvedAccessExpression(argumentReceiverVariable.source, argumentReceiverVariable).let { receiver ->
val firArgumentSelector = argumentSelector?.convert() ?: buildErrorExpression {
source = argument.toFirSourceElement()
diagnostic = ConeSimpleDiagnostic("Qualified expression without selector", DiagnosticKind.Syntax)
}
firArgumentSelector.also { if (it is FirQualifiedAccessExpression) it.replaceExplicitReceiver(receiver) }
}
// initialValueVar is only used for postfix increment/decrement (stores the argument value before increment/decrement).
val initialValueVar = generateTemporaryVariable(
this@BaseFirBuilder.baseSession,
desugaredSource,
Name.special("<unary>"),
firArgument
)
// resultInitializer is the expression for `argument.inc()`
val resultInitializer = buildFunctionCall {
source = desugaredSource
calleeReference = buildSimpleNamedReference {
source = operationReference?.toFirSourceElement()
name = callName
}
explicitReceiver = if (prefix) {
firArgument
} else {
generateResolvedAccessExpression(desugaredSource, initialValueVar)
}
}
// resultVar is only used for prefix increment/decrement.
val resultVar = generateTemporaryVariable(
this@BaseFirBuilder.baseSession,
desugaredSource,
Name.special("<unary-result>"),
resultInitializer
)
fun appendAssignment() {
if (firArgument is FirQualifiedAccessExpression) {
statements += buildVariableAssignment {
source = desugaredSource
rValue = if (prefix) {
generateResolvedAccessExpression(source, resultVar)
} else {
resultInitializer
}
explicitReceiver = generateResolvedAccessExpression(argumentReceiverVariable.source, argumentReceiverVariable)
calleeReference = buildSimpleNamedReference {
source = firArgument.calleeReference.source
name = (firArgument.calleeReference as FirSimpleNamedReference).name
}
}
}
}
if (prefix) {
statements += resultVar
appendAssignment()
statements += generateResolvedAccessExpression(desugaredSource, resultVar)
} else {
statements += initialValueVar
appendAssignment()
statements += generateResolvedAccessExpression(desugaredSource, initialValueVar)
}
}
}
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
var holder = ""
var globalA: A = A(-1)
get(): A {
@@ -106,22 +106,18 @@ FILE fqName:<root> fileName:/breakContinueInLoopHeader.kt
WHILE label=Outer origin=WHILE_LOOP
condition: CONST Boolean type=kotlin.Boolean value=true
body: BLOCK type=kotlin.Unit origin=WHILE_LOOP
VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:kotlin.Int [val]
GET_VAR 'var i: kotlin.Int [var] declared in <root>.test5' type=kotlin.Int origin=null
SET_VAR 'var i: kotlin.Int [var] declared in <root>.test5' type=kotlin.Unit origin=EQ
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.test5' type=kotlin.Int origin=null
$this: GET_VAR 'var i: kotlin.Int [var] declared in <root>.test5' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'var i: kotlin.Int [var] declared in <root>.test5' type=kotlin.Int origin=null
VAR name:j type:kotlin.Int [var]
CONST Int type=kotlin.Int value=0
DO_WHILE label=Inner origin=DO_WHILE_LOOP
body: COMPOSITE type=kotlin.Int origin=DO_WHILE_LOOP
VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:kotlin.Int [val]
GET_VAR 'var j: kotlin.Int [var] declared in <root>.test5' type=kotlin.Int origin=null
SET_VAR 'var j: kotlin.Int [var] declared in <root>.test5' type=kotlin.Unit origin=EQ
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_7: kotlin.Int [val] declared in <root>.test5' type=kotlin.Int origin=null
$this: GET_VAR 'var j: kotlin.Int [var] declared in <root>.test5' type=kotlin.Int origin=null
GET_VAR 'var j: kotlin.Int [var] declared in <root>.test5' type=kotlin.Int origin=null
condition: WHEN type=kotlin.Boolean origin=IF
BRANCH
@@ -109,11 +109,9 @@ FILE fqName:<root> fileName:/breakContinueInWhen.kt
CONST String type=kotlin.String value=""
DO_WHILE label=null origin=DO_WHILE_LOOP
body: COMPOSITE type=kotlin.Unit origin=DO_WHILE_LOOP
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val]
GET_VAR 'var k: kotlin.Int [var] declared in <root>.testContinueDoWhile' type=kotlin.Int origin=null
SET_VAR 'var k: kotlin.Int [var] declared in <root>.testContinueDoWhile' type=kotlin.Unit origin=EQ
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.testContinueDoWhile' type=kotlin.Int origin=null
$this: GET_VAR 'var k: kotlin.Int [var] declared in <root>.testContinueDoWhile' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'var k: kotlin.Int [var] declared in <root>.testContinueDoWhile' type=kotlin.Int origin=null
WHEN type=kotlin.Unit origin=WHEN
@@ -143,33 +143,39 @@ FILE fqName:<root> fileName:/complexAugmentedAssignment.kt
GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.test1' type=kotlin.Int origin=null
FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val]
CALL 'public final fun <get-x1> (): kotlin.Int declared in <root>.X1' type=kotlin.Int origin=GET_PROPERTY
$this: GET_OBJECT 'CLASS OBJECT name:X1 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1
CALL 'public final fun <set-x1> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.X1' type=kotlin.Unit origin=EQ
$this: GET_OBJECT 'CLASS OBJECT name:X1 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1
<set-?>: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:<root>.X1 [val]
GET_OBJECT 'CLASS OBJECT name:X1 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1
VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:kotlin.Int [val]
CALL 'public final fun <get-x2> (): kotlin.Int declared in <root>.X1.X2' type=kotlin.Int origin=GET_PROPERTY
$this: GET_OBJECT 'CLASS OBJECT name:X2 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1.X2
CALL 'public final fun <set-x2> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.X1.X2' type=kotlin.Unit origin=EQ
$this: GET_OBJECT 'CLASS OBJECT name:X2 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1.X2
CALL 'public final fun <get-x1> (): kotlin.Int declared in <root>.X1' type=kotlin.Int origin=GET_PROPERTY
$this: GET_VAR 'val tmp_3: <root>.X1 [val] declared in <root>.test2' type=<root>.X1 origin=null
CALL 'public final fun <set-x1> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.X1' type=kotlin.Unit origin=EQ
$this: GET_VAR 'val tmp_3: <root>.X1 [val] declared in <root>.test2' type=<root>.X1 origin=null
<set-?>: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_4: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'val tmp_4: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.Int [val]
CALL 'public final fun <get-x3> (): kotlin.Int declared in <root>.X1.X2.X3' type=kotlin.Int origin=GET_PROPERTY
$this: GET_OBJECT 'CLASS OBJECT name:X3 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1.X2.X3
CALL 'public final fun <set-x3> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.X1.X2.X3' type=kotlin.Unit origin=EQ
$this: GET_OBJECT 'CLASS OBJECT name:X3 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1.X2.X3
VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:<root>.X1.X2 [val]
GET_OBJECT 'CLASS OBJECT name:X2 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1.X2
VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:kotlin.Int [val]
CALL 'public final fun <get-x2> (): kotlin.Int declared in <root>.X1.X2' type=kotlin.Int origin=GET_PROPERTY
$this: GET_VAR 'val tmp_5: <root>.X1.X2 [val] declared in <root>.test2' type=<root>.X1.X2 origin=null
CALL 'public final fun <set-x2> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.X1.X2' type=kotlin.Unit origin=EQ
$this: GET_VAR 'val tmp_5: <root>.X1.X2 [val] declared in <root>.test2' type=<root>.X1.X2 origin=null
<set-?>: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_5: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'val tmp_5: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:<root>.X1.X2.X3 [val]
GET_OBJECT 'CLASS OBJECT name:X3 modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.X1.X2.X3
VAR IR_TEMPORARY_VARIABLE name:tmp_8 type:kotlin.Int [val]
CALL 'public final fun <get-x3> (): kotlin.Int declared in <root>.X1.X2.X3' type=kotlin.Int origin=GET_PROPERTY
$this: GET_VAR 'val tmp_7: <root>.X1.X2.X3 [val] declared in <root>.test2' type=<root>.X1.X2.X3 origin=null
CALL 'public final fun <set-x3> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.X1.X2.X3' type=kotlin.Unit origin=EQ
$this: GET_VAR 'val tmp_7: <root>.X1.X2.X3 [val] declared in <root>.test2' type=<root>.X1.X2.X3 origin=null
<set-?>: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_8: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'val tmp_8: kotlin.Int [val] declared in <root>.test2' type=kotlin.Int origin=null
CLASS CLASS name:B modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.B
CONSTRUCTOR visibility:public <> (s:kotlin.Int) returnType:<root>.B [primary]
@@ -33,19 +33,15 @@ FILE fqName:<root> fileName:/incrementDecrement.kt
CONST Int type=kotlin.Int value=0
VAR name:x1 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
SET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Unit origin=EQ
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
$this: GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
VAR name:x2 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
SET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Unit origin=EQ
CALL 'public final fun dec (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
$this: GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPrefix' type=kotlin.Int origin=null
FUN name:testVarPostfix visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
@@ -53,91 +49,81 @@ FILE fqName:<root> fileName:/incrementDecrement.kt
CONST Int type=kotlin.Int value=0
VAR name:x1 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
SET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPostfix' type=kotlin.Unit origin=EQ
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
VAR name:x2 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
SET_VAR 'var x: kotlin.Int [var] declared in <root>.testVarPostfix' type=kotlin.Unit origin=EQ
CALL 'public final fun dec (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.testVarPostfix' type=kotlin.Int origin=null
FUN name:testPropPrefix visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:p1 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:kotlin.Int [val]
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <set-p> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=EQ
<set-?>: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_4: kotlin.Int [val] declared in <root>.testPropPrefix' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
VAR name:p2 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.Int [val]
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <set-p> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=EQ
<set-?>: CALL 'public final fun dec (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_5: kotlin.Int [val] declared in <root>.testPropPrefix' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
FUN name:testPropPostfix visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:p1 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val]
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <set-p> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=EQ
<set-?>: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.testPropPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.testPropPostfix' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.testPropPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.testPropPostfix' type=kotlin.Int origin=null
VAR name:p2 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:kotlin.Int [val]
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <set-p> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=EQ
<set-?>: CALL 'public final fun dec (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_7: kotlin.Int [val] declared in <root>.testPropPostfix' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
CALL 'public final fun <get-p> (): kotlin.Int declared in <root>' type=kotlin.Int origin=GET_PROPERTY
FUN name:testArrayPrefix visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:a1 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_8 type:kotlin.Int [val]
CALL 'public final fun get (index: kotlin.Int): kotlin.Int [operator] declared in kotlin.IntArray' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
VAR IR_TEMPORARY_VARIABLE name:tmp_9 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val]
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_8: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
$this: CALL 'public final fun get (index: kotlin.Int): kotlin.Int [operator] declared in kotlin.IntArray' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
CALL 'public final fun set (index: kotlin.Int, value: kotlin.Int): kotlin.Unit [operator] declared in kotlin.IntArray' type=kotlin.Unit origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
value: GET_VAR 'val tmp_9: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
GET_VAR 'val tmp_9: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
value: GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
VAR name:a2 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_10 type:kotlin.Int [val]
CALL 'public final fun get (index: kotlin.Int): kotlin.Int [operator] declared in kotlin.IntArray' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
VAR IR_TEMPORARY_VARIABLE name:tmp_11 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:kotlin.Int [val]
CALL 'public final fun dec (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_10: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
$this: CALL 'public final fun get (index: kotlin.Int): kotlin.Int [operator] declared in kotlin.IntArray' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
CALL 'public final fun set (index: kotlin.Int, value: kotlin.Int): kotlin.Unit [operator] declared in kotlin.IntArray' type=kotlin.Unit origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
value: GET_VAR 'val tmp_11: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
GET_VAR 'val tmp_11: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
value: GET_VAR 'val tmp_4: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
GET_VAR 'val tmp_4: kotlin.Int [val] declared in <root>.testArrayPrefix' type=kotlin.Int origin=null
FUN name:testArrayPostfix visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:a1 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_12 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.Int [val]
CALL 'public final fun get (index: kotlin.Int): kotlin.Int [operator] declared in kotlin.IntArray' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
@@ -145,11 +131,11 @@ FILE fqName:<root> fileName:/incrementDecrement.kt
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
value: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_12: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_12: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_5: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_5: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
VAR name:a2 type:kotlin.Int [val]
BLOCK type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_13 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:kotlin.Int [val]
CALL 'public final fun get (index: kotlin.Int): kotlin.Int [operator] declared in kotlin.IntArray' type=kotlin.Int origin=null
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
@@ -157,5 +143,5 @@ FILE fqName:<root> fileName:/incrementDecrement.kt
$this: CALL 'public final fun <get-arr> (): kotlin.IntArray declared in <root>' type=kotlin.IntArray origin=GET_PROPERTY
index: CONST Int type=kotlin.Int value=0
value: CALL 'public final fun dec (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_13: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_13: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
GET_VAR 'val tmp_6: kotlin.Int [val] declared in <root>.testArrayPostfix' type=kotlin.Int origin=null
@@ -9,15 +9,17 @@ FILE fqName:<root> fileName:/javaSyntheticGenericPropertyAccess.kt
CALL 'public open fun setFoo (x: kotlin.Int): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=EQ
$this: GET_VAR 'j: <root>.J<F of <root>.test> declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
x: CONST Int type=kotlin.Int value=1
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.J<F of <root>.test> [val]
GET_VAR 'j: <root>.J<F of <root>.test> declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
CALL 'public open fun getFoo (): kotlin.Int declared in <root>.J' type=kotlin.Int origin=GET_PROPERTY
$this: GET_VAR 'j: <root>.J<F of <root>.test> declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
$this: GET_VAR 'val tmp_0: <root>.J<F of <root>.test> [val] declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
CALL 'public open fun setFoo (x: kotlin.Int): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=EQ
$this: GET_VAR 'j: <root>.J<F of <root>.test> declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
$this: GET_VAR 'val tmp_0: <root>.J<F of <root>.test> [val] declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
x: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
CALL 'public open fun setFoo (x: kotlin.Int): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=EQ
$this: GET_VAR 'j: <root>.J<F of <root>.test> declared in <root>.test' type=<root>.J<F of <root>.test> origin=null
x: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
@@ -8,15 +8,17 @@ FILE fqName:<root> fileName:/javaSyntheticPropertyAccess.kt
CALL 'public open fun setFoo (x: kotlin.Int): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=EQ
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
x: CONST Int type=kotlin.Int value=1
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.J [val]
GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
CALL 'public open fun getFoo (): kotlin.Int declared in <root>.J' type=kotlin.Int origin=GET_PROPERTY
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
$this: GET_VAR 'val tmp_0: <root>.J [val] declared in <root>.test' type=<root>.J origin=null
CALL 'public open fun setFoo (x: kotlin.Int): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=EQ
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
$this: GET_VAR 'val tmp_0: <root>.J [val] declared in <root>.test' type=<root>.J origin=null
x: CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
CALL 'public open fun setFoo (x: kotlin.Int): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=EQ
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
x: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null