Skip to content

Commit 6fe79fa

Browse files
authored
Merge pull request #33080 from rintaro/ide-completion-rdar66002497
[CodeCompletion] Use TypeContextInfo to get expected return types
2 parents 3459fe8 + dab216d commit 6fe79fa

File tree

5 files changed

+142
-27
lines changed

5 files changed

+142
-27
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6241,7 +6241,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
62416241

62426242
case CompletionKind::ReturnStmtExpr : {
62436243
SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc();
6244-
Lookup.setExpectedTypes(getReturnTypeFromContext(CurDeclContext),
6244+
SmallVector<Type, 2> possibleReturnTypes;
6245+
collectPossibleReturnTypesFromContext(CurDeclContext, possibleReturnTypes);
6246+
Lookup.setExpectedTypes(possibleReturnTypes,
62456247
/*isSingleExpressionBody*/ false);
62466248
Lookup.getValueCompletionsInDeclContext(Loc);
62476249
break;

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -285,40 +285,61 @@ bool swift::ide::removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr) {
285285
}
286286

287287
//===----------------------------------------------------------------------===//
288-
// getReturnTypeFromContext(DeclContext)
288+
// collectPossibleReturnTypesFromContext(DeclContext, SmallVectorImpl<Type>)
289289
//===----------------------------------------------------------------------===//
290290

291-
Type swift::ide::getReturnTypeFromContext(const DeclContext *DC) {
291+
void swift::ide::collectPossibleReturnTypesFromContext(
292+
DeclContext *DC, SmallVectorImpl<Type> &candidates) {
292293
if (auto FD = dyn_cast<AbstractFunctionDecl>(DC)) {
293294
auto Ty = FD->getInterfaceType();
294295
if (FD->getDeclContext()->isTypeContext())
295296
Ty = FD->getMethodInterfaceType();
296-
if (auto FT = Ty->getAs<AnyFunctionType>())
297-
return DC->mapTypeIntoContext(FT->getResult());
298-
} else if (auto ACE = dyn_cast<AbstractClosureExpr>(DC)) {
299-
if (ACE->getType() && !ACE->getType()->hasError())
300-
return ACE->getResultType();
297+
if (auto FT = Ty->getAs<AnyFunctionType>()) {
298+
candidates.push_back(DC->mapTypeIntoContext(FT->getResult()));
299+
}
300+
}
301+
302+
if (auto ACE = dyn_cast<AbstractClosureExpr>(DC)) {
303+
// Use the type checked type if it has.
304+
if (ACE->getType() && !ACE->getType()->hasError() &&
305+
!ACE->getResultType()->hasUnresolvedType()) {
306+
candidates.push_back(ACE->getResultType());
307+
return;
308+
}
309+
301310
if (auto CE = dyn_cast<ClosureExpr>(ACE)) {
302311
if (CE->hasExplicitResultType()) {
312+
// If the closure has a explicit return type, use it.
303313
if (auto ty = CE->getExplicitResultType()) {
304-
return ty;
314+
candidates.push_back(ty);
315+
return;
316+
} else {
317+
auto typeLoc = TypeLoc{CE->getExplicitResultTypeRepr()};
318+
if (!swift::performTypeLocChecking(
319+
DC->getASTContext(), typeLoc, /*isSILMode=*/false,
320+
/*isSILType=*/false, DC->getGenericEnvironmentOfContext(),
321+
const_cast<DeclContext *>(DC), /*diagnostics=*/false)) {
322+
candidates.push_back(typeLoc.getType());
323+
return;
324+
}
305325
}
306-
307-
auto typeLoc = TypeLoc{CE->getExplicitResultTypeRepr()};
308-
if (swift::performTypeLocChecking(DC->getASTContext(),
309-
typeLoc,
310-
/*isSILMode*/ false,
311-
/*isSILType*/ false,
312-
DC->getGenericEnvironmentOfContext(),
313-
const_cast<DeclContext *>(DC),
314-
/*diagnostics*/ false)) {
315-
return Type();
326+
} else {
327+
// Otherwise, check the context type of the closure.
328+
ExprContextInfo closureCtxInfo(CE->getParent(), CE);
329+
for (auto closureTy : closureCtxInfo.getPossibleTypes()) {
330+
if (auto funcTy = closureTy->getAs<AnyFunctionType>())
331+
candidates.push_back(funcTy->getResult());
316332
}
317-
return typeLoc.getType();
333+
if (!candidates.empty())
334+
return;
318335
}
319336
}
337+
338+
// Even if the type checked type has unresolved types, it's better than
339+
// nothing.
340+
if (ACE->getType() && !ACE->getType()->hasError())
341+
candidates.push_back(ACE->getResultType());
320342
}
321-
return Type();
322343
}
323344

324345
//===----------------------------------------------------------------------===//
@@ -929,7 +950,10 @@ class ExprContextAnalyzer {
929950
auto *CE = cast<ClosureExpr>(Parent);
930951
assert(isSingleExpressionBodyForCodeCompletion(CE->getBody()));
931952
singleExpressionBody = true;
932-
recordPossibleType(getReturnTypeFromContext(CE));
953+
SmallVector<Type, 2> candidates;
954+
collectPossibleReturnTypesFromContext(CE, candidates);
955+
for (auto ty : candidates)
956+
recordPossibleType(ty);
933957
break;
934958
}
935959
default:
@@ -939,9 +963,13 @@ class ExprContextAnalyzer {
939963

940964
void analyzeStmt(Stmt *Parent) {
941965
switch (Parent->getKind()) {
942-
case StmtKind::Return:
943-
recordPossibleType(getReturnTypeFromContext(DC));
966+
case StmtKind::Return: {
967+
SmallVector<Type, 2> candidates;
968+
collectPossibleReturnTypesFromContext(DC, candidates);
969+
for (auto ty : candidates)
970+
recordPossibleType(ty);
944971
break;
972+
}
945973
case StmtKind::ForEach:
946974
if (auto SEQ = cast<ForEachStmt>(Parent)->getSequence()) {
947975
if (containsTarget(SEQ)) {
@@ -1004,7 +1032,10 @@ class ExprContextAnalyzer {
10041032
if (auto *FD = dyn_cast<FuncDecl>(D)) {
10051033
assert(isSingleExpressionBodyForCodeCompletion(FD->getBody()));
10061034
singleExpressionBody = true;
1007-
recordPossibleType(getReturnTypeFromContext(FD));
1035+
SmallVector<Type, 2> candidates;
1036+
collectPossibleReturnTypesFromContext(DC, candidates);
1037+
for (auto ty : candidates)
1038+
recordPossibleType(ty);
10081039
break;
10091040
}
10101041
llvm_unreachable("Unhandled decl kind.");

lib/IDE/ExprContextAnalysis.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ Expr *findParsedExpr(const DeclContext *DC, SourceRange TargetRange);
4141
/// position.
4242
bool removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr);
4343

44-
/// Returns expected return type of the given decl context.
44+
/// Collects possible expected return types of the given decl context.
4545
/// \p DC should be an \c AbstractFunctionDecl or an \c AbstractClosureExpr.
46-
Type getReturnTypeFromContext(const DeclContext *DC);
46+
void collectPossibleReturnTypesFromContext(DeclContext *DC,
47+
SmallVectorImpl<Type> &candidates);
4748

4849
struct FunctionTypeAndDecl {
4950
AnyFunctionType *Type;

test/IDE/complete_sr13271.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %swift-ide-test -code-completion -source-filename=%s -code-completion-token=A | %FileCheck %s --check-prefix=A
2+
// RUN: %swift-ide-test -code-completion -source-filename=%s -code-completion-token=B | %FileCheck %s --check-prefix=B
3+
// RUN: %swift-ide-test -code-completion -source-filename=%s -code-completion-token=D | %FileCheck %s --check-prefix=D
4+
5+
// https://bugs.swift.org/browse/SR-13271
6+
// https://forums.swift.org/t/code-completion-enhancement-request/38677
7+
8+
enum AIdentifier {
9+
case a
10+
}
11+
12+
enum BIdentifier {
13+
case b
14+
}
15+
16+
struct X { }
17+
struct Y { }
18+
19+
struct A <T> {
20+
private init(){}
21+
static func foo (arg: Bool) -> A<X> { A<X>() }
22+
static func bar (arg: Int) -> A<Y> { A<Y>() }
23+
}
24+
25+
struct B {
26+
static var baz: B { B() }
27+
}
28+
29+
func C<T>(_ identifier: AIdentifier, _ a: ()->A<T>) -> D<T> { }
30+
func C(_ identifier: BIdentifier, _ b: ()->B) { }
31+
32+
struct D <T> {
33+
func sink (_ handler: @escaping (T)->()) { }
34+
}
35+
36+
func test() {
37+
C(.a) {
38+
.#^A^#
39+
}
40+
// A: Begin completions, 2 items
41+
// A-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: foo({#arg: Bool#})[#A<X>#];
42+
// A-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: bar({#arg: Int#})[#A<Y>#];
43+
// A: End completions
44+
}
45+
46+
func test() {
47+
C(.b) {
48+
.#^B^#
49+
}
50+
// B: Begin completions, 2 items
51+
// B-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: baz[#B#]; name=baz
52+
// B-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#B#]; name=init()
53+
// B: End completions
54+
}
55+
56+
func test() {
57+
C(.a) {
58+
.foo(arg: true)
59+
}
60+
.sink { value in
61+
value.#^D^#
62+
}
63+
// D: Begin completions, 1 items
64+
// D-DAG: Keyword[self]/CurrNominal: self[#X#];
65+
// D: End completions
66+
}

test/IDE/complete_unresolved_members.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TERNARY_5 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL
123123
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TERNARY_6 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL
124124
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TERNARY_CONDITION | %FileCheck %s -check-prefix=TERNARY_CONDITION
125+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_CLOSURE_RETURN | %FileCheck %s -check-prefix=OVERLOADED_CLOSURE_RETURN
125126

126127
enum SomeEnum1 {
127128
case South
@@ -783,3 +784,17 @@ func testTernaryOperator2(cond: Bool) {
783784
// TERNARY_CONDITION-DAG: Decl[Constructor]/CurrNominal/IsSystem/TypeRelation[Identical]: init()[#Bool#]; name=init()
784785
// TERNARY_CONDITION: End completions
785786
}
787+
788+
func overloadedClosureRcv(_: () -> SomeEnum1) {}
789+
func overloadedClosureRcv(_: () -> SomeEnum2) {}
790+
func testClosureReturnTypeForOverloaded() {
791+
overloadedClosureRcv {
792+
.#^OVERLOADED_CLOSURE_RETURN^#
793+
}
794+
// OVERLOADED_CLOSURE_RETURN: Begin completions, 4 items
795+
// OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#];
796+
// OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#];
797+
// OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#];
798+
// OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#];
799+
// OVERLOADED_CLOSURE_RETURN: End completions
800+
}

0 commit comments

Comments
 (0)