Skip to content

Commit 6783efd

Browse files
authored
Merge pull request #70413 from rintaro/ast-stmtcondeleemnt-pointerunion
[AST] Make `StmtConditionElement` a single `PointerIntPair`
2 parents 99f4bad + d655643 commit 6783efd

File tree

6 files changed

+135
-86
lines changed

6 files changed

+135
-86
lines changed

include/swift/AST/Stmt.h

Lines changed: 97 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,47 @@ class DeferStmt : public Stmt {
386386
static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Defer; }
387387
};
388388

389-
389+
/// Represent `let`/`var` optional binding, or `case` pattern matching in
390+
/// conditional statements (i.e. `if`, `guard`, `while`).
391+
class alignas(8) ConditionalPatternBindingInfo
392+
: public ASTAllocated<ConditionalPatternBindingInfo> {
393+
public:
394+
/// Location of the var/let/case keyword.
395+
SourceLoc IntroducerLoc;
396+
397+
/// Pattern being matched. In the case of an "implicit optional" pattern, the
398+
/// OptionalSome pattern is explicitly added to this as an 'implicit' pattern.
399+
Pattern *ThePattern;
400+
401+
/// The value for matching.
402+
Expr *Initializer;
403+
404+
ConditionalPatternBindingInfo(SourceLoc IntroducerLoc, Pattern *ThePattern,
405+
Expr *Initializer)
406+
: IntroducerLoc(IntroducerLoc), ThePattern(ThePattern),
407+
Initializer(Initializer) {}
408+
409+
public:
410+
static ConditionalPatternBindingInfo *create(ASTContext &ctx,
411+
SourceLoc IntroducerLoc,
412+
Pattern *ThePattern,
413+
Expr *Initializer) {
414+
return new (ctx)
415+
ConditionalPatternBindingInfo(IntroducerLoc, ThePattern, Initializer);
416+
}
417+
418+
SourceLoc getIntroducerLoc() const { return IntroducerLoc; }
419+
void setIntroducerLoc(SourceLoc Loc) { IntroducerLoc = Loc; }
420+
Pattern *getPattern() const { return ThePattern; }
421+
void setPattern(Pattern *P) { ThePattern = P; }
422+
Expr *getInitializer() const { return Initializer; }
423+
void setInitializer(Expr *E) { Initializer = E; }
424+
425+
SourceRange getSourceRange() const;
426+
SourceLoc getStartLoc() const { return getSourceRange().Start; };
427+
SourceLoc getEndLoc() const { return getSourceRange().End; };
428+
};
429+
390430
/// An expression that guards execution based on whether the run-time
391431
/// configuration supports a given API, e.g.,
392432
/// #available(OSX >= 10.9, iOS >= 7.0).
@@ -505,46 +545,39 @@ class PoundHasSymbolInfo final : public ASTAllocated<PoundHasSymbolInfo> {
505545
}
506546
};
507547

