Skip to content

Commit 640cfac

Browse files
committed
[CodeComplete] Compute type relations for global cached results
Computing the type relation for every item in the code completion cache is way to expensive (~4x slowdown for global completion that imports `SwiftUI`). Instead, compute a type’s supertypes (protocol conformances and superclasses) once and write their USRs to the cache. To compute a type relation we can then check if the contextual type is in the completion item’s supertypes. This reduces the overhead of computing the type relations (again global completion that imports `SwiftUI`) to ~6% – measured by instructions executed. Technically, we might miss some conversions like - retroactive conformances inside another module (because we can’t cache them if that other module isn’t imported) - complex generic conversions (just too complicated to model using USRs) Because of this, we never report an `unrelated` type relation for global items but always default to `unknown`. But I believe this change covers the most common cases and is a good tradeoff between accuracy and performance. rdar://83846531
1 parent 6d97905 commit 640cfac

21 files changed

+994
-156
lines changed

Diff for: include/swift/IDE/CodeCompletion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ bool isDynamicLookup(Type T);
6363

6464
void postProcessCompletionResults(
6565
MutableArrayRef<CodeCompletionResult *> results, CompletionKind Kind,
66-
DeclContext *DC, CodeCompletionResultSink *Sink);
66+
const DeclContext *DC, CodeCompletionResultSink *Sink);
6767

6868
void deliverCompletionResults(CodeCompletionContext &CompletionContext,
6969
CompletionLookup &Lookup, DeclContext *DC,

Diff for: include/swift/IDE/CodeCompletionCache.h

+4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class CodeCompletionCache {
7070

7171
std::vector<const ContextFreeCodeCompletionResult *> Results;
7272

73+
/// The arena that contains the \c USRBasedTypes of the
74+
/// \c ContextFreeCodeCompletionResult in this cache value.
75+
USRBasedTypeArena USRTypeArena;
76+
7377
Value() : Allocator(std::make_shared<llvm::BumpPtrAllocator>()) {}
7478
};
7579
using ValueRefCntPtr = llvm::IntrusiveRefCntPtr<Value>;

Diff for: include/swift/IDE/CodeCompletionConsumer.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class CodeCompletionConsumer {
2929
virtual void
3030
handleResultsAndModules(CodeCompletionContext &context,
3131
ArrayRef<RequestedCachedModule> requestedModules,
32-
DeclContext *DC) = 0;
32+
const ExpectedTypeContext *TypeContext,
33+
const DeclContext *DC) = 0;
3334
};
3435

3536
/// A simplified code completion consumer interface that clients can use to get
@@ -40,7 +41,8 @@ struct SimpleCachingCodeCompletionConsumer : public CodeCompletionConsumer {
4041
// Implement the CodeCompletionConsumer interface.
4142
void handleResultsAndModules(CodeCompletionContext &context,
4243
ArrayRef<RequestedCachedModule> requestedModules,
43-
DeclContext *DCForModules) override;
44+
const ExpectedTypeContext *TypeContext,
45+
const DeclContext *DCForModules) override;
4446

4547
/// Clients should override this method to receive \p Results.
4648
virtual void handleResults(CodeCompletionContext &context) = 0;

