From 3dc7b6c3eec1ceee1917563ca9e8e71a12539d08 Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 12 Jul 2021 15:30:55 +0200 Subject: [PATCH] IR: preserve argument evaluation order more carefully 1. receivers should be evaluated before named arguments; 2. just because an argument has no side effects doesn't mean it is not affected by the other arguments' side effects - in that case it should still be evaluated in source order. #KT-47660 Fixed --- .../generators/CallAndReferenceGenerator.kt | 105 ++++++-------- .../FirBlackBoxCodegenTestGenerated.java | 6 + .../kotlin/psi2ir/generators/CallGenerator.kt | 50 +++---- .../kotlin/psi2ir/intermediate/CallBuilder.kt | 3 +- .../codegen/box/argumentOrder/arguments.kt | 21 +-- .../box/argumentOrder/singleSideEffect.kt | 8 ++ ...ringInDelegatingConstructorCall.fir.kt.txt | 44 ------ ...rderingInDelegatingConstructorCall.fir.txt | 133 ------------------ ...ntReorderingInDelegatingConstructorCall.kt | 1 + ...orderingInDelegatingConstructorCall.kt.txt | 12 +- ...tReorderingInDelegatingConstructorCall.txt | 21 ++- .../codegen/BlackBoxCodegenTestGenerated.java | 6 + .../IrBlackBoxCodegenTestGenerated.java | 6 + .../LightAnalysisModeTestGenerated.java | 5 + 14 files changed, 123 insertions(+), 298 deletions(-) create mode 100644 compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt delete mode 100644 compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.kt.txt delete mode 100644 compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.txt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index 22028b6957d..88b812ce67b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -43,6 +43,7 @@ import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects +import org.jetbrains.kotlin.psi2ir.generators.isUnchanging import org.jetbrains.kotlin.types.AbstractTypeChecker class CallAndReferenceGenerator( @@ -294,8 +295,8 @@ class CallAndReferenceGenerator( is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol) else -> generateErrorCallExpression(startOffset, endOffset, qualifiedAccess.calleeReference, type) } - }.applyCallArguments(qualifiedAccess as? FirCall, annotationMode) - .applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, explicitReceiverExpression) + }.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, explicitReceiverExpression) + .applyCallArguments(qualifiedAccess as? FirCall, annotationMode) } catch (e: Throwable) { throw IllegalStateException( "Error while translating ${qualifiedAccess.render()} " + @@ -537,31 +538,32 @@ class CallAndReferenceGenerator( substitutor: ConeSubstitutor, annotationMode: Boolean ): IrExpression { - // Assuming compile-time constants only inside annotation, we don't need a block to reorder arguments to preserve semantics. - // But, we still need to pick correct indices for named arguments. - if (!annotationMode && + val converted = argumentMapping.entries.map { (argument, parameter) -> + parameter to convertArgument(argument, parameter, substitutor, annotationMode) + } + // If none of the parameters have side effects, the evaluation order doesn't matter anyway. + // For annotations, this is always true, since arguments have to be compile-time constants. + if (!annotationMode && !converted.all { (_, irArgument) -> irArgument.hasNoSideEffects() } && 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 = convertArgument(argument, parameter, substitutor) - 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)) - } + fun IrExpression.freeze(nameHint: String): IrExpression { + if (isUnchanging()) return this + val (variable, symbol) = createTemporaryVariable(this, conversionScope, nameHint) + statements.add(variable) + return IrGetValueImpl(startOffset, endOffset, symbol, null) } - this.statements.add(this@applyArgumentsWithReorderingIfNeeded) + + dispatchReceiver = dispatchReceiver?.freeze("\$this") + extensionReceiver = extensionReceiver?.freeze("\$receiver") + for ((parameter, irArgument) in converted) { + putValueArgument(valueParameters.indexOf(parameter), irArgument.freeze(parameter.name.asString())) + } + statements.add(this@applyArgumentsWithReorderingIfNeeded) } } else { - for ((argument, parameter) in argumentMapping) { - val argumentExpression = convertArgument(argument, parameter, substitutor, annotationMode) - putValueArgument(valueParameters.indexOf(parameter), argumentExpression) + for ((parameter, irArgument) in converted) { + putValueArgument(valueParameters.indexOf(parameter), irArgument) } if (annotationMode) { for ((index, parameter) in valueParameters.withIndex()) { @@ -733,39 +735,26 @@ class CallAndReferenceGenerator( } internal fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression { - return when (this) { - is IrMemberAccessExpression<*> -> { - val argumentsCount = access.typeArguments.size - if (argumentsCount <= typeArgumentsCount) { - apply { - for ((index, argument) in access.typeArguments.withIndex()) { - val typeParameter = access.findTypeParameter(index) - val argumentFirType = (argument as FirTypeProjectionWithVariance).typeRef - val argumentIrType = if (typeParameter?.isReified == true) { - argumentFirType.approximatedForPublicPosition(approximator).toIrType() - } else { - argumentFirType.toIrType() - } - putTypeArgument(index, argumentIrType) - } - } + if (this !is IrMemberAccessExpression<*>) return this + val argumentsCount = access.typeArguments.size + if (argumentsCount <= typeArgumentsCount) { + for ((index, argument) in access.typeArguments.withIndex()) { + val typeParameter = access.findTypeParameter(index) + val argumentFirType = (argument as FirTypeProjectionWithVariance).typeRef + val argumentIrType = if (typeParameter?.isReified == true) { + argumentFirType.approximatedForPublicPosition(approximator).toIrType() } else { - val name = if (this is IrCallImpl) symbol.owner.name else "???" - IrErrorExpressionImpl( - startOffset, endOffset, type, - "Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters" - ) + argumentFirType.toIrType() } + putTypeArgument(index, argumentIrType) } - is IrBlockImpl -> apply { - if (statements.isNotEmpty()) { - val lastStatement = statements.last() - if (lastStatement is IrExpression) { - statements[statements.size - 1] = lastStatement.applyTypeArguments(access) - } - } - } - else -> this + return this + } else { + val name = if (this is IrCallImpl) symbol.owner.name else "???" + return IrErrorExpressionImpl( + startOffset, endOffset, type, + "Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters" + ) } } @@ -795,7 +784,7 @@ class CallAndReferenceGenerator( } private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess, explicitReceiverExpression: IrExpression?): IrExpression { - return when (this) { + when (this) { is IrMemberAccessExpression<*> -> { val ownerFunction = symbol.owner as? IrFunction @@ -833,25 +822,15 @@ class CallAndReferenceGenerator( } ?: it } } - this } is IrFieldAccessExpression -> { val ownerField = symbol.owner if (!ownerField.isStatic) { receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression) } - 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 } + return this } private fun generateErrorCallExpression( diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 1e9ca3a33c1..64648898d95 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -607,6 +607,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testSimpleInClass() throws Exception { runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt"); } + + @Test + @TestMetadata("singleSideEffect.kt") + public void testSingleSideEffect() throws Exception { + runTest("compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt"); + } } @Nested diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 843f3017926..3b34466607b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor +import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.types.IrDynamicType @@ -383,48 +384,41 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator call: CallBuilder, irResultType: IrType ): IrExpression { - val resolvedCall = call.original - - val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values - val valueParameters = resolvedCall.resultingDescriptor.valueParameters - val irBlock = IrBlockImpl(startOffset, endOffset, irResultType, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL) - val valueArgumentsToValueParameters = HashMap() - for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) { - val valueParameter = valueParameters[index] - valueArgumentsToValueParameters[valueArgument] = valueParameter - } - - val irArgumentValues = HashMap() - - for (valueArgument in valueArgumentsInEvaluationOrder) { - val valueParameter = valueArgumentsToValueParameters[valueArgument]!! - val irArgument = call.getValueArgument(valueParameter) ?: continue - val irArgumentValue = if (irArgument.hasNoSideEffects()) - generateExpressionValue(irArgument.type) { irArgument } // Computing a lambda has no side effects, can generate in place + fun IrExpression.freeze(nameHint: String) = + if (isUnchanging()) + this else - scope.createTemporaryVariableInBlock(context, irArgument, irBlock, valueParameter.name.asString()) - irArgumentValues[valueParameter] = irArgumentValue - } + scope.createTemporaryVariableInBlock(context, this, irBlock, nameHint).load() - resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, _ -> - val valueParameter = valueParameters[index] - irCall.putValueArgument(index, irArgumentValues[valueParameter]?.load()) - } + irCall.dispatchReceiver = irCall.dispatchReceiver?.freeze("\$this") + irCall.extensionReceiver = irCall.extensionReceiver?.freeze("\$receiver") + val resolvedCall = call.original + val valueParameters = resolvedCall.resultingDescriptor.valueParameters + val valueArgumentsToIndex = HashMap() + for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) { + valueArgumentsToIndex[valueArgument] = index + } + for (valueArgument in resolvedCall.valueArguments.values) { + val index = valueArgumentsToIndex[valueArgument]!! + val irArgument = call.getValueArgument(valueParameters[index]) ?: continue + irCall.putValueArgument(index, irArgument.freeze(valueParameters[index].name.asString())) + } irBlock.statements.add(irCall) - return irBlock } } -fun IrExpression.hasNoSideEffects() = +fun IrExpression.isUnchanging() = this is IrFunctionExpression || (this is IrCallableReference<*> && dispatchReceiver == null && extensionReceiver == null) || this is IrClassReference || this is IrConst<*> || - this is IrGetValue + (this is IrGetValue && !symbol.owner.let { it is IrVariable && it.isVar }) + +fun IrExpression.hasNoSideEffects() = isUnchanging() || this is IrGetValue fun CallGenerator.generateCall(ktElement: KtElement, call: CallBuilder, origin: IrStatementOrigin? = null) = generateCall(ktElement.startOffsetSkippingComments, ktElement.endOffset, call, origin) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt index 5af5c2c023f..1e5460d00c9 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi2ir.intermediate import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects import org.jetbrains.kotlin.psi2ir.isValueArgumentReorderingRequired import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.types.KotlinType @@ -54,7 +55,7 @@ fun CallBuilder.getValueArgumentsInParameterOrder(): List = descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] } fun CallBuilder.isValueArgumentReorderingRequired() = - original.isValueArgumentReorderingRequired() + original.isValueArgumentReorderingRequired() && irValueArgumentsByIndex.any { it != null && !it.hasNoSideEffects() } val CallBuilder.hasExtensionReceiver: Boolean get() = diff --git a/compiler/testData/codegen/box/argumentOrder/arguments.kt b/compiler/testData/codegen/box/argumentOrder/arguments.kt index f3d4d9b9b33..d671f692591 100644 --- a/compiler/testData/codegen/box/argumentOrder/arguments.kt +++ b/compiler/testData/codegen/box/argumentOrder/arguments.kt @@ -1,13 +1,18 @@ - -fun test(a: String, b: String): String { - return a + b; +class C(val x: String) { + fun test(a: String, b: String): String = + x + a + b } +fun String.test(a: String, b: String): String = + this + a + b + fun box(): String { - var res = ""; - val call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}()) - - if (res != "KO" || call != "OK") return "fail: $res != KO or $call != OK" + var res = "" + var call = {res += "1"; "x"}().test(b = {res += "2"; "b"}(), a = {res += "3"; "a"}()) + if (res != "123" || call != "xab") return "fail1: $res != 123 or $call != xab" + res = "" + call = {res += "1"; C("x")}().test(b = {res += "2"; "b"}(), a = {res += "3"; "a"}()) + if (res != "123" || call != "xab") return "fail2: $res != 123 or $call != xab" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt b/compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt new file mode 100644 index 00000000000..6a9232e84ed --- /dev/null +++ b/compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt @@ -0,0 +1,8 @@ +fun box(): String { + var x = "c" + val call = test(c = x, b = { x = "a"; "b" }(), a = x) + return if (call == "abc") "OK" else "fail: $call != abc" +} + +fun test(a: String, b: String, c: String): String = + a + b + c diff --git a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.kt.txt b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.kt.txt deleted file mode 100644 index feb8a4114e0..00000000000 --- a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.kt.txt +++ /dev/null @@ -1,44 +0,0 @@ -open class Base { - constructor(x: Int, y: Int) /* primary */ { - super/*Any*/() - /* () */ - - } - - val x: Int - field = x - get - - val y: Int - field = y - get - -} - -class Test1 : Base { - constructor(xx: Int, yy: Int) /* primary */ { - { // BLOCK - super/*Base*/(x = xx, y = yy) - } - /* () */ - - } - -} - -class Test2 : Base { - constructor(xx: Int, yy: Int) { - { // BLOCK - super/*Base*/(x = xx, y = yy) - } - /* () */ - - } - - constructor(xxx: Int, yyy: Int, a: Any) { - { // BLOCK - this/*Test2*/(xx = xxx, yy = yyy) - } - } - -} diff --git a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.txt b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.txt deleted file mode 100644 index 9169765c62b..00000000000 --- a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.fir.txt +++ /dev/null @@ -1,133 +0,0 @@ -FILE fqName: fileName:/argumentReorderingInDelegatingConstructorCall.kt - CLASS CLASS name:Base modality:OPEN visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Base - CONSTRUCTOR visibility:public <> (x:kotlin.Int, y:kotlin.Int) returnType:.Base [primary] - VALUE_PARAMETER name:x index:0 type:kotlin.Int - VALUE_PARAMETER name:y index:1 type:kotlin.Int - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Base modality:OPEN visibility:public superTypes:[kotlin.Any]' - PROPERTY name:x visibility:public modality:FINAL [val] - FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Int visibility:private [final] - EXPRESSION_BODY - GET_VAR 'x: kotlin.Int declared in .Base.' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER - FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.Base) returnType:kotlin.Int - correspondingProperty: PROPERTY name:x visibility:public modality:FINAL [val] - $this: VALUE_PARAMETER name: type:.Base - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun (): kotlin.Int declared in .Base' - GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null - receiver: GET_VAR ': .Base declared in .Base.' type=.Base origin=null - PROPERTY name:y visibility:public modality:FINAL [val] - FIELD PROPERTY_BACKING_FIELD name:y type:kotlin.Int visibility:private [final] - EXPRESSION_BODY - GET_VAR 'y: kotlin.Int declared in .Base.' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER - FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.Base) returnType:kotlin.Int - correspondingProperty: PROPERTY name:y visibility:public modality:FINAL [val] - $this: VALUE_PARAMETER name: type:.Base - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun (): kotlin.Int declared in .Base' - GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:y type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null - receiver: GET_VAR ': .Base declared in .Base.' type=.Base origin=null - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] - overridden: - public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] - overridden: - public open fun hashCode (): kotlin.Int declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] - overridden: - public open fun toString (): kotlin.String declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[.Base] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Test1 - CONSTRUCTOR visibility:public <> (xx:kotlin.Int, yy:kotlin.Int) returnType:.Test1 [primary] - VALUE_PARAMETER name:xx index:0 type:kotlin.Int - VALUE_PARAMETER name:yy index:1 type:kotlin.Int - BLOCK_BODY - BLOCK type=.Base origin=ARGUMENTS_REORDERING_FOR_CALL - DELEGATING_CONSTRUCTOR_CALL 'public constructor (x: kotlin.Int, y: kotlin.Int) [primary] declared in .Base' - x: GET_VAR 'xx: kotlin.Int declared in .Test1.' type=kotlin.Int origin=null - y: GET_VAR 'yy: kotlin.Int declared in .Test1.' type=kotlin.Int origin=null - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[.Base]' - PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val] - overridden: - public final x: kotlin.Int [val] - FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:.Base) returnType:kotlin.Int [fake_override] - correspondingProperty: PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val] - overridden: - public final fun (): kotlin.Int declared in .Base - $this: VALUE_PARAMETER name: type:.Base - PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val] - overridden: - public final y: kotlin.Int [val] - FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:.Base) returnType:kotlin.Int [fake_override] - correspondingProperty: PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val] - overridden: - public final fun (): kotlin.Int declared in .Base - $this: VALUE_PARAMETER name: type:.Base - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] - overridden: - public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .Base - $this: VALUE_PARAMETER name: type:kotlin.Any - VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] - overridden: - public open fun hashCode (): kotlin.Int [fake_override] declared in .Base - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] - overridden: - public open fun toString (): kotlin.String [fake_override] declared in .Base - $this: VALUE_PARAMETER name: type:kotlin.Any - CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[.Base] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Test2 - CONSTRUCTOR visibility:public <> (xx:kotlin.Int, yy:kotlin.Int) returnType:.Test2 - VALUE_PARAMETER name:xx index:0 type:kotlin.Int - VALUE_PARAMETER name:yy index:1 type:kotlin.Int - BLOCK_BODY - BLOCK type=.Base origin=ARGUMENTS_REORDERING_FOR_CALL - DELEGATING_CONSTRUCTOR_CALL 'public constructor (x: kotlin.Int, y: kotlin.Int) [primary] declared in .Base' - x: GET_VAR 'xx: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null - y: GET_VAR 'yy: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[.Base]' - CONSTRUCTOR visibility:public <> (xxx:kotlin.Int, yyy:kotlin.Int, a:kotlin.Any) returnType:.Test2 - VALUE_PARAMETER name:xxx index:0 type:kotlin.Int - VALUE_PARAMETER name:yyy index:1 type:kotlin.Int - VALUE_PARAMETER name:a index:2 type:kotlin.Any - BLOCK_BODY - BLOCK type=.Test2 origin=ARGUMENTS_REORDERING_FOR_CALL - DELEGATING_CONSTRUCTOR_CALL 'public constructor (xx: kotlin.Int, yy: kotlin.Int) declared in .Test2' - xx: GET_VAR 'xxx: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null - yy: GET_VAR 'yyy: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null - PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val] - overridden: - public final x: kotlin.Int [val] - FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:.Base) returnType:kotlin.Int [fake_override] - correspondingProperty: PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val] - overridden: - public final fun (): kotlin.Int declared in .Base - $this: VALUE_PARAMETER name: type:.Base - PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val] - overridden: - public final y: kotlin.Int [val] - FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:.Base) returnType:kotlin.Int [fake_override] - correspondingProperty: PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val] - overridden: - public final fun (): kotlin.Int declared in .Base - $this: VALUE_PARAMETER name: type:.Base - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] - overridden: - public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .Base - $this: VALUE_PARAMETER name: type:kotlin.Any - VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] - overridden: - public open fun hashCode (): kotlin.Int [fake_override] declared in .Base - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] - overridden: - public open fun toString (): kotlin.String [fake_override] declared in .Base - $this: VALUE_PARAMETER name: type:kotlin.Any diff --git a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt index f019a7db5cb..67b9e9ea889 100644 --- a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt +++ b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL open class Base(val x: Int, val y: Int) class Test1(xx: Int, yy: Int) : Base(y = yy, x = xx) diff --git a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt.txt b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt.txt index 9ab2b723751..1c6432ff858 100644 --- a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt.txt +++ b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.kt.txt @@ -17,9 +17,7 @@ open class Base { class Test1 : Base { constructor(xx: Int, yy: Int) /* primary */ { - { // BLOCK - super/*Base*/(x = xx, y = yy) - } + super/*Base*/(x = xx, y = yy) /* () */ } @@ -28,17 +26,13 @@ class Test1 : Base { class Test2 : Base { constructor(xx: Int, yy: Int) { - { // BLOCK - super/*Base*/(x = xx, y = yy) - } + super/*Base*/(x = xx, y = yy) /* () */ } constructor(xxx: Int, yyy: Int, a: Any) { - { // BLOCK - this/*Test2*/(xx = xxx, yy = yyy) - } + this/*Test2*/(xx = xxx, yy = yyy) } } diff --git a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.txt b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.txt index 74d5ce3421b..ec5cd288843 100644 --- a/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.txt +++ b/compiler/testData/ir/irText/classes/argumentReorderingInDelegatingConstructorCall.txt @@ -48,10 +48,9 @@ FILE fqName: fileName:/argumentReorderingInDelegatingConstructorCall.kt VALUE_PARAMETER name:xx index:0 type:kotlin.Int VALUE_PARAMETER name:yy index:1 type:kotlin.Int BLOCK_BODY - BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL - DELEGATING_CONSTRUCTOR_CALL 'public constructor (x: kotlin.Int, y: kotlin.Int) [primary] declared in .Base' - x: GET_VAR 'xx: kotlin.Int declared in .Test1.' type=kotlin.Int origin=null - y: GET_VAR 'yy: kotlin.Int declared in .Test1.' type=kotlin.Int origin=null + DELEGATING_CONSTRUCTOR_CALL 'public constructor (x: kotlin.Int, y: kotlin.Int) [primary] declared in .Base' + x: GET_VAR 'xx: kotlin.Int declared in .Test1.' type=kotlin.Int origin=null + y: GET_VAR 'yy: kotlin.Int declared in .Test1.' type=kotlin.Int origin=null INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[.Base]' PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val] overridden: @@ -88,20 +87,18 @@ FILE fqName: fileName:/argumentReorderingInDelegatingConstructorCall.kt VALUE_PARAMETER name:xx index:0 type:kotlin.Int VALUE_PARAMETER name:yy index:1 type:kotlin.Int BLOCK_BODY - BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL - DELEGATING_CONSTRUCTOR_CALL 'public constructor (x: kotlin.Int, y: kotlin.Int) [primary] declared in .Base' - x: GET_VAR 'xx: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null - y: GET_VAR 'yy: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null + DELEGATING_CONSTRUCTOR_CALL 'public constructor (x: kotlin.Int, y: kotlin.Int) [primary] declared in .Base' + x: GET_VAR 'xx: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null + y: GET_VAR 'yy: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[.Base]' CONSTRUCTOR visibility:public <> (xxx:kotlin.Int, yyy:kotlin.Int, a:kotlin.Any) returnType:.Test2 VALUE_PARAMETER name:xxx index:0 type:kotlin.Int VALUE_PARAMETER name:yyy index:1 type:kotlin.Int VALUE_PARAMETER name:a index:2 type:kotlin.Any BLOCK_BODY - BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL - DELEGATING_CONSTRUCTOR_CALL 'public constructor (xx: kotlin.Int, yy: kotlin.Int) declared in .Test2' - xx: GET_VAR 'xxx: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null - yy: GET_VAR 'yyy: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null + DELEGATING_CONSTRUCTOR_CALL 'public constructor (xx: kotlin.Int, yy: kotlin.Int) declared in .Test2' + xx: GET_VAR 'xxx: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null + yy: GET_VAR 'yyy: kotlin.Int declared in .Test2.' type=kotlin.Int origin=null PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val] overridden: public final x: kotlin.Int [val] diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index a5eec068c1d..45430f9d3fd 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -607,6 +607,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testSimpleInClass() throws Exception { runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt"); } + + @Test + @TestMetadata("singleSideEffect.kt") + public void testSingleSideEffect() throws Exception { + runTest("compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 5fb7a71b7a6..090cd7609a6 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -607,6 +607,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testSimpleInClass() throws Exception { runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt"); } + + @Test + @TestMetadata("singleSideEffect.kt") + public void testSingleSideEffect() throws Exception { + runTest("compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt"); + } } @Nested diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 56250c06010..bd78340c4f0 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -538,6 +538,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testSimpleInClass() throws Exception { runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt"); } + + @TestMetadata("singleSideEffect.kt") + public void testSingleSideEffect() throws Exception { + runTest("compiler/testData/codegen/box/argumentOrder/singleSideEffect.kt"); + } } @TestMetadata("compiler/testData/codegen/box/arrays")