Skip to content

Commit 00eaed3

Browse files
committed
[CodeCompletion] Migrate postfix expr completion to solver-based
1 parent c385fe5 commit 00eaed3

25 files changed

+503
-161
lines changed

include/swift/IDE/CompletionLookup.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
519519

520520
void getPostfixKeywordCompletions(Type ExprType, Expr *ParsedExpr);
521521

522-
void getValueExprCompletions(Type ExprType, ValueDecl *VD = nullptr);
522+
/// Add code completion results after an expression of type \p ExprType.
523+
/// This includes members as well as call patterns if \p ExprType is a
524+
/// function type.
525+
/// If \p IsDeclUnapplied is \c true, we are completing after a refernce to
526+
/// \p VD that hasn't been called yet. Thus, \p VD has type \p ExprType and we
527+
/// can use \p VD to enrich call pattern completions of \p ExprType.
528+
void getValueExprCompletions(Type ExprType, ValueDecl *VD = nullptr,
529+
bool IsDeclUnapplied = false);
523530

524531
void collectOperators(SmallVectorImpl<OperatorDecl *> &results);
525532

@@ -529,7 +536,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
529536

530537
void tryPostfixOperator(Expr *expr, PostfixOperatorDecl *op);
531538

532-
void addAssignmentOperator(Type RHSType, Type resultType);
539+
void addAssignmentOperator(Type RHSType);
533540

534541
void addInfixOperatorCompletion(OperatorDecl *op, Type resultType,
535542
Type RHSType);

include/swift/IDE/PostfixCompletion.h

