Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit 3e30dab

Browse files
committed
Merge branch 'main' of github.com:apple/swift into tensorflow-stage
* 'main' of github.com:apple/swift: [CodeCompletion] Rename isSingleExpressionBody to isImplicitSingleExpressionReturn for clarity [Sema] Extract out expression-contains-completion-loc check into a method on ConstraintSystem (NFC) [test] Re-enable now-passing IDE/complete_unresolved_members.swift run line [CodeCompletion][Sema][Parse] Migrate unresolved member completion to the solver-based completion implementation
2 parents 134c7db + 1eb05b7 commit 3e30dab

24 files changed

+571
-317
lines changed

include/swift/Sema/CodeCompletionTypeChecking.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
#ifndef SWIFT_SEMA_CODECOMPLETIONTYPECHECKING_H
1919
#define SWIFT_SEMA_CODECOMPLETIONTYPECHECKING_H
2020

21+
#include "swift/Basic/LLVM.h"
22+
#include "swift/AST/Type.h"
23+
#include "llvm/ADT/DenseMap.h"
24+
#include "llvm/ADT/SmallVector.h"
25+
2126
namespace swift {
2227
class Decl;
2328
class DeclContext;
@@ -32,7 +37,7 @@ namespace swift {
3237
class TypeCheckCompletionCallback {
3338
public:
3439
/// Called for each solution produced while type-checking an expression
35-
/// containing a code completion expression.
40+
/// that the code completion expression participates in.
3641
virtual void sawSolution(const constraints::Solution &solution) = 0;
3742
virtual ~TypeCheckCompletionCallback() {}
3843
};
@@ -49,7 +54,7 @@ namespace swift {
4954
SmallVector<Type, 4> ExpectedTypes;
5055
bool ExpectsNonVoid;
5156
bool BaseIsStaticMetaType;
52-
bool IsSingleExpressionBody;
57+
bool IsImplicitSingleExpressionReturn;
5358
};
5459

5560
private:
@@ -78,6 +83,39 @@ namespace swift {
7883

7984
void sawSolution(const constraints::Solution &solution) override;
8085
};
86+
87+
/// Used to collect and store information needed to perform unresolved member
88+
/// completion (\c CompletionKind::UnresolvedMember ) from the solutions
89+
/// formed during expression type-checking.
90+
class UnresolvedMemberTypeCheckCompletionCallback: public TypeCheckCompletionCallback {
91+
public:
92+
struct Result {
93+
Type ExpectedTy;
94+
bool IsImplicitSingleExpressionReturn;
95+
};
96+
97+
private:
98+
CodeCompletionExpr *CompletionExpr;
99+
SmallVector<Result, 4> Results;
100+
bool GotCallback = false;
101+
102+
public:
103+
UnresolvedMemberTypeCheckCompletionCallback(CodeCompletionExpr *CompletionExpr)
104+
: CompletionExpr(CompletionExpr) {}
105+
106+
ArrayRef<Result> getResults() const { return Results; }
107+
108+
/// True if at least one solution was passed via the \c sawSolution
109+
/// callback.
110+
bool gotCallback() const { return GotCallback; }
111+
112+
/// Typecheck the code completion expression in its outermost expression
113+
/// context, calling \c sawSolution for each solution formed.
114+
void fallbackTypeCheck(DeclContext *DC);
115+
116+
void sawSolution(const constraints::Solution &solution) override;
117+
};
118+
81119
}
82120

83121
#endif

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2845,6 +2845,10 @@ class ConstraintSystem {
28452845
return TypeVariables.count(typeVar) > 0;
28462846
}
28472847

2848+
/// Whether the given expression's source range contains the code
2849+
/// completion location.
2850+
bool containsCodeCompletionLoc(Expr *expr) const;
2851+
28482852
void setClosureType(const ClosureExpr *closure, FunctionType *type) {
28492853
assert(closure);
28502854
assert(type && "Expected non-null type");

lib/IDE/CodeCompletion.cpp

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,14 +1171,14 @@ calculateMaxTypeRelation(Type Ty, const ExpectedTypeContext &typeContext,
11711171
//
11721172
// { ... -> Int in x } // x must be Int
11731173
// { ... -> () in return x } // x must be Void
1174-
if (typeContext.isSingleExpressionBody && expectedTy->isVoid())
1174+
if (typeContext.isImplicitSingleExpressionReturn && expectedTy->isVoid())
11751175
continue;
11761176

11771177
Result = std::max(Result, calculateTypeRelation(Ty, expectedTy, DC));
11781178

11791179
// Map invalid -> unrelated when in a single-expression body, since the
11801180
// input may be incomplete.
1181-
if (typeContext.isSingleExpressionBody &&
1181+
if (typeContext.isImplicitSingleExpressionReturn &&
11821182
Result == CodeCompletionResult::ExpectedTypeRelation::Invalid)
11831183
Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated;
11841184
}
@@ -1958,9 +1958,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
19581958
IsStaticMetatype = value;
19591959
}
19601960

1961-
void setExpectedTypes(ArrayRef<Type> Types, bool isSingleExpressionBody,
1961+
void setExpectedTypes(ArrayRef<Type> Types,
1962+
bool isImplicitSingleExpressionReturn,
19621963
bool preferNonVoid = false) {
1963-
expectedTypeContext.isSingleExpressionBody = isSingleExpressionBody;
1964+
expectedTypeContext.isImplicitSingleExpressionReturn =
1965+
isImplicitSingleExpressionReturn;
19641966
expectedTypeContext.preferNonVoid = preferNonVoid;
19651967
expectedTypeContext.possibleTypes.clear();
19661968
expectedTypeContext.possibleTypes.reserve(Types.size());
@@ -1976,7 +1978,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
19761978
CodeCompletionContext::TypeContextKind typeContextKind() const {
19771979
if (expectedTypeContext.empty() && !expectedTypeContext.preferNonVoid) {
19781980
return CodeCompletionContext::TypeContextKind::None;
1979-
} else if (expectedTypeContext.isSingleExpressionBody) {
1981+
} else if (expectedTypeContext.isImplicitSingleExpressionReturn) {
19801982
return CodeCompletionContext::TypeContextKind::SingleExpressionBody;
19811983
} else {
19821984
return CodeCompletionContext::TypeContextKind::Required;
@@ -4346,6 +4348,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43464348
if (!T->mayHaveMembers())
43474349
return;
43484350

4351+
if (auto objT = T->getOptionalObjectType()) {
4352+
// Add 'nil' keyword with erasing '.' instruction.
4353+
unsigned bytesToErase = 0;
4354+
auto &SM = CurrDeclContext->getASTContext().SourceMgr;
4355+
if (DotLoc.isValid())
4356+
bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc());
4357+
addKeyword("nil", T, SemanticContextKind::None,
4358+
CodeCompletionKeywordKind::kw_nil, bytesToErase);
4359+
}
4360+
43494361
// We can only say .foo where foo is a static member of the contextual
43504362
// type and has the same type (or if the member is a function, then the
43514363
// same result type) as the contextual type.
@@ -4384,14 +4396,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43844396
objT = objT->lookThroughAllOptionalTypes();
43854397
if (seenTypes.insert(objT->getCanonicalType()).second)
43864398
getUnresolvedMemberCompletions(objT);
4387-
4388-
// Add 'nil' keyword with erasing '.' instruction.
4389-
unsigned bytesToErase = 0;
4390-
auto &SM = CurrDeclContext->getASTContext().SourceMgr;
4391-
if (DotLoc.isValid())
4392-
bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc());
4393-
addKeyword("nil", T, SemanticContextKind::None,
4394-
CodeCompletionKeywordKind::kw_nil, bytesToErase);
43954399
}
43964400
getUnresolvedMemberCompletions(T);
43974401
}
@@ -6089,6 +6093,45 @@ static void deliverCompletionResults(CodeCompletionContext &CompletionContext,
60896093
DCForModules);
60906094
}
60916095

6096+
void deliverUnresolvedMemberResults(
6097+
ArrayRef<UnresolvedMemberTypeCheckCompletionCallback::Result> Results,
6098+
DeclContext *DC, SourceLoc DotLoc,
6099+
ide::CodeCompletionContext &CompletionCtx,
6100+
CodeCompletionConsumer &Consumer) {
6101+
ASTContext &Ctx = DC->getASTContext();
6102+
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
6103+
&CompletionCtx);
6104+
6105+
assert(DotLoc.isValid());
6106+
Lookup.setHaveDot(DotLoc);
6107+
Lookup.shouldCheckForDuplicates(Results.size() > 1);
6108+
6109+
// Get the canonical versions of the top-level types
6110+
SmallPtrSet<CanType, 4> originalTypes;
6111+
for (auto &Result: Results)
6112+
originalTypes.insert(Result.ExpectedTy->getCanonicalType());
6113+
6114+
for (auto &Result: Results) {
6115+
Lookup.setExpectedTypes({Result.ExpectedTy},
6116+
Result.IsImplicitSingleExpressionReturn,
6117+
/*expectsNonVoid*/true);
6118+
Lookup.setIdealExpectedType(Result.ExpectedTy);
6119+
6120+
// For optional types, also get members of the unwrapped type if it's not
6121+
// already equivalent to one of the top-level types. Handling it via the top
6122+
// level type and not here ensures we give the correct type relation
6123+
// (identical, rather than convertible).
6124+
if (Result.ExpectedTy->getOptionalObjectType()) {
6125+
Type Unwrapped = Result.ExpectedTy->lookThroughAllOptionalTypes();
6126+
if (originalTypes.insert(Unwrapped->getCanonicalType()).second)
6127+
Lookup.getUnresolvedMemberCompletions(Unwrapped);
6128+
}
6129+
Lookup.getUnresolvedMemberCompletions(Result.ExpectedTy);
6130+
}
6131+
SourceFile *SF = DC->getParentSourceFile();
6132+
deliverCompletionResults(CompletionCtx, Lookup, *SF, Consumer);
6133+
}
6134+
60926135
void deliverDotExprResults(
60936136
ArrayRef<DotExprTypeCheckCompletionCallback::Result> Results,
60946137
Expr *BaseExpr, DeclContext *DC, SourceLoc DotLoc, bool IsInSelector,
@@ -6119,7 +6162,7 @@ void deliverDotExprResults(
61196162
Lookup.setIsStaticMetatype(Result.BaseIsStaticMetaType);
61206163
Lookup.getPostfixKeywordCompletions(Result.BaseTy, BaseExpr);
61216164
Lookup.setExpectedTypes(Result.ExpectedTypes,
6122-
Result.IsSingleExpressionBody,
6165+
Result.IsImplicitSingleExpressionReturn,
61236166
Result.ExpectsNonVoid);
61246167
if (isDynamicLookup(Result.BaseTy))
61256168
Lookup.setIsDynamicLookup();
@@ -6164,6 +6207,23 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
61646207
Consumer);
61656208
return true;
61666209
}
6210+
case CompletionKind::UnresolvedMember: {
6211+
assert(CodeCompleteTokenExpr);
6212+
assert(CurDeclContext);
6213+
6214+
UnresolvedMemberTypeCheckCompletionCallback Lookup(CodeCompleteTokenExpr);
6215+
llvm::SaveAndRestore<TypeCheckCompletionCallback*>
6216+
CompletionCollector(Context.CompletionCallback, &Lookup);
6217+
typeCheckContextAt(CurDeclContext, CompletionLoc);
6218+
6219+
if (!Lookup.gotCallback())
6220+
Lookup.fallbackTypeCheck(CurDeclContext);
6221+
6222+
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);
6223+
deliverUnresolvedMemberResults(Lookup.getResults(), CurDeclContext, DotLoc,
6224+
CompletionContext, Consumer);
6225+
return true;
6226+
}
61676227
default:
61686228
return false;
61696229
}
@@ -6283,6 +6343,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
62836343
switch (Kind) {
62846344
case CompletionKind::None:
62856345
case CompletionKind::DotExpr:
6346+
case CompletionKind::UnresolvedMember:
62866347
llvm_unreachable("should be already handled");
62876348
return;
62886349

@@ -6342,7 +6403,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
63426403
case CompletionKind::PostfixExprBeginning: {
63436404
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
63446405
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6345-
ContextInfo.isSingleExpressionBody());
6406+
ContextInfo.isImplicitSingleExpressionReturn());
63466407
DoPostfixExprBeginning();
63476408
break;
63486409
}
@@ -6364,8 +6425,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
63646425

