Fix protected call to super method from lambda

Previously JVM back-end had an assumption that if we're calling a method
declared in the super class from a lambda via a synthetic accessor, that should
be a super call and it must be done with 'invokespecial'. Which is wrong
because a method declared in the super class may be open and overridden in the
subclass, so 'invokevirtual' should be used. Surprisingly, Java SE verifier
allowed both instructions, but on Android only the latter is possible

 #KT-8899 Fixed
 #KT-9052 Fixed
This commit is contained in:
Alexander Udalov
2015-09-07 13:34:15 +03:00
parent 1ccd0f9fc2
commit 3c4b2994a9
15 changed files with 281 additions and 146 deletions
@@ -17,9 +17,14 @@
package org.jetbrains.kotlin.codegen; package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor; import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.psi.JetSuperExpression;
public interface AccessorForCallableDescriptor<T extends CallableMemberDescriptor> { public interface AccessorForCallableDescriptor<T extends CallableMemberDescriptor> {
@NotNull @NotNull
T getCalleeDescriptor(); T getCalleeDescriptor();
@Nullable
JetSuperExpression getSuperCallExpression();
} }
@@ -17,37 +17,35 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetSuperExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import java.util.*
public class AccessorForConstructorDescriptor( public class AccessorForConstructorDescriptor(
private val calleeDescriptor: ConstructorDescriptor, private val calleeDescriptor: ConstructorDescriptor,
containingDeclaration: DeclarationDescriptor containingDeclaration: DeclarationDescriptor,
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>")) private val superCallExpression: JetSuperExpression?
, ConstructorDescriptor ) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>")),
, AccessorForCallableDescriptor<ConstructorDescriptor> { ConstructorDescriptor,
AccessorForCallableDescriptor<ConstructorDescriptor> {
override fun getCalleeDescriptor(): ConstructorDescriptor = calleeDescriptor override fun getCalleeDescriptor(): ConstructorDescriptor = calleeDescriptor
override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.getContainingDeclaration() override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.containingDeclaration
override fun isPrimary(): Boolean = false override fun isPrimary(): Boolean = false
override fun getReturnType(): JetType = super<AbstractAccessorForFunctionDescriptor>.getReturnType()!! override fun getReturnType(): JetType = super.getReturnType()!!
override fun getSuperCallExpression(): JetSuperExpression? = superCallExpression
init { init {
initialize( initialize(
DescriptorUtils.getReceiverParameterType(getExtensionReceiverParameter()), DescriptorUtils.getReceiverParameterType(extensionReceiverParameter),
calleeDescriptor.getDispatchReceiverParameter(), calleeDescriptor.dispatchReceiverParameter,
copyTypeParameters(calleeDescriptor), copyTypeParameters(calleeDescriptor),
copyValueParameters(calleeDescriptor), copyValueParameters(calleeDescriptor),
calleeDescriptor.getReturnType(), calleeDescriptor.returnType,
Modality.FINAL, Modality.FINAL,
Visibilities.INTERNAL Visibilities.INTERNAL
) )
@@ -17,23 +17,27 @@
package org.jetbrains.kotlin.codegen; package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor<FunctionDescriptor> { public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor<FunctionDescriptor> {
private final FunctionDescriptor calleeDescriptor; private final FunctionDescriptor calleeDescriptor;
private final JetSuperExpression superCallExpression;
public AccessorForFunctionDescriptor( public AccessorForFunctionDescriptor(
@NotNull FunctionDescriptor descriptor, @NotNull FunctionDescriptor descriptor,
@NotNull DeclarationDescriptor containingDeclaration, @NotNull DeclarationDescriptor containingDeclaration,
int index int index,
@Nullable JetSuperExpression superCallExpression
) { ) {
super(containingDeclaration, super(containingDeclaration,
Name.identifier("access$" + (descriptor instanceof ConstructorDescriptor ? "init" : descriptor.getName()) + "$" + index)); Name.identifier("access$" + (descriptor instanceof ConstructorDescriptor ? "init" : descriptor.getName()) + "$" + index));
this.calleeDescriptor = descriptor; this.calleeDescriptor = descriptor;
this.superCallExpression = superCallExpression;
initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()), initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()),
descriptor instanceof ConstructorDescriptor || AnnotationsPackage.isPlatformStaticInObjectOrClass(descriptor) descriptor instanceof ConstructorDescriptor || AnnotationsPackage.isPlatformStaticInObjectOrClass(descriptor)
@@ -51,4 +55,9 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
public FunctionDescriptor getCalleeDescriptor() { public FunctionDescriptor getCalleeDescriptor() {
return calleeDescriptor; return calleeDescriptor;
} }
@Override
public JetSuperExpression getSuperCallExpression() {
return superCallExpression;
}
} }
@@ -23,13 +23,12 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
public class AccessorForPropertyBackingFieldInOuterClass extends AccessorForPropertyDescriptor { public class AccessorForPropertyBackingFieldInOuterClass extends AccessorForPropertyDescriptor {
public AccessorForPropertyBackingFieldInOuterClass( public AccessorForPropertyBackingFieldInOuterClass(
@NotNull PropertyDescriptor pd, @NotNull PropertyDescriptor property,
@NotNull DeclarationDescriptor containingDeclaration, @NotNull DeclarationDescriptor containingDeclaration,
int index, int index,
@Nullable JetType delegationType @Nullable JetType delegationType
) { ) {
super(pd, delegationType != null ? delegationType : pd.getType(), null, null, containingDeclaration, index); super(property, delegationType != null ? delegationType : property.getType(), null, null, containingDeclaration, index, null);
} }
} }
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl; import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl; import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
@@ -33,9 +34,16 @@ import java.util.Collections;
public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implements AccessorForCallableDescriptor<PropertyDescriptor> { public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implements AccessorForCallableDescriptor<PropertyDescriptor> {
private final PropertyDescriptor calleeDescriptor; private final PropertyDescriptor calleeDescriptor;
private final int accessorIndex; private final int accessorIndex;
private final JetSuperExpression superCallExpression;
public AccessorForPropertyDescriptor(@NotNull PropertyDescriptor pd, @NotNull DeclarationDescriptor containingDeclaration, int index) { public AccessorForPropertyDescriptor(
this(pd, pd.getType(), DescriptorUtils.getReceiverParameterType(pd.getExtensionReceiverParameter()), pd.getDispatchReceiverParameter(), containingDeclaration, index); @NotNull PropertyDescriptor property,
@NotNull DeclarationDescriptor containingDeclaration,
int index,
@Nullable JetSuperExpression superCallExpression
) {
this(property, property.getType(), DescriptorUtils.getReceiverParameterType(property.getExtensionReceiverParameter()),
property.getDispatchReceiverParameter(), containingDeclaration, index, superCallExpression);
} }
protected AccessorForPropertyDescriptor( protected AccessorForPropertyDescriptor(
@@ -44,7 +52,8 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
@Nullable JetType receiverType, @Nullable JetType receiverType,
@Nullable ReceiverParameterDescriptor dispatchReceiverParameter, @Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
@NotNull DeclarationDescriptor containingDeclaration, @NotNull DeclarationDescriptor containingDeclaration,
int index int index,
@Nullable JetSuperExpression superCallExpression
) { ) {
super(containingDeclaration, null, Annotations.EMPTY, Modality.FINAL, Visibilities.LOCAL, super(containingDeclaration, null, Annotations.EMPTY, Modality.FINAL, Visibilities.LOCAL,
original.isVar(), Name.identifier("access$" + getIndexedAccessorSuffix(original, index)), original.isVar(), Name.identifier("access$" + getIndexedAccessorSuffix(original, index)),
@@ -52,6 +61,7 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
this.calleeDescriptor = original; this.calleeDescriptor = original;
this.accessorIndex = index; this.accessorIndex = index;
this.superCallExpression = superCallExpression;
setType(propertyType, Collections.<TypeParameterDescriptorImpl>emptyList(), dispatchReceiverParameter, receiverType); setType(propertyType, Collections.<TypeParameterDescriptorImpl>emptyList(), dispatchReceiverParameter, receiverType);
initialize(new Getter(this), new Setter(this)); initialize(new Getter(this), new Setter(this));
} }
@@ -69,6 +79,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
//noinspection ConstantConditions //noinspection ConstantConditions
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getGetter(); return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getGetter();
} }
@Nullable
@Override
public JetSuperExpression getSuperCallExpression() {
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getSuperCallExpression();
}
} }
public static class Setter extends PropertySetterDescriptorImpl implements AccessorForCallableDescriptor<PropertySetterDescriptor>{ public static class Setter extends PropertySetterDescriptorImpl implements AccessorForCallableDescriptor<PropertySetterDescriptor>{
@@ -84,6 +100,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
//noinspection ConstantConditions //noinspection ConstantConditions
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getSetter(); return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getSetter();
} }
@Nullable
@Override
public JetSuperExpression getSuperCallExpression() {
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getSuperCallExpression();
}
} }
@NotNull @NotNull
@@ -92,6 +114,11 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
return calleeDescriptor; return calleeDescriptor;
} }
@Override
public JetSuperExpression getSuperCallExpression() {
return superCallExpression;
}
@NotNull @NotNull
public String getIndexedAccessorSuffix() { public String getIndexedAccessorSuffix() {
return getIndexedAccessorSuffix(calleeDescriptor, accessorIndex); return getIndexedAccessorSuffix(calleeDescriptor, accessorIndex);
@@ -356,11 +356,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override @Override
public StackValue visitSuperExpression(@NotNull JetSuperExpression expression, StackValue data) { public StackValue visitSuperExpression(@NotNull JetSuperExpression expression, StackValue data) {
return StackValue.thisOrOuter(this, getSuperCallLabelTarget(expression), true, true); return StackValue.thisOrOuter(this, getSuperCallLabelTarget(context, expression), true, true);
} }
@NotNull @NotNull
private ClassDescriptor getSuperCallLabelTarget(JetSuperExpression expression) { public static ClassDescriptor getSuperCallLabelTarget(
@NotNull CodegenContext<?> context,
@NotNull JetSuperExpression expression
) {
BindingContext bindingContext = context.getState().getBindingContext();
PsiElement labelPsi = bindingContext.get(LABEL_TARGET, expression.getTargetLabel()); PsiElement labelPsi = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, labelPsi); ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, labelPsi);
DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference()); DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
@@ -2007,7 +2011,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL; expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
JetSuperExpression superExpression = JetSuperExpression superExpression =
resolvedCall == null ? null : CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall()); resolvedCall == null ? null : CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall());
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor); propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
if (directToField) { if (directToField) {
receiver = StackValue.receiverWithoutReceiverArgument(receiver); receiver = StackValue.receiverWithoutReceiverArgument(receiver);
@@ -2137,14 +2141,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Nullable JetSuperExpression superExpression, @Nullable JetSuperExpression superExpression,
@NotNull StackValue receiver @NotNull StackValue receiver
) { ) {
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL, receiver); return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false, receiver);
} }
public StackValue.Property intermediateValueForProperty( public StackValue.Property intermediateValueForProperty(
@NotNull PropertyDescriptor propertyDescriptor, @NotNull PropertyDescriptor propertyDescriptor,
boolean forceField, boolean forceField,
@Nullable JetSuperExpression superExpression, @Nullable JetSuperExpression superExpression,
@NotNull MethodKind methodKind, boolean skipAccessorsForPrivateFieldInOuterClass,
StackValue receiver StackValue receiver
) { ) {
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) { if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
@@ -2165,56 +2169,54 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
CallableMethod callableGetter = null; CallableMethod callableGetter = null;
CallableMethod callableSetter = null; CallableMethod callableSetter = null;
boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass; CodegenContext backingFieldContext;
boolean changeOwnerOnTypeMapping;
CodegenContext backingFieldContext = context.getParentContext(); boolean skipPropertyAccessors;
boolean changeOwnerOnTypeMapping = isBackingFieldInAnotherClass;
if (isBackingFieldInAnotherClass && forceField) { if (isBackingFieldInAnotherClass && forceField) {
backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration()); backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty); int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
skipPropertyAccessors = skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
(flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
if (!skipPropertyAccessors) { if (!skipPropertyAccessors) {
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType); //noinspection ConstantConditions
changeOwnerOnTypeMapping = propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass); propertyDescriptor, true, delegateType, superExpression
);
changeOwnerOnTypeMapping = !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
} }
else {
changeOwnerOnTypeMapping = true;
}
}
else {
backingFieldContext = context.getParentContext();
changeOwnerOnTypeMapping = isBackingFieldInAnotherClass;
skipPropertyAccessors = forceField;
} }
if (!skipPropertyAccessors) { if (!skipPropertyAccessors) {
if (couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) { if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
callableGetter = null;
}
else {
if (isSuper && !isInterface(containingDeclaration)) { if (isSuper && !isInterface(containingDeclaration)) {
ClassDescriptor owner = getSuperCallLabelTarget(superExpression); ClassDescriptor owner = getSuperCallLabelTarget(context, superExpression);
CodegenContext c = context.findParentContextWithDescriptor(owner); CodegenContext c = context.findParentContextWithDescriptor(owner);
assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor; assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor;
if (c != context.getParentContext()) { if (c != context.getParentContext()) {
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor); propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor, superExpression);
} }
} }
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor); propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
if (getter != null) { if (getter != null) {
callableGetter = callableGetter = typeMapper.mapToCallableMethod(getter, isSuper, context);
typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
} }
} }
if (propertyDescriptor.isVar()) { if (propertyDescriptor.isVar()) {
PropertySetterDescriptor setter = propertyDescriptor.getSetter(); PropertySetterDescriptor setter = propertyDescriptor.getSetter();
if (setter != null) { if (setter != null && !couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context)) {
if (couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context)) { callableSetter = typeMapper.mapToCallableMethod(setter, isSuper, context);
callableSetter = null;
}
else {
callableSetter =
typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
}
} }
} }
} }
@@ -2329,7 +2331,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
descriptor = originalIfSamAdapter; descriptor = originalIfSamAdapter;
} }
// $default method is not private, so you need no accessor to call it // $default method is not private, so you need no accessor to call it
return usesDefaultArguments(resolvedCall) ? descriptor : context.accessibleDescriptor(descriptor); return usesDefaultArguments(resolvedCall)
? descriptor
: context.accessibleDescriptor(descriptor, CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall()));
} }
private static boolean usesDefaultArguments(@NotNull ResolvedCall<?> resolvedCall) { private static boolean usesDefaultArguments(@NotNull ResolvedCall<?> resolvedCall) {
@@ -2355,11 +2359,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
boolean superCall = superCallExpression != null; boolean superCall = superCallExpression != null;
if (superCall && !isInterface(fd.getContainingDeclaration())) { if (superCall && !isInterface(fd.getContainingDeclaration())) {
ClassDescriptor owner = getSuperCallLabelTarget(superCallExpression); ClassDescriptor owner = getSuperCallLabelTarget(context, superCallExpression);
CodegenContext c = context.findParentContextWithDescriptor(owner); CodegenContext c = context.findParentContextWithDescriptor(owner);
assert c != null : "Couldn't find a context for a super-call: " + fd; assert c != null : "Couldn't find a context for a super-call: " + fd;
if (c != context.getParentContext()) { if (c != context.getParentContext()) {
fd = (FunctionDescriptor) c.getAccessor(fd); fd = (FunctionDescriptor) c.getAccessor(fd, superCallExpression);
} }
} }
@@ -210,7 +210,7 @@ public class FunctionCodegen {
mv.visitCode(); mv.visitCode();
FunctionDescriptor staticFunctionDescriptor = PlatformStaticGenerator.createStaticFunctionDescriptor(functionDescriptor); FunctionDescriptor staticFunctionDescriptor = PlatformStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
JvmMethodSignature jvmMethodSignature = JvmMethodSignature jvmMethodSignature =
typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor)); typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration()); Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
generateDelegateToMethodBody(false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName()); generateDelegateToMethodBody(false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName());
} }
@@ -857,32 +857,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
protected void generateSyntheticAccessors() { protected void generateSyntheticAccessors() {
Map<DeclarationDescriptor, DeclarationDescriptor> accessors = ((CodegenContext<?>) context).getAccessors(); for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) {
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) { generateSyntheticAccessor(accessor);
generateSyntheticAccessor(entry);
} }
} }
private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) { private void generateSyntheticAccessor(@NotNull AccessorForCallableDescriptor<?> accessorForCallableDescriptor) {
if (entry.getValue() instanceof FunctionDescriptor) { if (accessorForCallableDescriptor instanceof FunctionDescriptor) {
final FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue(); final FunctionDescriptor accessor = (FunctionDescriptor) accessorForCallableDescriptor;
final FunctionDescriptor original = (FunctionDescriptor) entry.getKey(); final FunctionDescriptor original = (FunctionDescriptor) accessorForCallableDescriptor.getCalleeDescriptor();
functionCodegen.generateMethod( functionCodegen.generateMethod(
Synthetic(null, original), bridge, Synthetic(null, original), accessor,
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) { new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, accessor) {
@Override @Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
markLineNumberForSyntheticFunction(descriptor, codegen.v); markLineNumberForSyntheticFunction(descriptor, codegen.v);
generateMethodCallTo(original, bridge, codegen.v); generateMethodCallTo(original, accessor, codegen.v);
codegen.v.areturn(signature.getReturnType()); codegen.v.areturn(signature.getReturnType());
} }
} }
); );
} }
else if (entry.getValue() instanceof PropertyDescriptor) { else if (accessorForCallableDescriptor instanceof AccessorForPropertyDescriptor) {
final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue(); final AccessorForPropertyDescriptor accessor = (AccessorForPropertyDescriptor) accessorForCallableDescriptor;
final PropertyDescriptor original = (PropertyDescriptor) entry.getKey(); final PropertyDescriptor original = accessor.getCalleeDescriptor();
class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> { class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
public PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) { public PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) {
@@ -892,10 +891,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override @Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
!isCompanionObject(bridge.getContainingDeclaration()); !isCompanionObject(accessor.getContainingDeclaration());
StackValue property = StackValue property = codegen.intermediateValueForProperty(
codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR, original, forceField, accessor.getSuperCallExpression(), true, StackValue.none()
StackValue.none()); );
InstructionAdapter iv = codegen.v; InstructionAdapter iv = codegen.v;
@@ -920,14 +919,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
PropertyGetterDescriptor getter = bridge.getGetter(); PropertyGetterDescriptor getter = accessor.getGetter();
assert getter != null; assert getter != null;
functionCodegen.generateMethod(Synthetic(null, original.getGetter() != null ? original.getGetter() : original), functionCodegen.generateMethod(Synthetic(null, original.getGetter() != null ? original.getGetter() : original),
getter, new PropertyAccessorStrategy(getter)); getter, new PropertyAccessorStrategy(getter));
if (bridge.isVar()) { if (accessor.isVar()) {
PropertySetterDescriptor setter = bridge.getSetter(); PropertySetterDescriptor setter = accessor.getSetter();
assert setter != null; assert setter != null;
functionCodegen.generateMethod(Synthetic(null, original.getSetter() != null ? original.getSetter() : original), functionCodegen.generateMethod(Synthetic(null, original.getSetter() != null ? original.getSetter() : original),
@@ -957,24 +956,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateMethodCallTo( private void generateMethodCallTo(
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
@Nullable FunctionDescriptor bridgeDescriptor, @Nullable FunctionDescriptor accessorDescriptor,
@NotNull InstructionAdapter iv @NotNull InstructionAdapter iv
) { ) {
boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor; boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor;
boolean bridgeIsAccessorConstructor = bridgeDescriptor instanceof AccessorForConstructorDescriptor; boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
boolean callFromAccessor = bridgeIsAccessorConstructor
|| (bridgeDescriptor != null && JetTypeMapper.isAccessor(bridgeDescriptor)); boolean superCall = accessorDescriptor instanceof AccessorForCallableDescriptor &&
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallExpression() != null;
CallableMethod callableMethod = isConstructor ? CallableMethod callableMethod = isConstructor ?
typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) : typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) :
typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor, context); typeMapper.mapToCallableMethod(functionDescriptor, superCall, context);
int reg = 1; int reg = 1;
if (isConstructor && !bridgeIsAccessorConstructor) { if (isConstructor && !accessorIsConstructor) {
iv.anew(callableMethod.getOwner()); iv.anew(callableMethod.getOwner());
iv.dup(); iv.dup();
reg = 0; reg = 0;
} }
else if (callFromAccessor) { else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor))) {
if (!AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor)) { if (!AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor)) {
iv.load(0, OBJECT_TYPE); iv.load(0, OBJECT_TYPE);
} }
@@ -989,6 +989,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
reg += argType.getSize(); reg += argType.getSize();
} }
} }
callableMethod.genInvokeInstruction(iv); callableMethod.genInvokeInstruction(iv);
} }
@@ -1074,8 +1075,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) { private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
ExpressionCodegen codegen = createOrGetClInitCodegen(); ExpressionCodegen codegen = createOrGetClInitCodegen();
FunctionDescriptor constructor = FunctionDescriptor constructor = (FunctionDescriptor) context.accessibleDescriptor(
(FunctionDescriptor) context.accessibleDescriptor(KotlinPackage.single(companionObject.getConstructors())); KotlinPackage.single(companionObject.getConstructors()), /* superCallExpression = */ null
);
generateMethodCallTo(constructor, null, codegen.v); generateMethodCallTo(constructor, null, codegen.v);
codegen.v.dup(); codegen.v.dup();
StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject)); StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
@@ -360,8 +360,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
JetExpression initializer = property.getDelegateExpressionOrInitializer(); JetExpression initializer = property.getDelegateExpressionOrInitializer();
assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER, StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, true, StackValue.LOCAL_0);
StackValue.LOCAL_0);
propValue.store(codegen.gen(initializer), codegen.v); propValue.store(codegen.gen(initializer), codegen.v);
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen;
public enum MethodKind {
GENERAL,
INITIALIZER,
SYNTHETIC_ACCESSOR
}
@@ -23,20 +23,19 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetNamedFunction import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import kotlin.platform.platformStatic
class PlatformStaticGenerator( class PlatformStaticGenerator(
val descriptor: FunctionDescriptor, val descriptor: FunctionDescriptor,
val declarationOrigin: JvmDeclarationOrigin, val declarationOrigin: JvmDeclarationOrigin,
val state: GenerationState val state: GenerationState
) : Function2<ImplementationBodyCodegen, ClassBuilder, Unit> { ) : Function2<ImplementationBodyCodegen, ClassBuilder, Unit> {
private val typeMapper = state.typeMapper
override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) { override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) {
val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor) val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor)
@@ -51,40 +50,37 @@ class PlatformStaticGenerator(
frameMap: FrameMap, frameMap: FrameMap,
signature: JvmMethodSignature, signature: JvmMethodSignature,
context: MethodContext, context: MethodContext,
parentCodegen: MemberCodegen<out JetElement> parentCodegen: MemberCodegen<*>
) { ) {
val typeMapper = parentCodegen.typeMapper
val iv = InstructionAdapter(mv) val iv = InstructionAdapter(mv)
val classDescriptor = descriptor.getContainingDeclaration() as ClassDescriptor val classDescriptor = descriptor.containingDeclaration as ClassDescriptor
val singletonValue = StackValue.singleton(classDescriptor, typeMapper) val singletonValue = StackValue.singleton(classDescriptor, typeMapper)
singletonValue.put(singletonValue.type, iv); singletonValue.put(singletonValue.type, iv)
var index = 0; var index = 0
val asmMethod = signature.getAsmMethod() val asmMethod = signature.asmMethod
for (paramType in asmMethod.getArgumentTypes()) { for (paramType in asmMethod.argumentTypes) {
iv.load(index, paramType); iv.load(index, paramType)
index += paramType.getSize(); index += paramType.size
} }
val syntheticOrOriginalMethod = typeMapper.mapToCallableMethod( val syntheticOrOriginalMethod = typeMapper.mapToCallableMethod(
codegen.getContext().accessibleDescriptor(descriptor), codegen.getContext().accessibleDescriptor(descriptor, /* superCallExpression = */ null),
false, false,
codegen.getContext() codegen.getContext()
) )
syntheticOrOriginalMethod.genInvokeInstruction(iv) syntheticOrOriginalMethod.genInvokeInstruction(iv)
iv.areturn(asmMethod.getReturnType()); iv.areturn(asmMethod.returnType)
} }
} }
) )
if (originElement is JetNamedFunction) { if (originElement is JetNamedFunction) {
codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor) codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor)
} }
} }
companion object { companion object {
@platformStatic @JvmStatic
public fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor { public fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.getCorrespondingProperty() else descriptor val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.getCorrespondingProperty() else descriptor
val copies = CodegenUtil.copyFunctions( val copies = CodegenUtil.copyFunctions(
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.storage.LockBasedStorageManager;
@@ -47,8 +48,38 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
private final LocalLookup enclosingLocalLookup; private final LocalLookup enclosingLocalLookup;
private final NullableLazyValue<StackValue.Field> outerExpression; private final NullableLazyValue<StackValue.Field> outerExpression;
private Map<DeclarationDescriptor, DeclarationDescriptor> accessors;
private Map<DeclarationDescriptor, CodegenContext> childContexts; private Map<DeclarationDescriptor, CodegenContext> childContexts;
private Map<AccessorKey, AccessorForCallableDescriptor<?>> accessors;
private static class AccessorKey {
public final DeclarationDescriptor descriptor;
public final ClassDescriptor superCallLabelTarget;
public AccessorKey(@NotNull DeclarationDescriptor descriptor, @Nullable ClassDescriptor superCallLabelTarget) {
this.descriptor = descriptor;
this.superCallLabelTarget = superCallLabelTarget;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AccessorKey)) return false;
AccessorKey other = (AccessorKey) obj;
return descriptor.equals(other.descriptor) &&
(superCallLabelTarget == null
? other.superCallLabelTarget == null
: superCallLabelTarget.equals(other.superCallLabelTarget));
}
@Override
public int hashCode() {
return 31 * descriptor.hashCode() + (superCallLabelTarget == null ? 0 : superCallLabelTarget.hashCode());
}
@Override
public String toString() {
return descriptor.toString();
}
}
public CodegenContext( public CodegenContext(
@NotNull T contextDescriptor, @NotNull T contextDescriptor,
@@ -227,20 +258,28 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
} }
@NotNull @NotNull
public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor) { public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable JetSuperExpression superCallExpression) {
return getAccessor(descriptor, false, null); return getAccessor(descriptor, false, null, superCallExpression);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@NotNull @NotNull
public <D extends CallableMemberDescriptor> D getAccessor( public <D extends CallableMemberDescriptor> D getAccessor(
@NotNull D descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType @NotNull D possiblySubstitutedDescriptor,
boolean isForBackingFieldInOuterClass,
@Nullable JetType delegateType,
@Nullable JetSuperExpression superCallExpression
) { ) {
if (accessors == null) { if (accessors == null) {
accessors = new LinkedHashMap<DeclarationDescriptor, DeclarationDescriptor>(); accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
} }
descriptor = (D) descriptor.getOriginal();
DeclarationDescriptor accessor = accessors.get(descriptor); D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
AccessorKey key = new AccessorKey(
descriptor, superCallExpression == null ? null : ExpressionCodegen.getSuperCallLabelTarget(this, superCallExpression)
);
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
if (accessor != null) { if (accessor != null) {
assert !isForBackingFieldInOuterClass || assert !isForBackingFieldInOuterClass ||
accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context"; accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context";
@@ -249,10 +288,12 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
int accessorIndex = accessors.size(); int accessorIndex = accessors.size();
if (descriptor instanceof SimpleFunctionDescriptor) { if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex); accessor = new AccessorForFunctionDescriptor(
(FunctionDescriptor) descriptor, contextDescriptor, accessorIndex, superCallExpression
);
} }
else if (descriptor instanceof ConstructorDescriptor) { else if (descriptor instanceof ConstructorDescriptor) {
accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor); accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallExpression);
} }
else if (descriptor instanceof PropertyDescriptor) { else if (descriptor instanceof PropertyDescriptor) {
if (isForBackingFieldInOuterClass) { if (isForBackingFieldInOuterClass) {
@@ -260,13 +301,16 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
accessorIndex, delegateType); accessorIndex, delegateType);
} }
else { else {
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex); accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor,
accessorIndex, superCallExpression);
} }
} }
else { else {
throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor); throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
} }
accessors.put(descriptor, accessor);
accessors.put(key, accessor);
return (D) accessor; return (D) accessor;
} }
@@ -314,25 +358,29 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
} }
@NotNull @NotNull
public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() { public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors; return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
} }
@NotNull @NotNull
public <D extends CallableMemberDescriptor> D accessibleDescriptor(D descriptor) { public <D extends CallableMemberDescriptor> D accessibleDescriptor(
@NotNull D descriptor,
@Nullable JetSuperExpression superCallExpression
) {
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration(); DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
if (!hasThisDescriptor() || enclosing == getThisDescriptor() || if (!hasThisDescriptor() || enclosing == getThisDescriptor() ||
enclosing == getClassOrPackageParentContext().getContextDescriptor()) { enclosing == getClassOrPackageParentContext().getContextDescriptor()) {
return descriptor; return descriptor;
} }
return accessibleDescriptorIfNeeded(descriptor); return accessibleDescriptorIfNeeded(descriptor, superCallExpression);
} }
public void recordSyntheticAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BindingContext bindingContext) { public void recordSyntheticAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BindingContext bindingContext) {
if (hasThisDescriptor() && if (hasThisDescriptor() &&
(descriptor instanceof ConstructorDescriptor || Boolean.TRUE.equals(bindingContext.get(NEED_SYNTHETIC_ACCESSOR, descriptor)))) { (descriptor instanceof ConstructorDescriptor || Boolean.TRUE.equals(bindingContext.get(NEED_SYNTHETIC_ACCESSOR, descriptor)))) {
accessibleDescriptorIfNeeded(descriptor); // Not a super call because neither constructors nor private members can be targets of super calls
accessibleDescriptorIfNeeded(descriptor, /* superCallExpression = */ null);
} }
} }
@@ -352,7 +400,10 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@NotNull @NotNull
private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(@NotNull D descriptor) { private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
@NotNull D descriptor,
@Nullable JetSuperExpression superCallExpression
) {
CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor); CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
int flag = getAccessFlags(unwrappedDescriptor); int flag = getAccessFlags(unwrappedDescriptor);
if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) { if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) {
@@ -385,7 +436,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
} }
} }
return (D) descriptorContext.getAccessor(descriptor); return (D) descriptorContext.getAccessor(descriptor, superCallExpression);
} }
private void addChild(@NotNull CodegenContext child) { private void addChild(@NotNull CodegenContext child) {
@@ -0,0 +1,49 @@
import test.A
import kotlin.test.assertEquals
open class B : A() {
fun box(): String {
val overriddenMethod: () -> String = {
method()
}
assertEquals("C.method", overriddenMethod())
val superMethod: () -> String = {
super.method()
}
assertEquals("A.method", superMethod())
val overriddenPropertyGetter: () -> String = {
property
}
assertEquals("C.property", overriddenPropertyGetter())
val superPropertyGetter: () -> String = {
super.property
}
assertEquals("A.property", superPropertyGetter())
val overriddenPropertySetter: () -> Unit = {
property = ""
}
overriddenPropertySetter()
val superPropertySetter: () -> Unit = {
super.property = ""
}
superPropertySetter()
assertEquals("C.property;A.property;", state)
return "OK"
}
}
class C : B() {
override fun method() = "C.method"
override var property: String
get() = "C.property"
set(value) { state += "C.property;" }
}
fun box() = C().box()
@@ -0,0 +1,13 @@
package test
abstract class A {
public var state = ""
// These implementations should not be called, because they are overridden in C
protected open fun method(): String = "A.method"
protected open var property: String
get() = "A.property"
set(value) { state += "A.property;" }
}
@@ -37,6 +37,12 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg
doTestMultiFile(fileName); doTestMultiFile(fileName);
} }
@TestMetadata("accessorForProtectedInvokeVirtual")
public void testAccessorForProtectedInvokeVirtual() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/accessorForProtectedInvokeVirtual/");
doTestMultiFile(fileName);
}
public void testAllFilesPresentInBoxMultiFile() throws Exception { public void testAllFilesPresentInBoxMultiFile() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultiFile"), Pattern.compile("^([^\\.]+)$"), false); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultiFile"), Pattern.compile("^([^\\.]+)$"), false);
} }