Skip to content

Commit 0da6c25

Browse files
committed
[CS] Unify ReturnStmt handling
Unify the implementation between single-expression and multi-statement closures. Because we're now storing a contextual type for single expression closure returns, update a code completion test to bring its behavior inline with the multi-statement case.
1 parent 59ce061 commit 0da6c25

File tree

4 files changed

+53
-66
lines changed

4 files changed

+53
-66
lines changed

include/swift/Sema/SyntacticElementTarget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,11 @@ class SyntacticElementTarget {
431431
expression.contextualInfo.typeLoc = type;
432432
}
433433

434+
void setExprContextualTypePurpose(ContextualTypePurpose ctp) {
435+
assert(kind == Kind::expression);
436+
expression.contextualInfo.purpose = ctp;
437+
}
438+
434439
/// Whether this target is for an initialization expression and pattern.
435440
bool isForInitialization() const {
436441
return kind == Kind::expression &&

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9595,22 +9595,8 @@ ExprWalker::rewriteTarget(SyntacticElementTarget target) {
95959595

95969596
auto *locator = target.getExprConvertTypeLocator();
95979597
if (!locator) {
9598-
// Bodies of single-expression closures use a special locator
9599-
// for contextual type conversion to make sure that result is
9600-
// convertible to `Void` when `return` is not used explicitly.
9601-
auto *closure = dyn_cast<ClosureExpr>(target.getDeclContext());
9602-
if (closure && closure->hasSingleExpressionBody() &&
9603-
contextualTypePurpose == CTP_ClosureResult) {
9604-
auto *returnStmt =
9605-
castToStmt<ReturnStmt>(closure->getBody()->getLastElement());
9606-
9607-
locator = cs.getConstraintLocator(
9608-
closure, LocatorPathElt::ClosureBody(
9609-
/*hasImpliedReturn*/ returnStmt->isImplied()));
9610-
} else {
9611-
locator = cs.getConstraintLocator(
9612-
expr, LocatorPathElt::ContextualType(contextualTypePurpose));
9613-
}
9598+
locator = cs.getConstraintLocator(
9599+
expr, LocatorPathElt::ContextualType(contextualTypePurpose));
96149600
}
96159601
assert(locator);
96169602

lib/Sema/CSSyntacticElement.cpp

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ struct SyntacticElementContext
485485
}
486486
}
487487

488-
bool isSingleExpressionClosure(ConstraintSystem &cs) {
488+
bool isSingleExpressionClosure(ConstraintSystem &cs) const {
489489
if (auto ref = getAsAnyFunctionRef()) {
490490
if (cs.getAppliedResultBuilderTransform(*ref))
491491
return false;
@@ -1242,32 +1242,7 @@ class SyntacticElementConstraintGenerator
12421242
}
12431243

12441244
void visitReturnStmt(ReturnStmt *returnStmt) {
1245-
// Single-expression closures are effectively a `return` statement,
1246-
// so let's give them a special locator as to indicate that.
1247-
// Return statements might not have a result if we have a closure whose
1248-
// implicit returned value is coerced to Void.
1249-
if (context.isSingleExpressionClosure(cs) && returnStmt->hasResult()) {
1250-
auto *expr = returnStmt->getResult();
1251-
assert(expr && "single expression closure without expression?");
1252-
1253-
expr = cs.generateConstraints(expr, context.getAsDeclContext());
1254-
if (!expr) {
1255-
hadError = true;
1256-
return;
1257-
}
1258-
1259-
auto contextualResultInfo = getContextualResultInfo();
1260-
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
1261-
contextualResultInfo.getType(),
1262-
cs.getConstraintLocator(
1263-
context.getAsAbstractClosureExpr().get(),
1264-
LocatorPathElt::ClosureBody(
1265-
/*hasImpliedReturn=*/returnStmt->isImplied())));
1266-
return;
1267-
}
1268-
12691245
Expr *resultExpr;
1270-
12711246
if (returnStmt->hasResult()) {
12721247
resultExpr = returnStmt->getResult();
12731248
assert(resultExpr && "non-empty result without expression?");
@@ -1279,10 +1254,10 @@ class SyntacticElementConstraintGenerator
12791254
resultExpr = getVoidExpr(cs.getASTContext(), returnStmt->getEndLoc());
12801255
}
12811256

1282-
auto contextualResultInfo = getContextualResultInfo();
1257+
auto contextualResultInfo = getContextualResultInfoFor(returnStmt);
1258+
12831259
SyntacticElementTarget target(resultExpr, context.getAsDeclContext(),
1284-
contextualResultInfo,
1285-
/*isDiscarded=*/false);
1260+
contextualResultInfo, /*isDiscarded=*/false);
12861261

12871262
if (cs.generateConstraints(target)) {
12881263
hadError = true;
@@ -1327,7 +1302,7 @@ class SyntacticElementConstraintGenerator
13271302
createConjunction({resultElt}, locator);
13281303
}
13291304

1330-
ContextualTypeInfo getContextualResultInfo() const {
1305+
ContextualTypeInfo getContextualResultInfoFor(ReturnStmt *returnStmt) const {
13311306
auto funcRef = AnyFunctionRef::fromDeclContext(context.getAsDeclContext());
13321307
if (!funcRef)
13331308
return {Type(), CTP_Unused};
@@ -1336,8 +1311,19 @@ class SyntacticElementConstraintGenerator
13361311
return {transform->bodyResultType, CTP_ReturnStmt};
13371312

13381313
if (auto *closure =
1339-
getAsExpr<ClosureExpr>(funcRef->getAbstractClosureExpr()))
1340-
return {cs.getClosureType(closure)->getResult(), CTP_ClosureResult};
1314+
getAsExpr<ClosureExpr>(funcRef->getAbstractClosureExpr())) {
1315+
// Single-expression closures need their contextual type locator anchored
1316+
// on the closure itself. Otherwise we use the default contextual type
1317+
// locator, which will be created for us.
1318+
ConstraintLocator *loc = nullptr;
1319+
if (context.isSingleExpressionClosure(cs) && returnStmt->hasResult()) {
1320+
loc = cs.getConstraintLocator(
1321+
context.getAsAbstractClosureExpr().get(),
1322+
{LocatorPathElt::ClosureBody(
1323+
/*hasImpliedReturn=*/returnStmt->isImplied())});
1324+
}
1325+
return {cs.getClosureType(closure)->getResult(), CTP_ClosureResult, loc};
1326+
}
13411327

13421328
return {funcRef->getBodyResultType(), CTP_ReturnStmt};
13431329
}
@@ -2155,22 +2141,15 @@ class SyntacticElementSolutionApplication
21552141
mode = convertToResult;
21562142
}
21572143

