[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