Skip to content

Commit dab216d

Browse files
committed
[CodeCompletion] Use TypeContextInfo to get expected return types
If the type check return type from the context has unresolved types, it can't be used for checking convertibility. Fallback to get 'TypeContextInfo' of the closure position. rdar://problem/66002497
1 parent 192ccf1 commit dab216d

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)