Merge pull request #71272 from hamishknight/cleanup-return

[CS] Unify ReturnStmt handling
This commit is contained in:
Hamish Knight
2024-02-01 01:25:08 +00:00
committed by GitHub
8 changed files with 105 additions and 76 deletions

View File

@@ -491,7 +491,7 @@ struct SyntacticElementContext
}
}
bool isSingleExpressionClosure(ConstraintSystem &cs) {
bool isSingleExpressionClosure(ConstraintSystem &cs) const {
if (auto ref = getAsAnyFunctionRef()) {
if (cs.getAppliedResultBuilderTransform(*ref))
return false;
@@ -1121,8 +1121,8 @@ private:
for (auto node : braceStmt->getElements()) {
if (auto expr = node.dyn_cast<Expr *>()) {
auto generatedExpr = cs.generateConstraints(
expr, context.getAsDeclContext(), /*isInputExpression=*/false);
auto generatedExpr =
cs.generateConstraints(expr, context.getAsDeclContext());
if (!generatedExpr) {
hadError = true;
}
@@ -1248,33 +1248,7 @@ private:
}
void visitReturnStmt(ReturnStmt *returnStmt) {
// Single-expression closures are effectively a `return` statement,
// so let's give them a special locator as to indicate that.
// Return statements might not have a result if we have a closure whose
// implicit returned value is coerced to Void.
if (context.isSingleExpressionClosure(cs) && returnStmt->hasResult()) {
auto *expr = returnStmt->getResult();
assert(expr && "single expression closure without expression?");
expr = cs.generateConstraints(expr, context.getAsDeclContext(),
/*isInputExpression=*/false);
if (!expr) {
hadError = true;
return;
}
auto contextualResultInfo = getContextualResultInfo();
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
contextualResultInfo.getType(),
cs.getConstraintLocator(
context.getAsAbstractClosureExpr().get(),
LocatorPathElt::ClosureBody(
/*hasImpliedReturn=*/returnStmt->isImplied())));
return;
}
Expr *resultExpr;
if (returnStmt->hasResult()) {
resultExpr = returnStmt->getResult();
assert(resultExpr && "non-empty result without expression?");
@@ -1286,10 +1260,10 @@ private:
resultExpr = getVoidExpr(cs.getASTContext(), returnStmt->getEndLoc());
}
auto contextualResultInfo = getContextualResultInfo();
auto contextualResultInfo = getContextualResultInfoFor(returnStmt);
SyntacticElementTarget target(resultExpr, context.getAsDeclContext(),
contextualResultInfo,
/*isDiscarded=*/false);
contextualResultInfo, /*isDiscarded=*/false);
if (cs.generateConstraints(target)) {
hadError = true;
@@ -1334,7 +1308,7 @@ private:
createConjunction({resultElt}, locator);
}
ContextualTypeInfo getContextualResultInfo() const {
ContextualTypeInfo getContextualResultInfoFor(ReturnStmt *returnStmt) const {
auto funcRef = AnyFunctionRef::fromDeclContext(context.getAsDeclContext());
if (!funcRef)
return {Type(), CTP_Unused};
@@ -1343,8 +1317,18 @@ private:
return {transform->bodyResultType, CTP_ReturnStmt};
if (auto *closure =
getAsExpr<ClosureExpr>(funcRef->getAbstractClosureExpr()))
return {cs.getClosureType(closure)->getResult(), CTP_ClosureResult};
getAsExpr<ClosureExpr>(funcRef->getAbstractClosureExpr())) {
// Single-expression closures need their contextual type locator anchored
// on the closure itself. Otherwise we use the default contextual type
// locator, which will be created for us.
ConstraintLocator *loc = nullptr;
if (context.isSingleExpressionClosure(cs) && returnStmt->hasResult()) {
loc = cs.getConstraintLocator(
closure, {LocatorPathElt::ClosureBody(
/*hasImpliedReturn=*/returnStmt->isImplied())});
}
return {cs.getClosureType(closure)->getResult(), CTP_ClosureResult, loc};
}
return {funcRef->getBodyResultType(), CTP_ReturnStmt};
}
@@ -2162,22 +2146,15 @@ private:
mode = convertToResult;
}
llvm::Optional<SyntacticElementTarget> resultTarget;
if (auto target = cs.getTargetFor(returnStmt)) {
resultTarget = *target;
} else {
// Single-expression closures have to handle returns in a special
// way so the target has to be created for them during solution
// application based on the resolved type.
assert(context.isSingleExpressionClosure(cs));
resultTarget = SyntacticElementTarget(
resultExpr, context.getAsDeclContext(),
mode == convertToResult ? CTP_ClosureResult : CTP_Unused,
mode == convertToResult ? resultType : Type(),
/*isDiscarded=*/false);
auto target = *cs.getTargetFor(returnStmt);
// If we're not converting to a result, unset the contextual type.
if (mode != convertToResult) {
target.setExprConversionType(Type());
target.setExprContextualTypePurpose(CTP_Unused);
}
if (auto newResultTarget = rewriteTarget(*resultTarget)) {
if (auto newResultTarget = rewriteTarget(target)) {
resultExpr = newResultTarget->getAsExpr();
}