Skip to content

Commit b8b6e37

Browse files
authored
Merge pull request #24288 from benlangmuir/cc-omit-return-51-04-24-2019
[5.1-04-24-2019] [code-completion] Add type context for single-expression function bodies
2 parents 26e763a + 47c891a commit b8b6e37

14 files changed

+601
-63
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`.

include/swift/Parse/CodeCompletionCallbacks.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ class CodeCompletionCallbacks {
180180
SmallVectorImpl<StringRef> &Keywords, SourceLoc introducerLoc) {};
181181

182182
/// Complete at the beginning of accessor in a accessor block.
183-
virtual void completeAccessorBeginning() {};
183+
virtual void completeAccessorBeginning(CodeCompletionExpr *E) {};
184184

185185
/// Complete the keyword in attribute, for instance, @available.
186186
virtual void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) {};

lib/IDE/CodeCompletion.cpp

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

@@ -1360,7 +1372,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
13601372
void completeInPrecedenceGroup(SyntaxKind SK) override;
13611373
void completeNominalMemberBeginning(
13621374
SmallVectorImpl<StringRef> &Keywords, SourceLoc introducerLoc) override;
1363-
void completeAccessorBeginning() override;
1375+
void completeAccessorBeginning(CodeCompletionExpr *E) override;
13641376

13651377
void completePoundAvailablePlatform() override;
13661378
void completeImportDecl(std::vector<std::pair<Identifier, SourceLoc>> &Path) override;
@@ -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;
@@ -3549,9 +3569,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35493569
builder.addSimpleNamedParameter("values");
35503570
builder.addRightParen();
35513571
for (auto T : expectedTypeContext.possibleTypes) {
3552-
if (!T)
3553-
continue;
3554-
if (T->is<TupleType>()) {
3572+
if (T && T->is<TupleType>() && !T->isVoid()) {
35553573
addTypeAnnotation(builder, T);
35563574
builder.setExpectedTypeRelation(CodeCompletionResult::Identical);
35573575
break;
@@ -4620,9 +4638,11 @@ void CodeCompletionCallbacksImpl::completeNominalMemberBeginning(
46204638
CurDeclContext = P.CurDeclContext;
46214639
}
46224640

4623-
void CodeCompletionCallbacksImpl::completeAccessorBeginning() {
4641+
void CodeCompletionCallbacksImpl::completeAccessorBeginning(
4642+
CodeCompletionExpr *E) {
46244643
Kind = CompletionKind::AccessorBeginning;
46254644
CurDeclContext = P.CurDeclContext;
4645+
CodeCompleteTokenExpr = E;
46264646
}
46274647

46284648
static bool isDynamicLookup(Type T) {
@@ -5205,8 +5225,12 @@ void CodeCompletionCallbacksImpl::doneParsing() {
52055225
}
52065226

52075227
case CompletionKind::AccessorBeginning: {
5208-
if (isa<AccessorDecl>(ParsedDecl))
5228+
if (isa<AccessorDecl>(ParsedDecl)) {
5229+
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
5230+
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
5231+
ContextInfo.isSingleExpressionBody());
52095232
DoPostfixExprBeginning();
5233+
}
52105234
break;
52115235
}
52125236

@@ -5395,7 +5419,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
53955419
Lookup.RequestedCachedResults.clear();
53965420
}
53975421

5398-
CompletionContext.HasExpectedTypeRelation = Lookup.hasExpectedTypes();
5422+
CompletionContext.typeContextKind = Lookup.typeContextKind();
53995423

54005424
deliverCompletionResults();
54015425
}

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()) {

lib/Parse/ParseDecl.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4473,20 +4473,30 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
44734473

44744474
if (Tok.is(tok::code_complete)) {
44754475
if (CodeCompletion) {
4476+
CodeCompletionExpr *CCE = nullptr;
44764477
if (IsFirstAccessor && !parsingLimitedSyntax) {
44774478
// If CC token is the first token after '{', it might be implicit
44784479
// getter. Set up dummy accessor as the decl context to populate
44794480
// 'self' decl.
4481+
4482+
// FIXME: if there is already code inside the body, we should fall
4483+
// through to parseImplicitGetter and handle the completion there so
4484+
// that we can differentiate a single-expression body from the first
4485+
// expression in a multi-statement body.
44804486
auto getter = createAccessorFunc(
44814487
accessors.LBLoc, /*ValueNamePattern*/ nullptr, GenericParams,
44824488
Indices, ElementTy, StaticLoc, Flags, AccessorKind::Get,
44834489
storage, this, /*AccessorKeywordLoc*/ SourceLoc());
4490+
CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
4491+
getter->setBody(BraceStmt::create(Context, Tok.getLoc(),
4492+
ASTNode(CCE), Tok.getLoc(),
4493+
/*implicit*/ true));
44844494
accessors.add(getter);
44854495
CodeCompletion->setParsedDecl(getter);
44864496
} else {
44874497
CodeCompletion->setParsedDecl(storage);
44884498
}
4489-
CodeCompletion->completeAccessorBeginning();
4499+
CodeCompletion->completeAccessorBeginning(CCE);
44904500
}
44914501
consumeToken(tok::code_complete);
44924502
accessorHasCodeCompletion = true;

test/IDE/complete_accessor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
// NO_OBSERVER-NOT: willSet
136136
// NO_OBSERVER-NOT: didSet
137137

138-
// WITH_GLOBAL: Decl[GlobalVar]/CurrModule: globalValue[#String#];
138+
// WITH_GLOBAL: Decl[GlobalVar]/CurrModule{{(/TypeRelation\[Identical\])?}}: globalValue[#String#];
139139
// NO_GLOBAL-NOT: globalValue;
140140

141141
// WITH_SELF: Decl[LocalVar]/Local: self[#{{.+}}#]; name=self

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_crashes.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ while true {
6767
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERIC_PARAM_AND_ASSOC_TYPE | %FileCheck %s -check-prefix=GENERIC_PARAM_AND_ASSOC_TYPE
6868
struct CustomGenericCollection<Key> : ExpressibleByDictionaryLiteral {
6969
// GENERIC_PARAM_AND_ASSOC_TYPE: Begin completions
70-
// GENERIC_PARAM_AND_ASSOC_TYPE-DAG: Decl[InstanceVar]/CurrNominal: count[#Int#]; name=count
70+
// GENERIC_PARAM_AND_ASSOC_TYPE-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: count[#Int#]; name=count
7171
// GENERIC_PARAM_AND_ASSOC_TYPE-DAG: Decl[GenericTypeParam]/Local: Key[#Key#]; name=Key
7272
// GENERIC_PARAM_AND_ASSOC_TYPE-DAG: Decl[TypeAlias]/CurrNominal: Value[#CustomGenericCollection<Key>.Value#]; name=Value
7373
// GENERIC_PARAM_AND_ASSOC_TYPE: End completions

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)