Skip to content

Commit 1a62f36

Browse files
committed
Eliminate recursion from USRBasedType::typeRelation
Use a worklist instead, and bump the size of the inline set storage. This shaves ~30ms off the time it takes to do this cached completion: ``` import SwiftUI Table(#^CC^# ```
1 parent 09c89fb commit 1a62f36

File tree

2 files changed

+31
-40
lines changed

2 files changed

+31
-40
lines changed

include/swift/IDE/CodeCompletionResultType.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,6 @@ class USRBasedType {
251251
: USR(USR), Supertypes(Supertypes),
252252
CustomAttributeKinds(CustomAttributeKinds) {}
253253

254-
/// Implementation of \c typeRelation. \p VisistedTypes keeps track which
255-
/// types have already been visited.
256-
CodeCompletionResultTypeRelation
257-
typeRelationImpl(const USRBasedType *ResultType, const USRBasedType *VoidType,
258-
SmallPtrSetImpl<const USRBasedType *> &VisitedTypes) const;
259-
260254
public:
261255
/// A null \c USRBasedType that's represented by an empty USR and has no
262256
/// supertypes.

lib/IDE/CodeCompletionResultType.cpp

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -122,38 +122,6 @@ const USRBasedType *USRBasedTypeArena::getVoidType() const { return VoidType; }
122122

123123
// MARK: - USRBasedType
124124

125-
TypeRelation USRBasedType::typeRelationImpl(
126-
const USRBasedType *ResultType, const USRBasedType *VoidType,
127-
SmallPtrSetImpl<const USRBasedType *> &VisitedTypes) const {
128-
129-
// `this` is the contextual type.
130-
if (this == VoidType) {
131-
// We don't report Void <-> Void matches because that would boost
132-
// methods returning Void in e.g.
133-
// func foo() { #^COMPLETE^# }
134-
// because #^COMPLETE^# is implicitly returned. But that's not very
135-
// helpful.
136-
return TypeRelation::Unknown;
137-
}
138-
if (ResultType == this) {
139-
return TypeRelation::Convertible;
140-
}
141-
for (const USRBasedType *Supertype : ResultType->getSupertypes()) {
142-
if (!VisitedTypes.insert(Supertype).second) {
143-
// Already visited this type.
144-
continue;
145-
}
146-
if (this->typeRelation(Supertype, VoidType) >= TypeRelation::Convertible) {
147-
return TypeRelation::Convertible;
148-
}
149-
}
150-
// TypeRelation computation based on USRs is an under-approximation because we
151-
// don't take into account generic conversions or retroactive conformance of
152-
// library types. Hence, we can't know for sure that ResultType is not
153-
// convertible to `this` type and thus can't return Unrelated or Invalid here.
154-
return TypeRelation::Unknown;
155-
}
156-
157125
const USRBasedType *USRBasedType::null(USRBasedTypeArena &Arena) {
158126
return USRBasedType::fromUSR(/*USR=*/"", /*Supertypes=*/{}, {}, Arena);
159127
}
@@ -337,8 +305,37 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
337305

338306
TypeRelation USRBasedType::typeRelation(const USRBasedType *ResultType,
339307
const USRBasedType *VoidType) const {
340-
SmallPtrSet<const USRBasedType *, 4> VisitedTypes;
341-
return this->typeRelationImpl(ResultType, VoidType, VisitedTypes);
308+
// `this` is the contextual type.
309+
if (this == VoidType) {
310+
// We don't report Void <-> Void matches because that would boost
311+
// methods returning Void in e.g.
312+
// func foo() { #^COMPLETE^# }
313+
// because #^COMPLETE^# is implicitly returned. But that's not very
314+
// helpful.
315+
return TypeRelation::Unknown;
316+
}
317+
318+
SmallPtrSet<const USRBasedType *, 16> VisitedTypes;
319+
SmallVector<const USRBasedType *, 16> Worklist;
320+
Worklist.push_back(ResultType);
321+
while (!Worklist.empty()) {
322+
auto *CurrentType = Worklist.pop_back_val();
323+
if (CurrentType == this)
324+
return TypeRelation::Convertible;
325+
326+
for (const USRBasedType *Supertype : CurrentType->getSupertypes()) {
327+
if (!VisitedTypes.insert(Supertype).second) {
328+
// Already visited this type.
329+
continue;
330+
}
331+
Worklist.push_back(Supertype);
332+
}
333+
}
334+
// TypeRelation computation based on USRs is an under-approximation because we
335+
// don't take into account generic conversions or retroactive conformance of
336+
// library types. Hence, we can't know for sure that ResultType is not
337+
// convertible to `this` type and thus can't return Unrelated or Invalid here.
338+
return TypeRelation::Unknown;
342339
}
343340

344341
// MARK: - USRBasedTypeContext

0 commit comments

Comments
 (0)