Fix Kotlin default interface methods calls for inline classes

When mapping callable method signature for erased inline class methods,
use original function descriptor instead of super declaration
(otherwise it would map to a default interface method with mismatching
signature).

When generating delegates to Kotlin default interface methods, keep
track of the original Kotlin types for delegating method arguments and
interface method arguments.

'original' for value parameters of fake overrides points to the
overridden function value parameters instead of the value parameter of
the unsubstituted function. This causes inconsistent type mapping for
inline classes implementing generic interfaces with default methods.

 #KT-25295 Fixed Target versions 1.3.20
 #KT-26931 Fixed Target versions 1.3.20
This commit is contained in:
Dmitry Petrov
2018-09-20 12:40:01 +03:00
parent 8536ef5b43
commit 8d2b1950e6
14 changed files with 363 additions and 9 deletions
@@ -66,13 +66,16 @@ interface CallGenerator {
}
val value = codegen.gen(argumentExpression)
value.put(parameterType, valueParameterDescriptor.original.type, v)
value.put(parameterType, valueParameterDescriptor.unsubstitutedType, v)
if (isVarargInvoke) {
v.astore(OBJECT_TYPE)
}
}
private val ValueParameterDescriptor.unsubstitutedType
get() = containingDeclaration.original.valueParameters[index].type
override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) {
stackValue.put(stackValue.type, stackValue.kotlinType, codegen.v)
}
@@ -20,10 +20,12 @@ import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptorKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method;
@@ -274,15 +276,56 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
InstructionAdapter iv = codegen.v;
Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
Type[] originalArgTypes = traitMethod.getArgumentTypes();
assert originalArgTypes.length == argTypes.length + 1 :
"Invalid trait implementation signature: " + signature + " vs " + traitMethod + " for " + interfaceFun;
boolean isErasedInlineClass =
InlineClassesUtilsKt.isInlineClass(descriptor) && kind == OwnerKind.ERASED_INLINE_CLASS;
iv.load(0, OBJECT_TYPE);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i + 1], iv);
//noinspection AssignmentToForLoopParameter
reg += argTypes[i].getSize();
int argI = 0;
int reg = 0;
Type receiverType = typeMapper.mapType(descriptor);
KotlinType interfaceKotlinType = ((ClassDescriptor) inheritedFun.getContainingDeclaration()).getDefaultType();
StackValue.local(reg, receiverType, descriptor.getDefaultType()).put(OBJECT_TYPE, interfaceKotlinType, iv);
if (isErasedInlineClass) argI++;
reg += receiverType.getSize();
int originalArgI = 1;
List<ParameterDescriptor> argsDescriptors = getParameters(inheritedFun);
List<ParameterDescriptor> originalArgsDescriptors = getParameters(interfaceFun);
assert argsDescriptors.size() == originalArgsDescriptors.size() :
"Inconsistent value parameters between delegating fun " + inheritedFun +
"and interface fun " + interfaceFun;
Iterator<ParameterDescriptor> argsIterator = argsDescriptors.iterator();
Iterator<ParameterDescriptor> originalArgsIterator = originalArgsDescriptors.iterator();
for (; argI < argTypes.length; argI++, originalArgI++) {
Type argType = argTypes[argI];
KotlinType argKotlinType = argsIterator.next().getType();
Type originalArgType = originalArgTypes[originalArgI];
KotlinType originalArgKotlinType = originalArgsIterator.next().getType();
StackValue.local(reg, argType, argKotlinType)
.put(originalArgType, originalArgKotlinType, iv);
reg += argType.getSize();
}
assert originalArgI == originalArgTypes.length :
"Invalid trait implementation signature: " + signature + " vs " + traitMethod + " for " + interfaceFun;
}
private List<ParameterDescriptor> getParameters(FunctionDescriptor functionDescriptor) {
List<ParameterDescriptor> valueParameterDescriptors =
new ArrayList<>(functionDescriptor.getValueParameters().size() + 1);
ReceiverParameterDescriptor extensionReceiverParameter = functionDescriptor.getExtensionReceiverParameter();
if (extensionReceiverParameter != null) {
valueParameterDescriptors.add(extensionReceiverParameter);
}
valueParameterDescriptors.addAll(functionDescriptor.getValueParameters());
return valueParameterDescriptors;
}
}
);
@@ -49,6 +49,7 @@ class ErasedInlineClassBodyCodegen(
override fun generateSyntheticPartsAfterBody() {
super.generateSyntheticPartsAfterBody()
generateTraitMethods()
generateUnboxMethod()
generateFunctionsFromAny()
generateSpecializedEqualsStub()
@@ -890,7 +890,7 @@ public class KotlinTypeMapper {
: functionDescriptor.getOriginal();
signature = toInlinedErasedClass
? mapSignatureForInlineErasedClassSkipGeneric(functionToCall)
? mapSignatureForInlineErasedClassSkipGeneric(descriptor.getOriginal())
: mapSignatureSkipGeneric(functionToCall);
returnKotlinType = functionToCall.getReturnType();