Skip to content

Commit 240a262

Browse files
author
Nathan Hawes
committed
[CodeCompletion] Rename isSingleExpressionBody to isImplicitSingleExpressionReturn for clarity
This bool was true only for single-expression closure and function bodies that do not have an explicit `return` in the source. Rename it and its associated methods, to avoid confusion with the hasSingleExpressionBody methods on ClosureExpr and AbstractFuncDecl. Those don't care whether the expression was explicitly written in the source or not.
1 parent 86ddd52 commit 240a262

6 files changed

+68
-50
lines changed

Diff for: include/swift/Sema/CodeCompletionTypeChecking.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ namespace swift {
5454
SmallVector<Type, 4> ExpectedTypes;
5555
bool ExpectsNonVoid;
5656
bool BaseIsStaticMetaType;
57-
bool IsSingleExpressionBody;
57+
bool IsImplicitSingleExpressionReturn;
5858
};
5959

6060
private:
@@ -91,7 +91,7 @@ namespace swift {
9191
public:
9292
struct Result {
9393
Type ExpectedTy;
94-
bool IsSingleExpressionBody;
94+
bool IsImplicitSingleExpressionReturn;
9595
};
9696

9797
private:

Diff for: lib/IDE/CodeCompletion.cpp

+20-17
Original file line numberDiff line numberDiff line change
@@ -1171,14 +1171,14 @@ calculateMaxTypeRelation(Type Ty, const ExpectedTypeContext &typeContext,
11711171
//
11721172
// { ... -> Int in x } // x must be Int
11731173
// { ... -> () in return x } // x must be Void
1174-
if (typeContext.isSingleExpressionBody && expectedTy->isVoid())
1174+
if (typeContext.isImplicitSingleExpressionReturn && expectedTy->isVoid())
11751175
continue;
11761176

11771177
Result = std::max(Result, calculateTypeRelation(Ty, expectedTy, DC));
11781178

11791179
// Map invalid -> unrelated when in a single-expression body, since the
11801180
// input may be incomplete.
1181-
if (typeContext.isSingleExpressionBody &&
1181+
if (typeContext.isImplicitSingleExpressionReturn &&
11821182
Result == CodeCompletionResult::ExpectedTypeRelation::Invalid)
11831183
Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated;
11841184
}
@@ -1958,9 +1958,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
19581958
IsStaticMetatype = value;
19591959
}
19601960

1961-
void setExpectedTypes(ArrayRef<Type> Types, bool isSingleExpressionBody,
1961+
void setExpectedTypes(ArrayRef<Type> Types,
1962+
bool isImplicitSingleExpressionReturn,
19621963
bool preferNonVoid = false) {
1963-
expectedTypeContext.isSingleExpressionBody = isSingleExpressionBody;
1964+
expectedTypeContext.isImplicitSingleExpressionReturn =
1965+
isImplicitSingleExpressionReturn;
19641966
expectedTypeContext.preferNonVoid = preferNonVoid;
19651967
expectedTypeContext.possibleTypes.clear();
19661968
expectedTypeContext.possibleTypes.reserve(Types.size());
@@ -1976,7 +1978,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
19761978
CodeCompletionContext::TypeContextKind typeContextKind() const {
19771979
if (expectedTypeContext.empty() && !expectedTypeContext.preferNonVoid) {
19781980
return CodeCompletionContext::TypeContextKind::None;
1979-
} else if (expectedTypeContext.isSingleExpressionBody) {
1981+
} else if (expectedTypeContext.isImplicitSingleExpressionReturn) {
19801982
return CodeCompletionContext::TypeContextKind::SingleExpressionBody;
19811983
} else {
19821984
return CodeCompletionContext::TypeContextKind::Required;
@@ -6105,7 +6107,7 @@ void deliverUnresolvedMemberResults(
61056107

61066108
for (auto &Result: Results) {
61076109
Lookup.setExpectedTypes({Result.ExpectedTy},
6108-
Result.IsSingleExpressionBody,
6110+
Result.IsImplicitSingleExpressionReturn,
61096111
/*expectsNonVoid*/true);
61106112
Lookup.setIdealExpectedType(Result.ExpectedTy);
61116113

@@ -6154,7 +6156,7 @@ void deliverDotExprResults(
61546156
Lookup.setIsStaticMetatype(Result.BaseIsStaticMetaType);
61556157
Lookup.getPostfixKeywordCompletions(Result.BaseTy, BaseExpr);
61566158
Lookup.setExpectedTypes(Result.ExpectedTypes,
6157-
Result.IsSingleExpressionBody,
6159+
Result.IsImplicitSingleExpressionReturn,
61586160
Result.ExpectsNonVoid);
61596161
if (isDynamicLookup(Result.BaseTy))
61606162
Lookup.setIsDynamicLookup();
@@ -6395,7 +6397,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
63956397
case CompletionKind::PostfixExprBeginning: {
63966398
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
63976399
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6398-
ContextInfo.isSingleExpressionBody());
6400+
ContextInfo.isImplicitSingleExpressionReturn());
63996401
DoPostfixExprBeginning();
64006402
break;
64016403
}
@@ -6417,8 +6419,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
64176419

64186420
if (ShouldCompleteCallPatternAfterParen) {
64196421
ExprContextInfo ParentContextInfo(CurDeclContext, ParsedExpr);
6420-
Lookup.setExpectedTypes(ParentContextInfo.getPossibleTypes(),
6421-
ParentContextInfo.isSingleExpressionBody());
6422+
Lookup.setExpectedTypes(
6423+
ParentContextInfo.getPossibleTypes(),
6424+
ParentContextInfo.isImplicitSingleExpressionReturn());
64226425
if (!ContextInfo.getPossibleCallees().empty()) {
64236426
for (auto &typeAndDecl : ContextInfo.getPossibleCallees())
64246427
Lookup.tryFunctionCallCompletions(typeAndDecl.Type, typeAndDecl.Decl,
@@ -6436,7 +6439,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
64366439
(Lookup.FoundFunctionCalls &&
64376440
Lookup.FoundFunctionsWithoutFirstKeyword)) {
64386441
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6439-
ContextInfo.isSingleExpressionBody());
6442+
ContextInfo.isImplicitSingleExpressionReturn());
64406443
Lookup.setHaveLParen(false);
64416444
DoPostfixExprBeginning();
64426445
}
@@ -6485,7 +6488,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
64856488
case CompletionKind::CaseStmtBeginning: {
64866489
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
64876490
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6488-
ContextInfo.isSingleExpressionBody());
6491+
ContextInfo.isImplicitSingleExpressionReturn());
64896492
Lookup.setIdealExpectedType(CodeCompleteTokenExpr->getType());
64906493
Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes());
64916494
DoPostfixExprBeginning();
@@ -6504,7 +6507,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
65046507
if (isa<AccessorDecl>(ParsedDecl)) {
65056508
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
65066509
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6507-
ContextInfo.isSingleExpressionBody());
6510+
ContextInfo.isImplicitSingleExpressionReturn());
65086511
DoPostfixExprBeginning();
65096512
}
65106513
break;
@@ -6578,7 +6581,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
65786581

65796582
if (shouldPerformGlobalCompletion) {
65806583
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6581-
ContextInfo.isSingleExpressionBody());
6584+
ContextInfo.isImplicitSingleExpressionReturn());
65826585
DoPostfixExprBeginning();
65836586
}
65846587
break;
@@ -6697,7 +6700,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
66976700
SmallVector<Type, 2> possibleReturnTypes;
66986701
collectPossibleReturnTypesFromContext(CurDeclContext, possibleReturnTypes);
66996702
Lookup.setExpectedTypes(possibleReturnTypes,
6700-
/*isSingleExpressionBody*/ false);
6703+
/*isImplicitSingleExpressionReturn*/ false);
67016704
Lookup.getValueCompletionsInDeclContext(Loc);
67026705
break;
67036706
}
@@ -6708,7 +6711,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
67086711
if (FD->isCoroutine()) {
67096712
// TODO: handle multi-value yields.
67106713
Lookup.setExpectedTypes(FD->getStorage()->getValueInterfaceType(),
6711-
/*isSingleExpressionBody*/ false);
6714+
/*isImplicitSingleExpressionReturn*/ false);
67126715
}
67136716
}
67146717
Lookup.getValueCompletionsInDeclContext(Loc);
@@ -6718,7 +6721,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
67186721
case CompletionKind::AfterPoundExpr: {
67196722
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
67206723
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
6721-
ContextInfo.isSingleExpressionBody());
6724+
ContextInfo.isImplicitSingleExpressionReturn());
67226725

