Skip to content

Commit b14cd91

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 35f5c7a commit b14cd91

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

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

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

16561676
bool needDot() const {
16571677
return NeedLeadingDot;
@@ -3515,9 +3535,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35153535
builder.addSimpleNamedParameter("values");
35163536
builder.addRightParen();
35173537
for (auto T : expectedTypeContext.possibleTypes) {
3518-
if (!T)
3519-
continue;
3520-
if (T->is<TupleType>()) {
3538+
if (T && T->is<TupleType>() && !T->isVoid()) {
35213539
addTypeAnnotation(builder, T);
35223540
builder.setExpectedTypeRelation(CodeCompletionResult::Identical);
35233541
break;
@@ -5325,7 +5343,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
53255343
Lookup.RequestedCachedResults.clear();
53265344
}
53275345

5328-
CompletionContext.HasExpectedTypeRelation = Lookup.hasExpectedTypes();
5346+
CompletionContext.typeContextKind = Lookup.typeContextKind();
53295347

53305348
deliverCompletionResults();
53315349
}

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,12 @@ class ExprContextAnalyzer {
695695
break;
696696
}
697697
default:
698+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
699+
assert(isSingleExpressionBodyForCodeCompletion(AFD->getBody()));
700+
singleExpressionBody = true;
701+
recordPossibleType(getReturnTypeFromContext(AFD));
702+
break;
703+
}
698704
llvm_unreachable("Unhandled decl kind.");
699705
}
700706
}
@@ -715,6 +721,14 @@ class ExprContextAnalyzer {
715721
}
716722
}
717723

724+
/// Whether the given \c BraceStmt, which must be the body of a function or
725+
/// closure, should be treated as a single-expression return for the purposes
726+
/// of code-completion.
727+
///
728+
/// We cannot use hasSingleExpressionBody, because we explicitly do not use
729+
/// the single-expression-body when there is code-completion in the expression
730+
/// in order to avoid a base expression affecting the type. However, now that
731+
/// we've typechecked, we will take the context type into account.
718732
static bool isSingleExpressionBodyForCodeCompletion(BraceStmt *body) {
719733
return body->getNumElements() == 1 && body->getElements()[0].is<Expr *>();
720734
}
@@ -751,15 +765,9 @@ class ExprContextAnalyzer {
751765
(!isa<CallExpr>(ParentE) && !isa<SubscriptExpr>(ParentE) &&
752766
!isa<BinaryExpr>(ParentE) && !isa<ArgumentShuffleExpr>(ParentE));
753767
}
754-
case ExprKind::Closure: {
755-
// Note: we cannot use hasSingleExpressionBody, because we explicitly
756-
// do not use the single-expression-body when there is code-completion
757-
// in the expression in order to avoid a base expression affecting
758-
// the type. However, now that we've typechecked, we will take the
759-
// context type into account.
768+
case ExprKind::Closure:
760769
return isSingleExpressionBodyForCodeCompletion(
761770
cast<ClosureExpr>(E)->getBody());
762-
}
763771
default:
764772
return false;
765773
}
@@ -780,6 +788,9 @@ class ExprContextAnalyzer {
780788
case DeclKind::PatternBinding:
781789
return true;
782790
default:
791+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
792+
if (auto *body = AFD->getBody())
793+
return isSingleExpressionBodyForCodeCompletion(body);
783794
return false;
784795
}
785796
} 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
@@ -298,7 +298,7 @@ _ = {
298298
}()
299299
// TOP_LEVEL_CLOSURE_1: Begin completions
300300
// TOP_LEVEL_CLOSURE_1-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]{{; name=.+$}}
301-
// TOP_LEVEL_CLOSURE_1-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Identical]: fooFunc1()[#Void#]{{; name=.+$}}
301+
// TOP_LEVEL_CLOSURE_1-DAG: Decl[FreeFunction]/CurrModule: fooFunc1()[#Void#]{{; name=.+$}}
302302
// TOP_LEVEL_CLOSURE_1-DAG: Decl[GlobalVar]/Local: fooObject[#FooStruct#]{{; name=.+$}}
303303
// TOP_LEVEL_CLOSURE_1: End completions
304304

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)