Skip to content

Commit 21b3a00

Browse files
committed
[code-completion] Add type context for single-expression functions
Extend the support for single-expression closures to handle single-expression functions of all kinds. This allows, e.g. func foo() -> MyEnum { .<here> } to complete members of `MyEnum`.
1 parent 2335540 commit 21b3a00

10 files changed

+479
-56
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,21 @@ class CodeCompletionContext {
805805
public:
806806
CodeCompletionCache &Cache;
807807
CompletionKind CodeCompletionKind = CompletionKind::None;
808-
bool HasExpectedTypeRelation = false;
808+
809+
enum class TypeContextKind {
810+
/// There is no known contextual type. All types are equally good.
811+
None,
812+
813+
/// There is a contextual type from a single-expression closure/function
814+
/// body. The context is a hint, and enables unresolved member completion,
815+
/// but should not hide any results.
816+
SingleExpressionBody,
817+
818+
/// There are known contextual types.
819+
Required,
820+
};
821+
822+
TypeContextKind typeContextKind = TypeContextKind::None;
809823

810824
/// Whether there may be members that can use implicit member syntax,
811825
/// e.g. `x = .foo`.

lib/IDE/CodeCompletion.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,18 @@ calculateMaxTypeRelationForDecl(
929929
bool IsImplicitlyCurriedInstanceMethod = false) {
930930
auto Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated;
931931
for (auto Type : typeContext.possibleTypes) {
932+
// Do not use Void type context for a single-expression body, since the
933+
// implicit return does not constrain the expression.
934+
//
935+
// { ... -> () in x } // x can be anything
936+
//
937+
// This behaves differently from explicit return, and from non-Void:
938+
//
939+
// { ... -> Int in x } // x must be Int
940+
// { ... -> () in return x } // x must be Void
941+
if (typeContext.isSingleExpressionBody && Type->isVoid())
942+
continue;
943+
932944
Result = std::max(Result, calculateTypeRelationForDecl(
933945
D, Type, IsImplicitlyCurriedInstanceMethod));
934946

@@ -1650,7 +1662,15 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
16501662
expectedTypeContext.possibleTypes.push_back(T);
16511663
}
16521664

1653-
bool hasExpectedTypes() const { return !expectedTypeContext.empty(); }
1665+
CodeCompletionContext::TypeContextKind typeContextKind() const {
1666+
if (expectedTypeContext.empty()) {
1667+
return CodeCompletionContext::TypeContextKind::None;
1668+
} else if (expectedTypeContext.isSingleExpressionBody) {
1669+
return CodeCompletionContext::TypeContextKind::SingleExpressionBody;
1670+
} else {
1671+
return CodeCompletionContext::TypeContextKind::Required;
1672+
}
1673+
}
16541674

16551675
bool needDot() const {
16561676
return NeedLeadingDot;
@@ -3548,9 +3568,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35483568
builder.addSimpleNamedParameter("values");
35493569
builder.addRightParen();
35503570
for (auto T : expectedTypeContext.possibleTypes) {
3551-
if (!T)
3552-
continue;
3553-
if (T->is<TupleType>()) {
3571+
if (T && T->is<TupleType>() && !T->isVoid()) {
35543572
addTypeAnnotation(builder, T);
35553573
builder.setExpectedTypeRelation(CodeCompletionResult::Identical);
35563574
break;
@@ -5394,7 +5412,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
53945412
Lookup.RequestedCachedResults.clear();
53955413
}
53965414

5397-
CompletionContext.HasExpectedTypeRelation = Lookup.hasExpectedTypes();
5415+
CompletionContext.typeContextKind = Lookup.typeContextKind();
53985416

53995417
deliverCompletionResults();
54005418
}

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,12 @@ class ExprContextAnalyzer {
711711
break;
712712
}
713713
default:
714+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
715+
assert(isSingleExpressionBodyForCodeCompletion(AFD->getBody()));
716+
singleExpressionBody = true;
717+
recordPossibleType(getReturnTypeFromContext(AFD));
718+
break;
719+
}
714720
llvm_unreachable("Unhandled decl kind.");
715721
}
716722
}
@@ -731,6 +737,14 @@ class ExprContextAnalyzer {
731737
}
732738
}
733739