+19-5
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
namespace swift {
2121
namespace ide {
2222

23-
/// Used to collect and store information needed to perform member completion
24-
/// (\c CompletionKind::DotExpr ) from the solutions formed during expression
25-
/// type-checking.
23+
/// Used to collect and store information needed to perform postfix completion
24+
/// (either <base>.#^COMPLETE^# or <base> #^COMPLETE^#).
2625
class PostfixCompletionCallback : public TypeCheckCompletionCallback {
2726
struct Result {
2827
/// The type that we are completing on. Will never be null.
@@ -32,6 +31,11 @@ class PostfixCompletionCallback : public TypeCheckCompletionCallback {
3231
/// on an expression.
3332
ValueDecl *BaseDecl;
3433

34+
/// Whether \c BaseDecl refers to a function that has not been called yet.
35+
/// In such cases, we know that \p BaseTy is the type of \p BaseDecl and we
36+
/// can use \p BaseDecl for more detailed call pattern completions.
37+
bool IsBaseDeclUnapplied;
38+
3539
/// If the expression we are completing on statically refers to a metatype,
3640
/// that is if it's something like 'MyType'. In such cases we want to offer
3741
/// constructor call pattern completions and don't want to suggeste
@@ -90,8 +94,18 @@ class PostfixCompletionCallback : public TypeCheckCompletionCallback {
9094
/// \c sawSolution for each solution formed.
9195
void fallbackTypeCheck(DeclContext *DC) override;
9296

93-
void deliverResults(Expr *BaseExpr, DeclContext *DC, SourceLoc DotLoc,
94-
bool IsInSelector, CodeCompletionContext &CompletionCtx,
97+
/// Deliver code completion results that were discoverd by \c sawSolution to
98+
/// \p Consumer.
99+
/// \param DotLoc If we are completing after a dot, the location of the dot,
100+
/// otherwise an invalid SourceLoc.
101+
/// \param IsInSelector Whether we are completing in an Objective-C selector.
102+
/// \param IncludeOperators If operators should be suggested. Assumes that
103+
/// \p DotLoc is invalid
104+
/// \param HasLeadingSpace Whether there is a space separating the exiting
105+
/// expression and the code completion token.
106+
void deliverResults(SourceLoc DotLoc, bool IsInSelector,
107+
bool IncludeOperators, bool HasLeadingSpace,
108+
CodeCompletionContext &CompletionCtx,
95109
CodeCompletionConsumer &Consumer);
96110
};
97111

include/swift/Parse/IDEInspectionCallbacks.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,9 @@ class CodeCompletionCallbacks {
147147
/// Complete the \c in keyword in a for-each loop.
148148
virtual void completeForEachInKeyword(){};
149149

150-
/// Complete a given expr-postfix.
151-
virtual void completePostfixExpr(Expr *E, bool hasSpace) {};
150+
/// Complete a expr-postfix. The \c CodeCompletionExpr has the expression it
151+
/// is completing after set as its base.
152+
virtual void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace){};
152153

153154
/// Complete a given expr-postfix, given that there is a following
154155
/// left parenthesis.

lib/IDE/CodeCompletion.cpp

+15-25
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
259259
void completePostfixExprBeginning(CodeCompletionExpr *E) override;
260260
void completeForEachSequenceBeginning(CodeCompletionExpr *E) override;
261261
void completeForEachInKeyword() override;
262-
void completePostfixExpr(Expr *E, bool hasSpace) override;
262+
void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace) override;
263263
void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override;
264264
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override;
265265

@@ -391,7 +391,8 @@ void CodeCompletionCallbacksImpl::completeForEachInKeyword() {
391391
CurDeclContext = P.CurDeclContext;
392392
}
393393

394-
void CodeCompletionCallbacksImpl::completePostfixExpr(Expr *E, bool hasSpace) {
394+
void CodeCompletionCallbacksImpl::completePostfixExpr(CodeCompletionExpr *E,
395+
bool hasSpace) {
395396
assert(P.Tok.is(tok::code_complete));
396397

397398
// Don't produce any results in an enum element.
@@ -405,7 +406,8 @@ void CodeCompletionCallbacksImpl::completePostfixExpr(Expr *E, bool hasSpace) {
405406
CompleteExprSelectorContext = ParseExprSelectorContext;
406407
}
407408

408-
ParsedExpr = E;
409+
ParsedExpr = E->getBase();
410+
CodeCompleteTokenExpr = E;
409411
CurDeclContext = P.CurDeclContext;
410412
}
411413

@@ -1469,6 +1471,7 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
14691471
};
14701472

14711473
switch (Kind) {
1474+
case CompletionKind::PostfixExpr:
14721475
case CompletionKind::DotExpr: {
14731476
assert(CodeCompleteTokenExpr);
14741477
assert(CurDeclContext);
@@ -1478,9 +1481,10 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
14781481

14791482
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);
14801483

1481-
Expr *CheckedBase = CodeCompleteTokenExpr->getBase();
1482-
Lookup.deliverResults(CheckedBase, CurDeclContext, DotLoc,
1483-
isInsideObjCSelector(), CompletionContext, Consumer);
1484+
bool IncludeOperators = (Kind == CompletionKind::PostfixExpr);
1485+
1486+
Lookup.deliverResults(DotLoc, isInsideObjCSelector(), IncludeOperators,
1487+
HasSpace, CompletionContext, Consumer);
14841488
return true;
14851489
}
14861490
case CompletionKind::UnresolvedMember: {
@@ -1694,26 +1698,10 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
16941698
case CompletionKind::AccessorBeginning:
16951699
case CompletionKind::CaseStmtBeginning:
16961700
case CompletionKind::PostfixExprParen:
1701+
case CompletionKind::PostfixExpr:
16971702
llvm_unreachable("should be already handled");
16981703
return;
16991704

1700-
case CompletionKind::PostfixExpr: {
1701-
Lookup.setHaveLeadingSpace(HasSpace);
1702-
if (isDynamicLookup(*ExprType))
1703-
Lookup.setIsDynamicLookup();
1704-
Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl());
1705-
/// We set the type of ParsedExpr explicitly above. But we don't want an
1706-
/// unresolved type in our AST when we type check again for operator
1707-
/// completions. Remove the type of the ParsedExpr and see if we can come up
1708-
/// with something more useful based on the the full sequence expression.
1709-
if (ParsedExpr->getType()->is<UnresolvedType>()) {
1710-
ParsedExpr->setType(nullptr);
1711-
}
1712-
Lookup.getOperatorCompletions(ParsedExpr, leadingSequenceExprs);
1713-
Lookup.getPostfixKeywordCompletions(*ExprType, ParsedExpr);
1714-
break;
1715-
}
1716-
17171705
case CompletionKind::KeyPathExprObjC: {
17181706
if (DotLoc.isValid())
17191707
Lookup.setHaveDot(DotLoc);
@@ -1724,7 +1712,8 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17241712
if (isDynamicLookup(*ExprType))
17251713
Lookup.setIsDynamicLookup();
17261714

1727-
Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl());
1715+
Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl(),
1716+
/*IncludeFunctionCallCompletions=*/true);
17281717
} else {
17291718
SourceLoc Loc = P.Context.SourceMgr.getIDEInspectionTargetLoc();
17301719
Lookup.getValueCompletionsInDeclContext(Loc, KeyPathFilter,
@@ -1949,7 +1938,8 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
19491938

19501939
if (isDynamicLookup(resultTy))
19511940
Lookup.setIsDynamicLookup();
1952-
Lookup.getValueExprCompletions(resultTy, /*VD=*/nullptr);
1941+
Lookup.getValueExprCompletions(resultTy, /*VD=*/nullptr,
1942+
/*IncludeFunctionCallCompletions=*/true);
19531943
Lookup.getOperatorCompletions(analyzedExpr, leadingSequenceExprs);
19541944
Lookup.getPostfixKeywordCompletions(resultTy, analyzedExpr);
19551945
}

lib/IDE/CompletionLookup.cpp

+8-7
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,8 @@ void CompletionLookup::getPostfixKeywordCompletions(Type ExprType,
23072307
if (IsSuperRefExpr)
23082308
return;
23092309

2310+
NeedLeadingDot = !HaveDot;
2311+
23102312
if (!ExprType->getAs<ModuleType>()) {
23112313
addKeyword(getTokenText(tok::kw_self), ExprType->getRValueType(),
23122314
SemanticContextKind::CurrentNominal,
@@ -2329,7 +2331,8 @@ void CompletionLookup::getPostfixKeywordCompletions(Type ExprType,
23292331
}
23302332
}
23312333

2332-
void CompletionLookup::getValueExprCompletions(Type ExprType, ValueDecl *VD) {
2334+
void CompletionLookup::getValueExprCompletions(Type ExprType, ValueDecl *VD,
2335+
bool IsDeclUnapplied) {
23332336
Kind = LookupKind::ValueExpr;
23342337
NeedLeadingDot = !HaveDot;
23352338

@@ -2362,7 +2365,7 @@ void CompletionLookup::getValueExprCompletions(Type ExprType, ValueDecl *VD) {
23622365

23632366
// Handle special cases
23642367
bool isIUO = VD && VD->isImplicitlyUnwrappedOptional();
2365-
if (tryFunctionCallCompletions(ExprType, VD))
2368+
if (tryFunctionCallCompletions(ExprType, IsDeclUnapplied ? VD : nullptr))
23662369
return;
23672370
if (tryModuleCompletions(ExprType, {CodeCompletionFilterFlag::Expr,
23682371
CodeCompletionFilterFlag::Type}))
@@ -2425,7 +2428,7 @@ void CompletionLookup::tryPostfixOperator(Expr *expr, PostfixOperatorDecl *op) {
24252428
addPostfixOperatorCompletion(op, funcTy->getResult());
24262429
}
24272430

2428-
void CompletionLookup::addAssignmentOperator(Type RHSType, Type resultType) {
2431+
void CompletionLookup::addAssignmentOperator(Type RHSType) {
24292432
CodeCompletionResultBuilder builder = makeResultBuilder(
24302433
CodeCompletionResultKind::BuiltinOperator, SemanticContextKind::None);
24312434

@@ -2435,12 +2438,11 @@ void CompletionLookup::addAssignmentOperator(Type RHSType, Type resultType) {
24352438
builder.addWhitespace(" ");
24362439
builder.addEqual();
24372440
builder.addWhitespace(" ");
2438-
assert(RHSType && resultType);
2441+
assert(RHSType);
24392442
Type contextTy;
24402443
if (auto typeContext = CurrDeclContext->getInnermostTypeContext())
24412444
contextTy = typeContext->getDeclaredTypeInContext();
24422445
builder.addCallArgument(Identifier(), RHSType, contextTy);
2443-
addTypeAnnotation(builder, resultType);
24442446
}
24452447

24462448
void CompletionLookup::addInfixOperatorCompletion(OperatorDecl *op,
@@ -2559,8 +2561,7 @@ void CompletionLookup::getOperatorCompletions(
25592561

25602562
if (leadingSequence.empty() && LHS->getType() &&
25612563
LHS->getType()->hasLValueType()) {
2562-
addAssignmentOperator(LHS->getType()->getRValueType(),
2563-
CurrDeclContext->getASTContext().TheEmptyTupleType);
2564+
addAssignmentOperator(LHS->getType()->getRValueType());
25642565
}
25652566

25662567
// FIXME: unify this with the ?.member completions.

lib/IDE/ConformingMethodList.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class ConformingMethodListCallbacks : public CodeCompletionCallbacks,
4747
// Only handle callbacks for suffix completions.
4848
// {
4949
void completeDotExpr(CodeCompletionExpr *E, SourceLoc DotLoc) override;
50-
void completePostfixExpr(Expr *E, bool hasSpace) override;
50+
void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace) override;
5151
// }
5252

5353
void doneParsing(SourceFile *SrcFile) override;
@@ -59,10 +59,10 @@ void ConformingMethodListCallbacks::completeDotExpr(CodeCompletionExpr *E,
5959
ParsedExpr = E->getBase();
6060
}
6161

62-
void ConformingMethodListCallbacks::completePostfixExpr(Expr *E,
62+
void ConformingMethodListCallbacks::completePostfixExpr(CodeCompletionExpr *E,
6363
bool hasSpace) {
6464
CurDeclContext = P.CurDeclContext;
65-
ParsedExpr = E;
65+
ParsedExpr = E->getBase();
6666
}
6767

6868
void ConformingMethodListCallbacks::doneParsing(SourceFile *SrcFile) {

0 commit comments

Comments
 (0)