[AST] Introduce CaseStmt::createImplicit

This allows us to re-use the same logic to create the case body
variables.
This commit is contained in:
Hamish Knight
2025-09-09 13:48:40 +01:00
parent 245e2874ae
commit c02c69a783
9 changed files with 55 additions and 131 deletions

View File

@@ -1243,13 +1243,17 @@ public:
ArrayRef<CaseLabelItem> CaseLabelItems,
BraceStmt *Body);
static CaseStmt *
createImplicit(ASTContext &ctx, CaseParentKind parentKind,
ArrayRef<CaseLabelItem> caseLabelItems, BraceStmt *body,
NullablePtr<FallthroughStmt> fallthroughStmt = nullptr);
static CaseStmt *
create(ASTContext &C, CaseParentKind ParentKind, SourceLoc ItemIntroducerLoc,
ArrayRef<CaseLabelItem> CaseLabelItems, SourceLoc UnknownAttrLoc,
SourceLoc ItemTerminatorLoc, BraceStmt *Body,
ArrayRef<VarDecl *> CaseBodyVariables,
std::optional<bool> Implicit = std::nullopt,
NullablePtr<FallthroughStmt> fallthroughStmt = nullptr);
ArrayRef<VarDecl *> CaseBodyVariables, std::optional<bool> Implicit,
NullablePtr<FallthroughStmt> fallthroughStmt);
CaseParentKind getParentKind() const { return ParentKind; }

View File

@@ -897,10 +897,22 @@ CaseStmt *CaseStmt::createParsedDoCatch(ASTContext &ctx, SourceLoc catchLoc,
}
CaseStmt *
CaseStmt::create(ASTContext &ctx, CaseParentKind ParentKind, SourceLoc caseLoc,
CaseStmt::createImplicit(ASTContext &ctx, CaseParentKind parentKind,
ArrayRef<CaseLabelItem> caseLabelItems,
SourceLoc unknownAttrLoc, SourceLoc colonLoc, BraceStmt *body,
ArrayRef<VarDecl *> caseVarDecls, std::optional<bool> implicit,
BraceStmt *body,
NullablePtr<FallthroughStmt> fallthroughStmt) {
auto caseVarDecls = getCaseVarDecls(ctx, caseLabelItems);
return create(ctx, parentKind, /*catchLoc*/ SourceLoc(), caseLabelItems,
/*unknownAttrLoc*/ SourceLoc(), /*colonLoc*/ SourceLoc(), body,
caseVarDecls, /*implicit*/ true, fallthroughStmt);
}
CaseStmt *CaseStmt::create(ASTContext &ctx, CaseParentKind ParentKind,
SourceLoc caseLoc,
ArrayRef<CaseLabelItem> caseLabelItems,
SourceLoc unknownAttrLoc, SourceLoc colonLoc,
BraceStmt *body, ArrayRef<VarDecl *> caseVarDecls,
std::optional<bool> implicit,
NullablePtr<FallthroughStmt> fallthroughStmt) {
void *mem =
ctx.Allocate(totalSizeToAlloc<FallthroughStmt *, CaseLabelItem>(

View File

@@ -805,9 +805,8 @@ DeclRefExpr *DerivedConformance::convertEnumToIndex(SmallVectorImpl<ASTNode> &st
assignExpr->setType(TupleType::getEmpty(C));
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(assignExpr),
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(), body,
/*case body vardecls*/ std::nullopt));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body));
}
// generate: switch enumVar { }
@@ -967,9 +966,7 @@ CaseStmt *DerivedConformance::unavailableEnumElementCaseStmt(
auto *callExpr =
DerivedConformance::createDiagnoseUnavailableCodeReachedCallExpr(C);
auto body = BraceStmt::create(C, SourceLoc(), {callExpr}, SourceLoc());
return CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(), labelItem,
SourceLoc(), SourceLoc(), body, {},
/*implicit*/ true);
return CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body);
}
/// Creates a named variable based on a prefix character and a numeric index.

View File

@@ -946,27 +946,10 @@ createEnumSwitch(ASTContext &C, DeclContext *DC, Expr *expr, EnumDecl *enumDecl,
// .<elt>(let a0, let a1, ...)
SmallVector<VarDecl *, 3> payloadVars;
Pattern *subpattern = nullptr;
ArrayRef<VarDecl *> caseBodyVarDecls;
if (createSubpattern) {
subpattern = DerivedConformance::enumElementPayloadSubpattern(
elt, 'a', DC, payloadVars, /* useLabels */ true);
auto hasBoundDecls = !payloadVars.empty();
if (hasBoundDecls) {
// We allocated a direct copy of our var decls for the case
// body.
auto copy = C.Allocate<VarDecl *>(payloadVars.size());
for (unsigned i : indices(payloadVars)) {
auto *vOld = payloadVars[i];
auto *vNew = new (C) VarDecl(
/*IsStatic*/ false, vOld->getIntroducer(), vOld->getNameLoc(),
vOld->getName(), vOld->getDeclContext());
vNew->setImplicit();
copy[i] = vNew;
}
caseBodyVarDecls = copy;
}
}
// CodingKeys.x
@@ -985,10 +968,8 @@ createEnumSwitch(ASTContext &C, DeclContext *DC, Expr *expr, EnumDecl *enumDecl,
subpattern, DC);
auto labelItem = CaseLabelItem(pat);
auto stmt =
CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(), labelItem,
SourceLoc(), SourceLoc(), caseBody,
caseBodyVarDecls);
auto stmt = CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem,
caseBody);
cases.push_back(stmt);
}
}

