[FIR2IR] Introduce IrBlock for reordering arguments if needed

This commit is contained in:
Juan Chen
2020-04-09 16:56:14 -07:00
committed by Mikhail Glukhikh
parent acc5633811
commit bae41ddf6d
14 changed files with 55 additions and 48 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.psi
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
internal class CallAndReferenceGenerator(
private val components: Fir2IrComponents,
@@ -304,11 +306,30 @@ internal class CallAndReferenceGenerator(
((call.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
val valueParameters = function?.valueParameters
if (valueParameters != null) {
for ((argument, parameter) in argumentMapping) {
val argumentExpression = visitor.convertToIrExpression(argument)
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
if (needArgumentReordering(argumentMapping.values, valueParameters)) {
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
for ((argument, parameter) in argumentMapping) {
val parameterIndex = valueParameters.indexOf(parameter)
val irArgument = visitor.convertToIrExpression(argument)
if (irArgument.hasNoSideEffects()) {
putValueArgument(parameterIndex, irArgument)
} else {
val tempVar = declarationStorage.declareTemporaryVariable(irArgument, parameter.name.asString()).apply {
parent = conversionScope.parentFromStack()
}
this.statements.add(tempVar)
putValueArgument(parameterIndex, IrGetValueImpl(startOffset, endOffset, tempVar.symbol, null))
}
}
this.statements.add(this@applyCallArguments)
}
} else {
for ((argument, parameter) in argumentMapping) {
val argumentExpression = visitor.convertToIrExpression(argument)
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
}
return this
}
return this
}
}
for ((index, argument) in call.arguments.withIndex()) {
@@ -337,6 +358,18 @@ internal class CallAndReferenceGenerator(
}
}
private fun needArgumentReordering(parametersInActualOrder: Collection<FirValueParameter>, valueParameters: List<FirValueParameter>): Boolean {
var lastValueParameterIndex = -1
for (parameter in parametersInActualOrder) {
val index = valueParameters.indexOf(parameter)
if (index < lastValueParameterIndex) {
return true
}
lastValueParameterIndex = index
}
return false
}
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
return when (this) {
is IrMemberAccessExpressionBase -> {
@@ -356,6 +389,14 @@ internal class CallAndReferenceGenerator(
)
}
}
is IrBlockImpl -> apply {
if (statements.isNotEmpty()) {
val lastStatement = statements.last()
if (lastStatement is IrExpression) {
statements[statements.size - 1] = lastStatement.applyTypeArguments(access)
}
}
}
else -> this
}
}
@@ -418,6 +459,14 @@ internal class CallAndReferenceGenerator(
}
this
}
is IrBlockImpl -> apply {
if (statements.isNotEmpty()) {
val lastStatement = statements.last()
if (lastStatement is IrExpression) {
statements[statements.size - 1] = lastStatement.applyReceivers(qualifiedAccess, explicitReceiverExpression)
}
}
}
else -> this
}
}
@@ -449,4 +498,4 @@ internal class CallAndReferenceGenerator(
"Unresolved reference: ${calleeReference.render()}"
)
}
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun test(a: String, b: String): String {
return a + b;
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
var invokeOrder = "";
val expectedResult = "0_1_9"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
var invokeOrder = "";
val expectedResult = "1_0_1_9"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
var invokeOrder: String = ""
fun test(x: Double = { invokeOrder += "x"; 1.0 }(), a: String, y: Long = { invokeOrder += "y"; 1 }(), b: String): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
var invokeOrder = "";
val expectedResult = "1_0_1_L"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
return Z().test()
}
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KT-9277 Unexpected NullPointerException in an invocaton with named arguments
fun box(): String {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
var res = "";
var call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"})
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
var res = "";
var call = Z("Z").test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"})
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperComputationOrderOfTailrecDefaultParameters
// IGNORE_BACKEND_FIR: JVM_IR
// Flag above doesn't matter cause 1 default value is passed explicitly in tail recursion call
// DONT_RUN_GENERATED_CODE: JS
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
var res = ""
fun getM(): String {
@@ -1,32 +0,0 @@
FILE fqName:<root> fileName:/callWithReorderedArguments.kt
FUN name:foo visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Unit
VALUE_PARAMETER name:a index:0 type:kotlin.Int
VALUE_PARAMETER name:b index:1 type:kotlin.Int
BLOCK_BODY
FUN name:noReorder1 visibility:public modality:FINAL <> () returnType:kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun noReorder1 (): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=1
FUN name:noReorder2 visibility:public modality:FINAL <> () returnType:kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun noReorder2 (): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=2
FUN name:reordered1 visibility:public modality:FINAL <> () returnType:kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun reordered1 (): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=1
FUN name:reordered2 visibility:public modality:FINAL <> () returnType:kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun reordered2 (): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=2
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun foo (a: kotlin.Int, b: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
a: CALL 'public final fun noReorder1 (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
b: CALL 'public final fun noReorder2 (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
CALL 'public final fun foo (a: kotlin.Int, b: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
a: CALL 'public final fun reordered2 (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
b: CALL 'public final fun reordered1 (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
CALL 'public final fun foo (a: kotlin.Int, b: kotlin.Int): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
a: CALL 'public final fun reordered2 (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
b: CONST Int type=kotlin.Int value=1
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun foo(a: Int, b: Int) {}
fun noReorder1() = 1