Refine signature calculation for methods with default parameters

The problem was that he number of mask parameters for defaults when
generating methods declaration was being calculated upon resulting signature
(with additional parameters: extension receivers, enum name/ordinal),
while on call-sites the masks number was calculated by the arguments number
in resolved call, i.e. by the number of real value parameters.

And because of the additional synthetic parameters (like enum.ordinal) these
two numbers could be different.

The solution is just to use value parameters number in both places.
Note, that we only count value parameters from the original sourse
declaration, ignoring synthetic ones generated by backend (e.g.
Continuation for suspend functions)

 #KT-14565 Fixed
This commit is contained in:
Denis Zharkov
2017-02-22 16:11:27 +03:00
parent 9e03b712de
commit ecec87cbc7
12 changed files with 343 additions and 14 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
@@ -31,7 +32,12 @@ abstract class ArgumentGenerator {
*
* @see kotlin.reflect.jvm.internal.KCallableImpl.callBy
*/
open fun generate(valueArgumentsByIndex: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>): DefaultCallArgs {
open fun generate(
valueArgumentsByIndex: List<ResolvedValueArgument>,
actualArgs: List<ResolvedValueArgument>,
// may be null for a constructor of an object literal
calleeDescriptor: CallableDescriptor?
): DefaultCallArgs {
assert(valueArgumentsByIndex.size == actualArgs.size) {
"Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}"
}
@@ -48,7 +54,8 @@ abstract class ArgumentGenerator {
}
}
val defaultArgs = DefaultCallArgs(valueArgumentsByIndex.size)
// Use unwrapped version, because additional synthetic parameters can't have default values
val defaultArgs = DefaultCallArgs(calleeDescriptor?.unwrapFrontendVersion()?.valueParameters?.size ?: 0)
for (argumentWithDeclIndex in actualArgsWithDeclIndex) {
val argument = argumentWithDeclIndex.arg
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.ValueArgument;
@@ -54,11 +56,12 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
@Override
public DefaultCallArgs generate(
@NotNull List<? extends ResolvedValueArgument> valueArgumentsByIndex,
@NotNull List<? extends ResolvedValueArgument> valueArgs
@NotNull List<? extends ResolvedValueArgument> valueArgs,
@Nullable CallableDescriptor calleeDescriptor
) {
boolean shouldMarkLineNumbers = this.codegen.isShouldMarkLineNumbers();
this.codegen.setShouldMarkLineNumbers(false);
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs);
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs, calleeDescriptor);
this.codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers);
return defaultArgs;
}
@@ -1709,7 +1709,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
ArgumentGenerator argumentGenerator =
new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
argumentGenerator.generate(valueArguments, valueArguments);
argumentGenerator.generate(valueArguments, valueArguments, null);
}
Collection<ClassConstructorDescriptor> constructors = classDescriptor.getConstructors();
@@ -2867,7 +2867,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
DefaultCallArgs defaultArgs =
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
argumentGenerator.generate(
valueArguments,
new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()),
resolvedCall.getResultingDescriptor()
);
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
tailRecursionCodegen.generateTailRecursion(resolvedCall);
@@ -883,7 +883,7 @@ public abstract class StackValue {
newReceiver.put(newReceiver.type, v);
callGenerator.processAndPutHiddenParameters(false);
defaultArgs = generator.generate(valueArguments, valueArguments);
defaultArgs = generator.generate(valueArguments, valueArguments, call.getResultingDescriptor());
}
private ArgumentGenerator createArgumentGenerator() {
@@ -1154,13 +1154,13 @@ public class KotlinTypeMapper {
}
@NotNull
private static String getDefaultDescriptor(@NotNull Method method, @Nullable String dispatchReceiverDescriptor, boolean isExtension) {
private static String getDefaultDescriptor(
@NotNull Method method,
@Nullable String dispatchReceiverDescriptor,
@NotNull CallableDescriptor callableDescriptor
) {
String descriptor = method.getDescriptor();
int argumentsCount = Type.getArgumentTypes(descriptor).length;
if (isExtension) {
argumentsCount--;
}
int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE;
int maskArgumentsCount = (callableDescriptor.getValueParameters().size() + Integer.SIZE - 1) / Integer.SIZE;
String additionalArgs = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
additionalArgs += (isConstructor(method) ? DEFAULT_CONSTRUCTOR_MARKER : OBJECT_TYPE).getDescriptor();
String result = descriptor.replace(")", additionalArgs + ")");
@@ -1186,7 +1186,7 @@ public class KotlinTypeMapper {
String descriptor = getDefaultDescriptor(
jvmSignature,
isStaticMethod(kind, functionDescriptor) || isConstructor ? null : ownerType.getDescriptor(),
functionDescriptor.getExtensionReceiverParameter() != null
CodegenUtilKt.unwrapFrontendVersion(functionDescriptor)
);
return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);