JVM_IR: Fix bug in suspend function with many default arguments.

This commit is contained in:
Mads Ager
2020-01-13 13:44:18 +01:00
committed by Ilmir Usmanov
parent e46adbae29
commit ca05ff1791
3 changed files with 53 additions and 11 deletions
@@ -197,7 +197,7 @@ fun IrFunction.copyValueParametersInsertingContinuationFrom(from: IrFunction, in
var additionalShift = 0
from.valueParameters.forEach {
// The continuation parameter goes before the default argument mask and handler.
if (it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION) {
if (it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION && additionalShift == 0) {
insertContinuation()
additionalShift = 1
}
@@ -167,7 +167,7 @@ private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFuncti
it.copyTypeParametersFrom(this)
// Copy the value parameters and insert the continuation parameter. The continuation parameter
// goes before the default argument mask and handler for default argument stubs.
// goes before the default argument mask(s) and handler for default argument stubs.
// TODO: It would be nice if AddContinuationLowering could insert the continuation argument before default stub generation.
// That would avoid the reshuffling both here and in createSuspendFunctionClassViewIfNeeded.
var continuationValueParam: IrValueParameter? = null
@@ -203,9 +203,9 @@ internal fun IrCall.createSuspendFunctionCallViewIfNeeded(
it.copyTypeArgumentsFrom(this)
it.dispatchReceiver = dispatchReceiver
it.extensionReceiver = extensionReceiver
// Locate the caller continuation parameter. The continuation parameter is before default argument mask and handler params.
val callerHasDefaultMask = caller.valueParameters.lastOrNull()?.origin == IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION
val callerContinuationIndex = caller.valueParameters.size - 1 - (if (callerHasDefaultMask) 2 else 0)
// Locate the caller continuation parameter. The continuation parameter is before default argument mask(s) and handler params.
val callerNumberOfMasks = caller.valueParameters.count { it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION }
val callerContinuationIndex = caller.valueParameters.size - 1 - (if (callerNumberOfMasks != 0) callerNumberOfMasks + 1 else 0)
val continuationParameter =
when {
caller.isInvokeSuspendOfLambda() || caller.isInvokeSuspendOfContinuation() ||
@@ -215,16 +215,17 @@ internal fun IrCall.createSuspendFunctionCallViewIfNeeded(
else -> IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, caller.valueParameters[callerContinuationIndex].symbol)
}
// If the suspend function view that we are calling has default parameters, we need to make sure to pass the
// continuation before the default parameter mask and handler.
val hasDefaultMask = view.valueParameters.last().origin == IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION
val continuationIndex = valueArgumentsCount - (if (hasDefaultMask) 2 else 0)
// continuation before the default parameter mask(s) and handler.
val numberOfMasks = view.valueParameters.count { it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION }
val continuationIndex = valueArgumentsCount - (if (numberOfMasks != 0) numberOfMasks + 1 else 0)
for (i in 0 until continuationIndex) {
it.putValueArgument(i, getValueArgument(i))
}
it.putValueArgument(continuationIndex, continuationParameter)
if (hasDefaultMask) {
it.putValueArgument(valueArgumentsCount - 1, getValueArgument(continuationIndex))
it.putValueArgument(valueArgumentsCount, getValueArgument(continuationIndex + 1))
if (numberOfMasks != 0) {
for (i in 0 until numberOfMasks + 1) {
it.putValueArgument(valueArgumentsCount + i - 1, getValueArgument(continuationIndex + i))
}
}
}
}
@@ -24,6 +24,43 @@ fun ordinary() = "OK"
suspend fun withDefault(s: String = "OK") = s
suspend fun withManyDefault(
s0: String = "NOT OK 0",
s1: String = "NOT OK 1",
s2: String = "NOT OK 2",
s3: String = "NOT OK 3",
s4: String = "NOT OK 4",
s5: String = "NOT OK 5",
s6: String = "NOT OK 6",
s7: String = "NOT OK 7",
s8: String = "NOT OK 8",
s9: String = "NOT OK 9",
s10: String = "NOT OK 10",
s11: String = "NOT OK 11",
s12: String = "NOT OK 12",
s13: String = "NOT OK 13",
s14: String = "NOT OK 14",
s15: String = "NOT OK 15",
s16: String = "NOT OK 16",
s17: String = "NOT OK 17",
s18: String = "NOT OK 18",
s19: String = "NOT OK 19",
s20: String = "NOT OK 20",
s21: String = "NOT OK 21",
s22: String = "NOT OK 22",
s23: String = "NOT OK 23",
s24: String = "NOT OK 24",
s25: String = "NOT OK 25",
s26: String = "NOT OK 26",
s27: String = "NOT OK 27",
s28: String = "NOT OK 28",
s29: String = "NOT OK 29",
s30: String = "NOT OK 30",
s31: String = "NOT OK 31",
s32: String = "NOT OK 32",
ok: String = "OK"
) = ok
var log = ""
var proceed = {}
@@ -64,6 +101,10 @@ fun box(): String {
builder {
res = ::withDefault.callSuspendBy(emptyMap()) as String?
}
if (res != "OK") return res ?: "FAIL 5"
builder {
res = ::withManyDefault.callSuspendBy(emptyMap()) as String?
}
builder {
::suspending.callSuspendBy(emptyMap())
}