Skip to content

Commit cf34fa5

Browse files
author
Nathan Hawes
authored
Merge pull request swiftlang#34253 from nathawes/nfc-always-form-single-expression-return-and-undo-if-needed
[Parse][CodeCompletion] Don't special case code completion when forming single-expression closures/function bodies (NFC)
2 parents b13ce50 + a91cede commit cf34fa5

File tree

5 files changed

+41
-71
lines changed

5 files changed

+41
-71
lines changed

include/swift/Parse/Parser.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -709,15 +709,6 @@ class Parser {
709709
Context.LangOpts.ParseForSyntaxTreeOnly;
710710
}
711711

712-
/// If a function or closure body consists of a single expression, determine
713-
/// whether we should turn wrap it in a return statement or not.
714-
///
715-
/// We don't do this transformation for non-solver-based code completion
716-
/// positions, as the source may be incomplete and the type mismatch in the
717-
/// return statement will just confuse the type checker.
718-
bool shouldSuppressSingleExpressionBodyTransform(
719-
ParserStatus Status, MutableArrayRef<ASTNode> BodyElems);
720-
721712
public:
722713
InFlightDiagnostic diagnose(SourceLoc Loc, Diagnostic Diag) {
723714
if (Diags.isDiagnosticPointsToFirstBadToken(Diag.getID()) &&

lib/IDE/CodeCompletion.cpp

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,7 +1672,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
16721672

16731673
private:
16741674
void addKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody);
1675-
bool trySolverCompletion();
1675+
bool trySolverCompletion(bool MaybeFuncBody);
16761676
};
16771677
} // end anonymous namespace
16781678

@@ -6054,25 +6054,7 @@ void deliverDotExprResults(
60546054
deliverCompletionResults(CompletionCtx, Lookup, *SF, Consumer);
60556055
}
60566056

6057-
bool CodeCompletionCallbacksImpl::trySolverCompletion() {
6058-
CompletionContext.CodeCompletionKind = Kind;
6059-
6060-
if (Kind == CompletionKind::None)
6061-
return true;
6062-
6063-
bool MaybeFuncBody = true;
6064-
if (CurDeclContext) {
6065-
auto *CD = CurDeclContext->getLocalContext();
6066-
if (!CD || CD->getContextKind() == DeclContextKind::Initializer ||
6067-
CD->getContextKind() == DeclContextKind::TopLevelCodeDecl)
6068-
MaybeFuncBody = false;
6069-
}
6070-
6071-
if (auto *DC = dyn_cast_or_null<DeclContext>(ParsedDecl)) {
6072-
if (DC->isChildContextOf(CurDeclContext))
6073-
CurDeclContext = DC;
6074-
}
6075-
6057+
bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
60766058
assert(ParsedExpr || CurDeclContext);
60776059

60786060
SourceLoc CompletionLoc = ParsedExpr
@@ -6111,12 +6093,42 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion() {
61116093
}
61126094
}
61136095

