Generate private methods in TraitImpl as private, don't generate delegation to private trait methods

This commit is contained in:
Michael Bogdanov
2015-12-04 16:12:11 +03:00
parent a2d644f708
commit 7c7786f7d0
14 changed files with 81 additions and 18 deletions

View File

@@ -93,14 +93,14 @@ public class CodegenUtil {
}
@NotNull
public static Map<FunctionDescriptor, FunctionDescriptor> getTraitMethods(ClassDescriptor descriptor) {
public static Map<FunctionDescriptor, FunctionDescriptor> getNonPrivateTraitMethods(ClassDescriptor descriptor) {
Map<FunctionDescriptor, FunctionDescriptor> result = new LinkedHashMap<FunctionDescriptor, FunctionDescriptor>();
for (DeclarationDescriptor declaration : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
if (!(declaration instanceof CallableMemberDescriptor)) continue;
CallableMemberDescriptor inheritedMember = (CallableMemberDescriptor) declaration;
CallableMemberDescriptor traitMember = ImplKt.findTraitImplementation(inheritedMember);
if (traitMember == null) continue;
if (traitMember == null || Visibilities.isPrivate(traitMember.getVisibility())) continue;
assert traitMember.getModality() != Modality.ABSTRACT : "Cannot delegate to abstract trait method: " + inheritedMember;

View File

@@ -325,9 +325,6 @@ public class AsmUtil {
private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
Visibility memberVisibility = memberDescriptor.getVisibility();
if (isJvmInterface(containingDeclaration)) {
return memberVisibility == Visibilities.PRIVATE ? NO_FLAG_PACKAGE_PRIVATE : ACC_PUBLIC;
}
if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
return ACC_PUBLIC;

View File

@@ -77,6 +77,8 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
generatePrimaryConstructorProperties();
generateConstructors();
generateDefaultImplsIfNeeded();
for (KtObjectDeclaration companion : companions) {
generateDeclaration(companion);
}
@@ -109,6 +111,10 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
}
protected void generateDefaultImplsIfNeeded() {
}
private static boolean shouldProcessFirst(KtDeclaration declaration) {
return !(declaration instanceof KtProperty || declaration instanceof KtNamedFunction);
}

View File

@@ -230,7 +230,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
@Override
protected void generateBody() {
protected void generateDefaultImplsIfNeeded() {
if (isInterface(descriptor) && !isLocal) {
Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor);
ClassBuilder defaultImplsBuilder =
@@ -242,7 +242,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ClassContext defaultImplsContext = parentContext.intoDefaultImplsClass(descriptor, (ClassContext) context, state);
new InterfaceImplBodyCodegen(myClass, defaultImplsContext, defaultImplsBuilder, state, this).generate();
}
super.generateBody();
}
@Override
@@ -378,7 +377,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateDelegates(delegationFieldsInfo);
generateSyntheticAccessors();
if (!isInterface(descriptor) || kind == OwnerKind.DEFAULT_IMPLS) {
generateSyntheticAccessors();
}
generateEnumMethods();
@@ -1332,7 +1333,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateTraitMethods() {
if (isInterface(descriptor)) return;
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getTraitMethods(descriptor).entrySet()) {
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
FunctionDescriptor traitFun = entry.getKey();
//skip java 8 default methods
if (!(traitFun instanceof JavaCallableMemberDescriptor)) {

View File

@@ -103,6 +103,8 @@ public class InterfaceImplBodyCodegen(
}
}
}
generateSyntheticAccessors()
}
private fun generateDelegationToSuperTraitImpl(descriptor: FunctionDescriptor, implementation: FunctionDescriptor) {

View File

@@ -66,6 +66,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isStaticDeclaration;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
@@ -684,7 +685,7 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallTarget() != null
);
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor);
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor) && !isInterface(functionDescriptor.getContainingDeclaration());
int reg = hasDispatchReceiver ? 1 : 0;
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {

View File

@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.context;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
@@ -27,7 +28,6 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.java.JavaVisibilities;
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.storage.NullableLazyValue;
@@ -505,6 +505,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
@NotNull
@ReadOnly
public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.codegen.AccessorForCallableDescriptor
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -33,4 +34,11 @@ class DefaultImplsClassContext(
override fun getCompanionObjectContext(): CodegenContext<*>? {
return interfaceContext.companionObjectContext
}
override fun getAccessors(): Collection<AccessorForCallableDescriptor<*>> {
val accessors = super.getAccessors()
val alreadyExistKeys = accessors.map ({ Pair(it.calleeDescriptor, it.superCallTarget) })
val filtered = interfaceContext.accessors.toMap ({ Pair(it.calleeDescriptor, it.superCallTarget) }, {it}) - alreadyExistKeys
return accessors + filtered.values
}
}

View File

@@ -758,7 +758,7 @@ public class JetTypeMapper {
ClassDescriptor ownerForDefault = (ClassDescriptor) baseMethodDescriptor.getContainingDeclaration();
ownerForDefaultImpl = isJvmInterface(ownerForDefault) ? mapDefaultImpls(ownerForDefault) : mapClass(ownerForDefault);
if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE)) {
if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) {
thisClass = mapClass(currentOwner);
if (declarationOwner instanceof JavaClassDescriptor) {
invokeOpcode = INVOKESPECIAL;

View File

@@ -1,11 +1,9 @@
public interface PrivateInTrait {
final class DefaultImpls {
@org.jetbrains.annotations.NotNull
static java.lang.String getNn(PrivateInTrait $this) { /* compiled code */ }
private static java.lang.String getNn(PrivateInTrait $this) { /* compiled code */ }
static void setNn(@org.jetbrains.annotations.NotNull PrivateInTrait $this, java.lang.String value) { /* compiled code */ }
private static void setNn(PrivateInTrait $this, java.lang.String value) { /* compiled code */ }
@org.jetbrains.annotations.Nullable
static java.lang.String getN(PrivateInTrait $this) { /* compiled code */ }
private static java.lang.String getN(PrivateInTrait $this) { /* compiled code */ }
}
}

View File

@@ -0,0 +1,16 @@
interface Z{
private fun extension(): String {
return "OK"
}
}
object Z2 : Z {
}
fun box() : String {
val size = Class.forName("Z2").declaredMethods.size
if (size != 0) return "fail: $size"
return "OK"
}

View File

@@ -0,0 +1,21 @@
var result = "fail"
interface B {
private fun test() {
result = "OK"
}
class Z {
fun ztest(b: B) {
b.test()
}
}
}
class C : B
fun box(): String {
B.Z().ztest(C())
return result
}

View File

@@ -7876,6 +7876,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("noPrivateDelegation.kt")
public void testNoPrivateDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/noPrivateDelegation.kt");
doTest(fileName);
}
@TestMetadata("syntheticAccessor.kt")
public void testSyntheticAccessor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/syntheticAccessor.kt");
doTest(fileName);
}
@TestMetadata("traitImplDelegationWithCovariantOverride.kt")
public void testTraitImplDelegationWithCovariantOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/traitImplDelegationWithCovariantOverride.kt");

View File

@@ -232,7 +232,7 @@ public class ClassTranslator private constructor(
}
private fun generateBridgesToTraitImpl(properties: MutableList<JsPropertyInitializer>) {
for (entry in CodegenUtil.getTraitMethods(descriptor).entrySet()) {
for (entry in CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
if (!areNamesEqual(entry.getKey(), entry.getValue())) {
properties.add(generateDelegateCall(entry.getValue(), entry.getKey(), JsLiteral.THIS, context()))
}