JVM_IR: fix copying of receivers when unboxing inline class parameters

If an extension receiver is copied into a normal parameter, this may
later cause default argument masks to be shifted.
This commit is contained in:
pyos
2020-09-29 11:59:25 +02:00
committed by Alexander Udalov
parent adcbfc7b4c
commit 1190457759
7 changed files with 64 additions and 33 deletions
@@ -118,6 +118,11 @@ public class FirCompileKotlinAgainstKotlinTestGenerated extends AbstractFirCompi
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
}
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -146,45 +146,37 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean, pr
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, function.origin) {
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
val newValueParameters = ArrayList<IrValueParameter>()
for ((index, parameter) in function.explicitParameters.withIndex()) {
val name = if (parameter == function.extensionReceiverParameter) Name.identifier("\$receiver") else parameter.name
val newParameter: IrValueParameter
if (parameter == function.dispatchReceiverParameter) {
newParameter = parameter.copyTo(this, index = -1, name = name, defaultValue = null)
dispatchReceiverParameter = newParameter
} else {
newParameter = parameter.copyTo(this, index = index - 1, name = name, defaultValue = null)
newValueParameters += newParameter
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this, index = -1, name = Name.identifier("\$receiver"))
valueParameters = function.valueParameters.mapIndexed { index, parameter ->
parameter.copyTo(this, index = index, defaultValue = null).also {
// Assuming that constructors and non-override functions are always replaced with the unboxed
// equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`.
it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
}
// Assuming that constructors and non-override functions are always replaced with the unboxed
// equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`.
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
}
valueParameters = newValueParameters
}
private fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT, noFakeOverride = true) {
val newValueParameters = ArrayList<IrValueParameter>()
for ((index, parameter) in function.explicitParameters.withIndex()) {
newValueParameters += when (parameter) {
// FAKE_OVERRIDEs have broken dispatch receivers
function.dispatchReceiverParameter ->
function.parentAsClass.thisReceiver!!.copyTo(
this, index = index, name = Name.identifier("arg$index"),
type = function.parentAsClass.defaultType, origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
)
function.extensionReceiverParameter ->
parameter.copyTo(
this, index = index, name = Name.identifier("\$this\$${function.name}"),
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
)
else ->
parameter.copyTo(this, index = index, defaultValue = null).also {
// See comment next to a similar line above.
it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
}
val newValueParameters = mutableListOf<IrValueParameter>()
if (function.dispatchReceiverParameter != null) {
// FAKE_OVERRIDEs have broken dispatch receivers
newValueParameters += function.parentAsClass.thisReceiver!!.copyTo(
this, index = newValueParameters.size, name = Name.identifier("arg${newValueParameters.size}"),
type = function.parentAsClass.defaultType, origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
)
}
function.extensionReceiverParameter?.let {
newValueParameters += it.copyTo(
this, index = newValueParameters.size, name = Name.identifier("\$this\$${function.name}"),
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
)
}
for (parameter in function.valueParameters) {
newValueParameters += parameter.copyTo(this, index = newValueParameters.size, defaultValue = null).also {
// See comment next to a similar line above.
it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
}
}
valueParameters = newValueParameters
@@ -0,0 +1,14 @@
// !LANGUAGE: +InlineClasses
// FILE: A.kt
package z
inline class Z(val s: String)
class X {
fun Int.foo(z: Z, value: String = "OK") = value
}
// FILE: B.kt
import z.*
fun box(): String = with(X()) { 1.foo(Z("")) }
@@ -123,6 +123,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
}
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -118,6 +118,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
}
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -118,6 +118,11 @@ public class JvmIrAgainstOldBoxTestGenerated extends AbstractJvmIrAgainstOldBoxT
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
}
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -118,6 +118,11 @@ public class JvmOldAgainstIrBoxTestGenerated extends AbstractJvmOldAgainstIrBoxT
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
}
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");