From de6d5a4a96f3757e8eed6d116b637712a100ebd5 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Tue, 21 May 2013 16:37:24 +0400 Subject: [PATCH] Fixed loading SAM interfaces when they inherit abstract methods. --- .../resolve/java/provider/MembersCache.java | 3 -- .../java/resolver/JavaClassResolver.java | 34 +++++++++++++++++-- .../java/resolver/JavaFunctionResolver.java | 6 ++-- .../java/sam/SingleAbstractMethodUtils.java | 2 +- .../SubstitutedSamInterface.java | 6 ++++ .../SubstitutedSamInterface.txt | 7 ++++ ...stitutedSamInterfaceSubclassOfBuiltin.java | 4 +++ ...bstitutedSamInterfaceSubclassOfBuiltin.txt | 7 ++++ .../jvm/compiler/LoadJavaTestGenerated.java | 10 ++++++ ...esolveNamespaceComparingTestGenerated.java | 5 +++ 10 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.java create mode 100644 compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.txt create mode 100644 compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.java create mode 100644 compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.txt diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java index 5c305bcfcee..1b3eaa095d8 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java @@ -409,9 +409,6 @@ public final class MembersCache { // Returns null if not SAM interface @Nullable public static PsiMethod getSamInterfaceMethod(@NotNull PsiClass psiClass) { - if (psiClass.hasModifierProperty(PsiModifier.PRIVATE)) { // TODO hacky - return null; - } if (DescriptorResolverUtils.isKotlinClass(psiClass)) { return null; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java index edb7177da25..980ad38d540 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java @@ -44,6 +44,8 @@ import org.jetbrains.jet.lang.resolve.name.FqNameBase; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; +import org.jetbrains.jet.lang.types.TypeUtils; import javax.inject.Inject; import java.util.ArrayList; @@ -275,14 +277,42 @@ public final class JavaClassResolver { PsiMethod samInterfaceMethod = MembersCache.getSamInterfaceMethod(psiClass); if (samInterfaceMethod != null) { - SimpleFunctionDescriptor abstractMethod = functionResolver.resolveFunctionMutely( - psiClass, new PsiMethodWrapper(samInterfaceMethod), classDescriptor); + SimpleFunctionDescriptor abstractMethod = resolveFunctionOfSamInterface(psiClass, samInterfaceMethod, classDescriptor); classDescriptor.setFunctionTypeForSamInterface(SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod)); } return classDescriptor; } + @NotNull + private SimpleFunctionDescriptor resolveFunctionOfSamInterface( + @NotNull PsiClass psiClass, + @NotNull PsiMethod samInterfaceMethod, + @NotNull ClassDescriptorFromJvmBytecode samInterface + ) { + PsiClass methodContainer = samInterfaceMethod.getContainingClass(); + assert methodContainer != null : "method container is null for " + methodContainer; + String containerQualifiedName = methodContainer.getQualifiedName(); + assert containerQualifiedName != null : "qualified name is null for " + psiClass; + + if (DescriptorUtils.getFQName(samInterface).getFqName().equals(containerQualifiedName)) { + SimpleFunctionDescriptor abstractMethod = + functionResolver.resolveFunctionMutely(new PsiMethodWrapper(samInterfaceMethod), samInterface); + assert abstractMethod != null : "couldn't resolve method " + samInterfaceMethod; + return abstractMethod; + } + else { + Set supertypes = TypeUtils.getAllSupertypes(samInterface.getDefaultType()); + for (JetType supertype : supertypes) { + List abstractMembers = SingleAbstractMethodUtils.getAbstractMembers(supertype); + if (!abstractMembers.isEmpty()) { + return (SimpleFunctionDescriptor) abstractMembers.get(0); + } + } + throw new IllegalStateException("Couldn't find abstract method in supertypes " + supertypes); + } + } + private void cache(@NotNull FqNameBase fqName, @Nullable ClassDescriptor classDescriptor) { if (classDescriptor == null) { cacheNegativeValue(fqName); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java index 8d2e5dd7a40..5a6ca428aaf 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java @@ -92,10 +92,12 @@ public final class JavaFunctionResolver { @Nullable SimpleFunctionDescriptor resolveFunctionMutely( - @NotNull PsiClass psiClass, PsiMethodWrapper method, + @NotNull PsiMethodWrapper method, @NotNull ClassOrNamespaceDescriptor ownerDescriptor ) { - return resolveMethodToFunctionDescriptor(psiClass, method, DeclarationOrigin.JAVA, ownerDescriptor, false); + PsiClass containingClass = method.getPsiMethod().getContainingClass(); + assert containingClass != null : "containing class is null for " + method; + return resolveMethodToFunctionDescriptor(containingClass, method, DeclarationOrigin.JAVA, ownerDescriptor, false); } @Nullable diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index dc8c30aa1e0..791161d5abc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -40,7 +40,7 @@ import static org.jetbrains.jet.lang.types.Variance.INVARIANT; public class SingleAbstractMethodUtils { @NotNull - private static List getAbstractMembers(@NotNull JetType type) { + public static List getAbstractMembers(@NotNull JetType type) { List abstractMembers = Lists.newArrayList(); for (DeclarationDescriptor member : type.getMemberScope().getAllDescriptors()) { if (member instanceof CallableMemberDescriptor && diff --git a/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.java b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.java new file mode 100644 index 00000000000..0585609ad95 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.java @@ -0,0 +1,6 @@ +package test; + +import java.util.Comparator; + +public interface SubstitutedSamInterface extends Comparator { +} diff --git a/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.txt b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.txt new file mode 100644 index 00000000000..d292208116a --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.txt @@ -0,0 +1,7 @@ +package test + +public /*synthesized*/ fun SubstitutedSamInterface(/*0*/ function: (jet.String?, jet.String?) -> jet.Int): test.SubstitutedSamInterface + +public trait SubstitutedSamInterface : java.util.Comparator { + public abstract override /*1*/ /*fake_override*/ fun compare(/*0*/ p0: jet.String?, /*1*/ p1: jet.String?): jet.Int +} diff --git a/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.java b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.java new file mode 100644 index 00000000000..f60d884bf46 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.java @@ -0,0 +1,4 @@ +package test; + +public interface SubstitutedSamInterfaceSubclassOfBuiltin extends Comparable { +} diff --git a/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.txt b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.txt new file mode 100644 index 00000000000..cd1b36fa97e --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.txt @@ -0,0 +1,7 @@ +package test + +public /*synthesized*/ fun SubstitutedSamInterfaceSubclassOfBuiltin(/*0*/ function: (test.SubstitutedSamInterfaceSubclassOfBuiltin) -> jet.Int): test.SubstitutedSamInterfaceSubclassOfBuiltin + +public trait SubstitutedSamInterfaceSubclassOfBuiltin : jet.Comparable { + public abstract override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: test.SubstitutedSamInterfaceSubclassOfBuiltin): jet.Int +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 6506c2d5255..5d88070a54a 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -1218,6 +1218,16 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/Runnable.java"); } + @TestMetadata("SubstitutedSamInterface.java") + public void testSubstitutedSamInterface() throws Exception { + doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterface.java"); + } + + @TestMetadata("SubstitutedSamInterfaceSubclassOfBuiltin.java") + public void testSubstitutedSamInterfaceSubclassOfBuiltin() throws Exception { + doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/SubstitutedSamInterfaceSubclassOfBuiltin.java"); + } + @TestMetadata("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter") public static class Adapter extends AbstractLoadJavaTest { public void testAllFilesPresentInAdapter() throws Exception { diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java index 4c683e969e2..b2bcdbb32bf 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -130,6 +130,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/class/InheritClassWithParam.kt"); } + @TestMetadata("InheritSubstitutedMethod.kt") + public void testInheritSubstitutedMethod() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/class/InheritSubstitutedMethod.kt"); + } + @TestMetadata("InheritTraitWithParam.kt") public void testInheritTraitWithParam() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/class/InheritTraitWithParam.kt");