From 173f1fc7d15e7381a16c7ccdc659821726e24584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Tue, 23 Jul 2019 13:59:56 +0200 Subject: [PATCH] Fix statement order in LocalDeclarationsLowering Previously, the order of IrSetField statements in this lowering was non-deterministic. This broke the inliner in the JVM backend which expects statements to be in argument order. --- .../common/lower/LocalDeclarationsLowering.kt | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 5214faf992e..16b384b6428 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -87,7 +87,7 @@ class LocalDeclarationsLowering( abstract val declaration: IrFunction abstract val transformedDeclaration: IrFunction - val capturedValueToParameter: MutableMap = HashMap() + val capturedValueToParameter: MutableMap = mutableMapOf() override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? { val parameter = capturedValueToParameter[valueDeclaration] ?: return null @@ -114,7 +114,9 @@ class LocalDeclarationsLowering( private class LocalClassContext(val declaration: IrClass) : LocalContext() { lateinit var closure: Closure - val capturedValueToField: MutableMap = HashMap() + // NOTE: This map is iterated over in `rewriteClassMembers` and we're relying on + // the deterministic iteration order that `mutableMapOf` provides. + val capturedValueToField: MutableMap = mutableMapOf() override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? { val field = capturedValueToField[valueDeclaration] ?: return null @@ -380,26 +382,26 @@ class LocalDeclarationsLowering( assert(constructorsCallingSuper.any()) { "Expected at least one constructor calling super; class: $irClass" } - localClassContext.capturedValueToField.forEach { (capturedValue, field) -> - val startOffset = irClass.startOffset - val endOffset = irClass.endOffset - irClass.declarations.add(field) + irClass.declarations += localClassContext.capturedValueToField.values - for (constructorContext in constructorsCallingSuper) { - val blockBody = constructorContext.declaration.body as? IrBlockBody - ?: throw AssertionError("Unexpected constructor body: ${constructorContext.declaration.body}") - val capturedValueExpression = constructorContext.irGet(startOffset, endOffset, capturedValue)!! - blockBody.statements.add( - 0, + for (constructorContext in constructorsCallingSuper) { + val blockBody = constructorContext.declaration.body as? IrBlockBody + ?: throw AssertionError("Unexpected constructor body: ${constructorContext.declaration.body}") + + // NOTE: It's important to set the fields for captured values in the same order as the arguments, + // since `AnonymousObjectTransformer` relies on this ordering. + blockBody.statements.addAll( + 0, + localClassContext.capturedValueToField.map { (capturedValue, field) -> IrSetFieldImpl( - startOffset, endOffset, field.symbol, - IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol), - capturedValueExpression, + irClass.startOffset, irClass.endOffset, field.symbol, + IrGetValueImpl(irClass.startOffset, irClass.endOffset, irClass.thisReceiver!!.symbol), + constructorContext.irGet(irClass.startOffset, irClass.endOffset, capturedValue)!!, context.irBuiltIns.unitType, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE ) - ) - } + } + ) } }