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
This commit is contained in:
+42
-63
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
|
|||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
||||||
|
import org.jetbrains.kotlin.psi2ir.generators.isUnchanging
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
|
||||||
class CallAndReferenceGenerator(
|
class CallAndReferenceGenerator(
|
||||||
@@ -294,8 +295,8 @@ class CallAndReferenceGenerator(
|
|||||||
is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
|
is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
|
||||||
else -> generateErrorCallExpression(startOffset, endOffset, qualifiedAccess.calleeReference, type)
|
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) {
|
} catch (e: Throwable) {
|
||||||
throw IllegalStateException(
|
throw IllegalStateException(
|
||||||
"Error while translating ${qualifiedAccess.render()} " +
|
"Error while translating ${qualifiedAccess.render()} " +
|
||||||
@@ -537,31 +538,32 @@ class CallAndReferenceGenerator(
|
|||||||
substitutor: ConeSubstitutor,
|
substitutor: ConeSubstitutor,
|
||||||
annotationMode: Boolean
|
annotationMode: Boolean
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
// Assuming compile-time constants only inside annotation, we don't need a block to reorder arguments to preserve semantics.
|
val converted = argumentMapping.entries.map { (argument, parameter) ->
|
||||||
// But, we still need to pick correct indices for named arguments.
|
parameter to convertArgument(argument, parameter, substitutor, annotationMode)
|
||||||
if (!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)
|
needArgumentReordering(argumentMapping.values, valueParameters)
|
||||||
) {
|
) {
|
||||||
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
|
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
|
||||||
for ((argument, parameter) in argumentMapping) {
|
fun IrExpression.freeze(nameHint: String): IrExpression {
|
||||||
val parameterIndex = valueParameters.indexOf(parameter)
|
if (isUnchanging()) return this
|
||||||
val irArgument = convertArgument(argument, parameter, substitutor)
|
val (variable, symbol) = createTemporaryVariable(this, conversionScope, nameHint)
|
||||||
if (irArgument.hasNoSideEffects()) {
|
statements.add(variable)
|
||||||
putValueArgument(parameterIndex, irArgument)
|
return IrGetValueImpl(startOffset, endOffset, symbol, null)
|
||||||
} 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@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 {
|
} else {
|
||||||
for ((argument, parameter) in argumentMapping) {
|
for ((parameter, irArgument) in converted) {
|
||||||
val argumentExpression = convertArgument(argument, parameter, substitutor, annotationMode)
|
putValueArgument(valueParameters.indexOf(parameter), irArgument)
|
||||||
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
|
|
||||||
}
|
}
|
||||||
if (annotationMode) {
|
if (annotationMode) {
|
||||||
for ((index, parameter) in valueParameters.withIndex()) {
|
for ((index, parameter) in valueParameters.withIndex()) {
|
||||||
@@ -733,39 +735,26 @@ class CallAndReferenceGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
|
internal fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
|
||||||
return when (this) {
|
if (this !is IrMemberAccessExpression<*>) return this
|
||||||
is IrMemberAccessExpression<*> -> {
|
val argumentsCount = access.typeArguments.size
|
||||||
val argumentsCount = access.typeArguments.size
|
if (argumentsCount <= typeArgumentsCount) {
|
||||||
if (argumentsCount <= typeArgumentsCount) {
|
for ((index, argument) in access.typeArguments.withIndex()) {
|
||||||
apply {
|
val typeParameter = access.findTypeParameter(index)
|
||||||
for ((index, argument) in access.typeArguments.withIndex()) {
|
val argumentFirType = (argument as FirTypeProjectionWithVariance).typeRef
|
||||||
val typeParameter = access.findTypeParameter(index)
|
val argumentIrType = if (typeParameter?.isReified == true) {
|
||||||
val argumentFirType = (argument as FirTypeProjectionWithVariance).typeRef
|
argumentFirType.approximatedForPublicPosition(approximator).toIrType()
|
||||||
val argumentIrType = if (typeParameter?.isReified == true) {
|
|
||||||
argumentFirType.approximatedForPublicPosition(approximator).toIrType()
|
|
||||||
} else {
|
|
||||||
argumentFirType.toIrType()
|
|
||||||
}
|
|
||||||
putTypeArgument(index, argumentIrType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
val name = if (this is IrCallImpl) symbol.owner.name else "???"
|
argumentFirType.toIrType()
|
||||||
IrErrorExpressionImpl(
|
|
||||||
startOffset, endOffset, type,
|
|
||||||
"Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
putTypeArgument(index, argumentIrType)
|
||||||
}
|
}
|
||||||
is IrBlockImpl -> apply {
|
return this
|
||||||
if (statements.isNotEmpty()) {
|
} else {
|
||||||
val lastStatement = statements.last()
|
val name = if (this is IrCallImpl) symbol.owner.name else "???"
|
||||||
if (lastStatement is IrExpression) {
|
return IrErrorExpressionImpl(
|
||||||
statements[statements.size - 1] = lastStatement.applyTypeArguments(access)
|
startOffset, endOffset, type,
|
||||||
}
|
"Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters"
|
||||||
}
|
)
|
||||||
}
|
|
||||||
else -> this
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,7 +784,7 @@ class CallAndReferenceGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess, explicitReceiverExpression: IrExpression?): IrExpression {
|
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess, explicitReceiverExpression: IrExpression?): IrExpression {
|
||||||
return when (this) {
|
when (this) {
|
||||||
is IrMemberAccessExpression<*> -> {
|
is IrMemberAccessExpression<*> -> {
|
||||||
val ownerFunction =
|
val ownerFunction =
|
||||||
symbol.owner as? IrFunction
|
symbol.owner as? IrFunction
|
||||||
@@ -833,25 +822,15 @@ class CallAndReferenceGenerator(
|
|||||||
} ?: it
|
} ?: it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this
|
|
||||||
}
|
}
|
||||||
is IrFieldAccessExpression -> {
|
is IrFieldAccessExpression -> {
|
||||||
val ownerField = symbol.owner
|
val ownerField = symbol.owner
|
||||||
if (!ownerField.isStatic) {
|
if (!ownerField.isStatic) {
|
||||||
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
|
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(
|
private fun generateErrorCallExpression(
|
||||||
|
|||||||
+6
@@ -607,6 +607,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
public void testSimpleInClass() throws Exception {
|
public void testSimpleInClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt");
|
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
|
@Nested
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
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.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrDynamicType
|
import org.jetbrains.kotlin.ir.types.IrDynamicType
|
||||||
@@ -383,48 +384,41 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
|||||||
call: CallBuilder,
|
call: CallBuilder,
|
||||||
irResultType: IrType
|
irResultType: IrType
|
||||||
): IrExpression {
|
): 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 irBlock = IrBlockImpl(startOffset, endOffset, irResultType, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL)
|
||||||
|
|
||||||
val valueArgumentsToValueParameters = HashMap<ResolvedValueArgument, ValueParameterDescriptor>()
|
fun IrExpression.freeze(nameHint: String) =
|
||||||
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
|
if (isUnchanging())
|
||||||
val valueParameter = valueParameters[index]
|
this
|
||||||
valueArgumentsToValueParameters[valueArgument] = valueParameter
|
|
||||||
}
|
|
||||||
|
|
||||||
val irArgumentValues = HashMap<ValueParameterDescriptor, IntermediateValue>()
|
|
||||||
|
|
||||||
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
|
|
||||||
else
|
else
|
||||||
scope.createTemporaryVariableInBlock(context, irArgument, irBlock, valueParameter.name.asString())
|
scope.createTemporaryVariableInBlock(context, this, irBlock, nameHint).load()
|
||||||
irArgumentValues[valueParameter] = irArgumentValue
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, _ ->
|
irCall.dispatchReceiver = irCall.dispatchReceiver?.freeze("\$this")
|
||||||
val valueParameter = valueParameters[index]
|
irCall.extensionReceiver = irCall.extensionReceiver?.freeze("\$receiver")
|
||||||
irCall.putValueArgument(index, irArgumentValues[valueParameter]?.load())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val resolvedCall = call.original
|
||||||
|
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
|
||||||
|
val valueArgumentsToIndex = HashMap<ResolvedValueArgument, Int>()
|
||||||
|
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)
|
irBlock.statements.add(irCall)
|
||||||
|
|
||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrExpression.hasNoSideEffects() =
|
fun IrExpression.isUnchanging() =
|
||||||
this is IrFunctionExpression ||
|
this is IrFunctionExpression ||
|
||||||
(this is IrCallableReference<*> && dispatchReceiver == null && extensionReceiver == null) ||
|
(this is IrCallableReference<*> && dispatchReceiver == null && extensionReceiver == null) ||
|
||||||
this is IrClassReference ||
|
this is IrClassReference ||
|
||||||
this is IrConst<*> ||
|
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) =
|
fun CallGenerator.generateCall(ktElement: KtElement, call: CallBuilder, origin: IrStatementOrigin? = null) =
|
||||||
generateCall(ktElement.startOffsetSkippingComments, ktElement.endOffset, call, origin)
|
generateCall(ktElement.startOffsetSkippingComments, ktElement.endOffset, call, origin)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
||||||
import org.jetbrains.kotlin.psi2ir.isValueArgumentReorderingRequired
|
import org.jetbrains.kotlin.psi2ir.isValueArgumentReorderingRequired
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -54,7 +55,7 @@ fun CallBuilder.getValueArgumentsInParameterOrder(): List<IrExpression?> =
|
|||||||
descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] }
|
descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] }
|
||||||
|
|
||||||
fun CallBuilder.isValueArgumentReorderingRequired() =
|
fun CallBuilder.isValueArgumentReorderingRequired() =
|
||||||
original.isValueArgumentReorderingRequired()
|
original.isValueArgumentReorderingRequired() && irValueArgumentsByIndex.any { it != null && !it.hasNoSideEffects() }
|
||||||
|
|
||||||
val CallBuilder.hasExtensionReceiver: Boolean
|
val CallBuilder.hasExtensionReceiver: Boolean
|
||||||
get() =
|
get() =
|
||||||
|
|||||||
+13
-8
@@ -1,13 +1,18 @@
|
|||||||
|
class C(val x: String) {
|
||||||
fun test(a: String, b: String): String {
|
fun test(a: String, b: String): String =
|
||||||
return a + b;
|
x + a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.test(a: String, b: String): String =
|
||||||
|
this + a + b
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
var res = "";
|
var res = ""
|
||||||
val call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}())
|
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"
|
||||||
if (res != "KO" || call != "OK") return "fail: $res != KO or $call != OK"
|
|
||||||
|
|
||||||
|
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"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
Vendored
-44
@@ -1,44 +0,0 @@
|
|||||||
open class Base {
|
|
||||||
constructor(x: Int, y: Int) /* primary */ {
|
|
||||||
super/*Any*/()
|
|
||||||
/* <init>() */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
/* <init>() */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class Test2 : Base {
|
|
||||||
constructor(xx: Int, yy: Int) {
|
|
||||||
{ // BLOCK
|
|
||||||
super/*Base*/(x = xx, y = yy)
|
|
||||||
}
|
|
||||||
/* <init>() */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(xxx: Int, yyy: Int, a: Any) {
|
|
||||||
{ // BLOCK
|
|
||||||
this/*Test2*/(xx = xxx, yy = yyy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-133
@@ -1,133 +0,0 @@
|
|||||||
FILE fqName:<root> fileName:/argumentReorderingInDelegatingConstructorCall.kt
|
|
||||||
CLASS CLASS name:Base modality:OPEN visibility:public superTypes:[kotlin.Any]
|
|
||||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Base
|
|
||||||
CONSTRUCTOR visibility:public <> (x:kotlin.Int, y:kotlin.Int) returnType:<root>.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 <init> () [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 <root>.Base.<init>' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER
|
|
||||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int
|
|
||||||
correspondingProperty: PROPERTY name:x visibility:public modality:FINAL [val]
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.Base
|
|
||||||
BLOCK_BODY
|
|
||||||
RETURN type=kotlin.Nothing from='public final fun <get-x> (): kotlin.Int declared in <root>.Base'
|
|
||||||
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null
|
|
||||||
receiver: GET_VAR '<this>: <root>.Base declared in <root>.Base.<get-x>' type=<root>.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 <root>.Base.<init>' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER
|
|
||||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-y> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int
|
|
||||||
correspondingProperty: PROPERTY name:y visibility:public modality:FINAL [val]
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.Base
|
|
||||||
BLOCK_BODY
|
|
||||||
RETURN type=kotlin.Nothing from='public final fun <get-y> (): kotlin.Int declared in <root>.Base'
|
|
||||||
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:y type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null
|
|
||||||
receiver: GET_VAR '<this>: <root>.Base declared in <root>.Base.<get-y>' type=<root>.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:<this> 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:<this> 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:<this> type:kotlin.Any
|
|
||||||
CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[<root>.Base]
|
|
||||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Test1
|
|
||||||
CONSTRUCTOR visibility:public <> (xx:kotlin.Int, yy:kotlin.Int) returnType:<root>.Test1 [primary]
|
|
||||||
VALUE_PARAMETER name:xx index:0 type:kotlin.Int
|
|
||||||
VALUE_PARAMETER name:yy index:1 type:kotlin.Int
|
|
||||||
BLOCK_BODY
|
|
||||||
BLOCK type=<root>.Base origin=ARGUMENTS_REORDERING_FOR_CALL
|
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
|
||||||
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
|
||||||
y: GET_VAR 'yy: kotlin.Int 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]'
|
|
||||||
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
|
|
||||||
overridden:
|
|
||||||
public final x: kotlin.Int [val]
|
|
||||||
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]
|
|
||||||
overridden:
|
|
||||||
public final fun <get-x> (): kotlin.Int declared in <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.Base
|
|
||||||
PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val]
|
|
||||||
overridden:
|
|
||||||
public final y: kotlin.Int [val]
|
|
||||||
FUN FAKE_OVERRIDE name:<get-y> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
|
|
||||||
correspondingProperty: PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val]
|
|
||||||
overridden:
|
|
||||||
public final fun <get-y> (): kotlin.Int declared in <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.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 <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> 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 <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> 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 <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
|
||||||
CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[<root>.Base]
|
|
||||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Test2
|
|
||||||
CONSTRUCTOR visibility:public <> (xx:kotlin.Int, yy:kotlin.Int) returnType:<root>.Test2
|
|
||||||
VALUE_PARAMETER name:xx index:0 type:kotlin.Int
|
|
||||||
VALUE_PARAMETER name:yy index:1 type:kotlin.Int
|
|
||||||
BLOCK_BODY
|
|
||||||
BLOCK type=<root>.Base origin=ARGUMENTS_REORDERING_FOR_CALL
|
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
|
||||||
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
|
||||||
y: GET_VAR 'yy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
|
||||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[<root>.Base]'
|
|
||||||
CONSTRUCTOR visibility:public <> (xxx:kotlin.Int, yyy:kotlin.Int, a:kotlin.Any) returnType:<root>.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=<root>.Test2 origin=ARGUMENTS_REORDERING_FOR_CALL
|
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (xx: kotlin.Int, yy: kotlin.Int) declared in <root>.Test2'
|
|
||||||
xx: GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
|
||||||
yy: GET_VAR 'yyy: kotlin.Int declared in <root>.Test2.<init>' 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:<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]
|
|
||||||
overridden:
|
|
||||||
public final fun <get-x> (): kotlin.Int declared in <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.Base
|
|
||||||
PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val]
|
|
||||||
overridden:
|
|
||||||
public final y: kotlin.Int [val]
|
|
||||||
FUN FAKE_OVERRIDE name:<get-y> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
|
|
||||||
correspondingProperty: PROPERTY FAKE_OVERRIDE name:y visibility:public modality:FINAL [fake_override,val]
|
|
||||||
overridden:
|
|
||||||
public final fun <get-y> (): kotlin.Int declared in <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.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 <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> 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 <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> 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 <root>.Base
|
|
||||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
open class Base(val x: Int, val y: Int)
|
open class Base(val x: Int, val y: Int)
|
||||||
|
|
||||||
class Test1(xx: Int, yy: Int) : Base(y = yy, x = xx)
|
class Test1(xx: Int, yy: Int) : Base(y = yy, x = xx)
|
||||||
|
|||||||
+3
-9
@@ -17,9 +17,7 @@ open class Base {
|
|||||||
|
|
||||||
class Test1 : Base {
|
class Test1 : Base {
|
||||||
constructor(xx: Int, yy: Int) /* primary */ {
|
constructor(xx: Int, yy: Int) /* primary */ {
|
||||||
{ // BLOCK
|
super/*Base*/(x = xx, y = yy)
|
||||||
super/*Base*/(x = xx, y = yy)
|
|
||||||
}
|
|
||||||
/* <init>() */
|
/* <init>() */
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -28,17 +26,13 @@ class Test1 : Base {
|
|||||||
|
|
||||||
class Test2 : Base {
|
class Test2 : Base {
|
||||||
constructor(xx: Int, yy: Int) {
|
constructor(xx: Int, yy: Int) {
|
||||||
{ // BLOCK
|
super/*Base*/(x = xx, y = yy)
|
||||||
super/*Base*/(x = xx, y = yy)
|
|
||||||
}
|
|
||||||
/* <init>() */
|
/* <init>() */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(xxx: Int, yyy: Int, a: Any) {
|
constructor(xxx: Int, yyy: Int, a: Any) {
|
||||||
{ // BLOCK
|
this/*Test2*/(xx = xxx, yy = yyy)
|
||||||
this/*Test2*/(xx = xxx, yy = yyy)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-12
@@ -48,10 +48,9 @@ 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
|
||||||
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
||||||
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
y: GET_VAR 'yy: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
|
||||||
y: GET_VAR 'yy: kotlin.Int 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]
|
||||||
overridden:
|
overridden:
|
||||||
@@ -88,20 +87,18 @@ 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
|
||||||
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
|
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
y: GET_VAR 'yy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
y: GET_VAR 'yy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
|
||||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[<root>.Base]'
|
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[<root>.Base]'
|
||||||
CONSTRUCTOR visibility:public <> (xxx:kotlin.Int, yyy:kotlin.Int, a:kotlin.Any) returnType:<root>.Test2
|
CONSTRUCTOR visibility:public <> (xxx:kotlin.Int, yyy:kotlin.Int, a:kotlin.Any) returnType:<root>.Test2
|
||||||
VALUE_PARAMETER name:xxx index:0 type:kotlin.Int
|
VALUE_PARAMETER name:xxx index:0 type:kotlin.Int
|
||||||
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
|
||||||
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (xx: kotlin.Int, yy: kotlin.Int) declared in <root>.Test2'
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (xx: kotlin.Int, yy: kotlin.Int) declared in <root>.Test2'
|
xx: GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
xx: GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
yy: GET_VAR 'yyy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
|
||||||
yy: GET_VAR 'yyy: kotlin.Int 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]
|
||||||
overridden:
|
overridden:
|
||||||
public final x: kotlin.Int [val]
|
public final x: kotlin.Int [val]
|
||||||
|
|||||||
+6
@@ -607,6 +607,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
public void testSimpleInClass() throws Exception {
|
public void testSimpleInClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt");
|
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
|
@Nested
|
||||||
|
|||||||
+6
@@ -607,6 +607,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
public void testSimpleInClass() throws Exception {
|
public void testSimpleInClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt");
|
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
|
@Nested
|
||||||
|
|||||||
+5
@@ -538,6 +538,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
public void testSimpleInClass() throws Exception {
|
public void testSimpleInClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/arrays")
|
||||||
|
|||||||
Reference in New Issue
Block a user