Diff for: include/swift/IDE/CodeCompletionResult.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class ContextFreeCodeCompletionResult {
390390
/// StringRefs outlive this result, typically by storing them in the same
391391
/// \c CodeCompletionResultSink as the result itself.
392392
static ContextFreeCodeCompletionResult *createPatternOrBuiltInOperatorResult(
393-
llvm::BumpPtrAllocator &Allocator, CodeCompletionResultKind Kind,
393+
CodeCompletionResultSink &Sink, CodeCompletionResultKind Kind,
394394
CodeCompletionString *CompletionString,
395395
CodeCompletionOperatorKind KnownOperatorKind,
396396
NullTerminatedStringRef BriefDocComment,
@@ -405,7 +405,7 @@ class ContextFreeCodeCompletionResult {
405405
/// \p BriefDocComment outlive this result, typically by storing them in
406406
/// the same \c CodeCompletionResultSink as the result itself.
407407
static ContextFreeCodeCompletionResult *
408-
createKeywordResult(llvm::BumpPtrAllocator &Allocator,
408+
createKeywordResult(CodeCompletionResultSink &Sink,
409409
CodeCompletionKeywordKind Kind,
410410
CodeCompletionString *CompletionString,
411411
NullTerminatedStringRef BriefDocComment,
@@ -417,7 +417,7 @@ class ContextFreeCodeCompletionResult {
417417
/// result, typically by storing them in the same \c CodeCompletionResultSink
418418
/// as the result itself.
419419
static ContextFreeCodeCompletionResult *
420-
createLiteralResult(llvm::BumpPtrAllocator &Allocator,
420+
createLiteralResult(CodeCompletionResultSink &Sink,
421421
CodeCompletionLiteralKind LiteralKind,
422422
CodeCompletionString *CompletionString,
423423
CodeCompletionResultType ResultType);
@@ -428,7 +428,7 @@ class ContextFreeCodeCompletionResult {
428428
/// \c StringRefs outlive this result, typically by storing them in the same
429429
/// \c CodeCompletionResultSink as the result itself.
430430
static ContextFreeCodeCompletionResult *createDeclResult(
431-
llvm::BumpPtrAllocator &Allocator, CodeCompletionString *CompletionString,
431+
CodeCompletionResultSink &Sink, CodeCompletionString *CompletionString,
432432
const Decl *AssociatedDecl, NullTerminatedStringRef ModuleName,
433433
NullTerminatedStringRef BriefDocComment,
434434
ArrayRef<NullTerminatedStringRef> AssociatedUSRs,
@@ -566,6 +566,8 @@ class CodeCompletionResult {
566566
/// information.
567567
/// This computes the type relation between the completion item and its
568568
/// expected type context.
569+
/// See \c CodeCompletionResultType::calculateTypeRelation for documentation
570+
/// on \p USRTypeContext.
569571
/// The \c ContextFree result must outlive this result. Typically, this is
570572
/// done by allocating the two in the same sink or adopting the context free
571573
/// sink in the sink that allocates this result.
@@ -574,6 +576,7 @@ class CodeCompletionResult {
574576
CodeCompletionFlair Flair, uint8_t NumBytesToErase,
575577
const ExpectedTypeContext *TypeContext,
576578
const DeclContext *DC,
579+
const USRBasedTypeContext *USRTypeContext,
577580
ContextualNotRecommendedReason NotRecommended,
578581
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
579582
NullTerminatedStringRef DiagnosticMessage);

Diff for: include/swift/IDE/CodeCompletionResultSink.h

+32
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ struct CodeCompletionResultSink {
4444
/// Whether to include an item without any default arguments.
4545
bool addCallWithNoDefaultArgs = true;
4646

47+
private:
48+
/// Whether the code completion results computed for this sink are intended to
49+
/// only be stored in the cache. In this case no contextual information is
50+
/// computed and all types in \c ContextFreeCodeCompletionResult should be
51+
/// USR-based instead of AST-based.
52+
USRBasedTypeArena *USRTypeArena = nullptr;
53+
54+
public:
4755
std::vector<CodeCompletionResult *> Results;
4856

4957
/// A single-element cache for module names stored in Allocator, keyed by a
@@ -52,6 +60,30 @@ struct CodeCompletionResultSink {
5260

5361
CodeCompletionResultSink()
5462
: Allocator(std::make_shared<llvm::BumpPtrAllocator>()) {}
63+
64+
llvm::BumpPtrAllocator &getAllocator() { return *Allocator; }
65+
66+
/// Marks the sink as producing results for the code completion cache.
67+
/// In this case the produced results will not contain any contextual
68+
/// information and all types in the \c ContextFreeCodeCompletionResult are
69+
/// USR-based.
70+
void setProduceContextFreeResults(USRBasedTypeArena &USRTypeArena) {
71+
this->USRTypeArena = &USRTypeArena;
72+
}
73+
74+
/// See \c setProduceContextFreeResults.
75+
bool shouldProduceContextFreeResults() const {
76+
return USRTypeArena != nullptr;
77+
}
78+
79+
/// If \c shouldProduceContextFreeResults is \c true, returns the arena in
80+
/// which the USR-based types of the \c ContextFreeCodeCompletionResult should
81+
/// be stored.
82+
USRBasedTypeArena &getUSRTypeArena() const {
83+
assert(USRTypeArena != nullptr &&
84+
"Must only be called if shouldProduceContextFreeResults is true");
85+
return *USRTypeArena;
86+
}
5587
};
5688

5789
} // end namespace ide

0 commit comments

Comments
 (0)