Generate accessor for private companion object
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class AccessorForCompanionObjectInstanceFieldDescriptor(
|
||||
val companionObjectDescriptor: ClassDescriptor,
|
||||
name: Name
|
||||
) :
|
||||
SimpleFunctionDescriptorImpl(
|
||||
companionObjectDescriptor.containingDeclaration,
|
||||
null, Annotations.EMPTY,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE
|
||||
) {
|
||||
|
||||
init {
|
||||
initialize(
|
||||
null, null, emptyList(), emptyList(),
|
||||
companionObjectDescriptor.defaultType,
|
||||
Modality.FINAL,
|
||||
Visibilities.LOCAL
|
||||
)
|
||||
}
|
||||
|
||||
override fun createSubstitutedCopy(
|
||||
newOwner: DeclarationDescriptor,
|
||||
original: FunctionDescriptor?,
|
||||
kind: CallableMemberDescriptor.Kind,
|
||||
newName: Name?,
|
||||
annotations: Annotations,
|
||||
source: SourceElement
|
||||
): FunctionDescriptorImpl {
|
||||
throw UnsupportedOperationException("Accessor for companion object $companionObjectDescriptor should not be substituted")
|
||||
}
|
||||
}
|
||||
@@ -400,6 +400,10 @@ public class AsmUtil {
|
||||
return NO_FLAG_PACKAGE_PRIVATE;
|
||||
}
|
||||
|
||||
if (memberDescriptor instanceof AccessorForCompanionObjectInstanceFieldDescriptor) {
|
||||
return NO_FLAG_PACKAGE_PRIVATE;
|
||||
}
|
||||
|
||||
// the following code is only for PRIVATE visibility of member
|
||||
if (memberDescriptor instanceof ConstructorDescriptor) {
|
||||
if (isEnumEntry(containingDeclaration)) {
|
||||
|
||||
@@ -1756,6 +1756,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (shouldGenerateSingletonAsThisOrOuterFromContext(classDescriptor)) {
|
||||
return generateThisOrOuterFromContext(classDescriptor, false, false);
|
||||
}
|
||||
if (isCompanionObject(classDescriptor) && !couldUseDirectAccessToCompanionObject(classDescriptor, context)) {
|
||||
return generateAccessorCallForCompanionObject(classDescriptor);
|
||||
}
|
||||
if (isObject(classDescriptor)) {
|
||||
return StackValue.singleton(classDescriptor, typeMapper);
|
||||
}
|
||||
@@ -2612,9 +2615,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
else if (isPossiblyUninitializedSingleton(receiverDescriptor) && isInsideSingleton(receiverDescriptor)) {
|
||||
return generateThisOrOuterFromContext(receiverDescriptor, false, false);
|
||||
}
|
||||
else {
|
||||
else if (couldUseDirectAccessToCompanionObject(receiverDescriptor, context)) {
|
||||
return StackValue.singleton(receiverDescriptor, typeMapper);
|
||||
}
|
||||
else {
|
||||
return generateAccessorCallForCompanionObject(receiverDescriptor);
|
||||
}
|
||||
}
|
||||
else if (receiverDescriptor instanceof ScriptDescriptor) {
|
||||
return generateScriptReceiver((ScriptDescriptor) receiverDescriptor);
|
||||
@@ -2642,6 +2648,41 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateAccessorCallForCompanionObject(@NotNull ClassDescriptor companionObjectDescriptor) {
|
||||
DeclarationDescriptor hostClassDescriptor = companionObjectDescriptor.getContainingDeclaration();
|
||||
assert hostClassDescriptor instanceof ClassDescriptor :
|
||||
"Containing declaration of the companion object " + companionObjectDescriptor +
|
||||
": expected a class, actual: " + hostClassDescriptor;
|
||||
|
||||
CodegenContext hostClassContext = context;
|
||||
while (hostClassContext.getContextDescriptor() != hostClassDescriptor) {
|
||||
hostClassContext = hostClassContext.getParentContext();
|
||||
assert hostClassContext != null :
|
||||
"Host class context for " + hostClassDescriptor + " not found in context hierarchy for " + context;
|
||||
}
|
||||
|
||||
hostClassContext.markCompanionObjectDescriptorWithAccessorRequired(companionObjectDescriptor);
|
||||
|
||||
Type hostClassType = typeMapper.mapClass((ClassifierDescriptor) hostClassDescriptor);
|
||||
Type companionObjectType = typeMapper.mapClass(companionObjectDescriptor);
|
||||
|
||||
// TODO given that we actually have corresponding AccessorForCompanionObjectInstanceFieldDescriptor,
|
||||
// it might be a better idea to use general method call generation
|
||||
return StackValue.operation(
|
||||
companionObjectType,
|
||||
companionObjectDescriptor.getDefaultType(),
|
||||
v -> {
|
||||
v.invokestatic(
|
||||
hostClassType.getInternalName(),
|
||||
getCompanionObjectAccessorName(companionObjectDescriptor),
|
||||
Type.getMethodDescriptor(companionObjectType),
|
||||
/* itf */ false
|
||||
);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateExtensionReceiver(@NotNull CallableDescriptor descriptor) {
|
||||
ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
|
||||
|
||||
@@ -22,9 +22,6 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement;
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt;
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping;
|
||||
import org.jetbrains.kotlin.psi.Call;
|
||||
@@ -153,6 +150,29 @@ public class JvmCodegenUtil {
|
||||
return propertyDescriptor.isConst() || hasJvmFieldAnnotation(propertyDescriptor);
|
||||
}
|
||||
|
||||
public static boolean couldUseDirectAccessToCompanionObject(
|
||||
@NotNull ClassDescriptor companionObjectDescriptor,
|
||||
@NotNull MethodContext contextBeforeInline
|
||||
) {
|
||||
if (!Visibilities.isPrivate(companionObjectDescriptor.getVisibility())) {
|
||||
// Non-private companion object can be directly accessed anywhere it's allowed by the front-end.
|
||||
return true;
|
||||
}
|
||||
|
||||
CodegenContext context = contextBeforeInline.getFirstCrossInlineOrNonInlineContext();
|
||||
if (context.isInlineMethodContext()) {
|
||||
// Inline method can be called from a nested class.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Private companion object is directly accessible only from the corresponding class
|
||||
return context.getContextDescriptor().getContainingDeclaration() == companionObjectDescriptor.getContainingDeclaration();
|
||||
}
|
||||
|
||||
public static String getCompanionObjectAccessorName(@NotNull ClassDescriptor companionObjectDescriptor) {
|
||||
return "access$" + companionObjectDescriptor.getName();
|
||||
}
|
||||
|
||||
public static boolean couldUseDirectAccessToProperty(
|
||||
@NotNull PropertyDescriptor property,
|
||||
boolean forGetter,
|
||||
|
||||
@@ -708,6 +708,30 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
generateSyntheticAccessor(accessor);
|
||||
}
|
||||
}
|
||||
|
||||
AccessorForCompanionObjectInstanceFieldDescriptor accessorForCompanionObjectInstanceFieldDescriptor =
|
||||
context.getAccessorForCompanionObjectDescriptorIfRequired();
|
||||
if (accessorForCompanionObjectInstanceFieldDescriptor != null) {
|
||||
generateSyntheticAccessorForCompanionObject(accessorForCompanionObjectInstanceFieldDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSyntheticAccessorForCompanionObject(@NotNull AccessorForCompanionObjectInstanceFieldDescriptor accessor) {
|
||||
ClassDescriptor companionObjectDescriptor = accessor.getCompanionObjectDescriptor();
|
||||
DeclarationDescriptor hostClassDescriptor = companionObjectDescriptor.getContainingDeclaration();
|
||||
assert hostClassDescriptor instanceof ClassDescriptor : "Class descriptor expected: " + hostClassDescriptor;
|
||||
functionCodegen.generateMethod(
|
||||
Synthetic(null, companionObjectDescriptor),
|
||||
accessor,
|
||||
new FunctionGenerationStrategy.CodegenBased(state) {
|
||||
@Override
|
||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||
Type companionObjectType = typeMapper.mapClass(companionObjectDescriptor);
|
||||
StackValue.singleton(companionObjectDescriptor, typeMapper).put(companionObjectType, codegen.v);
|
||||
codegen.v.areturn(companionObjectType);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void generateSyntheticAccessor(@NotNull AccessorForCallableDescriptor<?> accessorForCallableDescriptor) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities;
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
@@ -44,12 +45,12 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
private Map<DeclarationDescriptor, CodegenContext> childContexts;
|
||||
private Map<AccessorKey, AccessorForCallableDescriptor<?>> accessors;
|
||||
private Map<AccessorKey, AccessorForPropertyDescriptorFactory> propertyAccessorFactories;
|
||||
private AccessorForCompanionObjectInstanceFieldDescriptor accessorForCompanionObjectInstanceFieldDescriptor = null;
|
||||
|
||||
private static class AccessorKey {
|
||||
public final DeclarationDescriptor descriptor;
|
||||
public final ClassDescriptor superCallLabelTarget;
|
||||
public final AccessorKind accessorKind;
|
||||
|
||||
public AccessorKey(
|
||||
@NotNull DeclarationDescriptor descriptor,
|
||||
@Nullable ClassDescriptor superCallLabelTarget,
|
||||
@@ -742,4 +743,30 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
public LocalLookup getEnclosingLocalLookup() {
|
||||
return enclosingLocalLookup;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AccessorForCompanionObjectInstanceFieldDescriptor markCompanionObjectDescriptorWithAccessorRequired(@NotNull ClassDescriptor companionObjectDescriptor) {
|
||||
assert DescriptorUtils.isCompanionObject(companionObjectDescriptor) : "Companion object expected: " + companionObjectDescriptor;
|
||||
|
||||
assert accessorForCompanionObjectInstanceFieldDescriptor == null
|
||||
|| accessorForCompanionObjectInstanceFieldDescriptor.getCompanionObjectDescriptor() == companionObjectDescriptor
|
||||
: "Unexpected companion object descriptor with accessor required: " + companionObjectDescriptor +
|
||||
"; should be " + accessorForCompanionObjectInstanceFieldDescriptor.getCompanionObjectDescriptor();
|
||||
|
||||
if (accessorForCompanionObjectInstanceFieldDescriptor == null) {
|
||||
accessorForCompanionObjectInstanceFieldDescriptor =
|
||||
new AccessorForCompanionObjectInstanceFieldDescriptor(
|
||||
companionObjectDescriptor,
|
||||
Name.identifier(JvmCodegenUtil.getCompanionObjectAccessorName(companionObjectDescriptor))
|
||||
);
|
||||
}
|
||||
|
||||
return accessorForCompanionObjectInstanceFieldDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AccessorForCompanionObjectInstanceFieldDescriptor getAccessorForCompanionObjectDescriptorIfRequired() {
|
||||
return accessorForCompanionObjectInstanceFieldDescriptor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -948,7 +948,8 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
public static boolean isAccessor(@Nullable CallableMemberDescriptor descriptor) {
|
||||
return descriptor instanceof AccessorForCallableDescriptor<?>;
|
||||
return descriptor instanceof AccessorForCallableDescriptor<?> ||
|
||||
descriptor instanceof AccessorForCompanionObjectInstanceFieldDescriptor;
|
||||
}
|
||||
|
||||
public static boolean isStaticAccessor(@Nullable CallableMemberDescriptor descriptor) {
|
||||
|
||||
Reference in New Issue
Block a user