508-
/// This represents an entry in an "if" or "while" condition. Pattern bindings
509-
/// can bind any number of names in the pattern binding decl, and may have an
510-
/// associated where clause. When "if let" is involved, an arbitrary number of
511-
/// pattern bindings and conditional expressions are permitted, e.g.:
548+
/// This represents an entry in an "if" or "while" condition.
549+
/// Either a boolean expression, optional binding, pattern matching,
550+
/// `#available`, or `#_hasSymbol`.
512551
///
513-
/// if let x = ..., y = ... where x > y,
514-
/// let z = ...
515-
/// which would be represented as four StmtConditionElement entries, one for
516-
/// the "x" binding, one for the "y" binding, one for the where clause, one for
517-
/// "z"'s binding. A simple "if" statement is represented as a single binding.
552+
/// E.g. this 'if' statement has 5 'StmtConditionElement'.
553+
/// if
554+
/// list.count == 1, // CK_Boolean
555+
/// let firstElem = list.first, // CK_PatternBinding
556+
/// case .foo(let value?, "int") = firstElem, // CK_PatternBinding
557+
/// #available(myOS 13), // CK_Availability
558+
/// #_hasSymbol(MyStruct.peform(operation:)) // CK_HasSymbol
559+
/// { ... }
518560
///
519561
class alignas(1 << PatternAlignInBits) StmtConditionElement {
520-
/// If this is a pattern binding, it may be the first one in a declaration, in
521-
/// which case this is the location of the var/let/case keyword. If this is
522-
/// the second pattern (e.g. for 'y' in "var x = ..., y = ...") then this
523-
/// location is invalid.
524-
SourceLoc IntroducerLoc;
525-
526-
/// In a pattern binding, this is pattern being matched. In the case of an
527-
/// "implicit optional" pattern, the OptionalSome pattern is explicitly added
528-
/// to this as an 'implicit' pattern.
529-
Pattern *ThePattern = nullptr;
530-
531-
/// This is either the boolean condition, the #available information, or
532-
/// the #_hasSymbol information.
533-
llvm::PointerUnion<Expr *, PoundAvailableInfo *, PoundHasSymbolInfo *>
562+
private:
563+
llvm::PointerUnion<Expr *, ConditionalPatternBindingInfo *,
564+
PoundAvailableInfo *, PoundHasSymbolInfo *>
534565
Condition;
535566

536567
public:
537-
StmtConditionElement() {}
538-
StmtConditionElement(SourceLoc IntroducerLoc, Pattern *ThePattern, Expr *Init)
539-
: IntroducerLoc(IntroducerLoc), ThePattern(ThePattern), Condition(Init) {}
568+
StmtConditionElement() : Condition(nullptr) {}
540569
StmtConditionElement(Expr *cond) : Condition(cond) {}
541-
570+
StmtConditionElement(ConditionalPatternBindingInfo *Info) : Condition(Info) {}
542571
StmtConditionElement(PoundAvailableInfo *Info) : Condition(Info) {}
543-
544572
StmtConditionElement(PoundHasSymbolInfo *Info) : Condition(Info) {}
545573

546-
SourceLoc getIntroducerLoc() const { return IntroducerLoc; }
547-
void setIntroducerLoc(SourceLoc loc) { IntroducerLoc = loc; }
574+
static StmtConditionElement fromOpaqueValue(void *opaque) {
575+
StmtConditionElement val;
576+
val.Condition = decltype(Condition)::getFromOpaqueValue(opaque);
577+
return val;
578+
}
579+
580+
void *getOpaqueValue() const { return Condition.getOpaqueValue(); }
548581

549582
/// ConditionKind - This indicates the sort of condition this is.
550583
enum ConditionKind {
@@ -555,20 +588,19 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
555588
};
556589

557590
ConditionKind getKind() const {
558-
if (ThePattern)
559-
return CK_PatternBinding;
560591
if (Condition.is<Expr *>())
561592
return CK_Boolean;
593+
if (Condition.is<ConditionalPatternBindingInfo *>())
594+
return CK_PatternBinding;
562595
if (Condition.is<PoundAvailableInfo *>())
563596
return CK_Availability;
564-
assert(Condition.is<PoundHasSymbolInfo *>());
565-
return CK_HasSymbol;
597+
if (Condition.is<PoundHasSymbolInfo *>())
598+
return CK_HasSymbol;
599+
return CK_Boolean;
566600
}
567601

568602
/// Boolean Condition Accessors.
569-
Expr *getBooleanOrNull() const {
570-
return getKind() == CK_Boolean ? Condition.get<Expr *>() : nullptr;
571-
}
603+
Expr *getBooleanOrNull() const { return Condition.dyn_cast<Expr *>(); }
572604

573605
Expr *getBoolean() const {
574606
assert(getKind() == CK_Boolean && "Not a condition");
@@ -580,35 +612,43 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
580612
}
581613

582614
/// Pattern Binding Accessors.
583-
Pattern *getPatternOrNull() const {
584-
return ThePattern;
615+
ConditionalPatternBindingInfo *getPatternBindingOrNull() const {
616+
return Condition.dyn_cast<ConditionalPatternBindingInfo *>();
585617
}
586618

587-
Pattern *getPattern() const {
619+
ConditionalPatternBindingInfo *getPatternBinding() const {
588620
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
589-
return ThePattern;
621+
return Condition.get<ConditionalPatternBindingInfo *>();
590622
}
591623

592-
void setPattern(Pattern *P) {
593-
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
594-
ThePattern = P;
624+
SourceLoc getIntroducerLoc() const {
625+
return getPatternBinding()->getIntroducerLoc();
595626
}
596-
597-
/// Pattern Binding Accessors.
598-
Expr *getInitializerOrNull() const {
599-
return getKind() == CK_PatternBinding ? Condition.get<Expr *>() : nullptr;
627+
628+
void setIntroducerLoc(SourceLoc loc) {
629+
getPatternBinding()->setIntroducerLoc(loc);
600630
}
601631

602-
Expr *getInitializer() const {
603-
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
604-
return Condition.get<Expr *>();
632+
Pattern *getPatternOrNull() const {
633+
if (auto *binding = getPatternBindingOrNull())
634+
return binding->getPattern();
635+
return nullptr;
605636
}
606-
607-
void setInitializer(Expr *E) {
608-
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
609-
Condition = E;
637+
638+
Pattern *getPattern() const { return getPatternBinding()->getPattern(); }
639+
640+
void setPattern(Pattern *P) { getPatternBinding()->setPattern(P); }
641+
642+
Expr *getInitializerOrNull() const {
643+
if (auto *binding = getPatternBindingOrNull())
644+
return binding->getInitializer();
645+
return nullptr;
610646
}
611-
647+
648+
Expr *getInitializer() const { return getPatternBinding()->getInitializer(); }
649+
650+
void setInitializer(Expr *E) { getPatternBinding()->setInitializer(E); }
651+
612652
// Availability Accessors
613653
PoundAvailableInfo *getAvailability() const {
614654
assert(getKind() == CK_Availability && "Not an #available condition");

lib/AST/Stmt.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,21 @@ bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
571571
return false;
572572
}
573573

574+
SourceRange ConditionalPatternBindingInfo::getSourceRange() const {
575+
SourceLoc Start;
576+
if (IntroducerLoc.isValid())
577+
Start = IntroducerLoc;
578+
else
579+
Start = ThePattern->getStartLoc();
580+
581+
SourceLoc End = Initializer->getEndLoc();
582+
if (Start.isValid() && End.isValid()) {
583+
return SourceRange(Start, End);
584+
} else {
585+
return SourceRange();
586+
}
587+
}
588+
574589
PoundAvailableInfo *
575590
PoundAvailableInfo::create(ASTContext &ctx, SourceLoc PoundLoc,
576591
SourceLoc LParenLoc,
@@ -603,18 +618,7 @@ SourceRange StmtConditionElement::getSourceRange() const {
603618
case StmtConditionElement::CK_HasSymbol:
604619
return getHasSymbolInfo()->getSourceRange();
605620
case StmtConditionElement::CK_PatternBinding:
606-
SourceLoc Start;
607-
if (IntroducerLoc.isValid())
608-
Start = IntroducerLoc;
609-
else
610-
Start = getPattern()->getStartLoc();
611-
612-
SourceLoc End = getInitializer()->getEndLoc();
613-
if (Start.isValid() && End.isValid()) {
614-
return SourceRange(Start, End);
615-
} else {
616-
return SourceRange();
617-
}
621+
return getPatternBinding()->getSourceRange();
618622
}
619623

620624
llvm_unreachable("Unhandled StmtConditionElement in switch.");
@@ -636,7 +640,7 @@ SourceLoc StmtConditionElement::getStartLoc() const {
636640
case StmtConditionElement::CK_Availability:
637641
return getAvailability()->getStartLoc();
638642
case StmtConditionElement::CK_PatternBinding:
639-
return getSourceRange().Start;
643+
return getPatternBinding()->getStartLoc();
640644
case StmtConditionElement::CK_HasSymbol:
641645
return getHasSymbolInfo()->getStartLoc();
642646
}
@@ -651,7 +655,7 @@ SourceLoc StmtConditionElement::getEndLoc() const {
651655
case StmtConditionElement::CK_Availability:
652656
return getAvailability()->getEndLoc();
653657
case StmtConditionElement::CK_PatternBinding:
654-
return getSourceRange().End;
658+
return getPatternBinding()->getEndLoc();
655659
case StmtConditionElement::CK_HasSymbol:
656660
return getHasSymbolInfo()->getEndLoc();
657661
}

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,8 @@ Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
18621862
ErrorExpr(ThePattern.get()->getEndLoc()));
18631863
}
18641864

1865-
result.push_back({IntroducerLoc, ThePattern.get(), Init.get()});
1865+
result.push_back(ConditionalPatternBindingInfo::create(
1866+
Context, IntroducerLoc, ThePattern.get(), Init.get()));
18661867
return Status;
18671868
}
18681869

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,8 +1676,8 @@ deriveBodyDecodable_enum_init(AbstractFunctionDecl *initDecl, void *) {
16761676
C, VarDecl::Introducer::Let,
16771677
NamedPattern::createImplicit(C, theKeyDecl));
16781678

1679-
guardElements.emplace_back(SourceLoc(), theKeyPattern,
1680-
allKeysPopFirstCallExpr);
1679+
guardElements.emplace_back(ConditionalPatternBindingInfo::create(
1680+
C, SourceLoc(), theKeyPattern, allKeysPopFirstCallExpr));
16811681

16821682
// generate: allKeys.isEmpty;
16831683
auto *allKeysIsEmptyExpr =

lib/Sema/TypeCheckStorage.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1644,7 +1644,8 @@ synthesizeLazyGetterBody(AccessorDecl *Get, VarDecl *VD, VarDecl *Storage,
16441644
createPropertyLoadOrCallSuperclassGetter(Get, Storage,
16451645
TargetImpl::Storage, Ctx);
16461646
SmallVector<StmtConditionElement, 1> Cond;
1647-
Cond.emplace_back(SourceLoc(), Some, StoredValueExpr);
1647+
Cond.emplace_back(ConditionalPatternBindingInfo::create(
1648+
Ctx, SourceLoc(), Some, StoredValueExpr));
16481649

16491650
// Build the early return inside the if.
16501651
auto *Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, DeclNameLoc(), /*Implicit*/true,

unittests/AST/SourceLocTests.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,36 +162,39 @@ TEST(SourceLoc, StmtConditionElement) {
162162
, false);
163163

164164
// Case a, when the IntroducerLoc is valid.
165-
auto introducer = StmtConditionElement( start.getAdvancedLoc(3)
166-
, pattern, init);
167-
165+
auto introducer = StmtConditionElement(ConditionalPatternBindingInfo::create(
166+
C.Ctx, start.getAdvancedLoc(3), pattern, init));
167+
168168
EXPECT_EQ(start.getAdvancedLoc(3), introducer.getStartLoc());
169169
EXPECT_EQ(start.getAdvancedLoc(25), introducer.getEndLoc());
170170
EXPECT_EQ( SourceRange(start.getAdvancedLoc(3), start.getAdvancedLoc(25))
171171
, introducer.getSourceRange());
172172

173173
// Case b, when the IntroducerLoc is invalid, but the pattern has a valid loc.
174-
auto patternStmtCond = StmtConditionElement(SourceLoc(), pattern, init);
175-
174+
auto patternStmtCond = StmtConditionElement(
175+
ConditionalPatternBindingInfo::create(C.Ctx, SourceLoc(), pattern, init));
176+
176177
EXPECT_EQ(start.getAdvancedLoc(7), patternStmtCond.getStartLoc());
177178
EXPECT_EQ(start.getAdvancedLoc(25), patternStmtCond.getEndLoc());
178179
EXPECT_EQ( SourceRange(start.getAdvancedLoc(7), start.getAdvancedLoc(25))
179180
, patternStmtCond.getSourceRange());
180181

181182
// If the IntroducerLoc is valid but the stmt cond init is invalid.
182183
auto invalidInit = new (C.Ctx) IntegerLiteralExpr("1", SourceLoc(), false);
183-
auto introducerStmtInvalid = StmtConditionElement( start.getAdvancedLoc(3)
184-
, pattern, invalidInit);
185-
184+
auto introducerStmtInvalid =
185+
StmtConditionElement(ConditionalPatternBindingInfo::create(
186+
C.Ctx, start.getAdvancedLoc(3), pattern, invalidInit));
187+
186188
EXPECT_EQ(SourceLoc(), introducerStmtInvalid.getStartLoc());
187189
EXPECT_EQ(SourceLoc(), introducerStmtInvalid.getEndLoc());
188190
EXPECT_EQ(SourceRange(), introducerStmtInvalid.getSourceRange());
189191

190192
// If the IntroducerLoc is invalid, the pattern is valid, but the stmt cond
191193
// init is invalid.
192-
auto patternStmtInvalid = StmtConditionElement( SourceLoc(), pattern
193-
, invalidInit);
194-
194+
auto patternStmtInvalid =
195+
StmtConditionElement(ConditionalPatternBindingInfo::create(
196+
C.Ctx, SourceLoc(), pattern, invalidInit));
197+
195198
EXPECT_EQ(SourceLoc(), patternStmtInvalid.getStartLoc());
196199
EXPECT_EQ(SourceLoc(), patternStmtInvalid.getEndLoc());
197200
EXPECT_EQ(SourceRange(), patternStmtInvalid.getSourceRange());

0 commit comments

Comments
 (0)