63656426
if (ShouldCompleteCallPatternAfterParen) {
63666427
ExprContextInfo ParentContextInfo(CurDeclContext, ParsedExpr);
6367-
Lookup.setExpectedTypes(ParentContextInfo.getPossibleTypes(),
6368-
ParentContextInfo.isSingleExpressionBody());
6428+
Lookup.setExpectedTypes(
6429+
ParentContextInfo.getPossibleTypes(),
6430+
ParentContextInfo.isImplicitSingleExpressionReturn());
63696431
if (!ContextInfo.getPossibleCallees().empty()) {
63706432
for (auto &typeAndDecl : ContextInfo.getPossibleCallees())
63716433
Lookup.tryFunctionCallCompletions(typeAndDecl.Type, typeAndDecl.Decl,
@@ -6383,7 +6445,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
63836445
(Lookup.FoundFunctionCalls &&
63846446
Lookup.FoundFunctionsWithoutFirstKeyword)) {
63856447
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6386-
ContextInfo.isSingleExpressionBody());
6448+
ContextInfo.isImplicitSingleExpressionReturn());
63876449
Lookup.setHaveLParen(false);
63886450
DoPostfixExprBeginning();
63896451
}
@@ -6432,7 +6494,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
64326494
case CompletionKind::CaseStmtBeginning: {
64336495
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
64346496
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6435-
ContextInfo.isSingleExpressionBody());
6497+
ContextInfo.isImplicitSingleExpressionReturn());
64366498
Lookup.setIdealExpectedType(CodeCompleteTokenExpr->getType());
64376499
Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes());
64386500
DoPostfixExprBeginning();
@@ -6451,7 +6513,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
64516513
if (isa<AccessorDecl>(ParsedDecl)) {
64526514
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
64536515
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6454-
ContextInfo.isSingleExpressionBody());
6516+
ContextInfo.isImplicitSingleExpressionReturn());
64556517
DoPostfixExprBeginning();
64566518
}
64576519
break;
@@ -6484,15 +6546,6 @@ void CodeCompletionCallbacksImpl::doneParsing() {
64846546
Lookup.addImportModuleNames();
64856547
break;
64866548
}
6487-
case CompletionKind::UnresolvedMember: {
6488-
Lookup.setHaveDot(DotLoc);
6489-
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
6490-
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6491-
ContextInfo.isSingleExpressionBody());
6492-
Lookup.setIdealExpectedType(CodeCompleteTokenExpr->getType());
6493-
Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes());
6494-
break;
6495-
}
64966549
case CompletionKind::CallArg: {
64976550
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
64986551

@@ -6534,7 +6587,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
65346587

65356588
if (shouldPerformGlobalCompletion) {
65366589
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6537-
ContextInfo.isSingleExpressionBody());
6590+
ContextInfo.isImplicitSingleExpressionReturn());
65386591
DoPostfixExprBeginning();
65396592
}
65406593
break;
@@ -6653,7 +6706,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
66536706
SmallVector<Type, 2> possibleReturnTypes;
66546707
collectPossibleReturnTypesFromContext(CurDeclContext, possibleReturnTypes);
66556708
Lookup.setExpectedTypes(possibleReturnTypes,
6656-
/*isSingleExpressionBody*/ false);
6709+
/*isImplicitSingleExpressionReturn*/ false);
66576710
Lookup.getValueCompletionsInDeclContext(Loc);
66586711
break;
66596712
}
@@ -6664,7 +6717,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
66646717
if (FD->isCoroutine()) {
66656718
// TODO: handle multi-value yields.
66666719
Lookup.setExpectedTypes(FD->getStorage()->getValueInterfaceType(),
6667-
/*isSingleExpressionBody*/ false);
6720+
/*isImplicitSingleExpressionReturn*/ false);
66686721
}
66696722
}
66706723
Lookup.getValueCompletionsInDeclContext(Loc);
@@ -6674,7 +6727,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
66746727
case CompletionKind::AfterPoundExpr: {
66756728
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
66766729
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6677-
ContextInfo.isSingleExpressionBody());
6730+
ContextInfo.isImplicitSingleExpressionReturn());
66786731

