Support default parameter values for inline class constructors and funs

#KT-26908
 #KT-26554

Move default parameter value tests to separate directory
This commit is contained in:
Dmitry Petrov
2018-10-02 18:04:45 +03:00
parent 8ce1d09f8a
commit f68ce4b35b
26 changed files with 435 additions and 135 deletions
@@ -106,8 +106,10 @@ public class ConstructorCodegen {
}
);
functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION,
DefaultParameterValueLoader.DEFAULT, null);
OwnerKind ownerKindForDefault = context.getContextKind() == OwnerKind.ERASED_INLINE_CLASS
? OwnerKind.ERASED_INLINE_CLASS
: OwnerKind.IMPLEMENTATION;
functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, ownerKindForDefault, DefaultParameterValueLoader.DEFAULT, null);
registerAccessorForHiddenConstructorIfNeeded(constructorDescriptor);
@@ -140,7 +142,10 @@ public class ConstructorCodegen {
}
);
functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION,
OwnerKind ownerKindForDefault = context.getContextKind() == OwnerKind.ERASED_INLINE_CLASS
? OwnerKind.ERASED_INLINE_CLASS
: OwnerKind.IMPLEMENTATION;
functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, ownerKindForDefault,
DefaultParameterValueLoader.DEFAULT, null);
new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded(
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.KtPureElement
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOriginFromPure
@@ -223,7 +224,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
v.aconst(null)
val defaultMethod = typeMapper.mapDefaultMethod(delegateFunctionDescriptor, contextKind)
if (functionDescriptor is ConstructorDescriptor) {
if (functionDescriptor is ConstructorDescriptor && !functionDescriptor.containingDeclaration.isInlineClass()) {
v.invokespecial(methodOwner.internalName, defaultMethod.name, defaultMethod.descriptor, false)
} else {
v.invokestatic(methodOwner.internalName, defaultMethod.name, defaultMethod.descriptor, false)
@@ -250,6 +251,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
if (classDescriptor.kind != ClassKind.CLASS) return false
if (classOrObject.isLocal) return false
if (classDescriptor.isInline) return false
if (CodegenBinding.canHaveOuter(state.bindingContext, classDescriptor)) return false
@@ -1151,6 +1151,10 @@ public class FunctionCodegen {
return;
}
if (InlineClassesUtilsKt.isInlineClass(contextClass) && kind != OwnerKind.ERASED_INLINE_CLASS) {
return;
}
if (!isDefaultNeeded(functionDescriptor, function)) {
return;
}
@@ -1161,7 +1165,9 @@ public class FunctionCodegen {
isEffectivelyInlineOnly(functionDescriptor) ?
AsmUtil.NO_FLAG_PACKAGE_PRIVATE : Opcodes.ACC_PUBLIC;
int flags = visibilityFlag | getDeprecatedAccessFlag(functionDescriptor) | ACC_SYNTHETIC;
if (!(functionDescriptor instanceof ConstructorDescriptor)) {
if (!(functionDescriptor instanceof ConstructorDescriptor &&
!InlineClassesUtilsKt.isInlineClass(functionDescriptor.getContainingDeclaration()))
) {
flags |= ACC_STATIC;
}
@@ -1283,7 +1289,7 @@ public class FunctionCodegen {
generator.putValueIfNeeded(new JvmKotlinType(type, null), StackValue.local(parameterIndex, type));
}
CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false);
CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false, methodContext.getContextKind());
generator.genCall(method, null, false, codegen);
@@ -1047,6 +1047,9 @@ public class KotlinTypeMapper {
else if (isInterface(containingDeclaration)) {
return OwnerKind.DEFAULT_IMPLS;
}
else if (InlineClassesUtilsKt.isInlineClass(containingDeclaration)) {
return OwnerKind.ERASED_INLINE_CLASS;
}
return OwnerKind.IMPLEMENTATION;
}
@@ -1368,8 +1371,12 @@ public class KotlinTypeMapper {
) {
String descriptor = method.getDescriptor();
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();
Type defaultConstructorMarkerType =
isConstructor(method) || isInlineClassConstructor(callableDescriptor)
? DEFAULT_CONSTRUCTOR_MARKER
: OBJECT_TYPE;
String additionalArgs = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount)
+ defaultConstructorMarkerType.getDescriptor();
String result = descriptor.replace(")", additionalArgs + ")");
if (dispatchReceiverDescriptor != null && !isConstructor(method)) {
return result.replace("(", "(" + dispatchReceiverDescriptor);
@@ -1385,6 +1392,11 @@ public class KotlinTypeMapper {
return "<init>".equals(method.getName());
}
private static boolean isInlineClassConstructor(@NotNull CallableDescriptor callableDescriptor) {
return callableDescriptor instanceof ClassConstructorDescriptor
&& InlineClassesUtilsKt.isInlineClass(callableDescriptor.getContainingDeclaration());
}
@NotNull
public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind) {
Method jvmSignature = mapAsmMethod(functionDescriptor, kind);