Skip to content

Commit 928a03a

Browse files
committed
[CodeCompletion] Migrate conforming methods list to solver-based
1 parent 4d1e44f commit 928a03a

File tree

3 files changed

+71
-19
lines changed

3 files changed

+71
-19
lines changed

lib/IDE/ConformingMethodList.cpp

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
#include "swift/AST/GenericEnvironment.h"
1717
#include "swift/AST/NameLookup.h"
1818
#include "swift/AST/USRGeneration.h"
19+
#include "swift/IDE/TypeCheckCompletionCallback.h"
1920
#include "swift/Parse/IDEInspectionCallbacks.h"
2021
#include "swift/Sema/IDETypeChecking.h"
22+
#include "swift/Sema/ConstraintSystem.h"
2123
#include "clang/AST/Attr.h"
2224
#include "clang/AST/Decl.h"
2325

@@ -30,7 +32,7 @@ class ConformingMethodListCallbacks : public CodeCompletionCallbacks,
3032
ArrayRef<const char *> ExpectedTypeNames;
3133
ConformingMethodListConsumer &Consumer;
3234
SourceLoc Loc;
33-
Expr *ParsedExpr = nullptr;
35+
CodeCompletionExpr *CCExpr = nullptr;
3436
DeclContext *CurDeclContext = nullptr;
3537

3638
void getMatchingMethods(Type T,
@@ -56,34 +58,67 @@ class ConformingMethodListCallbacks : public CodeCompletionCallbacks,
5658
void ConformingMethodListCallbacks::completeDotExpr(CodeCompletionExpr *E,
5759
SourceLoc DotLoc) {
5860
CurDeclContext = P.CurDeclContext;
59-
ParsedExpr = E->getBase();
61+
CCExpr = E;
6062
}
6163

6264
void ConformingMethodListCallbacks::completePostfixExpr(CodeCompletionExpr *E,
6365
bool hasSpace) {
6466
CurDeclContext = P.CurDeclContext;
65-
ParsedExpr = E->getBase();
67+
CCExpr = E;
6668
}
6769

68-
void ConformingMethodListCallbacks::doneParsing(SourceFile *SrcFile) {
69-
if (!ParsedExpr)
70-
return;
70+
class ConformingMethodListCallback : public TypeCheckCompletionCallback {
71+
public:
72+
struct Result {
73+
Type Ty;
7174

72-
typeCheckContextAt(TypeCheckASTNodeAtLocContext::declContext(CurDeclContext),
73-
ParsedExpr->getLoc());
75+
/// Types of variables that were determined in the solution that produced
76+
/// this result. This in particular includes parameters of closures that
77+
/// were type-checked with the code completion expression.
78+
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;
79+
};
80+
private:
81+
CodeCompletionExpr *CCExpr;
7482

75-
Type T = ParsedExpr->getType();
83+
SmallVector<Result> Results;
7684

77-
// Type check the expression if needed.
78-
if (!T || T->is<ErrorType>()) {
79-
ConcreteDeclRef ReferencedDecl = nullptr;
80-
auto optT = getTypeOfCompletionContextExpr(P.Context, CurDeclContext,
81-
CompletionTypeCheckKind::Normal,
82-
ParsedExpr, ReferencedDecl);
83-
if (!optT)
85+
void sawSolutionImpl(const constraints::Solution &S) override {
86+
if (!S.hasType(CCExpr->getBase())) {
8487
return;
85-
T = *optT;
88+
}
89+
if (Type T = getTypeForCompletion(S, CCExpr->getBase())) {
90+
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;
91+
getSolutionSpecificVarTypes(S, SolutionSpecificVarTypes);
92+
Results.push_back({T, SolutionSpecificVarTypes});
93+
}
94+
}
95+
96+
public:
97+
ConformingMethodListCallback(CodeCompletionExpr *CCExpr) : CCExpr(CCExpr) {}
98+
99+
ArrayRef<Result> getResults() const { return Results; }
100+
};
101+
102+
void ConformingMethodListCallbacks::doneParsing(SourceFile *SrcFile) {
103+
if (!CCExpr || !CCExpr->getBase())
104+
return;
105+
106+
ConformingMethodListCallback TypeCheckCallback(CCExpr);
107+
{
108+
llvm::SaveAndRestore<TypeCheckCompletionCallback *> CompletionCollector(
109+
Context.CompletionCallback, &TypeCheckCallback);
110+
typeCheckContextAt(
111+
TypeCheckASTNodeAtLocContext::declContext(CurDeclContext),
112+
CCExpr->getLoc());
113+
}
114+
115+
if (TypeCheckCallback.getResults().size() != 1) {
116+
// Either no results or results were ambiguous, which we cannot handle.
117+
return;
86118
}
119+
auto Res = TypeCheckCallback.getResults()[0];
120+
Type T = Res.Ty;
121+
WithSolutionSpecificVarTypesRAII VarType(Res.SolutionSpecificVarTypes);
87122

88123
if (!T || T->is<ErrorType>() || T->is<UnresolvedType>())
89124
return;

lib/Sema/TypeCheckStmt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,8 +2586,8 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25862586
auto optBody = TypeChecker::applyResultBuilderBodyTransform(
25872587
func, builderType,
25882588
/*ClosuresInResultBuilderDontParticipateInInference=*/
2589-
ctx.CompletionCallback == nullptr && ctx.SolutionCallback == nullptr);
2590-
if (ctx.CompletionCallback && ctx.CompletionCallback->gotCallback()) {
2589+
ctx.CompletionCallback == nullptr && ctx.SolutionCallback == nullptr);
2590+
if ((ctx.CompletionCallback && ctx.CompletionCallback->gotCallback()) || (ctx.SolutionCallback && ctx.SolutionCallback->gotCallback())) {
25912591
// We already informed the completion callback of solutions found by
25922592
// type checking the entire result builder from
25932593
// applyResultBuilderBodyTransform. No need to typecheck the requested
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token COMPLETE
2+
3+
// This test used to crash while PostfixExpr completion was migrated to solver-based.
4+
5+
struct MyPublisher {
6+
func removeDuplicates() {}
7+
}
8+
9+
func handleEvents(receiveOutput: ((String) -> Void)? = nil) -> MyPublisher {}
10+
11+
protocol AnyCancellable {}
12+
13+
class CategoriesSearchViewModel {
14+
func foo() {
15+
var searchCancellable: AnyCancellable = handleEvents(receiveOutput: { [weak self] _ in }).removeDuplicates #^COMPLETE^#
16+
}
17+
}

0 commit comments

Comments
 (0)