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,47 +146,39 @@ 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) {
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
}
// Assuming that constructors and non-override functions are always replaced with the unboxed // Assuming that constructors and non-override functions are always replaced with the unboxed
// equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`. // equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`.
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this) it.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
function.dispatchReceiverParameter -> newValueParameters += function.parentAsClass.thisReceiver!!.copyTo(
function.parentAsClass.thisReceiver!!.copyTo( this, index = newValueParameters.size, name = Name.identifier("arg${newValueParameters.size}"),
this, index = index, name = Name.identifier("arg$index"),
type = function.parentAsClass.defaultType, origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER type = function.parentAsClass.defaultType, origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
) )
function.extensionReceiverParameter -> }
parameter.copyTo( function.extensionReceiverParameter?.let {
this, index = index, name = Name.identifier("\$this\$${function.name}"), newValueParameters += it.copyTo(
this, index = newValueParameters.size, name = Name.identifier("\$this\$${function.name}"),
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
) )
else -> }
parameter.copyTo(this, index = index, defaultValue = null).also { for (parameter in function.valueParameters) {
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");