From b84f068c3320fa5e28ee79357272859dd8f32cbc Mon Sep 17 00:00:00 2001 From: Kirill Berezin Date: Sun, 26 Aug 2012 17:51:36 +0400 Subject: [PATCH] kt-1760 delegation to java iface: - removed codegen's unnecessary lookup for a declaration - skipped class' only supertype (if any) methods when delegating --- .../codegen/ImplementationBodyCodegen.java | 8 +-- .../jet/lang/resolve/DelegationResolver.java | 56 +++++++++++++++++-- .../codegen/classes/delegationJava.kt | 13 +++++ .../tests/DelegationToJavaIface.kt | 3 + .../checkers/JetDiagnosticsTestGenerated.java | 5 ++ .../jetbrains/jet/codegen/ClassGenTest.java | 5 ++ 6 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/classes/delegationJava.kt create mode 100644 compiler/testData/diagnostics/tests/DelegationToJavaIface.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 557ad43313c..a2e2fab45f5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -779,7 +779,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { StackValue field = StackValue.field(fieldType, classname, delegateField, false); field.store(fieldType, iv); - JetClass superClass = (JetClass) classDescriptorToDeclaration(bindingContext, superClassDescriptor); final CodegenContext delegateContext = context.intoClass(superClassDescriptor, new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), @@ -788,7 +787,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { MapTypeMode.IMPL) .getInternalName()), state); - generateDelegates(superClass, delegateContext, field); + generateDelegates(superClassDescriptor, delegateContext, field); } private void lookupConstructorExpressionsInClosureIfPresent(final ConstructorContext constructorContext) { @@ -1208,18 +1207,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return false; } - protected void generateDelegates(JetClass toClass, CodegenContext delegateContext, StackValue field) { + protected void generateDelegates(ClassDescriptor toClass, CodegenContext delegateContext, StackValue field) { final FunctionCodegen functionCodegen = new FunctionCodegen(delegateContext, v, state); final PropertyCodegen propertyCodegen = new PropertyCodegen(delegateContext, v, functionCodegen, state); - ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, toClass); for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { if (declaration instanceof CallableMemberDescriptor) { CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declaration; if (callableMemberDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) { Set overriddenDescriptors = callableMemberDescriptor.getOverriddenDescriptors(); for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) { - if (overriddenDescriptor.getContainingDeclaration() == classDescriptor) { + if (overriddenDescriptor.getContainingDeclaration() == toClass) { if (declaration instanceof PropertyDescriptor) { propertyCodegen .genDelegate((PropertyDescriptor) declaration, (PropertyDescriptor) overriddenDescriptor, field); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java index 7cd54fd292e..f906d0c0848 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java @@ -16,17 +16,21 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetClassOrObject; import org.jetbrains.jet.lang.psi.JetDelegationSpecifier; import org.jetbrains.jet.lang.psi.JetDelegatorByExpressionSpecifier; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; import java.util.Collection; +import java.util.Collections; /** * @author abreslav @@ -41,12 +45,22 @@ public class DelegationResolver { JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier; JetType type = trace.get(BindingContext.TYPE, specifier.getTypeReference()); if (type != null) { - @SuppressWarnings("unchecked") - Collection callableDescriptors = (Collection) Collections2.filter( - type.getMemberScope().getAllDescriptors(), - Predicates.instanceOf(CallableMemberDescriptor.class)); - Collection descriptors = generateDelegatedMembers(classDescriptor, callableDescriptors); - for (CallableMemberDescriptor descriptor : descriptors) { + final Collection membersToSkip = getMembersFromClassSupertype(type); + Collection descriptorsToDelegate = Collections2.filter(extractCallableMembers(type), + new Predicate() { + @Override + public boolean apply(@Nullable CallableMemberDescriptor descriptor) { + for (CallableMemberDescriptor memberToSkip : membersToSkip) { + if (haveSameSignatures(memberToSkip, descriptor)) { + return false; + } + } + return true; + } + }); + + Collection generatedDescriptors = generateDelegatedMembers(classDescriptor, descriptorsToDelegate); + for (CallableMemberDescriptor descriptor : generatedDescriptors) { if (descriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor); @@ -61,6 +75,36 @@ public class DelegationResolver { } } + private static boolean haveSameSignatures(CallableDescriptor memberOne, CallableDescriptor memberTwo) { + return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE; + } + + private static Collection getMembersFromClassSupertype(JetType type) { + JetType classSupertype = null; + for (JetType supertype : TypeUtils.getAllSupertypes(type)) { + if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) { + classSupertype = supertype; + break; + } + } + + return classSupertype != null ? extractCallableMembers(classSupertype) : Collections.emptyList(); + } + + @SuppressWarnings("unchecked") + private static Collection extractCallableMembers(JetType type) { + return (Collection) Collections2.filter(type.getMemberScope().getAllDescriptors(), + Predicates.instanceOf(CallableMemberDescriptor.class)); + } + + private static boolean isNotTrait(DeclarationDescriptor descriptor) { + if (descriptor instanceof ClassDescriptor) { + final ClassKind kind = ((ClassDescriptor) descriptor).getKind(); + return kind != ClassKind.TRAIT; + } + return false; + } + public static Collection generateDelegatedMembers(DeclarationDescriptor newOwner, Collection delegatedDescriptors) { Collection result = Lists.newArrayList(); for (CallableMemberDescriptor memberDescriptor : delegatedDescriptors) { diff --git a/compiler/testData/codegen/classes/delegationJava.kt b/compiler/testData/codegen/classes/delegationJava.kt new file mode 100644 index 00000000000..f7e209dc450 --- /dev/null +++ b/compiler/testData/codegen/classes/delegationJava.kt @@ -0,0 +1,13 @@ +class TestJava(r : Runnable) : Runnable by r {} +class TestRunnable() : Runnable { + public override fun run() = System.out.println("foobar") +} + +fun box() : String { + var del = TestJava(TestRunnable()) + del.run() + if (del !is Runnable) + return "Fail #1" + + return "OK" +} diff --git a/compiler/testData/diagnostics/tests/DelegationToJavaIface.kt b/compiler/testData/diagnostics/tests/DelegationToJavaIface.kt new file mode 100644 index 00000000000..f943fa61284 --- /dev/null +++ b/compiler/testData/diagnostics/tests/DelegationToJavaIface.kt @@ -0,0 +1,3 @@ +class TestIface(r : Runnable) : Runnable by r {} + +class TestObject(o : Object) : Object by o {} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 799f749e89e..27e92ab48e2 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -187,6 +187,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage public void testDelegation_ScopeInitializationOrder() throws Exception { doTest("compiler/testData/diagnostics/tests/Delegation_ScopeInitializationOrder.kt"); } + + @TestMetadata("DelegationToJavaIface.kt") + public void testDelegationToJavaIface() throws Exception { + doTest("compiler/testData/diagnostics/tests/DelegationToJavaIface.kt"); + } @TestMetadata("DiamondFunction.kt") public void testDiamondFunction() throws Exception { diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 86800186409..e8eaa6898dc 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -53,6 +53,11 @@ public class ClassGenTest extends CodegenTestCase { assertInstanceOf(aClass.newInstance(), List.class); } + public void testDelegationJavaIface() throws Exception { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("classes/delegationJava.kt"); + } + public void testInheritanceAndDelegation_DelegatingDefaultConstructorProperties() throws Exception { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); blackBoxFile("classes/inheritance.jet");