View File

@@ -222,10 +222,8 @@ deriveBodyCodingKey_enum_stringValue(AbstractFunctionDecl *strValDecl, void *) {
auto *returnStmt = ReturnStmt::createImplicit(C, caseValue);
auto *caseBody = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(),
caseBody,
/*case body var decls*/ std::nullopt));
cases.push_back(CaseStmt::createImplicit(C, CaseParentKind::Switch,
labelItem, caseBody));
}
auto *selfRef = DerivedConformance::createSelfDeclRef(strValDecl);
@@ -292,9 +290,8 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl, void *) {
auto *body = BraceStmt::create(C, SourceLoc(), ASTNode(assignment),
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(), body,
/*case body var decls*/ std::nullopt));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body));
}
auto *anyPat = AnyPattern::createImplicit(C);
@@ -303,10 +300,8 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl, void *) {
auto *dfltReturnStmt = new (C) FailStmt(SourceLoc(), SourceLoc());
auto *dfltBody = BraceStmt::create(C, SourceLoc(), ASTNode(dfltReturnStmt),
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
dfltLabelItem, SourceLoc(), SourceLoc(),
dfltBody,
/*case body var decls*/ std::nullopt));
cases.push_back(CaseStmt::createImplicit(C, CaseParentKind::Switch,
dfltLabelItem, dfltBody));
auto *stringValueDecl = initDecl->getParameters()->get(0);
auto *stringValueRef = new (C) DeclRefExpr(stringValueDecl, DeclNameLoc(),

View File

@@ -127,23 +127,6 @@ deriveBodyComparable_enum_hasAssociatedValues_lt(AbstractFunctionDecl *ltDecl, v
auto *rhsElemPat = EnumElementPattern::createImplicit(
enumType, elt, rhsSubpattern, /*DC*/ ltDecl);
auto hasBoundDecls = !lhsPayloadVars.empty();
ArrayRef<VarDecl *> caseBodyVarDecls;
if (hasBoundDecls) {
// We allocated a direct copy of our lhs var decls for the case
// body.
auto copy = C.Allocate<VarDecl *>(lhsPayloadVars.size());
for (unsigned i : indices(lhsPayloadVars)) {
auto *vOld = lhsPayloadVars[i];
auto *vNew = new (C) VarDecl(
/*IsStatic*/ false, vOld->getIntroducer(),
vOld->getNameLoc(), vOld->getName(), vOld->getDeclContext());
vNew->setImplicit();
copy[i] = vNew;
}
caseBodyVarDecls = copy;
}
// case (.<elt>(let l0, let l1, ...), .<elt>(let r0, let r1, ...))
auto caseTuplePattern = TuplePattern::createImplicit(C, {
TuplePatternElt(lhsElemPat), TuplePatternElt(rhsElemPat) });
@@ -177,9 +160,8 @@ deriveBodyComparable_enum_hasAssociatedValues_lt(AbstractFunctionDecl *ltDecl, v
auto body = BraceStmt::create(C, SourceLoc(), statementsInCase,
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(), body,
caseBodyVarDecls));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body));
}
// default: result = <enum index>(lhs) < <enum index>(rhs)
@@ -190,10 +172,8 @@ deriveBodyComparable_enum_hasAssociatedValues_lt(AbstractFunctionDecl *ltDecl, v
auto defaultPattern = AnyPattern::createImplicit(C);
auto defaultItem = CaseLabelItem::getDefault(defaultPattern);
auto body = deriveBodyComparable_enum_noAssociatedValues_lt(ltDecl, nullptr).first;
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
defaultItem, SourceLoc(), SourceLoc(),
body,
/*case body var decls*/ std::nullopt));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, defaultItem, body));
}
// switch (a, b) { <case statements> }

View File