67236726
Lookup.addPoundAvailable(ParentStmtKind);
67246727
Lookup.addPoundLiteralCompletions(/*needPound=*/false);

Diff for: lib/IDE/CodeCompletionResultBuilder.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ struct ExpectedTypeContext {
4848
///
4949
/// Since the input may be incomplete, we take into account that the types are
5050
/// only a hint.
51-
bool isSingleExpressionBody = false;
51+
bool isImplicitSingleExpressionReturn = false;
5252
bool preferNonVoid = false;
5353

5454
bool empty() const { return possibleTypes.empty(); }
5555
bool requiresNonVoid() const {
56-
if (isSingleExpressionBody)
56+
if (isImplicitSingleExpressionReturn)
5757
return false;
5858
if (preferNonVoid)
5959
return true;
@@ -65,9 +65,9 @@ struct ExpectedTypeContext {
6565
}
6666

6767
ExpectedTypeContext() = default;
68-
ExpectedTypeContext(ArrayRef<Type> types, bool isSingleExpressionBody)
68+
ExpectedTypeContext(ArrayRef<Type> types, bool isImplicitSingleExprReturn)
6969
: possibleTypes(types.begin(), types.end()),
70-
isSingleExpressionBody(isSingleExpressionBody) {}
70+
isImplicitSingleExpressionReturn(isImplicitSingleExprReturn) {}
7171
};
7272

7373
class CodeCompletionResultBuilder {

Diff for: lib/IDE/ExprContextAnalysis.cpp

+20-16
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ class ExprContextAnalyzer {
750750
SmallVectorImpl<PossibleParamInfo> &PossibleParams;
751751
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees;
752752
Expr *&AnalyzedExpr;
753-
bool &singleExpressionBody;
753+
bool &implicitSingleExpressionReturn;
754754

755755
void recordPossibleType(Type ty) {
756756
if (!ty || ty->is<ErrorType>())
@@ -970,8 +970,8 @@ class ExprContextAnalyzer {
970970
}
971971
case ExprKind::Closure: {
972972
auto *CE = cast<ClosureExpr>(Parent);
973-
assert(isSingleExpressionBodyForCodeCompletion(CE->getBody()));
974-
singleExpressionBody = true;
973+
assert(hasImplicitSingleExpressionReturn(CE->getBody()));
974+
implicitSingleExpressionReturn = true;
975975
SmallVector<Type, 2> candidates;
976976
collectPossibleReturnTypesFromContext(CE, candidates);
977977
for (auto ty : candidates)
@@ -1052,8 +1052,8 @@ class ExprContextAnalyzer {
10521052
}
10531053
default:
10541054
if (auto *FD = dyn_cast<FuncDecl>(D)) {
1055-
assert(isSingleExpressionBodyForCodeCompletion(FD->getBody()));
1056-
singleExpressionBody = true;
1055+
assert(hasImplicitSingleExpressionReturn(FD->getBody()));
1056+
implicitSingleExpressionReturn = true;
10571057
SmallVector<Type, 2> candidates;
10581058
collectPossibleReturnTypesFromContext(DC, candidates);
10591059
for (auto ty : candidates)
@@ -1105,14 +1105,18 @@ class ExprContextAnalyzer {
11051105
}
11061106

11071107
/// Whether the given \c BraceStmt, which must be the body of a function or
1108-
/// closure, should be treated as a single-expression return for the purposes
1109-
/// of code-completion.
1108+
/// closure, contains a single expression that would be implicitly returned if
1109+
/// the single-expression-body transform had been performed.
11101110
///
11111111
/// We cannot use hasSingleExpressionBody, because we explicitly do not use
1112-
/// the single-expression-body when there is code-completion in the expression
1113-
/// in order to avoid a base expression affecting the type. However, now that
1114-
/// we've typechecked, we will take the context type into account.
1115-
static bool isSingleExpressionBodyForCodeCompletion(BraceStmt *body) {
1112+
/// the single-expression-body transform when there is a code-completion in
1113+
/// the expression in order to avoid a base expression affecting the type, and
1114+
/// need to distinguish whether the single expression body was explicitly
1115+
/// returned (in which case the expression's type *must* match the expected
1116+
/// return type) or not (in which case it *may* match, as the user could intend
1117+
/// it only as the first statement of many that they haven't finished writing
1118+
/// yet.
1119+
static bool hasImplicitSingleExpressionReturn(BraceStmt *body) {
11161120
if (body->getNumElements() == 2) {
11171121
if (auto *D = body->getFirstElement().dyn_cast<Decl *>()) {
11181122
// Step into nested active clause.
@@ -1138,12 +1142,12 @@ class ExprContextAnalyzer {
11381142
DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl<Type> &PossibleTypes,
11391143
SmallVectorImpl<PossibleParamInfo> &PossibleArgs,
11401144
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees,
1141-
Expr *&AnalyzedExpr, bool &singleExpressionBody)
1145+
Expr *&AnalyzedExpr, bool &implicitSingleExpressionReturn)
11421146
: DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr),
11431147
Context(DC->getASTContext()), PossibleTypes(PossibleTypes),
11441148
PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees),
11451149
AnalyzedExpr(AnalyzedExpr),
1146-
singleExpressionBody(singleExpressionBody) {}
1150+
implicitSingleExpressionReturn(implicitSingleExpressionReturn) {}
11471151

11481152
void Analyze() {
11491153
// We cannot analyze without target.
@@ -1184,7 +1188,7 @@ class ExprContextAnalyzer {
11841188
!isa<BinaryExpr>(ParentE));
11851189
}
11861190
case ExprKind::Closure:
1187-
return isSingleExpressionBodyForCodeCompletion(
1191+
return hasImplicitSingleExpressionReturn(
11881192
cast<ClosureExpr>(E)->getBody());
11891193
default:
11901194
return false;
@@ -1208,7 +1212,7 @@ class ExprContextAnalyzer {
12081212
default:
12091213
if (auto *FD = dyn_cast<FuncDecl>(D))
12101214
if (auto *body = FD->getBody())
1211-
return isSingleExpressionBodyForCodeCompletion(body);
1215+
return hasImplicitSingleExpressionReturn(body);
12121216
return false;
12131217
}
12141218
} else if (auto P = Node.getAsPattern()) {
@@ -1252,6 +1256,6 @@ class ExprContextAnalyzer {
12521256
ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
12531257
ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams,
12541258
PossibleCallees, AnalyzedExpr,
1255-
singleExpressionBody);
1259+
implicitSingleExpressionReturn);
12561260
Analyzer.Analyze();
12571261
}

Diff for: lib/IDE/ExprContextAnalysis.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,22 @@ class ExprContextInfo {
8282
SmallVector<PossibleParamInfo, 2> PossibleParams;
8383
SmallVector<FunctionTypeAndDecl, 2> PossibleCallees;
8484
Expr *AnalyzedExpr = nullptr;
85-
bool singleExpressionBody = false;
85+
bool implicitSingleExpressionReturn = false;
8686

8787
public:
8888
ExprContextInfo(DeclContext *DC, Expr *TargetExpr);
8989

9090
// Returns a list of possible context types.
9191
ArrayRef<Type> getPossibleTypes() const { return PossibleTypes; }
9292

93-
/// Whether the type context comes from a single-expression body, e.g.
94-
/// `foo({ here })`.
93+
/// Whether the type context comes from a single-expression body without
94+
/// and explicit return e.g. `foo({ <here> })` and not foo({ return <here>}).
9595
///
96-
/// If the input may be incomplete, such as in code-completion, take into
96+
/// Since the input may be incomplete, such as in code-completion, take into
9797
/// account that the types returned by `getPossibleTypes()` are only a hint.
98-
bool isSingleExpressionBody() const { return singleExpressionBody; }
98+
bool isImplicitSingleExpressionReturn() const {
99+
return implicitSingleExpressionReturn;
100+
}
99101

100102
// Returns a list of possible argument label names.
101103
// Valid only if \c getKind() is \c CallArgument.

Diff for: lib/Sema/TypeCheckCodeCompletion.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -1160,12 +1160,21 @@ static Type getTypeForCompletion(const constraints::Solution &S, Expr *E) {
11601160
return S.getResolvedType(E);
11611161
};
11621162

1163-
static bool isSingleExpressionBodyCompletion(ConstraintSystem &CS,
1163+
/// Whether the given completion expression is the only expression in its
1164+
/// containing closure or function body and its value is implicitly returned.
1165+
///
1166+
/// If these conditions are met, code completion needs to avoid penalizing
1167+
/// completion results that don't match the expected return type when computing
1168+
/// type relations, as since no return statement was explicitly written by the
1169+
/// user, it's possible they intend the single expression not as the return
1170+
/// value but merely the first entry in a multi-statement body they just haven't
1171+
/// finished writing yet.
1172+
static bool isImplicitSingleExpressionReturn(ConstraintSystem &CS,
11641173
Expr *CompletionExpr) {
11651174
Expr *ParentExpr = CS.getParentExpr(CompletionExpr);
1166-
if (!ParentExpr) {
1175+
if (!ParentExpr)
11671176
return CS.getContextualTypePurpose(CompletionExpr) == CTP_ReturnSingleExpr;
1168-
}
1177+
11691178
if (auto *ParentCE = dyn_cast<ClosureExpr>(ParentExpr)) {
11701179
if (ParentCE->hasSingleExpressionBody() &&
11711180
ParentCE->getSingleExpressionBody() == CompletionExpr) {
@@ -1205,14 +1214,14 @@ sawSolution(const constraints::Solution &S) {
12051214
auto Ret = BaseToSolutionIdx.insert({Key, Results.size()});
12061215
if (Ret.second) {
12071216
bool ISDMT = S.isStaticallyDerivedMetatype(ParsedExpr);
1208-
bool SingleExprBody = isSingleExpressionBodyCompletion(CS, CompletionExpr);
1217+
bool ImplicitReturn = isImplicitSingleExpressionReturn(CS, CompletionExpr);
12091218
bool DisallowVoid = ExpectedTy
12101219
? !ExpectedTy->isVoid()
12111220
: !ParentExpr && CS.getContextualTypePurpose(
12121221
CompletionExpr) != CTP_Unused;
12131222

12141223
Results.push_back(
1215-
{BaseTy, ReferencedDecl, {}, DisallowVoid, ISDMT, SingleExprBody});
1224+
{BaseTy, ReferencedDecl, {}, DisallowVoid, ISDMT, ImplicitReturn});
12161225
if (ExpectedTy)
12171226
Results.back().ExpectedTypes.push_back(ExpectedTy);
12181227
} else if (ExpectedTy) {
@@ -1242,6 +1251,6 @@ sawSolution(const constraints::Solution &S) {
12421251
return;
12431252
}
12441253

1245-
bool SingleExprBody = isSingleExpressionBodyCompletion(CS, CompletionExpr);
1254+
bool SingleExprBody = isImplicitSingleExpressionReturn(CS, CompletionExpr);
12461255
Results.push_back({ExpectedTy, SingleExprBody});
12471256
}

0 commit comments

Comments
 (0)