Skip to content

Commit 30a0ce6

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 bdbc475 commit 30a0ce6

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

lib/AST/LookupVisibleDecls.cpp

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

680680
} // namespace llvm
681681

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

684701
class OverrideFilteringConsumer : public VisibleDeclConsumer {
@@ -789,7 +806,8 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
789806
auto OtherSignature = OtherVD->getOverloadSignature();
790807
auto OtherSignatureType = OtherVD->getOverloadSignatureType();
791808
if (OtherSignatureType && shouldSubst) {
792-
auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD);
809+
auto ActualBaseTy = getBaseTypeForMember(M, OtherVD, BaseTy);
810+
auto subs = ActualBaseTy->getMemberSubstitutionMap(M, OtherVD);
793811
if (auto CT = OtherSignatureType.subst(subs))
794812
OtherSignatureType = CT->getCanonicalType();
795813
}

0 commit comments

Comments
 (0)