@@ -193,23 +193,6 @@ deriveBodyEquatable_enum_hasAssociatedValues_eq(AbstractFunctionDecl *eqDecl,
auto *rhsElemPat = EnumElementPattern::createImplicit(
enumType, elt, rhsSubpattern, /*DC*/ eqDecl);
auto hasBoundDecls = !lhsPayloadVars.empty();
ArrayRef<VarDecl *> caseBodyVarDecls;
if (hasBoundDecls) {
// We allocated a direct copy of our lhs var decls for the case
// body.
auto copy = C.Allocate<VarDecl *>(lhsPayloadVars.size());
for (unsigned i : indices(lhsPayloadVars)) {
auto *vOld = lhsPayloadVars[i];
auto *vNew = new (C) VarDecl(
/*IsStatic*/ false, vOld->getIntroducer(),
vOld->getNameLoc(), vOld->getName(), vOld->getDeclContext());
vNew->setImplicit();
copy[i] = vNew;
}
caseBodyVarDecls = copy;
}
// case (.<elt>(let l0, let l1, ...), .<elt>(let r0, let r1, ...))
auto caseTuplePattern = TuplePattern::createImplicit(C, {
TuplePatternElt(lhsElemPat), TuplePatternElt(rhsElemPat) });
@@ -244,9 +227,8 @@ deriveBodyEquatable_enum_hasAssociatedValues_eq(AbstractFunctionDecl *eqDecl,
auto body = BraceStmt::create(C, SourceLoc(), statementsInCase,
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(), body,
caseBodyVarDecls));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body));
}
// default: result = false
@@ -261,10 +243,8 @@ deriveBodyEquatable_enum_hasAssociatedValues_eq(AbstractFunctionDecl *eqDecl,
auto *returnStmt = ReturnStmt::createImplicit(C, falseExpr);
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
defaultItem, SourceLoc(), SourceLoc(),
body,
/*case body var decls*/ std::nullopt));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, defaultItem, body));
}
// switch (a, b) { <case statements> }
@@ -735,26 +715,9 @@ deriveBodyHashable_enum_hasAssociatedValues_hashInto(
statements.emplace_back(ASTNode(combineExpr));
}
auto hasBoundDecls = !payloadVars.empty();
ArrayRef<VarDecl *> caseBodyVarDecls;
if (hasBoundDecls) {
auto copy = C.Allocate<VarDecl *>(payloadVars.size());
for (unsigned i : indices(payloadVars)) {
auto *vOld = payloadVars[i];
auto *vNew = new (C) VarDecl(
/*IsStatic*/ false, vOld->getIntroducer(),
vOld->getNameLoc(), vOld->getName(), vOld->getDeclContext());
vNew->setImplicit();
copy[i] = vNew;
}
caseBodyVarDecls = copy;
}
auto body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(), body,
caseBodyVarDecls,
/*implicit*/ true));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body));
}
// generate: switch enumVar { }

View File

@@ -129,9 +129,8 @@ deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl, void *) {
auto body = BraceStmt::create(C, SourceLoc(),
ASTNode(returnStmt), SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
labelItem, SourceLoc(), SourceLoc(), body,
/*case body var decls*/ std::nullopt));
cases.push_back(
CaseStmt::createImplicit(C, CaseParentKind::Switch, labelItem, body));
}
auto selfRef = DerivedConformance::createSelfDeclRef(toRawDecl);
@@ -363,10 +362,8 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
stmts, SourceLoc());
// cases.append("case \(litPat): \(body)")
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
CaseLabelItem(litPat), SourceLoc(),
SourceLoc(), body,
/*case body var decls*/ std::nullopt));
cases.push_back(CaseStmt::createImplicit(C, CaseParentKind::Switch,
CaseLabelItem(litPat), body));
++Idx;
}
@@ -376,10 +373,8 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
auto dfltReturnStmt = new (C) FailStmt(SourceLoc(), SourceLoc());
auto dfltBody = BraceStmt::create(C, SourceLoc(),
ASTNode(dfltReturnStmt), SourceLoc());
cases.push_back(CaseStmt::create(C, CaseParentKind::Switch, SourceLoc(),
dfltLabelItem, SourceLoc(), SourceLoc(),
dfltBody,
/*case body var decls*/ std::nullopt));
cases.push_back(CaseStmt::createImplicit(C, CaseParentKind::Switch,
dfltLabelItem, dfltBody));
auto rawDecl = initDecl->getParameters()->get(0);
auto rawRef = new (C) DeclRefExpr(rawDecl, DeclNameLoc(), /*implicit*/true);

View File

@@ -286,10 +286,8 @@ TEST_F(SemaTest, TestSwitchExprLocator) {
{IntegerLiteralExpr::createFromUnsigned(Context, 1, SourceLoc())});
auto *truePattern = ExprPattern::createImplicit(
Context, new (Context) BooleanLiteralExpr(true, SourceLoc()), DC);
auto *trueCase =
CaseStmt::create(Context, CaseParentKind::Switch, SourceLoc(),
{CaseLabelItem(truePattern)}, SourceLoc(), SourceLoc(),
trueBrace, /*caseBodyVars*/ std::nullopt);
auto *trueCase = CaseStmt::createImplicit(
Context, CaseParentKind::Switch, {CaseLabelItem(truePattern)}, trueBrace);
// case false: 2
auto *falseBrace = BraceStmt::createImplicit(
@@ -298,9 +296,8 @@ TEST_F(SemaTest, TestSwitchExprLocator) {
auto *falsePattern = ExprPattern::createImplicit(
Context, new (Context) BooleanLiteralExpr(false, SourceLoc()), DC);
auto *falseCase =
CaseStmt::create(Context, CaseParentKind::Switch, SourceLoc(),
{CaseLabelItem(falsePattern)}, SourceLoc(), SourceLoc(),
falseBrace, /*caseBodyVars*/ std::nullopt);
CaseStmt::createImplicit(Context, CaseParentKind::Switch,
{CaseLabelItem(falsePattern)}, falseBrace);
auto *subject = new (Context) BooleanLiteralExpr(true, SourceLoc());