Support synthetic accessors for @JvmDefault members
This commit is contained in:
@@ -30,7 +30,8 @@ class CallableMethod(
|
||||
override val extensionReceiverKotlinType: KotlinType?,
|
||||
override val generateCalleeType: Type?,
|
||||
override val returnKotlinType: KotlinType?,
|
||||
private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode
|
||||
private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode,
|
||||
private val isDefaultMethodInInterface: Boolean = false
|
||||
) : Callable {
|
||||
fun getValueParameters(): List<JvmMethodParameterSignature> =
|
||||
signature.valueParameters
|
||||
@@ -67,7 +68,7 @@ class CallableMethod(
|
||||
} else {
|
||||
v.visitMethodInsn(
|
||||
INVOKESTATIC, defaultImplOwner.internalName,
|
||||
method.name + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodDesc, false
|
||||
method.name + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodDesc, isDefaultMethodInInterface
|
||||
)
|
||||
|
||||
StackValue.coerce(Type.getReturnType(defaultMethodDesc), Type.getReturnType(signature.asmMethod.descriptor), v)
|
||||
|
||||
@@ -400,9 +400,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
generateDelegates(delegationFieldsInfo);
|
||||
|
||||
if (!isInterface(descriptor) || kind == OwnerKind.DEFAULT_IMPLS) {
|
||||
generateSyntheticAccessors();
|
||||
}
|
||||
generateSyntheticAccessors();
|
||||
|
||||
generateEnumMethods();
|
||||
|
||||
|
||||
@@ -695,9 +695,16 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
}
|
||||
}
|
||||
|
||||
protected void generateSyntheticAccessors() {
|
||||
protected final void generateSyntheticAccessors() {
|
||||
for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) {
|
||||
generateSyntheticAccessor(accessor);
|
||||
boolean hasJvmDefaultAnnotation = CodegenUtilKt.hasJvmDefaultAnnotation(accessor.getCalleeDescriptor());
|
||||
OwnerKind kind = context.getContextKind();
|
||||
|
||||
if (!isInterface(context.getContextDescriptor()) ||
|
||||
(hasJvmDefaultAnnotation && kind == OwnerKind.IMPLEMENTATION) ||
|
||||
(!hasJvmDefaultAnnotation && kind == OwnerKind.DEFAULT_IMPLS)) {
|
||||
generateSyntheticAccessor(accessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -423,4 +423,8 @@ fun MethodNode.textifyMethodNode(): String {
|
||||
return "$sw"
|
||||
}
|
||||
|
||||
fun CallableMemberDescriptor.hasJvmDefaultAnnotation() = getDirectMember(this).annotations.hasAnnotation(JvmDefaultChecker.JVM_DEFAULT_FQ_NAME)
|
||||
fun CallableMemberDescriptor.hasJvmDefaultAnnotation() =
|
||||
getDirectMember(this).annotations.hasAnnotation(JvmDefaultChecker.JVM_DEFAULT_FQ_NAME)
|
||||
|
||||
fun DeclarationDescriptor.isCallableMemberWithJvmDefaultAnnotation() =
|
||||
(this as? CallableMemberDescriptor)?.hasJvmDefaultAnnotation() ?: false
|
||||
|
||||
@@ -569,10 +569,13 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
|
||||
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
|
||||
boolean isInliningContext = properContext.isInlineMethodContext();
|
||||
boolean sameJvmDefault = CodegenUtilKt.hasJvmDefaultAnnotation(descriptor) ==
|
||||
CodegenUtilKt.isCallableMemberWithJvmDefaultAnnotation(properContext.contextDescriptor) ||
|
||||
properContext.contextDescriptor instanceof AccessorForCallableDescriptor;
|
||||
if (!isInliningContext && (
|
||||
!properContext.hasThisDescriptor() ||
|
||||
enclosing == properContext.getThisDescriptor() ||
|
||||
enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor())) {
|
||||
((enclosing == properContext.getThisDescriptor()) && sameJvmDefault) ||
|
||||
((enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor()) && sameJvmDefault))) {
|
||||
return descriptor;
|
||||
}
|
||||
return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
|
||||
@@ -623,6 +626,11 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
if (descriptorContext == null) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
if (CodegenUtilKt.hasJvmDefaultAnnotation(descriptor) && descriptorContext instanceof DefaultImplsClassContext) {
|
||||
descriptorContext = ((DefaultImplsClassContext) descriptorContext).getInterfaceContext();
|
||||
}
|
||||
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
|
||||
|
||||
+9
-8
@@ -23,20 +23,21 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
|
||||
class DefaultImplsClassContext(
|
||||
typeMapper: KotlinTypeMapper,
|
||||
contextDescriptor: ClassDescriptor,
|
||||
contextKind: OwnerKind,
|
||||
parentContext: CodegenContext<*>?,
|
||||
localLookup: ((DeclarationDescriptor) -> Boolean)?,
|
||||
private val interfaceContext: ClassContext
|
||||
typeMapper: KotlinTypeMapper,
|
||||
contextDescriptor: ClassDescriptor,
|
||||
contextKind: OwnerKind,
|
||||
parentContext: CodegenContext<*>?,
|
||||
localLookup: ((DeclarationDescriptor) -> Boolean)?,
|
||||
val interfaceContext: ClassContext
|
||||
) : ClassContext(typeMapper, contextDescriptor, contextKind, parentContext, localLookup) {
|
||||
|
||||
override fun getCompanionObjectContext(): CodegenContext<*>? = interfaceContext.companionObjectContext
|
||||
|
||||
override fun getAccessors(): Collection<AccessorForCallableDescriptor<*>> {
|
||||
val accessors = super.getAccessors()
|
||||
val alreadyExistKeys = accessors.map ({ Pair(it.calleeDescriptor, it.superCallTarget) })
|
||||
val filtered = interfaceContext.accessors.associateByTo(linkedMapOf()) { Pair(it.calleeDescriptor, it.superCallTarget) }.apply { keys -= alreadyExistKeys }
|
||||
val alreadyExistKeys = accessors.map({ Pair(it.calleeDescriptor, it.superCallTarget) })
|
||||
val filtered = interfaceContext.accessors.associateByTo(linkedMapOf()) { Pair(it.calleeDescriptor, it.superCallTarget) }
|
||||
.apply { keys -= alreadyExistKeys }
|
||||
return accessors + filtered.values
|
||||
}
|
||||
}
|
||||
@@ -746,7 +746,7 @@ public class KotlinTypeMapper {
|
||||
String defaultImplDesc = mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION).getDescriptor();
|
||||
return new CallableMethod(
|
||||
owner, owner, defaultImplDesc, method, INVOKESPECIAL,
|
||||
null, null, null, null, null, originalDescriptor.getReturnType(), false
|
||||
null, null, null, null, null, originalDescriptor.getReturnType(), false, false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -770,6 +770,7 @@ public class KotlinTypeMapper {
|
||||
Type thisClass;
|
||||
KotlinType dispatchReceiverKotlinType;
|
||||
boolean isInterfaceMember = false;
|
||||
boolean isDefaultMethodInInterface = false;
|
||||
|
||||
if (functionParent instanceof ClassDescriptor) {
|
||||
FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
|
||||
@@ -784,6 +785,7 @@ public class KotlinTypeMapper {
|
||||
|
||||
baseMethodDescriptor = findBaseDeclaration(functionDescriptor).getOriginal();
|
||||
ClassDescriptor ownerForDefault = (ClassDescriptor) baseMethodDescriptor.getContainingDeclaration();
|
||||
isDefaultMethodInInterface = isJvmInterface(ownerForDefault) && CodegenUtilKt.hasJvmDefaultAnnotation(baseMethodDescriptor);
|
||||
ownerForDefaultImpl =
|
||||
isJvmInterface(ownerForDefault) && !CodegenUtilKt.hasJvmDefaultAnnotation(baseMethodDescriptor) ?
|
||||
mapDefaultImpls(ownerForDefault) : mapClass(ownerForDefault);
|
||||
@@ -803,7 +805,14 @@ public class KotlinTypeMapper {
|
||||
FunctionDescriptor originalDescriptor = descriptor.getOriginal();
|
||||
signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS);
|
||||
returnKotlinType = originalDescriptor.getReturnType();
|
||||
owner = mapDefaultImpls(currentOwner);
|
||||
if (descriptor instanceof AccessorForCallableDescriptor &&
|
||||
CodegenUtilKt.hasJvmDefaultAnnotation(((AccessorForCallableDescriptor) descriptor).getCalleeDescriptor())) {
|
||||
owner = mapClass(currentOwner);
|
||||
isInterfaceMember = true;
|
||||
}
|
||||
else {
|
||||
owner = mapDefaultImpls(currentOwner);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -893,7 +902,7 @@ public class KotlinTypeMapper {
|
||||
return new CallableMethod(
|
||||
owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode,
|
||||
thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType, calleeType, returnKotlinType,
|
||||
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE
|
||||
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE, isDefaultMethodInInterface
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user