[FIR2IR] Support argument reordering of constructor calls
This commit is contained in:
committed by
Mikhail Glukhikh
parent
bae41ddf6d
commit
e954aea4cc
+52
-35
@@ -305,31 +305,11 @@ internal class CallAndReferenceGenerator(
|
|||||||
val function =
|
val function =
|
||||||
((call.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
((call.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
||||||
val valueParameters = function?.valueParameters
|
val valueParameters = function?.valueParameters
|
||||||
|
|
||||||
if (valueParameters != null) {
|
if (valueParameters != null) {
|
||||||
if (needArgumentReordering(argumentMapping.values, valueParameters)) {
|
return applyArgumentsWithReordering(
|
||||||
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
|
argumentMapping, valueParameters, visitor, conversionScope, declarationStorage
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ((index, argument) in call.arguments.withIndex()) {
|
for ((index, argument) in call.arguments.withIndex()) {
|
||||||
@@ -358,17 +338,6 @@ 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 {
|
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
@@ -499,3 +468,51 @@ internal class CallAndReferenceGenerator(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun IrCallWithIndexedArgumentsBase.applyArgumentsWithReordering(
|
||||||
|
argumentMapping: Map<FirExpression, FirValueParameter>,
|
||||||
|
valueParameters: List<FirValueParameter>,
|
||||||
|
visitor: Fir2IrVisitor,
|
||||||
|
conversionScope: Fir2IrConversionScope,
|
||||||
|
declarationStorage: Fir2IrDeclarationStorage
|
||||||
|
): IrExpressionBase {
|
||||||
|
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@applyArgumentsWithReordering)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ((argument, parameter) in argumentMapping) {
|
||||||
|
val argumentExpression = visitor.convertToIrExpression(argument)
|
||||||
|
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
+17
-4
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
|
|||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
|
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.arguments
|
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
@@ -238,10 +239,22 @@ internal class ClassMemberGenerator(
|
|||||||
constructedIrType,
|
constructedIrType,
|
||||||
irConstructorSymbol
|
irConstructorSymbol
|
||||||
)
|
)
|
||||||
}.apply {
|
}.let {
|
||||||
for ((index, argument) in arguments.withIndex()) {
|
val argumentMapping = mutableMapOf<FirExpression, FirValueParameter>()
|
||||||
val argumentExpression = visitor.convertToIrExpression(argument)
|
val valueParameters = constructorSymbol.fir.valueParameters
|
||||||
putValueArgument(index, argumentExpression)
|
for (argument in arguments) {
|
||||||
|
if (argument is FirNamedArgumentExpression) {
|
||||||
|
valueParameters.firstOrNull { it.name == argument.name }?.let { argumentMapping[argument] = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argumentMapping.size == valueParameters.size) {
|
||||||
|
it.applyArgumentsWithReordering(argumentMapping, valueParameters, visitor, conversionScope, declarationStorage)
|
||||||
|
} else {
|
||||||
|
for ((index, argument) in arguments.withIndex()) {
|
||||||
|
val argumentExpression = visitor.convertToIrExpression(argument)
|
||||||
|
it.putValueArgument(index, argumentExpression)
|
||||||
|
}
|
||||||
|
it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
var result = "fail"
|
var result = "fail"
|
||||||
|
|
||||||
open class Base(val o: String, val k: String)
|
open class Base(val o: String, val k: String)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
var result = "fail"
|
var result = "fail"
|
||||||
|
|
||||||
open class Base(val o: String, val k: String)
|
open class Base(val o: String, val k: String)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
fun f(): String = "O"
|
fun f(): String = "O"
|
||||||
fun g(): String = "K"
|
fun g(): String = "K"
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
open class A(val a: String, val b: Int)
|
open class A(val a: String, val b: Int)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
open class Base(val addr: Long, val name: String)
|
open class Base(val addr: Long, val name: String)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
abstract class Base(val s: String, vararg ints: Int)
|
abstract class Base(val s: String, vararg ints: Int)
|
||||||
|
|
||||||
fun foo(s: String, ints: IntArray) = object : Base(ints = *ints, s = s) {}
|
fun foo(s: String, ints: IntArray) = object : Base(ints = *ints, s = s) {}
|
||||||
|
|||||||
+16
-6
@@ -48,9 +48,14 @@ FILE fqName:<root> fileName:/argumentReorderingInDelegatingConstructorCall.kt
|
|||||||
VALUE_PARAMETER name:xx index:0 type:kotlin.Int
|
VALUE_PARAMETER name:xx index:0 type:kotlin.Int
|
||||||
VALUE_PARAMETER name:yy index:1 type:kotlin.Int
|
VALUE_PARAMETER name:yy index:1 type:kotlin.Int
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
BLOCK type=<root>.Base origin=ARGUMENTS_REORDERING_FOR_CALL
|
||||||
x: GET_VAR 'yy: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
|
||||||
y: GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
GET_VAR 'yy: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
||||||
|
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
|
||||||
|
GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
||||||
|
x: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
||||||
|
y: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
||||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[<root>.Base]'
|
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[<root>.Base]'
|
||||||
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
||||||
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
|
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
|
||||||
@@ -90,9 +95,14 @@ FILE fqName:<root> fileName:/argumentReorderingInDelegatingConstructorCall.kt
|
|||||||
VALUE_PARAMETER name:yyy index:1 type:kotlin.Int
|
VALUE_PARAMETER name:yyy index:1 type:kotlin.Int
|
||||||
VALUE_PARAMETER name:a index:2 type:kotlin.Any
|
VALUE_PARAMETER name:a index:2 type:kotlin.Any
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (xx: kotlin.Int, yy: kotlin.Int) declared in <root>.Test2'
|
BLOCK type=<root>.Test2 origin=ARGUMENTS_REORDERING_FOR_CALL
|
||||||
xx: GET_VAR 'yyy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val]
|
||||||
yy: GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
GET_VAR 'yyy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
|
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val]
|
||||||
|
GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (xx: kotlin.Int, yy: kotlin.Int) declared in <root>.Test2'
|
||||||
|
xx: GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
|
yy: GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
||||||
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
|
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
|
||||||
correspondingProperty: PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
correspondingProperty: PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
||||||
|
|||||||
+8
-3
@@ -790,9 +790,14 @@ FILE fqName:<root> fileName:/enum.kt
|
|||||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.TestEnum6.TEST
|
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.TestEnum6.TEST
|
||||||
CONSTRUCTOR visibility:private <> () returnType:<root>.TestEnum6.TEST [primary]
|
CONSTRUCTOR visibility:private <> () returnType:<root>.TestEnum6.TEST [primary]
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
ENUM_CONSTRUCTOR_CALL 'private constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.TestEnum6'
|
BLOCK type=<root>.TestEnum6 origin=ARGUMENTS_REORDERING_FOR_CALL
|
||||||
x: CALL 'public final fun f (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
|
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
|
||||||
y: CALL 'public final fun f (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
|
CALL 'public final fun f (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
|
||||||
|
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
|
||||||
|
CALL 'public final fun f (): kotlin.Int declared in <root>' type=kotlin.Int origin=null
|
||||||
|
ENUM_CONSTRUCTOR_CALL 'private constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.TestEnum6'
|
||||||
|
x: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.TestEnum6.TEST.<init>' type=kotlin.Int origin=null
|
||||||
|
y: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.TestEnum6.TEST.<init>' type=kotlin.Int origin=null
|
||||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS ENUM_ENTRY name:TEST modality:FINAL visibility:private superTypes:[<root>.TestEnum6]'
|
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS ENUM_ENTRY name:TEST modality:FINAL visibility:private superTypes:[<root>.TestEnum6]'
|
||||||
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
||||||
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.TestEnum6) returnType:kotlin.Int [fake_override]
|
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.TestEnum6) returnType:kotlin.Int [fake_override]
|
||||||
|
|||||||
Reference in New Issue
Block a user