Simplify implementation of JvmField property in interface companion

Move parts of the logic to the only places where they're needed:
checking for public/final/val is only needed in
JvmFieldApplicabilityChecker, checking the proto flag is only needed in
reflection, checking the JvmField annotation presence is only needed in
backend
This commit is contained in:
Alexander Udalov
2018-07-16 19:24:17 +02:00
parent 79c2aa4acf
commit 1e675bdc01
7 changed files with 64 additions and 70 deletions
@@ -47,6 +47,8 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
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.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
@@ -928,9 +930,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
boolean isNonCompanionObject = isNonCompanionObject(descriptor);
boolean isInterfaceCompanion = isCompanionObjectInInterfaceNotIntrinsic(descriptor);
boolean isInterfaceCompanionWithBackingFieldsInOuter = isInterfaceCompanionWithBackingFieldsInOuter(descriptor);
boolean isMappedIntrinsicCompanionObject = isMappedIntrinsicCompanionObject(descriptor);
boolean objectWithBackingFieldsInOuter = isCompanionObjectWithBackingFieldsInOuter(descriptor);
if (isNonCompanionObject || (isInterfaceCompanion && !objectWithBackingFieldsInOuter) || isMappedIntrinsicCompanionObject) {
boolean isClassCompanionWithBackingFieldsInOuter = isClassCompanionObjectWithBackingFieldsInOuter(descriptor);
if (isNonCompanionObject ||
(isInterfaceCompanion && !isInterfaceCompanionWithBackingFieldsInOuter) ||
isMappedIntrinsicCompanionObject
) {
ExpressionCodegen clInitCodegen = createOrGetClInitCodegen();
InstructionAdapter v = clInitCodegen.v;
markLineNumberForElement(element.getPsiOrParent(), v);
@@ -958,7 +964,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
);
}
}
else if (objectWithBackingFieldsInOuter) {
else if (isClassCompanionWithBackingFieldsInOuter || isInterfaceCompanionWithBackingFieldsInOuter) {
ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen();
ExpressionCodegen parentClInitCodegen = parentCodegen.createOrGetClInitCodegen();
InstructionAdapter parentVisitor = parentClInitCodegen.v;
@@ -977,6 +983,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private static boolean isInterfaceCompanionWithBackingFieldsInOuter(@NotNull DeclarationDescriptor declarationDescriptor) {
DeclarationDescriptor interfaceClass = declarationDescriptor.getContainingDeclaration();
if (!isCompanionObject(declarationDescriptor) || !isJvmInterface(interfaceClass)) return false;
Collection<DeclarationDescriptor> descriptors = ((ClassDescriptor) declarationDescriptor).getUnsubstitutedMemberScope()
.getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.Companion.getALL_NAME_FILTER());
return CollectionsKt.any(descriptors, d -> d instanceof PropertyDescriptor && hasJvmFieldAnnotation((PropertyDescriptor) d));
}
private void generateCompanionObjectBackingFieldCopies() {
if (companionObjectPropertiesToCopy == null) return;
@@ -57,9 +57,9 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAn
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.DELEGATED_PROPERTIES;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND;
import static org.jetbrains.kotlin.load.java.JvmAbi.isInterfaceCompanionWithBackingFieldsInOuter;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PROPERTY_TYPE;
@@ -420,10 +420,6 @@ public class PropertyCodegen {
String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate);
v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name));
if (hasJvmFieldAnnotation(propertyDescriptor) &&
isInterfaceCompanionWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration())) {
v.getSerializationBindings().put(FIELD_MOVED_FROM_INTERFACE_COMPANION, propertyDescriptor, true);
}
FieldVisitor fv = builder.newField(
JvmDeclarationOriginKt.OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
@@ -140,7 +140,7 @@ fun populateCompanionBackingFieldNamesToOuterContextIfNeeded(
return
}
if (!JvmAbi.isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
if (!JvmAbi.isClassCompanionObjectWithBackingFieldsInOuter(descriptor)) {
return
}
val properties = companion.declarations.filterIsInstance<KtProperty>()
@@ -35,8 +35,6 @@ public final class JvmSerializationBindings {
SerializationMappingSlice.create();
public static final SerializationMappingSlice<PropertyDescriptor, Method> SYNTHETIC_METHOD_FOR_PROPERTY =
SerializationMappingSlice.create();
public static final SerializationMappingSlice<PropertyDescriptor, Boolean> FIELD_MOVED_FROM_INTERFACE_COMPANION =
SerializationMappingSlice.create();
static final class SerializationMappingSlice<K, V> extends BasicWritableSlice<K, V> {
public SerializationMappingSlice() {
@@ -181,18 +181,26 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
)
proto.setExtension(JvmProtoBuf.propertySignature, signature)
val flags = JvmFlags.getPropertyFlags(bindings.get(FIELD_MOVED_FROM_INTERFACE_COMPANION, descriptor) == true)
if (flags != 0) {
proto.setExtension(JvmProtoBuf.flags, flags)
}
if (JvmAbi.isInterfaceCompanionWithBackingFieldsInOuter(descriptor.containingDeclaration)) {
if (descriptor.isJvmFieldPropertyInInterfaceCompanion()) {
proto.setExtension(JvmProtoBuf.flags, JvmFlags.getPropertyFlags(true))
assert(!proto.hasVersionRequirement()) { "VersionRequirement should be empty for $descriptor" }
proto.versionRequirement =
writeVersionRequirement(1, 2, 70, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
}
}
private fun PropertyDescriptor.isJvmFieldPropertyInInterfaceCompanion(): Boolean {
if (!JvmAbi.hasJvmFieldAnnotation(this)) return false
val container = containingDeclaration
if (!DescriptorUtils.isCompanionObject(container)) return false
val grandParent = (container as ClassDescriptor).containingDeclaration
return DescriptorUtils.isInterface(grandParent) || DescriptorUtils.isAnnotationClass(grandParent)
}
override fun serializeErrorType(type: KotlinType, builder: ProtoBuf.Type.Builder) {
if (classBuilderMode === ClassBuilderMode.KAPT3) {
builder.className = stringTable.getStringIndex(NON_EXISTENT_CLASS_NAME)
@@ -31,6 +31,8 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmFieldApplicabilityChecker.Problem.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
class JvmFieldApplicabilityChecker : DeclarationChecker {
@@ -64,7 +66,7 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.JvmFieldInInterface))
INSIDE_COMPANION_OF_INTERFACE
else {
if (!JvmAbi.isInterfaceCompanionWithBackingFieldsInOuter(descriptor.containingDeclaration)) {
if (!isInterfaceCompanionWithPublicJvmFieldProperties(descriptor.containingDeclaration as ClassDescriptor)) {
NOT_PUBLIC_VAL_WITH_JVMFIELD
} else return
}
@@ -77,6 +79,19 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
context.trace.report(ErrorsJvm.INAPPLICABLE_JVM_FIELD.on(annotationEntry, problem.errorMessage))
}
private fun isInterfaceCompanionWithPublicJvmFieldProperties(companionObject: ClassDescriptor): Boolean {
for (next in companionObject.unsubstitutedMemberScope.getContributedDescriptors(
DescriptorKindFilter.VARIABLES, MemberScope.ALL_NAME_FILTER
)) {
if (next !is PropertyDescriptor) continue
if (next.visibility != Visibilities.PUBLIC || next.isVar || next.modality != Modality.FINAL) return false
if (!JvmAbi.hasJvmFieldAnnotation(next)) return false
}
return true
}
private fun PropertyDescriptor.hasCustomAccessor() = !(getter?.isDefault ?: true) || !(setter?.isDefault ?: true)
private fun PropertyDescriptor.hasBackingField(bindingContext: BindingContext) =
@@ -89,5 +104,4 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
val outerClassKind = (containingClass.containingDeclaration as? ClassDescriptor)?.kind
return outerClassKind == ClassKind.INTERFACE || outerClassKind == ClassKind.ANNOTATION_CLASS
}
}