Fix for KT-9140: Default parameters are passed as nulls when using indexing [ ] invocation

#KT-9140 Fixed
This commit is contained in:
Michael Bogdanov
2015-11-03 15:49:20 +03:00
parent b556037915
commit 0fcaaa80df
7 changed files with 143 additions and 18 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.org.objectweb.asm.Type
import java.util.*
class DefaultCallMask(val size: Int) {
@@ -48,4 +49,12 @@ class DefaultCallMask(val size: Int) {
return masks
}
public fun generateOnStackIfNeeded(callGenerator: CallGenerator): Boolean {
val toInts = toInts()
for (mask in toInts) {
callGenerator.putValueIfNeeded(null, Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE))
}
return toInts.isNotEmpty();
}
}
@@ -2477,18 +2477,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
List<Integer> masks =
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()))
.toInts();
DefaultCallMask masks =
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
tailRecursionCodegen.generateTailRecursion(resolvedCall);
return;
}
for (int mask : masks) {
callGenerator.putValueIfNeeded(null, Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE));
}
boolean defaultMaskWasGenerated = masks.generateOnStackIfNeeded(callGenerator);
// Extra constructor marker argument
if (callableMethod instanceof CallableMethod) {
@@ -2500,7 +2497,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
}
callGenerator.genCall(callableMethod, resolvedCall, !masks.isEmpty(), this);
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
}
@NotNull
@@ -3532,7 +3529,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Callable callableMethod = resolveToCallableMethod(operationDescriptor, false);
Type[] argumentTypes = callableMethod.getParameterTypes();
StackValue collectionElementReceiver = createCollectionElementReceiver(
StackValue.CollectionElementReceiver collectionElementReceiver = createCollectionElementReceiver(
expression, receiver, operationDescriptor, isGetter, resolvedGetCall, resolvedSetCall, callable
);
@@ -3542,7 +3539,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
private StackValue createCollectionElementReceiver(
private StackValue.CollectionElementReceiver createCollectionElementReceiver(
@NotNull KtArrayAccessExpression expression,
@NotNull StackValue receiver,
@NotNull FunctionDescriptor operationDescriptor,
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.codegen;
import com.intellij.psi.tree.IElementType;
import kotlin.ArraysKt;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.Contract;
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor;
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
@@ -201,7 +203,7 @@ public abstract class StackValue {
@NotNull
public static StackValue collectionElement(
StackValue collectionElementReceiver,
CollectionElementReceiver collectionElementReceiver,
Type type,
ResolvedCall<FunctionDescriptor> getter,
ResolvedCall<FunctionDescriptor> setter,
@@ -769,11 +771,12 @@ public abstract class StackValue {
private final boolean isGetter;
private final ExpressionCodegen codegen;
private final ArgumentGenerator argumentGenerator;
private final List<ResolvedValueArgument> valueArguments;
final List<ResolvedValueArgument> valueArguments;
private final FrameMap frame;
private final StackValue receiver;
private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
DefaultCallMask mask;
public CollectionElementReceiver(
@NotNull Callable callable,
@@ -803,7 +806,7 @@ public abstract class StackValue {
ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
newReceiver.put(newReceiver.type, v);
argumentGenerator.generate(valueArguments, valueArguments);
mask = argumentGenerator.generate(valueArguments, valueArguments);
}
@Override
@@ -912,7 +915,7 @@ public abstract class StackValue {
private final FunctionDescriptor getterDescriptor;
public CollectionElement(
@NotNull StackValue collectionElementReceiver,
@NotNull CollectionElementReceiver collectionElementReceiver,
@NotNull Type type,
@Nullable ResolvedCall<FunctionDescriptor> resolvedGetCall,
@Nullable ResolvedCall<FunctionDescriptor> resolvedSetCall,
@@ -933,11 +936,16 @@ public abstract class StackValue {
if (getter == null) {
throw new UnsupportedOperationException("no getter specified");
}
getter.genInvokeInstruction(v);
CallGenerator callGenerator = codegen.defaultCallGenerator;
callGenerator.genCall(getter, resolvedGetCall, genDefaultMaskIfPresent(callGenerator), codegen);
coerceTo(type, v);
}
private boolean genDefaultMaskIfPresent(CallGenerator callGenerator) {
DefaultCallMask mask = ((CollectionElementReceiver) receiver).mask;
return mask.generateOnStackIfNeeded(callGenerator);
}
@Override
public int receiverSize() {
if (isStandardStack(codegen.typeMapper, resolvedGetCall, 1) && isStandardStack(codegen.typeMapper, resolvedSetCall, 2)) {
@@ -985,9 +993,25 @@ public abstract class StackValue {
throw new UnsupportedOperationException("no setter specified");
}
Type[] argumentTypes = setter.getParameterTypes();
coerce(topOfStackType, argumentTypes[argumentTypes.length - 1], v);
setter.genInvokeInstruction(v);
Type lastParameterType = ArraysKt.last(setter.getParameterTypes());
coerce(topOfStackType, lastParameterType, v);
//*Convention setter couldn't have default parameters, just getter can have it at last positions
//We should remove default parameters of getter from stack*/
CollectionElementReceiver collectionElementReceiver = (CollectionElementReceiver) receiver;
if (collectionElementReceiver.isGetter) {
List<ResolvedValueArgument> arguments = collectionElementReceiver.valueArguments;
List<Type> types = getter.getValueParameterTypes();
for (int i = arguments.size() - 1; i >= 0; i--) {
ResolvedValueArgument argument = arguments.get(i);
if (argument instanceof DefaultValueArgument) {
Type defaultType = types.get(i);
AsmUtil.swap(v, lastParameterType, defaultType);
AsmUtil.pop(v, defaultType);
}
}
}
codegen.defaultCallGenerator.genCall(setter, resolvedSetCall, false, codegen);
Type returnType = setter.getReturnType();
if (returnType != Type.VOID_TYPE) {
pop(v, returnType);