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"); runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
} }
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt") @TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception { public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -146,45 +146,37 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean, pr
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction = private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, function.origin) { buildReplacement(function, function.origin) {
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction) require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
val newValueParameters = ArrayList<IrValueParameter>() dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
for ((index, parameter) in function.explicitParameters.withIndex()) { extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this, index = -1, name = Name.identifier("\$receiver"))
val name = if (parameter == function.extensionReceiverParameter) Name.identifier("\$receiver") else parameter.name valueParameters = function.valueParameters.mapIndexed { index, parameter ->
val newParameter: IrValueParameter parameter.copyTo(this, index = index, defaultValue = null).also {
if (parameter == function.dispatchReceiverParameter) { // Assuming that constructors and non-override functions are always replaced with the unboxed
newParameter = parameter.copyTo(this, index = -1, name = name, defaultValue = null) // equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`.
dispatchReceiverParameter = newParameter it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
} else {
newParameter = parameter.copyTo(this, index = index - 1, name = name, defaultValue = null)
newValueParameters += newParameter
} }
// 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 = private fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT, noFakeOverride = true) { buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT, noFakeOverride = true) {
val newValueParameters = ArrayList<IrValueParameter>() val newValueParameters = mutableListOf<IrValueParameter>()
for ((index, parameter) in function.explicitParameters.withIndex()) { if (function.dispatchReceiverParameter != null) {
newValueParameters += when (parameter) { // FAKE_OVERRIDEs have broken dispatch receivers
// FAKE_OVERRIDEs have broken dispatch receivers newValueParameters += function.parentAsClass.thisReceiver!!.copyTo(
function.dispatchReceiverParameter -> this, index = newValueParameters.size, name = Name.identifier("arg${newValueParameters.size}"),
function.parentAsClass.thisReceiver!!.copyTo( type = function.parentAsClass.defaultType, origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
this, index = index, name = Name.identifier("arg$index"), )
type = function.parentAsClass.defaultType, origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER }
) function.extensionReceiverParameter?.let {
function.extensionReceiverParameter -> newValueParameters += it.copyTo(
parameter.copyTo( this, index = newValueParameters.size, name = Name.identifier("\$this\$${function.name}"),
this, index = index, name = Name.identifier("\$this\$${function.name}"), origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER )
) }
else -> for (parameter in function.valueParameters) {
parameter.copyTo(this, index = index, defaultValue = null).also { newValueParameters += parameter.copyTo(this, index = newValueParameters.size, defaultValue = null).also {
// See comment next to a similar line above. // See comment next to a similar line above.
it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this) it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
}
} }
} }
valueParameters = newValueParameters 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"); runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
} }
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt") @TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception { public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -118,6 +118,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
} }
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt") @TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception { public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -118,6 +118,11 @@ public class JvmIrAgainstOldBoxTestGenerated extends AbstractJvmIrAgainstOldBoxT
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
} }
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt") @TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception { public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
@@ -118,6 +118,11 @@ public class JvmOldAgainstIrBoxTestGenerated extends AbstractJvmOldAgainstIrBoxT
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
} }
@TestMetadata("defaultWithInlineClassAndReceivers.kt")
public void testDefaultWithInlineClassAndReceivers() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("delegatedDefault.kt") @TestMetadata("delegatedDefault.kt")
public void testDelegatedDefault() throws Exception { public void testDelegatedDefault() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt"); runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");