Skip to content

Commit ef11b11

Browse files
committed
restore completion results order stability
1 parent 3d3f125 commit ef11b11

File tree

4 files changed

+144
-143
lines changed

4 files changed

+144
-143
lines changed

lib/AST/LookupVisibleDecls.cpp

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -473,67 +473,35 @@ lookupVisibleMemberDeclsImpl(Type BaseTy, VisibleDeclConsumer &Consumer,
473473
GenericSignatureBuilder *GSB,
474474
VisitedSet &Visited);
475475

476+
// Filters out restated declarations from a protocol hierarchy
477+
// or equivalent requirements from protocol composition types.
476478
class RestateFilteringConsumer : public VisibleDeclConsumer {
477-
VisibleDeclConsumer &parentConsumer;
478479
LazyResolver *resolver;
479480

480481
using FoundDecl = std::pair<ValueDecl*, DeclVisibilityKind>;
481482
using NameAndType = std::pair<DeclName, CanType>;
482483

483484
llvm::DenseMap<DeclName, FoundDecl> foundVars;
484485
llvm::DenseMap<NameAndType, FoundDecl> foundFuncs;
485-
486-
public:
487-
RestateFilteringConsumer(VisibleDeclConsumer &parentConsumer,
488-
Type baseTy, const DeclContext *DC,
489-
LazyResolver *resolver)
490-
: parentConsumer(parentConsumer), resolver(resolver) {
491-
assert(DC && baseTy && !baseTy->hasLValueType());
492-
}
493-
494-
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
495-
assert(VD);
496-
// If this isn't a protocol context, hand over the decl
497-
// to the parent consumer.
498-
if (!isa<ProtocolDecl>(VD->getDeclContext())) {
499-
parentConsumer.foundDecl(VD, Reason);
500-
return;
501-
}
502-
if (resolver)
503-
resolver->resolveDeclSignature(VD);
504-
505-
if (!VD->hasInterfaceType()) {
506-
parentConsumer.foundDecl(VD, Reason);
507-
return;
508-
}
509-
// Do not feed anything to the parent consumer if we found a valid
510-
// new declaration: there might be another conflicting one with a
511-
// higher access level that we want to prioritize later.
512-
if (auto GFT = VD->getInterfaceType()->getAs<GenericFunctionType>()) {
513-
auto type = stripSelfRequirementsIfNeeded(VD, GFT);
514-
NameAndType nameAndType = {VD->getFullName(), type};
515-
516-
if ((foundFuncs.find(nameAndType) == foundFuncs.end()) ||
517-
(foundFuncs[nameAndType].first->getFormalAccess() <
518-
VD->getFormalAccess()))
519-
foundFuncs[nameAndType] = {VD, Reason};
520-
return;
486+
llvm::MapVector<ValueDecl*, DeclVisibilityKind> declsToReport;
487+
488+
template <typename K>
489+
void addDecl(llvm::DenseMap<K, FoundDecl> &Map, K Key, FoundDecl FD) {
490+
// Add the declaration if we haven't found an equivalent yet, otherwise
491+
// replace the equivalent if the found decl has a higher access level.
492+
auto existingDecl = Map.find(Key);
493+
494+
if ((existingDecl == Map.end()) ||
495+
(Map[Key].first->getFormalAccess() < FD.first->getFormalAccess())) {
496+
if (existingDecl != Map.end())
497+
declsToReport.erase({existingDecl->getSecond().first});
498+
Map[Key] = FD;
499+
declsToReport.insert(FD);
521500
}
522-
auto declName = VD->getFullName();
523-
if ((foundVars.find(declName) == foundVars.end()) ||
524-
(foundVars[declName].first->getFormalAccess() <
525-
VD->getFormalAccess()))
526-
foundVars[declName] = {VD, Reason};
527501
}
528502

529-
void feedFilteredResultsToParentConsumer() const {
530-
for (auto entry: foundVars)
531-
parentConsumer.foundDecl(entry.getSecond().first, entry.getSecond().second);
532-
for (auto entry: foundFuncs)
533-
parentConsumer.foundDecl(entry.getSecond().first, entry.getSecond().second);
534-
}
535-
private:
536-
CanType stripSelfRequirementsIfNeeded(ValueDecl *VD, GenericFunctionType *GFT) const {
503+
CanType stripSelfRequirementsIfNeeded(ValueDecl *VD,
504+
GenericFunctionType *GFT) const {
537505
// Preserve the generic signature if this is a subscript, which are uncurried,
538506
// or if we have generic params other than Self. Otherwise, use
539507
// the resultType of the curried function type.
@@ -555,6 +523,40 @@ class RestateFilteringConsumer : public VisibleDeclConsumer {
555523
GFT->getResult(), GFT->getExtInfo())
556524
->getCanonicalType();
557525
}
526+
527+
public:
528+
RestateFilteringConsumer(Type baseTy, const DeclContext *DC,
529+
LazyResolver *resolver)
530+
: resolver(resolver) {
531+
assert(DC && baseTy && !baseTy->hasLValueType());
532+
}
533+
534+
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
535+
assert(VD);
536+
// If this isn't a protocol context, don't look further into the decl.
537+
if (!isa<ProtocolDecl>(VD->getDeclContext())) {
538+
declsToReport.insert({VD, Reason});
539+
return;
540+
}
541+
if (resolver)
542+
resolver->resolveDeclSignature(VD);
543+
544+
if (!VD->hasInterfaceType()) {
545+
declsToReport.insert({VD, Reason});
546+
return;
547+
}
548+
if (auto GFT = VD->getInterfaceType()->getAs<GenericFunctionType>()) {
549+
auto type = stripSelfRequirementsIfNeeded(VD, GFT);
550+
addDecl(foundFuncs, {VD->getFullName(), type}, {VD, Reason});
551+
return;
552+
}
553+
addDecl(foundVars, VD->getFullName(), {VD, Reason});
554+
}
555+
556+
void feedResultsToConsumer(VisibleDeclConsumer &Consumer) const {
557+
for (const auto entry: declsToReport)
558+
Consumer.foundDecl(entry.first, entry.second);
559+
}
558560
};
559561

560562
static void
@@ -933,14 +935,13 @@ static void lookupVisibleMemberDecls(
933935
LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver,
934936
GenericSignatureBuilder *GSB) {
935937
OverrideFilteringConsumer overrideConsumer(BaseTy, CurrDC, TypeResolver);
936-
RestateFilteringConsumer restateConsumer(overrideConsumer, BaseTy, CurrDC,
937-
TypeResolver);
938+
RestateFilteringConsumer restateConsumer(BaseTy, CurrDC, TypeResolver);
938939
VisitedSet Visited;
939940
lookupVisibleMemberDeclsImpl(BaseTy, restateConsumer, CurrDC, LS, Reason,
940941
TypeResolver, GSB, Visited);
941942

942943
// Report the declarations we found to the real consumer.
943-
restateConsumer.feedFilteredResultsToParentConsumer();
944+
restateConsumer.feedResultsToConsumer(overrideConsumer);
944945
for (const auto &DeclAndReason : overrideConsumer.DeclsToReport)
945946
Consumer.foundDecl(DeclAndReason.D, DeclAndReason.Reason);
946947
}

test/IDE/complete_associated_types.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,6 @@ struct StructWithBrokenConformance : FooProtocolWithAssociatedTypes {
267267
func testBrokenConformances1() {
268268
StructWithBrokenConformance.#^BROKEN_CONFORMANCE_1^#
269269
}
270-
271270
// BROKEN_CONFORMANCE_1: Begin completions, 35 items
272271
// BROKEN_CONFORMANCE_1-DAG: Decl[TypeAlias]/CurrNominal: DefaultedTypeCommonA[#StructWithBrokenConformance.DefaultedTypeCommonA#]; name=DefaultedTypeCommonA
273272
// BROKEN_CONFORMANCE_1-DAG: Decl[TypeAlias]/CurrNominal: DefaultedTypeCommonB[#StructWithBrokenConformance.DefaultedTypeCommonB#]; name=DefaultedTypeCommonB

test/IDE/complete_pound_keypath.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func completeInKeyPath2() {
4040

4141
// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop1[#String#]; name=prop1
4242
// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop2[#ObjCClass?#]; name=prop2
43-
// CHECK-IN_KEYPATH: Decl[InstanceVar]/Super: hash[#Int#]; name=hash
4443
// CHECK-IN_KEYPATH: Decl[InstanceVar]/Super: hashValue[#Int#]; name=hashValue
44+
// CHECK-IN_KEYPATH: Decl[InstanceVar]/Super: hash[#Int#]; name=hash
45+
4546

0 commit comments

Comments
 (0)