[silgen] Centralize SwitchEnumBuilder and SwitchCaseFullExpr into the same file: SwitchEnumBuilder.{h,cpp}.
Previously SwitchEnumBuilder was in SILGenBuilder.{h,cpp} and
SwitchEnumCaseFullExpr was in its own file. This really made no sense since:
1. The two classes are inherently related to each other so really should be
together in the source base.
2. SwitchEnumBuilder uses a SILGenBuilder, but is really a separate independent
concept/entity, so there really is no reason to keep it in SILGenBuilder.cpp.
Just a quick fix to eliminate something that was bugging me.
NFC.
diff --git a/lib/SILGen/CMakeLists.txt b/lib/SILGen/CMakeLists.txt
index 921d59a..cb130c9 100644
--- a/lib/SILGen/CMakeLists.txt
+++ b/lib/SILGen/CMakeLists.txt
@@ -7,7 +7,7 @@
ResultPlan.cpp
RValue.cpp
Scope.cpp
- SwitchCaseFullExpr.cpp
+ SwitchEnumBuilder.cpp
SILGen.cpp
SILGenApply.cpp
SILGenBridging.cpp
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index 4bf9ef2..c15aa22 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -15,7 +15,7 @@
#include "RValue.h"
#include "SILGenFunction.h"
#include "Scope.h"
-#include "SwitchCaseFullExpr.h"
+#include "SwitchEnumBuilder.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/SubstitutionMap.h"
@@ -833,120 +833,3 @@
});
return cloner.clone(createTuple(loc, type, forwardedValues));
}
-
-//===----------------------------------------------------------------------===//
-// Switch Enum Builder
-//===----------------------------------------------------------------------===//
-
-void SwitchEnumBuilder::emit() && {
- bool isAddressOnly = optional.getType().isAddressOnly(builder.getModule()) &&
- getSGF().silConv.useLoweredAddresses();
- using DeclBlockPair = std::pair<EnumElementDecl *, SILBasicBlock *>;
- {
- // TODO: We could store the data in CaseBB form and not have to do this.
- llvm::SmallVector<DeclBlockPair, 8> caseBlocks;
- llvm::SmallVector<ProfileCounter, 8> caseBlockCounts;
- std::transform(caseDataArray.begin(), caseDataArray.end(),
- std::back_inserter(caseBlocks),
- [](NormalCaseData &caseData) -> DeclBlockPair {
- return {caseData.decl, caseData.block};
- });
- std::transform(caseDataArray.begin(), caseDataArray.end(),
- std::back_inserter(caseBlockCounts),
- [](NormalCaseData &caseData) -> ProfileCounter {
- return caseData.count;
- });
- SILBasicBlock *defaultBlock =
- defaultBlockData ? defaultBlockData->block : nullptr;
- ProfileCounter defaultBlockCount =
- defaultBlockData ? defaultBlockData->count : ProfileCounter();
- ArrayRef<ProfileCounter> caseBlockCountsRef = caseBlockCounts;
- if (isAddressOnly) {
- builder.createSwitchEnumAddr(loc, optional.getValue(), defaultBlock,
- caseBlocks, caseBlockCountsRef,
- defaultBlockCount);
- } else {
- if (optional.getType().isAddress()) {
- // TODO: Refactor this into a maybe load.
- if (optional.hasCleanup()) {
- optional = builder.createLoadTake(loc, optional);
- } else {
- optional = builder.createLoadCopy(loc, optional);
- }
- }
- builder.createSwitchEnum(loc, optional.forward(getSGF()), defaultBlock,
- caseBlocks, caseBlockCountsRef,
- defaultBlockCount);
- }
- }
-
- // If we are asked to create a default block and it is specified that the
- // default block should be emitted before normal cases, emit it now.
- if (defaultBlockData &&
- defaultBlockData->dispatchTime ==
- DefaultDispatchTime::BeforeNormalCases) {
- SILBasicBlock *defaultBlock = defaultBlockData->block;
- NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
- DefaultCaseHandler handler = defaultBlockData->handler;
-
- // Don't allow cleanups to escape the conditional block.
- SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
- CleanupLocation::get(loc),
- contBB.getPtrOrNull());
- builder.emitBlock(defaultBlock);
- ManagedValue input = optional;
- if (!isAddressOnly) {
- input = builder.createOwnedPHIArgument(optional.getType());
- }
- handler(input, presentScope);
- assert(!builder.hasValidInsertionPoint());
- }
-
- for (NormalCaseData &caseData : caseDataArray) {
- EnumElementDecl *decl = caseData.decl;
- SILBasicBlock *caseBlock = caseData.block;
- NullablePtr<SILBasicBlock> contBlock = caseData.contBlock;
- NormalCaseHandler handler = caseData.handler;
-
- // Don't allow cleanups to escape the conditional block.
- SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
- CleanupLocation::get(loc),
- contBlock.getPtrOrNull());
-
- builder.emitBlock(caseBlock);
-
- ManagedValue input;
- if (decl->hasAssociatedValues()) {
- // Pull the payload out if we have one.
- SILType inputType =
- optional.getType().getEnumElementType(decl, builder.getModule());
- input = optional;
- if (!isAddressOnly) {
- input = builder.createOwnedPHIArgument(inputType);
- }
- }
- handler(input, presentScope);
- assert(!builder.hasValidInsertionPoint());
- }
-
- // If we are asked to create a default block and it is specified that the
- // default block should be emitted after normal cases, emit it now.
- if (defaultBlockData &&
- defaultBlockData->dispatchTime == DefaultDispatchTime::AfterNormalCases) {
- SILBasicBlock *defaultBlock = defaultBlockData->block;
- NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
- DefaultCaseHandler handler = defaultBlockData->handler;
-
- // Don't allow cleanups to escape the conditional block.
- SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
- CleanupLocation::get(loc),
- contBB.getPtrOrNull());
- builder.emitBlock(defaultBlock);
- ManagedValue input = optional;
- if (!isAddressOnly) {
- input = builder.createOwnedPHIArgument(optional.getType());
- }
- handler(input, presentScope);
- assert(!builder.hasValidInsertionPoint());
- }
-}
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index fa38dc2..4e27ff2e 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -372,86 +372,6 @@
ReturnInst *createReturn(SILLocation Loc, ManagedValue ReturnValue);
};
-class SwitchCaseFullExpr;
-
-/// A class for building switch enums that handles all of the ownership
-/// requirements for the user.
-///
-/// It assumes that the user passes in a block that takes in a ManagedValue and
-/// returns a ManagedValue for the blocks exit argument. Should return an empty
-/// ManagedValue to signal no result.
-class SwitchEnumBuilder {
-public:
- using NormalCaseHandler =
- std::function<void(ManagedValue, SwitchCaseFullExpr &)>;
- using DefaultCaseHandler =
- std::function<void(ManagedValue, SwitchCaseFullExpr &)>;
-
- enum class DefaultDispatchTime { BeforeNormalCases, AfterNormalCases };
-
-private:
- struct NormalCaseData {
- EnumElementDecl *decl;
- SILBasicBlock *block;
- NullablePtr<SILBasicBlock> contBlock;
- NormalCaseHandler handler;
- ProfileCounter count;
-
- NormalCaseData(EnumElementDecl *decl, SILBasicBlock *block,
- NullablePtr<SILBasicBlock> contBlock,
- NormalCaseHandler handler, ProfileCounter count)
- : decl(decl), block(block), contBlock(contBlock), handler(handler),
- count(count) {}
- ~NormalCaseData() = default;
- };
-
- struct DefaultCaseData {
- SILBasicBlock *block;
- NullablePtr<SILBasicBlock> contBlock;
- DefaultCaseHandler handler;
- DefaultDispatchTime dispatchTime;
- ProfileCounter count;
-
- DefaultCaseData(SILBasicBlock *block, NullablePtr<SILBasicBlock> contBlock,
- DefaultCaseHandler handler,
- DefaultDispatchTime dispatchTime, ProfileCounter count)
- : block(block), contBlock(contBlock), handler(handler),
- dispatchTime(dispatchTime), count(count) {}
- ~DefaultCaseData() = default;
- };
-
- SILGenBuilder &builder;
- SILLocation loc;
- ManagedValue optional;
- llvm::Optional<DefaultCaseData> defaultBlockData;
- llvm::SmallVector<NormalCaseData, 8> caseDataArray;
-
-public:
- SwitchEnumBuilder(SILGenBuilder &builder, SILLocation loc,
- ManagedValue optional)
- : builder(builder), loc(loc), optional(optional) {}
-
- void addDefaultCase(
- SILBasicBlock *defaultBlock, NullablePtr<SILBasicBlock> contBlock,
- DefaultCaseHandler handle,
- DefaultDispatchTime dispatchTime = DefaultDispatchTime::AfterNormalCases,
- ProfileCounter count = ProfileCounter()) {
- defaultBlockData.emplace(defaultBlock, contBlock, handle, dispatchTime,
- count);
- }
-
- void addCase(EnumElementDecl *decl, SILBasicBlock *caseBlock,
- NullablePtr<SILBasicBlock> contBlock, NormalCaseHandler handle,
- ProfileCounter count = ProfileCounter()) {
- caseDataArray.emplace_back(decl, caseBlock, contBlock, handle, count);
- }
-
- void emit() &&;
-
-private:
- SILGenFunction &getSGF() const { return builder.getSILGenFunction(); }
-};
-
} // namespace Lowering
} // namespace swift
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 1fd79c0..1dd9dfd 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -17,7 +17,7 @@
#include "LValue.h"
#include "RValue.h"
#include "Scope.h"
-#include "SwitchCaseFullExpr.h"
+#include "SwitchEnumBuilder.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ProtocolConformance.h"
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 06ecf6a..9597e69 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -16,7 +16,7 @@
#include "SILGen.h"
#include "SILGenDynamicCast.h"
#include "Scope.h"
-#include "SwitchCaseFullExpr.h"
+#include "SwitchEnumBuilder.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Module.h"
diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp
index 5fea55f..df40c33 100644
--- a/lib/SILGen/SILGenStmt.cpp
+++ b/lib/SILGen/SILGenStmt.cpp
@@ -16,7 +16,7 @@
#include "RValue.h"
#include "SILGen.h"
#include "Scope.h"
-#include "SwitchCaseFullExpr.h"
+#include "SwitchEnumBuilder.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/Basic/ProfileCounter.h"
#include "swift/SIL/SILArgument.h"
diff --git a/lib/SILGen/SwitchCaseFullExpr.cpp b/lib/SILGen/SwitchCaseFullExpr.cpp
deleted file mode 100644
index 32ae730..0000000
--- a/lib/SILGen/SwitchCaseFullExpr.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//===--- SwitchCaseFullExpr.cpp -------------------------------------------===//
-//
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See https://swift.org/LICENSE.txt for license information
-// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-//===----------------------------------------------------------------------===//
-
-#include "SwitchCaseFullExpr.h"
-#include "SILGenFunction.h"
-#include "Scope.h"
-#include "swift/SIL/SILLocation.h"
-
-using namespace swift;
-using namespace Lowering;
-
-SwitchCaseFullExpr::SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc,
- SILBasicBlock *contBlock)
- : SGF(SGF), scope(SGF.Cleanups, loc), loc(loc), contBlock(contBlock) {}
-
-void SwitchCaseFullExpr::exitAndBranch(SILLocation loc,
- ArrayRef<SILValue> branchArgs) {
- assert(contBlock &&
- "Should not call this if we do not have a continuation block");
- assert(SGF.B.hasValidInsertionPoint());
- scope.pop();
- SGF.B.createBranch(loc, contBlock.get(), branchArgs);
-}
-
-void SwitchCaseFullExpr::exit() {
- assert(!contBlock &&
- "Should not call this if we do have a continuation block");
- assert(SGF.B.hasValidInsertionPoint());
- scope.pop();
-}
diff --git a/lib/SILGen/SwitchCaseFullExpr.h b/lib/SILGen/SwitchCaseFullExpr.h
deleted file mode 100644
index ba025e3..0000000
--- a/lib/SILGen/SwitchCaseFullExpr.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//===--- SwitchCaseFullExpr.h -----------------------------------*- C++ -*-===//
-//
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See https://swift.org/LICENSE.txt for license information
-// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SWIFT_SILGEN_SWITCHCASEFULLEXPR_H
-#define SWIFT_SILGEN_SWITCHCASEFULLEXPR_H
-
-#include "Scope.h"
-
-namespace swift {
-namespace Lowering {
-
-class SILGenFunction;
-
-/// A cleanup scope RAII object, like FullExpr, that comes with a JumpDest for a
-/// continuation block. It is intended to be used to handle switch cases.
-///
-/// You *must* call exit() at some point.
-///
-/// This scope is also exposed to the debug info.
-class SwitchCaseFullExpr {
- SILGenFunction &SGF;
- Scope scope;
- CleanupLocation loc;
- NullablePtr<SILBasicBlock> contBlock;
-
-public:
- SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc);
- SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc,
- SILBasicBlock *contBlock);
-
- ~SwitchCaseFullExpr() = default;
-
- SwitchCaseFullExpr(const SwitchCaseFullExpr &) = delete;
- SwitchCaseFullExpr &operator=(const SwitchCaseFullExpr &) = delete;
-
- /// Pop the scope and branch to the cont block.
- void exitAndBranch(SILLocation loc, ArrayRef<SILValue> result = {});
-
- /// Pop the scope and do not branch to the cont block.
- void exit();
-};
-
-} // namespace Lowering
-} // namespace swift
-
-#endif
diff --git a/lib/SILGen/SwitchEnumBuilder.cpp b/lib/SILGen/SwitchEnumBuilder.cpp
new file mode 100644
index 0000000..935d043
--- /dev/null
+++ b/lib/SILGen/SwitchEnumBuilder.cpp
@@ -0,0 +1,159 @@
+//===--- SwitchEnumBuilder.cpp --------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "SwitchEnumBuilder.h"
+#include "SILGenFunction.h"
+#include "swift/SIL/SILLocation.h"
+
+using namespace swift;
+using namespace Lowering;
+
+//===----------------------------------------------------------------------===//
+// SwitchCaseFullExpr Implementation
+//===----------------------------------------------------------------------===//
+
+SwitchCaseFullExpr::SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc,
+ SILBasicBlock *contBlock)
+ : SGF(SGF), scope(SGF.Cleanups, loc), loc(loc), contBlock(contBlock) {}
+
+void SwitchCaseFullExpr::exitAndBranch(SILLocation loc,
+ ArrayRef<SILValue> branchArgs) {
+ assert(contBlock &&
+ "Should not call this if we do not have a continuation block");
+ assert(SGF.B.hasValidInsertionPoint());
+ scope.pop();
+ SGF.B.createBranch(loc, contBlock.get(), branchArgs);
+}
+
+void SwitchCaseFullExpr::exit() {
+ assert(!contBlock &&
+ "Should not call this if we do have a continuation block");
+ assert(SGF.B.hasValidInsertionPoint());
+ scope.pop();
+}
+
+//===----------------------------------------------------------------------===//
+// SwitchEnumBuilder Implementation
+//===----------------------------------------------------------------------===//
+
+void SwitchEnumBuilder::emit() && {
+ bool isAddressOnly = optional.getType().isAddressOnly(builder.getModule()) &&
+ getSGF().silConv.useLoweredAddresses();
+ using DeclBlockPair = std::pair<EnumElementDecl *, SILBasicBlock *>;
+ {
+ // TODO: We could store the data in CaseBB form and not have to do this.
+ llvm::SmallVector<DeclBlockPair, 8> caseBlocks;
+ llvm::SmallVector<ProfileCounter, 8> caseBlockCounts;
+ std::transform(caseDataArray.begin(), caseDataArray.end(),
+ std::back_inserter(caseBlocks),
+ [](NormalCaseData &caseData) -> DeclBlockPair {
+ return {caseData.decl, caseData.block};
+ });
+ std::transform(caseDataArray.begin(), caseDataArray.end(),
+ std::back_inserter(caseBlockCounts),
+ [](NormalCaseData &caseData) -> ProfileCounter {
+ return caseData.count;
+ });
+ SILBasicBlock *defaultBlock =
+ defaultBlockData ? defaultBlockData->block : nullptr;
+ ProfileCounter defaultBlockCount =
+ defaultBlockData ? defaultBlockData->count : ProfileCounter();
+ ArrayRef<ProfileCounter> caseBlockCountsRef = caseBlockCounts;
+ if (isAddressOnly) {
+ builder.createSwitchEnumAddr(loc, optional.getValue(), defaultBlock,
+ caseBlocks, caseBlockCountsRef,
+ defaultBlockCount);
+ } else {
+ if (optional.getType().isAddress()) {
+ // TODO: Refactor this into a maybe load.
+ if (optional.hasCleanup()) {
+ optional = builder.createLoadTake(loc, optional);
+ } else {
+ optional = builder.createLoadCopy(loc, optional);
+ }
+ }
+ builder.createSwitchEnum(loc, optional.forward(getSGF()), defaultBlock,
+ caseBlocks, caseBlockCountsRef,
+ defaultBlockCount);
+ }
+ }
+
+ // If we are asked to create a default block and it is specified that the
+ // default block should be emitted before normal cases, emit it now.
+ if (defaultBlockData &&
+ defaultBlockData->dispatchTime ==
+ DefaultDispatchTime::BeforeNormalCases) {
+ SILBasicBlock *defaultBlock = defaultBlockData->block;
+ NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
+ DefaultCaseHandler handler = defaultBlockData->handler;
+
+ // Don't allow cleanups to escape the conditional block.
+ SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
+ CleanupLocation::get(loc),
+ contBB.getPtrOrNull());
+ builder.emitBlock(defaultBlock);
+ ManagedValue input = optional;
+ if (!isAddressOnly) {
+ input = builder.createOwnedPHIArgument(optional.getType());
+ }
+ handler(input, presentScope);
+ assert(!builder.hasValidInsertionPoint());
+ }
+
+ for (NormalCaseData &caseData : caseDataArray) {
+ EnumElementDecl *decl = caseData.decl;
+ SILBasicBlock *caseBlock = caseData.block;
+ NullablePtr<SILBasicBlock> contBlock = caseData.contBlock;
+ NormalCaseHandler handler = caseData.handler;
+
+ // Don't allow cleanups to escape the conditional block.
+ SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
+ CleanupLocation::get(loc),
+ contBlock.getPtrOrNull());
+
+ builder.emitBlock(caseBlock);
+
+ ManagedValue input;
+ if (decl->hasAssociatedValues()) {
+ // Pull the payload out if we have one.
+ SILType inputType =
+ optional.getType().getEnumElementType(decl, builder.getModule());
+ input = optional;
+ if (!isAddressOnly) {
+ input = builder.createOwnedPHIArgument(inputType);
+ }
+ }
+ handler(input, presentScope);
+ assert(!builder.hasValidInsertionPoint());
+ }
+
+ // If we are asked to create a default block and it is specified that the
+ // default block should be emitted after normal cases, emit it now.
+ if (defaultBlockData &&
+ defaultBlockData->dispatchTime == DefaultDispatchTime::AfterNormalCases) {
+ SILBasicBlock *defaultBlock = defaultBlockData->block;
+ NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
+ DefaultCaseHandler handler = defaultBlockData->handler;
+
+ // Don't allow cleanups to escape the conditional block.
+ SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
+ CleanupLocation::get(loc),
+ contBB.getPtrOrNull());
+ builder.emitBlock(defaultBlock);
+ ManagedValue input = optional;
+ if (!isAddressOnly) {
+ input = builder.createOwnedPHIArgument(optional.getType());
+ }
+ handler(input, presentScope);
+ assert(!builder.hasValidInsertionPoint());
+ }
+}
diff --git a/lib/SILGen/SwitchEnumBuilder.h b/lib/SILGen/SwitchEnumBuilder.h
new file mode 100644
index 0000000..7ea05b9
--- /dev/null
+++ b/lib/SILGen/SwitchEnumBuilder.h
@@ -0,0 +1,133 @@
+//===--- SwitchEnumBuilder.h ----------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_SILGEN_SWITCHENUMBUILDER_H
+#define SWIFT_SILGEN_SWITCHENUMBUILDER_H
+
+#include "Scope.h"
+
+namespace swift {
+namespace Lowering {
+
+class SILGenFunction;
+
+/// A cleanup scope RAII object, like FullExpr, that comes with a JumpDest for a
+/// continuation block. It is intended to be used to handle switch cases.
+///
+/// You *must* call exit() at some point.
+///
+/// This scope is also exposed to the debug info.
+class SwitchCaseFullExpr {
+ SILGenFunction &SGF;
+ Scope scope;
+ CleanupLocation loc;
+ NullablePtr<SILBasicBlock> contBlock;
+
+public:
+ SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc);
+ SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc,
+ SILBasicBlock *contBlock);
+
+ ~SwitchCaseFullExpr() = default;
+
+ SwitchCaseFullExpr(const SwitchCaseFullExpr &) = delete;
+ SwitchCaseFullExpr &operator=(const SwitchCaseFullExpr &) = delete;
+
+ /// Pop the scope and branch to the cont block.
+ void exitAndBranch(SILLocation loc, ArrayRef<SILValue> result = {});
+
+ /// Pop the scope and do not branch to the cont block.
+ void exit();
+};
+
+/// A class for building switch enums that handles all of the ownership
+/// requirements for the user.
+///
+/// It assumes that the user passes in a block that takes in a ManagedValue and
+/// returns a ManagedValue for the blocks exit argument. Should return an empty
+/// ManagedValue to signal no result.
+class SwitchEnumBuilder {
+public:
+ using NormalCaseHandler =
+ std::function<void(ManagedValue, SwitchCaseFullExpr &)>;
+ using DefaultCaseHandler =
+ std::function<void(ManagedValue, SwitchCaseFullExpr &)>;
+
+ enum class DefaultDispatchTime { BeforeNormalCases, AfterNormalCases };
+
+private:
+ struct NormalCaseData {
+ EnumElementDecl *decl;
+ SILBasicBlock *block;
+ NullablePtr<SILBasicBlock> contBlock;
+ NormalCaseHandler handler;
+ ProfileCounter count;
+
+ NormalCaseData(EnumElementDecl *decl, SILBasicBlock *block,
+ NullablePtr<SILBasicBlock> contBlock,
+ NormalCaseHandler handler, ProfileCounter count)
+ : decl(decl), block(block), contBlock(contBlock), handler(handler),
+ count(count) {}
+ ~NormalCaseData() = default;
+ };
+
+ struct DefaultCaseData {
+ SILBasicBlock *block;
+ NullablePtr<SILBasicBlock> contBlock;
+ DefaultCaseHandler handler;
+ DefaultDispatchTime dispatchTime;
+ ProfileCounter count;
+
+ DefaultCaseData(SILBasicBlock *block, NullablePtr<SILBasicBlock> contBlock,
+ DefaultCaseHandler handler,
+ DefaultDispatchTime dispatchTime, ProfileCounter count)
+ : block(block), contBlock(contBlock), handler(handler),
+ dispatchTime(dispatchTime), count(count) {}
+ ~DefaultCaseData() = default;
+ };
+
+ SILGenBuilder &builder;
+ SILLocation loc;
+ ManagedValue optional;
+ llvm::Optional<DefaultCaseData> defaultBlockData;
+ llvm::SmallVector<NormalCaseData, 8> caseDataArray;
+
+public:
+ SwitchEnumBuilder(SILGenBuilder &builder, SILLocation loc,
+ ManagedValue optional)
+ : builder(builder), loc(loc), optional(optional) {}
+
+ void addDefaultCase(
+ SILBasicBlock *defaultBlock, NullablePtr<SILBasicBlock> contBlock,
+ DefaultCaseHandler handle,
+ DefaultDispatchTime dispatchTime = DefaultDispatchTime::AfterNormalCases,
+ ProfileCounter count = ProfileCounter()) {
+ defaultBlockData.emplace(defaultBlock, contBlock, handle, dispatchTime,
+ count);
+ }
+
+ void addCase(EnumElementDecl *decl, SILBasicBlock *caseBlock,
+ NullablePtr<SILBasicBlock> contBlock, NormalCaseHandler handle,
+ ProfileCounter count = ProfileCounter()) {
+ caseDataArray.emplace_back(decl, caseBlock, contBlock, handle, count);
+ }
+
+ void emit() &&;
+
+private:
+ SILGenFunction &getSGF() const { return builder.getSILGenFunction(); }
+};
+
+} // end Lowering namespace
+} // end swift namespace
+
+#endif