2158-
llvm::Optional<SyntacticElementTarget> resultTarget;
2159-
if (auto target = cs.getTargetFor(returnStmt)) {
2160-
resultTarget = *target;
2161-
} else {
2162-
// Single-expression closures have to handle returns in a special
2163-
// way so the target has to be created for them during solution
2164-
// application based on the resolved type.
2165-
assert(context.isSingleExpressionClosure(cs));
2166-
resultTarget = SyntacticElementTarget(
2167-
resultExpr, context.getAsDeclContext(),
2168-
mode == convertToResult ? CTP_ClosureResult : CTP_Unused,
2169-
mode == convertToResult ? resultType : Type(),
2170-
/*isDiscarded=*/false);
2171-
}
2172-
2173-
if (auto newResultTarget = rewriteTarget(*resultTarget)) {
2144+
auto target = *cs.getTargetFor(returnStmt);
2145+
2146+
// If we're not converting to a result, unset the contextual type.
2147+
if (mode != convertToResult) {
2148+
target.setExprConversionType(Type());
2149+
target.setExprContextualTypePurpose(CTP_Unused);
2150+
}
2151+
2152+
if (auto newResultTarget = rewriteTarget(target)) {
21742153
resultExpr = newResultTarget->getAsExpr();
21752154
}
21762155

test/IDE/complete_single_expression_return.swift

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,27 @@ struct TestExplicitSingleExprClosureBinding {
155155
return self.#^TestExplicitSingleExprClosureBinding^#
156156
}
157157
}
158-
// FIXME: Because we have an explicit return, and no expected type, we shouldn't suggest Void.
158+
// We have an explicit return, and no expected type, so we don't suggest Void.
159159
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
160160
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
161-
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: void()[#Void#];
161+
// TestExplicitSingleExprClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: void()[#Void#];
162+
}
163+
164+
struct TestExplicitMultiStmtClosureBinding {
165+
func void() -> Void {}
166+
func str() -> String { return "" }
167+
func int() -> Int { return 0 }
168+
169+
func test() {
170+
let fn = {
171+
()
172+
return self.#^TestExplicitMultiStmtClosureBinding^#
173+
}
174+
}
175+
// We have an explicit return, and no expected type, so we don't suggest Void.
176+
// TestExplicitMultiStmtClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
177+
// TestExplicitMultiStmtClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
178+
// TestExplicitMultiStmtClosureBinding-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: void()[#Void#];
162179
}
163180

164181
struct TestExplicitSingleExprClosureBindingWithContext {

0 commit comments

Comments
 (0)