Skip to content

Commit 583ed8d

Browse files
committed
[CodeComplete] Fall back to typechecking a single expression result builder doesn't typecheck
If a result builder body fails to typecheck, we currently don't provide any code completion results at all. Instead, try to recovery by type checking the expression in the result builder that conatins the code completion token on its own. This might be missing some information about contextual types but is preferrable over not providing any results at all. Resolves rdar://78015510
1 parent c777c4b commit 583ed8d

File tree

2 files changed

+17
-10
lines changed

2 files changed

+17
-10
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,11 +1922,18 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(Evaluator &evaluator,
19221922
if (Type builderType = getResultBuilderType(func)) {
19231923
auto optBody =
19241924
TypeChecker::applyResultBuilderBodyTransform(func, builderType);
1925-
if (!optBody || !*optBody)
1926-
return true;
1927-
// Wire up the function body now.
1928-
func->setBody(*optBody, AbstractFunctionDecl::BodyKind::TypeChecked);
1929-
return false;
1925+
if (optBody && *optBody) {
1926+
// Wire up the function body now.
1927+
func->setBody(*optBody, AbstractFunctionDecl::BodyKind::TypeChecked);
1928+
return false;
1929+
}
1930+
// FIXME: We failed to apply the result builder transform. Fall back to
1931+
// just type checking the node that contains the code completion token.
1932+
// This may be missing some context from the result builder but in
1933+
// practice it often contains sufficient information to provide a decent
1934+
// level of code completion that's better than providing nothing at all.
1935+
// The proper solution would be to only partially type check the result
1936+
// builder so that this fall back would not be necessary.
19301937
} else if (func->hasSingleExpressionBody() &&
19311938
func->getResultInterfaceType()->isVoid()) {
19321939
// The function returns void. We don't need an explicit return, no matter

test/IDE/complete_in_result_builder.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func testGlobalLookup() {
6161
@TupleBuilder<String> var x5 {
6262
"hello: \(#^GLOBAL_LOOKUP_IN_STRING_LITERAL^#)"
6363
// GLOBAL_LOOKUP_IN_STRING_LITERAL: Begin completions
64-
// GLOBAL_LOOKUP_IN_STRING_LITERAL: Decl[GlobalVar]/CurrModule: MyConstantString[#String#];
64+
// GLOBAL_LOOKUP_IN_STRING_LITERAL: Decl[GlobalVar]/CurrModule/TypeRelation[Convertible]: MyConstantString[#String#];
6565
// GLOBAL_LOOKUP_IN_STRING_LITERAL: End completions
6666
}
6767

@@ -103,7 +103,7 @@ struct FooStruct {
103103
func testPatternMatching() {
104104
@TupleBuilder<String> var x1 {
105105
let x = Letters.b
106-
if case .#^COMPLETE_PATTERN_MATCHING_IN_IF?check=COMPLETE_CASE;xfail=rdar78015510^# = x {
106+
if case .#^COMPLETE_PATTERN_MATCHING_IN_IF?check=COMPLETE_CASE^# = x {
107107
// COMPLETE_CASE: Begin completions
108108
// COMPLETE_CASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: a[#Letters#];
109109
// COMPLETE_CASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: b[#Letters#];
@@ -115,14 +115,14 @@ func testPatternMatching() {
115115
@TupleBuilder<String> var x2 {
116116
let x = Letters.a
117117
switch x {
118-
case .#^COMPLETE_CASE_IN_SWITCH?check=COMPLETE_CASE;xfail=rdar78015510^#:
118+
case .#^COMPLETE_CASE_IN_SWITCH?check=COMPLETE_CASE^#:
119119
break
120120
}
121121
}
122122

123123
@TupleBuilder<String> var x3 {
124124
let x: FooStruct? = FooStruct()
125-
guard case .#^GUARD_CASE_PATTERN_1?check=OPTIONAL_FOOSTRUCT;xfail=rdar78015510^# = x {}
125+
guard case .#^GUARD_CASE_PATTERN_1?check=OPTIONAL_FOOSTRUCT^# = x {}
126126
// OPTIONAL_FOOSTRUCT: Begin completions, 9 items
127127
// OPTIONAL_FOOSTRUCT-DAG: Keyword[nil]/None/Erase[1]/TypeRelation[Identical]: nil[#FooStruct?#]; name=nil
128128
// OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem/TypeRelation[Identical]: none[#Optional<FooStruct>#]; name=none
@@ -141,7 +141,7 @@ func testPatternMatching() {
141141

142142
@TupleBuilder<String> var x4 {
143143
let x: FooStruct? = FooStruct()
144-
guard case .#^GUARD_CASE_PATTERN_2?check=OPTIONAL_FOOSTRUCT;xfail=rdar78015510^#some() = x {}
144+
guard case .#^GUARD_CASE_PATTERN_2?check=OPTIONAL_FOOSTRUCT^#some() = x {}
145145
}
146146
}
147147

0 commit comments

Comments
 (0)