6096+
// Undoes the single-expression closure/function body transformation on the
6097+
// given DeclContext and its parent contexts if they have a single expression
6098+
// body that contains the code completion location.
6099+
//
6100+
// FIXME: Remove this once all expression position completions are migrated
6101+
// to work via TypeCheckCompletionCallback.
6102+
static void undoSingleExpressionReturn(DeclContext *DC) {
6103+
auto updateBody = [](BraceStmt *BS, ASTContext &Ctx) -> bool {
6104+
ASTNode FirstElem = BS->getFirstElement();
6105+
auto *RS = dyn_cast_or_null<ReturnStmt>(FirstElem.dyn_cast<Stmt*>());
6106+
6107+
if (!RS || !RS->isImplicit())
6108+
return false;
6109+
6110+
BS->setFirstElement(RS->getResult());
6111+
return true;
6112+
};
6113+
6114+
while (ClosureExpr *CE = dyn_cast_or_null<ClosureExpr>(DC)) {
6115+
if (CE->hasSingleExpressionBody()) {
6116+
if (updateBody(CE->getBody(), CE->getASTContext()))
6117+
CE->setBody(CE->getBody(), false);
6118+
}
6119+
DC = DC->getParent();
6120+
}
6121+
if (FuncDecl *FD = dyn_cast_or_null<FuncDecl>(DC)) {
6122+
if (FD->hasSingleExpressionBody()) {
6123+
if (updateBody(FD->getBody(), FD->getASTContext()))
6124+
FD->setHasSingleExpressionBody(false);
6125+
}
6126+
}
6127+
}
6128+
61146129
void CodeCompletionCallbacksImpl::doneParsing() {
61156130
CompletionContext.CodeCompletionKind = Kind;
61166131

6117-
if (trySolverCompletion())
6118-
return;
6119-
61206132
if (Kind == CompletionKind::None) {
61216133
return;
61226134
}
@@ -6134,6 +6146,10 @@ void CodeCompletionCallbacksImpl::doneParsing() {
61346146
CurDeclContext = DC;
61356147
}
61366148

6149+
if (trySolverCompletion(MaybeFuncBody))
6150+
return;
6151+
6152+
undoSingleExpressionReturn(CurDeclContext);
61376153
typeCheckContextAt(
61386154
CurDeclContext,
61396155
ParsedExpr

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6588,11 +6588,7 @@ BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
65886588

65896589
// If the body consists of a single expression, turn it into a return
65906590
// statement.
6591-
//
6592-
// But don't do this transformation when performing certain kinds of code
6593-
// completion, as the source may be incomplete and the type mismatch in return
6594-
// statement will just confuse the type checker.
6595-
if (shouldSuppressSingleExpressionBodyTransform(Body, BS->getElements()))
6591+
if (BS->getNumElements() != 1)
65966592
return BS;
65976593

65986594
auto Element = BS->getFirstElement();

lib/Parse/ParseExpr.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,13 +2841,8 @@ ParserResult<Expr> Parser::parseExprClosure() {
28412841

28422842
// If the body consists of a single expression, turn it into a return
28432843
// statement.
2844-
//
2845-
// But don't do this transformation when performing certain kinds of code
2846-
// completion, as the source may be incomplete and the type mismatch in return
2847-
// statement will just confuse the type checker.
28482844
bool hasSingleExpressionBody = false;
2849-
if (!missingRBrace &&
2850-
!shouldSuppressSingleExpressionBodyTransform(Status, bodyElements)) {
2845+
if (!missingRBrace && bodyElements.size() == 1) {
28512846
// If the closure's only body element is a single return statement,
28522847
// use that instead of creating a new wrapping return expression.
28532848
Expr *returnExpr = nullptr;

lib/Parse/Parser.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,34 +1185,6 @@ Parser::getStringLiteralIfNotInterpolated(SourceLoc Loc,
11851185
Segments.front().Length));
11861186
}
11871187

1188-
bool Parser::
1189-
shouldSuppressSingleExpressionBodyTransform(ParserStatus Status,
1190-
MutableArrayRef<ASTNode> BodyElems) {
1191-
if (BodyElems.size() != 1)
1192-
return true;
1193-
1194-
if (!Status.hasCodeCompletion())
1195-
return false;
1196-
1197-
struct HasMemberCompletion: public ASTWalker {
1198-
bool Value = false;
1199-
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
1200-
if (auto *CCE = dyn_cast<CodeCompletionExpr>(E)) {
1201-
// If it has a base expression this is member completion, which is
1202-
// performed using the new solver-based mechanism, so it's ok to go
1203-
// ahead with the transform (and necessary to pick up the correct
1204-
// expected type).
1205-
Value = CCE->getBase();
1206-
return {false, nullptr};
1207-
}
1208-
return {true, E};
1209-
}
1210-
};
1211-
HasMemberCompletion Check;
1212-
BodyElems.front().walk(Check);
1213-
return !Check.Value;
1214-
}
1215-
12161188
struct ParserUnit::Implementation {
12171189
std::shared_ptr<SyntaxParseActions> SPActions;
12181190
LangOptions LangOpts;

0 commit comments

Comments
 (0)