Refactor DelegationResolver
Fix an issue in lazy resolve : filter out methods from delegated traits superclass
This commit is contained in:
@@ -32,67 +32,126 @@ import org.jetbrains.jet.lang.types.TypeUtils;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*;
|
||||||
|
|
||||||
public class DelegationResolver {
|
public class DelegationResolver {
|
||||||
|
|
||||||
private DelegationResolver() {}
|
private DelegationResolver() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void addDelegatedMembers(@NotNull BindingTrace trace, @NotNull JetClassOrObject jetClass, @NotNull MutableClassDescriptor classDescriptor) {
|
@NotNull
|
||||||
|
public static Collection<CallableMemberDescriptor> generateDelegatedMembers(
|
||||||
|
@NotNull BindingTrace trace,
|
||||||
|
@NotNull JetClassOrObject jetClass,
|
||||||
|
@NotNull MutableClassDescriptor classDescriptor
|
||||||
|
) {
|
||||||
|
Collection<CallableMemberDescriptor> delegatedMembers = new HashSet<CallableMemberDescriptor>();
|
||||||
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
|
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
|
||||||
if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) {
|
if (!(delegationSpecifier instanceof JetDelegatorByExpressionSpecifier)) {
|
||||||
JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
|
continue;
|
||||||
JetType type = trace.get(BindingContext.TYPE, specifier.getTypeReference());
|
}
|
||||||
if (type != null) {
|
JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
|
||||||
final Collection<CallableMemberDescriptor> membersToSkip = getMembersFromClassSupertype(type);
|
JetType type = trace.get(BindingContext.TYPE, specifier.getTypeReference());
|
||||||
Collection<CallableMemberDescriptor> descriptorsToDelegate = Collections2.filter(extractCallableMembers(type),
|
if (type == null) {
|
||||||
new Predicate<CallableMemberDescriptor>() {
|
continue;
|
||||||
@Override
|
}
|
||||||
public boolean apply(@Nullable CallableMemberDescriptor descriptor) {
|
Collection<CallableMemberDescriptor> candidates =
|
||||||
for (CallableMemberDescriptor memberToSkip : membersToSkip) {
|
generateDelegationCandidates(classDescriptor, type, extractCallableMembers(type));
|
||||||
if (haveSameSignatures(memberToSkip, descriptor)) {
|
for (CallableMemberDescriptor candidate : candidates) {
|
||||||
return false;
|
if (existingMemberOverridesDelegatedMember(classDescriptor, candidate)) {
|
||||||
}
|
continue;
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Collection<CallableMemberDescriptor> generatedDescriptors = generateDelegatedMembers(classDescriptor, descriptorsToDelegate);
|
|
||||||
outer:
|
|
||||||
for (CallableMemberDescriptor descriptor : generatedDescriptors) {
|
|
||||||
for (CallableMemberDescriptor existingDescriptor : classDescriptor.getAllCallableMembers()) {
|
|
||||||
if (OverridingUtil.isOverridableBy(existingDescriptor, descriptor).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) {
|
|
||||||
if (existingDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
|
|
||||||
//trying to delegate to many traits with the same methods
|
|
||||||
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(jetClass.getNameIdentifier(), jetClass, existingDescriptor));
|
|
||||||
}
|
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor instanceof PropertyDescriptor) {
|
|
||||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
|
||||||
classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
|
|
||||||
}
|
|
||||||
else if (descriptor instanceof SimpleFunctionDescriptor) {
|
|
||||||
SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor;
|
|
||||||
classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//only leave the first delegated member
|
||||||
|
if (checkClashWithOtherDelegatedMember(trace, jetClass, delegatedMembers, candidate)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
delegatedMembers.add(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return delegatedMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean haveSameSignatures(CallableDescriptor memberOne, CallableDescriptor memberTwo) {
|
private static boolean checkClashWithOtherDelegatedMember(
|
||||||
return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
|
@NotNull BindingTrace trace,
|
||||||
|
@NotNull JetClassOrObject jetClass,
|
||||||
|
@NotNull Collection<CallableMemberDescriptor> delegatedMembers,
|
||||||
|
@NotNull CallableMemberDescriptor candidate
|
||||||
|
) {
|
||||||
|
for (CallableMemberDescriptor alreadyDelegatedMember : delegatedMembers) {
|
||||||
|
if (haveSameSignatures(alreadyDelegatedMember, candidate)) {
|
||||||
|
//trying to delegate to many traits with the same methods
|
||||||
|
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(jetClass.getNameIdentifier(), jetClass, alreadyDelegatedMember));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection<CallableMemberDescriptor> getMembersFromClassSupertype(JetType type) {
|
private static boolean existingMemberOverridesDelegatedMember(
|
||||||
|
MutableClassDescriptor classDescriptor,
|
||||||
|
CallableMemberDescriptor candidate
|
||||||
|
) {
|
||||||
|
for (CallableMemberDescriptor existingDescriptor : classDescriptor.getAllCallableMembers()) {
|
||||||
|
if (haveSameSignatures(existingDescriptor, candidate)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static <T extends CallableMemberDescriptor> Collection<T> generateDelegationCandidates(
|
||||||
|
@NotNull ClassDescriptor classDescriptor,
|
||||||
|
@NotNull JetType delegatedTraitType,
|
||||||
|
@NotNull Collection<T> membersFromTrait
|
||||||
|
) {
|
||||||
|
Collection<T> descriptorsToDelegate = filterMembersFromSuperClassOfDelegatedTrait(delegatedTraitType, membersFromTrait);
|
||||||
|
Collection<T> result = Lists.newArrayList();
|
||||||
|
for (T memberDescriptor : descriptorsToDelegate) {
|
||||||
|
if (memberDescriptor.getModality().isOverridable()) {
|
||||||
|
Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T copy = (T) memberDescriptor.copy(classDescriptor, modality, memberDescriptor.getVisibility(),
|
||||||
|
CallableMemberDescriptor.Kind.DELEGATION, false);
|
||||||
|
result.add(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static <T extends CallableMemberDescriptor> Collection<T> filterMembersFromSuperClassOfDelegatedTrait(
|
||||||
|
@NotNull JetType delegatedTraitType,
|
||||||
|
@NotNull Collection<T> membersFromTrait
|
||||||
|
) {
|
||||||
|
final Collection<CallableMemberDescriptor> membersToSkip = getMembersFromClassSupertypeOfTrait(delegatedTraitType);
|
||||||
|
return Collections2.filter(
|
||||||
|
membersFromTrait,
|
||||||
|
new Predicate<CallableMemberDescriptor>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(@Nullable CallableMemberDescriptor descriptor) {
|
||||||
|
for (CallableMemberDescriptor memberToSkip : membersToSkip) {
|
||||||
|
if (haveSameSignatures(memberToSkip, descriptor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean haveSameSignatures(@NotNull CallableDescriptor memberOne, @NotNull CallableDescriptor memberTwo) {
|
||||||
|
return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OVERRIDABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static Collection<CallableMemberDescriptor> getMembersFromClassSupertypeOfTrait(@NotNull JetType delegateTraitType) {
|
||||||
JetType classSupertype = null;
|
JetType classSupertype = null;
|
||||||
for (JetType supertype : TypeUtils.getAllSupertypes(type)) {
|
for (JetType supertype : TypeUtils.getAllSupertypes(delegateTraitType)) {
|
||||||
if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) {
|
if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) {
|
||||||
classSupertype = supertype;
|
classSupertype = supertype;
|
||||||
break;
|
break;
|
||||||
@@ -116,17 +175,20 @@ public class DelegationResolver {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends CallableMemberDescriptor> Collection<T> generateDelegatedMembers(DeclarationDescriptor newOwner, Collection<T> delegatedDescriptors) {
|
public static void generateDelegatesInAClass(
|
||||||
Collection<CallableMemberDescriptor> result = Lists.newArrayList();
|
@NotNull MutableClassDescriptor classDescriptor,
|
||||||
for (CallableMemberDescriptor memberDescriptor : delegatedDescriptors) {
|
@NotNull BindingTrace trace,
|
||||||
if (memberDescriptor.getModality().isOverridable()) {
|
@NotNull JetClassOrObject jetClassOrObject
|
||||||
Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true);
|
) {
|
||||||
CallableMemberDescriptor copy =
|
for (CallableMemberDescriptor descriptor : generateDelegatedMembers(trace, jetClassOrObject, classDescriptor)) {
|
||||||
memberDescriptor.copy(newOwner, modality, memberDescriptor.getVisibility(), CallableMemberDescriptor.Kind.DELEGATION, false);
|
if (descriptor instanceof PropertyDescriptor) {
|
||||||
result.add(copy);
|
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||||
|
classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
|
||||||
|
}
|
||||||
|
else if (descriptor instanceof SimpleFunctionDescriptor) {
|
||||||
|
SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor;
|
||||||
|
classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//noinspection unchecked
|
|
||||||
return (Collection) result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,9 +114,9 @@ public class OverrideResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PsiElement declaration = BindingContextUtils.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
|
JetClassOrObject classOrObject = (JetClassOrObject) BindingContextUtils
|
||||||
DelegationResolver.addDelegatedMembers(trace, (JetClassOrObject) declaration, classDescriptor);
|
.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
|
||||||
|
DelegationResolver.generateDelegatesInAClass(classDescriptor, trace, classOrObject);
|
||||||
generateOverridesInAClass(classDescriptor);
|
generateOverridesInAClass(classDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -42,6 +42,8 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.resolve.DelegationResolver.generateDelegationCandidates;
|
||||||
|
|
||||||
public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescriptor, ClassMemberDeclarationProvider> {
|
public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescriptor, ClassMemberDeclarationProvider> {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -268,9 +270,7 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
|
|||||||
typeReference,
|
typeReference,
|
||||||
resolveSession.getTrace(),
|
resolveSession.getTrace(),
|
||||||
false);
|
false);
|
||||||
Collection<T> descriptors =
|
result.addAll(generateDelegationCandidates(thisDescriptor, supertype, extractor.extract(supertype, name)));
|
||||||
DelegationResolver.generateDelegatedMembers(thisDescriptor, extractor.extract(supertype, name));
|
|
||||||
result.addAll(descriptors);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
abstract class A {
|
||||||
|
abstract fun foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
trait X : A {
|
||||||
|
fun bar() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class B() : A() {
|
||||||
|
override fun foo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C() : A(), X {
|
||||||
|
override fun foo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class D(val c: C) : B(), X by c {
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
internal abstract class A {
|
||||||
|
/*primary*/ public constructor A()
|
||||||
|
internal abstract fun foo(): jet.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
internal open class B : test.A {
|
||||||
|
/*primary*/ public constructor B()
|
||||||
|
internal open override /*1*/ fun foo(): jet.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final class C : test.A, test.X {
|
||||||
|
/*primary*/ public constructor C()
|
||||||
|
internal open override /*1*/ /*fake_override*/ fun bar(): jet.Unit
|
||||||
|
internal open override /*2*/ fun foo(): jet.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final class D : test.B, test.X {
|
||||||
|
/*primary*/ public constructor D(/*0*/ c: test.C)
|
||||||
|
internal final val c: test.C
|
||||||
|
internal final fun <get-c>(): test.C
|
||||||
|
internal open override /*1*/ /*delegation*/ fun bar(): jet.Unit
|
||||||
|
internal open override /*2*/ /*fake_override*/ fun foo(): jet.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
internal trait X : test.A {
|
||||||
|
internal open fun bar(): jet.Unit
|
||||||
|
internal abstract override /*1*/ /*fake_override*/ fun foo(): jet.Unit
|
||||||
|
}
|
||||||
+5
@@ -426,6 +426,11 @@ public class DescriptorSerializationTestGenerated extends AbstractDescriptorSeri
|
|||||||
doTest("compiler/testData/loadKotlin/fun/InheritValsDifferentTypes.kt");
|
doTest("compiler/testData/loadKotlin/fun/InheritValsDifferentTypes.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoDelegationForFunctionInheritedFromTraitSuperClass.kt")
|
||||||
|
public void testNoDelegationForFunctionInheritedFromTraitSuperClass() throws Exception {
|
||||||
|
doTest("compiler/testData/loadKotlin/fun/NoDelegationForFunctionInheritedFromTraitSuperClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NoSamAdapter.kt")
|
@TestMetadata("NoSamAdapter.kt")
|
||||||
public void testNoSamAdapter() throws Exception {
|
public void testNoSamAdapter() throws Exception {
|
||||||
doTest("compiler/testData/loadKotlin/fun/NoSamAdapter.kt");
|
doTest("compiler/testData/loadKotlin/fun/NoSamAdapter.kt");
|
||||||
|
|||||||
@@ -645,6 +645,11 @@ public class LoadCompiledKotlinTestGenerated extends AbstractLoadCompiledKotlinT
|
|||||||
doTestWithAccessors("compiler/testData/loadKotlin/fun/InheritValsDifferentTypes.kt");
|
doTestWithAccessors("compiler/testData/loadKotlin/fun/InheritValsDifferentTypes.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoDelegationForFunctionInheritedFromTraitSuperClass.kt")
|
||||||
|
public void testNoDelegationForFunctionInheritedFromTraitSuperClass() throws Exception {
|
||||||
|
doTestWithAccessors("compiler/testData/loadKotlin/fun/NoDelegationForFunctionInheritedFromTraitSuperClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NoSamAdapter.kt")
|
@TestMetadata("NoSamAdapter.kt")
|
||||||
public void testNoSamAdapter() throws Exception {
|
public void testNoSamAdapter() throws Exception {
|
||||||
doTestWithAccessors("compiler/testData/loadKotlin/fun/NoSamAdapter.kt");
|
doTestWithAccessors("compiler/testData/loadKotlin/fun/NoSamAdapter.kt");
|
||||||
|
|||||||
+5
@@ -647,6 +647,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso
|
|||||||
doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/fun/InheritValsDifferentTypes.kt");
|
doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/fun/InheritValsDifferentTypes.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoDelegationForFunctionInheritedFromTraitSuperClass.kt")
|
||||||
|
public void testNoDelegationForFunctionInheritedFromTraitSuperClass() throws Exception {
|
||||||
|
doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/fun/NoDelegationForFunctionInheritedFromTraitSuperClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NoSamAdapter.kt")
|
@TestMetadata("NoSamAdapter.kt")
|
||||||
public void testNoSamAdapter() throws Exception {
|
public void testNoSamAdapter() throws Exception {
|
||||||
doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/fun/NoSamAdapter.kt");
|
doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/fun/NoSamAdapter.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user