Skip to content

Commit d655643

Browse files
committed
[AST] Make 'StmtConditionElement' a single 'PointerUnion'
Previously, 'IntroducerLoc' and 'ThePattern' were only used for pattern binidng cases. Create a new 'ConditionalPatternBindingInfo' type to cover such cases, and make 'StmtConditionElement' a pure 'PointerUnion' type. This makes it clear which fields are used in which condition kind. Also, we can expect overall size reduction of StmtCondition when the majority of the conditions are simple boolean expressions.
1 parent b9f7acb commit d655643

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)