66796732
Lookup.addPoundAvailable(ParentStmtKind);
66806733
Lookup.addPoundLiteralCompletions(/*needPound=*/false);

lib/IDE/CodeCompletionResultBuilder.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ struct ExpectedTypeContext {
4848
///
4949
/// Since the input may be incomplete, we take into account that the types are
5050
/// only a hint.
51-
bool isSingleExpressionBody = false;
51+
bool isImplicitSingleExpressionReturn = false;
5252
bool preferNonVoid = false;
5353

5454
bool empty() const { return possibleTypes.empty(); }
5555
bool requiresNonVoid() const {
56-
if (isSingleExpressionBody)
56+
if (isImplicitSingleExpressionReturn)
5757
return false;
5858
if (preferNonVoid)
5959
return true;
@@ -65,9 +65,9 @@ struct ExpectedTypeContext {
6565
}
6666

6767
ExpectedTypeContext() = default;
68-
ExpectedTypeContext(ArrayRef<Type> types, bool isSingleExpressionBody)
68+
ExpectedTypeContext(ArrayRef<Type> types, bool isImplicitSingleExprReturn)
6969
: possibleTypes(types.begin(), types.end()),
70-
isSingleExpressionBody(isSingleExpressionBody) {}
70+
isImplicitSingleExpressionReturn(isImplicitSingleExprReturn) {}
7171
};
7272

7373
class CodeCompletionResultBuilder {

0 commit comments

Comments
 (0)