Skip to content

Commit 146f1a5

Browse files
committed
LookupVisibleDecls: Fix duplicate completion results when inheritance is used with protocol conformance
Consider this setup: protocol Proto { func foo() {} } class Base : Proto { func foo() {} } class Derived : Base { ... } When completing members of a Derived instance, we find both the protocol's foo() and the base class's foo(). These have the following types: - Proto.foo: <Self : Proto> (Self) -> () -> () - Base.foo: (Base) -> () -> () If we simply substitute the base type (Derived) into the type of the protocol member, we get (Derived) -> () -> (), which is different than the type of Base.foo, so we get both declarations in the completion list. Instead, use the 'Self' type for the specific class of the conformance, which in this case is 'Base' even if we're looking at members of 'Derived'. Fixes <rdar://problem/21161476>, <https://bugs.swift.org/browse/SR-1181>.
1 parent af34984 commit 146f1a5

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,23 @@ template <> struct DenseMapInfo<FoundDeclTy> {
674674

675675
} // namespace llvm
676676

677+
// If a class 'Base' conforms to 'Proto', and my base type is a subclass
678+
// 'Derived' of 'Base', use 'Base' not 'Derived' as the 'Self' type in the
679+
// substitution map.
680+
static Type getBaseTypeForMember(ModuleDecl *M, ValueDecl *OtherVD, Type BaseTy) {
681+
if (auto *Proto = OtherVD->getDeclContext()->getSelfProtocolDecl()) {
682+
if (BaseTy->getClassOrBoundGenericClass()) {
683+
if (auto Conformance = M->lookupConformance(BaseTy, Proto)) {
684+
auto *Superclass = Conformance->getConcrete()->getRootConformance()
685+
->getType()->getClassOrBoundGenericClass();
686+
return BaseTy->getSuperclassForDecl(Superclass);
687+
}
688+
}
689+
}
690+
691+
return BaseTy;
692+
}
693+
677694
namespace {
678695

679696
class OverrideFilteringConsumer : public VisibleDeclConsumer {
@@ -784,7 +801,8 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
784801
auto OtherSignature = OtherVD->getOverloadSignature();
785802
auto OtherSignatureType = OtherVD->getOverloadSignatureType();
786803
if (OtherSignatureType && shouldSubst) {
787-
auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD);
804+
auto ActualBaseTy = getBaseTypeForMember(M, OtherVD, BaseTy);
805+
auto subs = ActualBaseTy->getMemberSubstitutionMap(M, OtherVD);
788806
if (auto CT = OtherSignatureType.subst(subs))
789807
OtherSignatureType = CT->getCanonicalType();
790808
}

0 commit comments

Comments
 (0)