740+
/// Whether the given \c BraceStmt, which must be the body of a function or
741+
/// closure, should be treated as a single-expression return for the purposes
742+
/// of code-completion.
743+
///
744+
/// We cannot use hasSingleExpressionBody, because we explicitly do not use
745+
/// the single-expression-body when there is code-completion in the expression
746+
/// in order to avoid a base expression affecting the type. However, now that
747+
/// we've typechecked, we will take the context type into account.
734748
static bool isSingleExpressionBodyForCodeCompletion(BraceStmt *body) {
735749
return body->getNumElements() == 1 && body->getElements()[0].is<Expr *>();
736750
}
@@ -775,15 +789,9 @@ class ExprContextAnalyzer {
775789
(!isa<CallExpr>(ParentE) && !isa<SubscriptExpr>(ParentE) &&
776790
!isa<BinaryExpr>(ParentE) && !isa<ArgumentShuffleExpr>(ParentE));
777791
}
778-
case ExprKind::Closure: {
779-
// Note: we cannot use hasSingleExpressionBody, because we explicitly
780-
// do not use the single-expression-body when there is code-completion
781-
// in the expression in order to avoid a base expression affecting
782-
// the type. However, now that we've typechecked, we will take the
783-
// context type into account.
792+
case ExprKind::Closure:
784793
return isSingleExpressionBodyForCodeCompletion(
785794
cast<ClosureExpr>(E)->getBody());
786-
}
787795
default:
788796
return false;
789797
}
@@ -804,6 +812,9 @@ class ExprContextAnalyzer {
804812
case DeclKind::PatternBinding:
805813
return true;
806814
default:
815+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
816+
if (auto *body = AFD->getBody())
817+
return isSingleExpressionBodyForCodeCompletion(body);
807818
return false;
808819
}
809820
} else if (auto P = Node.getAsPattern()) {

test/IDE/complete_at_top_level.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ _ = {
299299
}()
300300
// TOP_LEVEL_CLOSURE_1: Begin completions
301301
// TOP_LEVEL_CLOSURE_1-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]{{; name=.+$}}
302-
// TOP_LEVEL_CLOSURE_1-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Identical]: fooFunc1()[#Void#]{{; name=.+$}}
302+
// TOP_LEVEL_CLOSURE_1-DAG: Decl[FreeFunction]/CurrModule: fooFunc1()[#Void#]{{; name=.+$}}
303303
// TOP_LEVEL_CLOSURE_1-DAG: Decl[GlobalVar]/Local: fooObject[#FooStruct#]{{; name=.+$}}
304304
// TOP_LEVEL_CLOSURE_1: End completions
305305

test/IDE/complete_in_accessors.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func returnsInt() -> Int {}
132132

133133
// WITH_GLOBAL_DECLS: Begin completions
134134
// WITH_GLOBAL_DECLS-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]{{; name=.+$}}
135-
// WITH_GLOBAL_DECLS-DAG: Decl[FreeFunction]/CurrModule: returnsInt()[#Int#]{{; name=.+$}}
135+
// WITH_GLOBAL_DECLS-DAG: Decl[FreeFunction]/CurrModule{{(/TypeRelation\[Identical\])?}}: returnsInt()[#Int#]{{; name=.+$}}
136136
// WITH_GLOBAL_DECLS: End completions
137137

138138
// WITH_GLOBAL_DECLS1: Begin completions
@@ -142,7 +142,7 @@ func returnsInt() -> Int {}
142142

143143
// WITH_MEMBER_DECLS: Begin completions
144144
// WITH_MEMBER_DECLS-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]{{; name=.+$}}
145-
// WITH_MEMBER_DECLS-DAG: Decl[FreeFunction]/CurrModule: returnsInt()[#Int#]{{; name=.+$}}
145+
// WITH_MEMBER_DECLS-DAG: Decl[FreeFunction]/CurrModule{{(/TypeRelation\[Identical\])?}}: returnsInt()[#Int#]{{; name=.+$}}
146146
// WITH_MEMBER_DECLS-DAG: Decl[LocalVar]/Local: self[#MemberAccessors#]{{; name=.+$}}
147147
// WITH_MEMBER_DECLS-DAG: Decl[InstanceVar]/CurrNominal: instanceVar[#Double#]{{; name=.+$}}
148148
// WITH_MEMBER_DECLS-DAG: Decl[InstanceMethod]/CurrNominal: instanceFunc({#(a): Int#})[#Float#]{{; name=.+$}}
@@ -159,8 +159,8 @@ func returnsInt() -> Int {}
159159

160160
// WITH_LOCAL_DECLS: Begin completions
161161
// WITH_LOCAL_DECLS-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]{{; name=.+$}}
162-
// WITH_LOCAL_DECLS-DAG: Decl[FreeFunction]/CurrModule: returnsInt()[#Int#]{{; name=.+$}}
163-
// WITH_LOCAL_DECLS-DAG: Decl[LocalVar]/Local: functionParam[#Int#]{{; name=.+$}}
162+
// WITH_LOCAL_DECLS-DAG: Decl[FreeFunction]/CurrModule{{(/TypeRelation\[Identical\])?}}: returnsInt()[#Int#]{{; name=.+$}}
163+
// WITH_LOCAL_DECLS-DAG: Decl[LocalVar]/Local{{(/TypeRelation\[Identical\])?}}: functionParam[#Int#]{{; name=.+$}}
164164
// WITH_LOCAL_DECLS-DAG: Decl[FreeFunction]/Local: localFunc({#(a): Int#})[#Float#]{{; name=.+$}}
165165
// WITH_LOCAL_DECLS: End completions
166166

@@ -456,7 +456,7 @@ func accessorsInFunction(_ functionParam: Int) {
456456

457457
// ACCESSORS_IN_MEMBER_FUNC_2: Begin completions
458458
// ACCESSORS_IN_MEMBER_FUNC_2-DAG: Decl[LocalVar]/Local: self[#AccessorsInMemberFunction#]
459-
// ACCESSORS_IN_MEMBER_FUNC_2-DAG: Decl[LocalVar]/Local: functionParam[#Int#]
459+
// ACCESSORS_IN_MEMBER_FUNC_2-DAG: Decl[LocalVar]/Local{{(/TypeRelation\[Identical\])?}}: functionParam[#Int#]
460460
// ACCESSORS_IN_MEMBER_FUNC_2-DAG: Decl[InstanceVar]/OutNominal: instanceVar[#Double#]
461461
// ACCESSORS_IN_MEMBER_FUNC_2-DAG: Decl[InstanceMethod]/OutNominal: instanceFunc({#(a): Int#})[#Float#]
462462
// ACCESSORS_IN_MEMBER_FUNC_2: End completions

0 commit comments

Comments
 (0)