Merge pull request #7256 from practicalswift/swiftc-28680-swift-typebase-getdesugaredtype

[swiftc (42 vs. 5451)] Add crasher in swift::TypeBase::getDesugaredType(...)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d66418c..b0adc8b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -149,6 +149,10 @@
 set(SWIFT_PARALLEL_LINK_JOBS "" CACHE STRING
   "Define the maximum number of linker jobs for swift.")
 
+option(SWIFT_FORCE_OPTIMIZED_TYPECHECKER "Override the optimization setting of
+  the type checker so that it always compiles with optimization. This eases
+  debugging after type checking occurs by speeding up type checking" FALSE)
+
 #
 # User-configurable Android specific options.
 #
@@ -333,11 +337,14 @@
     find_version("${SWIFT_PATH_TO_CMARK_BUILD}/src/cmark" "--version" FALSE)
   endif()
 
-  find_version(${CMAKE_C_COMPILER} "--version" FALSE)
-  find_version(${CMAKE_CXX_COMPILER} "--version" FALSE)
-endfunction()
+  message(STATUS "Finding version for: ${CMAKE_C_COMPILER}")
+  message(STATUS "Found version: ${CMAKE_C_COMPILER_VERSION}")
+  message(STATUS "")
 
-print_versions()
+  message(STATUS "Finding version for: ${CMAKE_CXX_COMPILER}")
+  message(STATUS "Found version: ${CMAKE_CXX_COMPILER_VERSION}")
+  message(STATUS "")
+endfunction()
 
 
 set(SWIFT_BUILT_STANDALONE FALSE)
@@ -381,6 +388,9 @@
 include(CheckCXXSourceRuns)
 include(CMakeParseArguments)
 include(CMakePushCheckState)
+
+print_versions()
+
 include(SwiftComponents)
 include(SwiftHandleGybSources)
 include(SwiftSetIfArchBitness)
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 7d83add..12eeb15 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -165,7 +165,7 @@
     DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS
     RESULT_VAR_NAME ENABLE_LTO)
   cmake_parse_arguments(CFLAGS
-    ""
+    "FORCE_BUILD_OPTIMIZED"
     "${oneValueArgs}"
     ""
     ${ARGN})
@@ -186,7 +186,7 @@
     RESULT_VAR_NAME result)
 
   is_build_type_optimized("${CFLAGS_BUILD_TYPE}" optimized)
-  if(optimized)
+  if(optimized OR CFLAGS_FORCE_BUILD_OPTIMIZED)
     list(APPEND result "-O2")
 
     # Add -momit-leaf-frame-pointer on x86.
@@ -196,7 +196,6 @@
   else()
     list(APPEND result "-O0")
   endif()
-
   is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debuginfo)
   if(debuginfo)
     _compute_lto_flag("${CFLAGS_ENABLE_LTO}" _lto_flag_out)
@@ -495,6 +494,7 @@
 #     [FILE_DEPENDS target1 ...]
 #     [DONT_EMBED_BITCODE]
 #     [IS_STDLIB]
+#     [FORCE_BUILD_OPTIMIZED]
 #     [IS_STDLIB_CORE]
 #     [IS_SDK_OVERLAY]
 #     [FORCE_BUILD_FOR_HOST_SDK]
@@ -576,7 +576,7 @@
   set(SWIFTLIB_SINGLE_options
       SHARED STATIC OBJECT_LIBRARY IS_STDLIB IS_STDLIB_CORE IS_SDK_OVERLAY
       TARGET_LIBRARY FORCE_BUILD_FOR_HOST_SDK
-      API_NOTES_NON_OVERLAY DONT_EMBED_BITCODE)
+      API_NOTES_NON_OVERLAY DONT_EMBED_BITCODE FORCE_BUILD_OPTIMIZED)
   cmake_parse_arguments(SWIFTLIB_SINGLE
     "${SWIFTLIB_SINGLE_options}"
     "MODULE_TARGET;SDK;ARCHITECTURE;INSTALL_IN_COMPONENT;DEPLOYMENT_VERSION_OSX;DEPLOYMENT_VERSION_IOS;DEPLOYMENT_VERSION_TVOS;DEPLOYMENT_VERSION_WATCHOS"
@@ -802,10 +802,14 @@
   _set_target_prefix_and_suffix("${target}" "${libkind}" "${SWIFTLIB_SINGLE_SDK}")
 
   if(SWIFTLIB_SINGLE_TARGET_LIBRARY)
-    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "")
+    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/include" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include")
       target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}")
     endif()
-    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "")
+    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/include" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include")
       target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}")
     endif()
   endif()
@@ -1055,6 +1059,7 @@
     DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}"
     DEPLOYMENT_VERSION_TVOS "${SWIFTLIB_DEPLOYMENT_VERSION_TVOS}"
     DEPLOYMENT_VERSION_WATCHOS "${SWIFTLIB_DEPLOYMENT_VERSION_WATCHOS}"
+    "${SWIFTLIB_FORCE_BUILD_OPTIMIZED_keyword}"
     RESULT_VAR_NAME c_compile_flags
     )
   _add_variant_link_flags(
@@ -1328,7 +1333,7 @@
   set(SWIFTLIB_options
       SHARED STATIC OBJECT_LIBRARY IS_STDLIB IS_STDLIB_CORE IS_SDK_OVERLAY
       TARGET_LIBRARY FORCE_BUILD_FOR_HOST_SDK
-      API_NOTES_NON_OVERLAY DONT_EMBED_BITCODE HAS_SWIFT_CONTENT)
+      API_NOTES_NON_OVERLAY DONT_EMBED_BITCODE HAS_SWIFT_CONTENT FORCE_BUILD_OPTIMIZED)
   cmake_parse_arguments(SWIFTLIB
     "${SWIFTLIB_options}"
     "INSTALL_IN_COMPONENT;DEPLOYMENT_VERSION_OSX;DEPLOYMENT_VERSION_IOS;DEPLOYMENT_VERSION_TVOS;DEPLOYMENT_VERSION_WATCHOS"
@@ -1566,6 +1571,7 @@
           ${SWIFTLIB_IS_SDK_OVERLAY_keyword}
           ${SWIFTLIB_TARGET_LIBRARY_keyword}
           ${SWIFTLIB_FORCE_BUILD_FOR_HOST_SDK_keyword}
+          ${SWIFTLIB_FORCE_BUILD_OPTIMIZED_keyword}
           INSTALL_IN_COMPONENT "${SWIFTLIB_INSTALL_IN_COMPONENT}"
           DEPLOYMENT_VERSION_OSX "${SWIFTLIB_DEPLOYMENT_VERSION_OSX}"
           DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}"
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index 51b030f..7d6a01f 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -548,20 +548,18 @@
   ///
   /// This distinguishes static references to types, like Int, from metatype
   /// values, "someTy: Any.Type".
-  bool isTypeReference(llvm::function_ref<Type(const Expr &)> getType
-                       = [](const Expr &E) -> Type {
-                         return E.getType();
-                       }) const;
+  bool isTypeReference(llvm::function_ref<Type(const Expr *)> getType =
+                           [](const Expr *E) -> Type {
+    return E->getType();
+  }) const;
 
   /// Determine whether this expression refers to a statically-derived metatype.
   ///
   /// This implies `isTypeReference`, but also requires that the referenced type
   /// is not an archetype or dependent type.
   bool isStaticallyDerivedMetatype(
-      llvm::function_ref<Type(const Expr &)> getType
-      = [](const Expr &E) -> Type {
-        return E.getType();
-      }) const;
+      llvm::function_ref<Type(const Expr *)> getType =
+          [](const Expr *E) -> Type { return E->getType(); }) const;
 
   /// isImplicit - Determines whether this expression was implicitly-generated,
   /// rather than explicitly written in the AST.
@@ -781,8 +779,10 @@
   LiteralExpr(ExprKind Kind, bool Implicit) : Expr(Kind, Implicit) {}
   
   // Make an exact copy of this one AST node.
-  LiteralExpr *shallowClone(ASTContext &Ctx) const;
-  
+  LiteralExpr *
+  shallowClone(ASTContext &Ctx,
+               llvm::function_ref<Type(const Expr *)> getType) const;
+
   static bool classof(const Expr *E) {
     return E->getKind() >= ExprKind::First_LiteralExpr &&
            E->getKind() <= ExprKind::Last_LiteralExpr;
@@ -1155,8 +1155,9 @@
   ///
   /// Note: prefer to use the second entry point, which separates out
   /// arguments/labels/etc.
-  static ObjectLiteralExpr *create(ASTContext &ctx, SourceLoc poundLoc,
-                                   LiteralKind kind, Expr *arg, bool implicit);
+  static ObjectLiteralExpr *
+  create(ASTContext &ctx, SourceLoc poundLoc, LiteralKind kind, Expr *arg,
+         bool implicit, llvm::function_ref<Type(const Expr *)> getType);
 
   /// Create a new object literal expression.
   static ObjectLiteralExpr *create(ASTContext &ctx, SourceLoc poundLoc,
@@ -1340,15 +1341,13 @@
 
   // The type of a TypeExpr is always a metatype type.  Return the instance
   // type, ErrorType if an error, or null if not set yet.
-  Type getInstanceType(llvm::function_ref<bool(const Expr &)> hasType
-                       = [](const Expr &E) -> bool {
-                         return !!E.getType();
-                       },
-                       llvm::function_ref<Type(const Expr &)> getType
-                       = [](const Expr &E) -> Type {
-                         return E.getType();
+  Type getInstanceType(llvm::function_ref<bool(const Expr *)> hasType =
+                           [](const Expr *E) -> bool { return !!E->getType(); },
+                       llvm::function_ref<Type(const Expr *)> getType =
+                           [](const Expr *E) -> Type {
+                         return E->getType();
                        }) const;
-  
+
   // Create an implicit TypeExpr, which has no location information.
   static TypeExpr *createImplicit(Type Ty, ASTContext &C) {
     return new (C) TypeExpr(Ty);
@@ -1714,9 +1713,11 @@
   ///
   /// Note: do not create new callers to this entry point; use the entry point
   /// that takes separate index arguments.
-  static DynamicSubscriptExpr *create(ASTContext &ctx, Expr *base, Expr *index,
-                                      ConcreteDeclRef decl,
-                                      bool implicit);
+  static DynamicSubscriptExpr *
+  create(ASTContext &ctx, Expr *base, Expr *index, ConcreteDeclRef decl,
+         bool implicit,
+         llvm::function_ref<Type(const Expr *)> getType =
+             [](const Expr *E) -> Type { return E->getType(); });
 
   /// Create a new dynamic subscript.
   static DynamicSubscriptExpr *create(ASTContext &ctx, Expr *base,
@@ -2263,11 +2264,12 @@
   ///
   /// Note: do not create new callers to this entry point; use the entry point
   /// that takes separate index arguments.
-  static SubscriptExpr *create(ASTContext &ctx, Expr *base, Expr *index,
-                               ConcreteDeclRef decl = ConcreteDeclRef(),
-                               bool implicit = false,
-                               AccessSemantics semantics
-                                 = AccessSemantics::Ordinary);
+  static SubscriptExpr *
+  create(ASTContext &ctx, Expr *base, Expr *index,
+         ConcreteDeclRef decl = ConcreteDeclRef(), bool implicit = false,
+         AccessSemantics semantics = AccessSemantics::Ordinary,
+         llvm::function_ref<Type(const Expr *)> getType =
+             [](const Expr *E) -> Type { return E->getType(); });
 
   /// Create a new subscript.
   static SubscriptExpr *create(ASTContext &ctx, Expr *base,
@@ -3751,11 +3753,12 @@
   /// Create a new call expression.
   ///
   /// Note: prefer to use the entry points that separate out the arguments.
-  static CallExpr *create(ASTContext &ctx, Expr *fn, Expr *arg,
-                          ArrayRef<Identifier> argLabels,
-                          ArrayRef<SourceLoc> argLabelLocs,
-                          bool hasTrailingClosure,
-                          bool implicit, Type type = Type());
+  static CallExpr *
+  create(ASTContext &ctx, Expr *fn, Expr *arg, ArrayRef<Identifier> argLabels,
+         ArrayRef<SourceLoc> argLabelLocs, bool hasTrailingClosure,
+         bool implicit, Type type = Type(),
+         llvm::function_ref<Type(const Expr *)> getType =
+             [](const Expr *E) -> Type { return E->getType(); });
 
   /// Create a new implicit call expression without any source-location
   /// information.
@@ -3764,11 +3767,13 @@
   /// \param args The call arguments, not including a trailing closure (if any).
   /// \param argLabels The argument labels, whose size must equal args.size(),
   /// or which must be empty.
-  static CallExpr *createImplicit(ASTContext &ctx, Expr *fn,
-                                  ArrayRef<Expr *> args,
-                                  ArrayRef<Identifier> argLabels) {
+  static CallExpr *
+  createImplicit(ASTContext &ctx, Expr *fn, ArrayRef<Expr *> args,
+                 ArrayRef<Identifier> argLabels,
+                 llvm::function_ref<Type(const Expr *)> getType =
+                     [](const Expr *E) -> Type { return E->getType(); }) {
     return create(ctx, fn, SourceLoc(), args, argLabels, { }, SourceLoc(),
-                  /*trailingClosure=*/nullptr, /*implicit=*/true);
+                  /*trailingClosure=*/nullptr, /*implicit=*/true, getType);
   }
 
   /// Create a new call expression.
@@ -3780,14 +3785,12 @@
   /// \param argLabelLocs The locations of the argument labels, whose size must
   /// equal args.size() or which must be empty.
   /// \param trailingClosure The trailing closure, if any.
-  static CallExpr *create(ASTContext &ctx, Expr *fn,
-                          SourceLoc lParenLoc,
-                          ArrayRef<Expr *> args,
-                          ArrayRef<Identifier> argLabels,
-                          ArrayRef<SourceLoc> argLabelLocs,
-                          SourceLoc rParenLoc,
-                          Expr *trailingClosure,
-                          bool implicit);
+  static CallExpr *
+  create(ASTContext &ctx, Expr *fn, SourceLoc lParenLoc, ArrayRef<Expr *> args,
+         ArrayRef<Identifier> argLabels, ArrayRef<SourceLoc> argLabelLocs,
+         SourceLoc rParenLoc, Expr *trailingClosure, bool implicit,
+         llvm::function_ref<Type(const Expr *)> getType =
+             [](const Expr *E) -> Type { return E->getType(); });
 
   SourceLoc getStartLoc() const {
     SourceLoc fnLoc = getFn()->getStartLoc();
diff --git a/include/swift/Basic/DiverseStack.h b/include/swift/Basic/DiverseStack.h
index 387515b..0b35138 100644
--- a/include/swift/Basic/DiverseStack.h
+++ b/include/swift/Basic/DiverseStack.h
@@ -116,6 +116,8 @@
       return Depth != (std::size_t) -1;
     }
 
+    std::size_t getDepth() const { return Depth; }
+
     /// A helper class that wraps a stable_iterator as something that
     /// pretends to be a non-null pointer.
     ///
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 2f9d8df..4b5166c 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -1,3 +1,8 @@
+
+if (SWIFT_FORCE_OPTIMIZED_TYPECHECKER)
+  set(EXTRA_AST_FLAGS "FORCE_BUILD_OPTIMIZED")
+endif()
+
 add_swift_library(swiftAST STATIC
   ArchetypeBuilder.cpp
   ASTContext.cpp
@@ -79,6 +84,8 @@
     bitreader bitwriter coroutines coverage irreader debuginfoDWARF
     profiledata instrumentation object objcarcopts mc mcparser
     bitreader bitwriter lto ipo option core support ${LLVM_TARGETS_TO_BUILD}
+
+  ${EXTRA_AST_FLAGS}
   )
 
 # intrinsics_gen is the LLVM tablegen target that generates the include files
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index cd344f0..fd13fad 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -569,10 +569,10 @@
   this->walk(ChildWalker(callback));
 }
 
-bool Expr::
-isTypeReference(llvm::function_ref<Type(const Expr &)> getType) const {
+bool Expr::isTypeReference(
+    llvm::function_ref<Type(const Expr *)> getType) const {
   // If the result isn't a metatype, there's nothing else to do.
-  if (!getType(*this)->is<AnyMetatypeType>())
+  if (!getType(this)->is<AnyMetatypeType>())
     return false;
   
   const Expr *expr = this;
@@ -604,14 +604,16 @@
 }
 
 bool Expr::isStaticallyDerivedMetatype(
-    llvm::function_ref<Type(const Expr &)> getType) const {
+    llvm::function_ref<Type(const Expr *)> getType) const {
   // The type must first be a type reference.
   if (!isTypeReference(getType))
     return false;
 
   // Archetypes are never statically derived.
-  return !getType(*this)->getAs<AnyMetatypeType>()->getInstanceType()
-    ->is<ArchetypeType>();
+  return !getType(this)
+              ->getAs<AnyMetatypeType>()
+              ->getInstanceType()
+              ->is<ArchetypeType>();
 }
 
 bool Expr::isSuperExpr() const {
@@ -858,12 +860,15 @@
 // Support methods for Exprs.
 //===----------------------------------------------------------------------===//
 
-static LiteralExpr *shallowCloneImpl(const NilLiteralExpr *E, ASTContext &Ctx) {
+static LiteralExpr *
+shallowCloneImpl(const NilLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   return new (Ctx) NilLiteralExpr(E->getLoc());
 }
 
 static LiteralExpr *
-shallowCloneImpl(const IntegerLiteralExpr *E, ASTContext &Ctx) {
+shallowCloneImpl(const IntegerLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   auto res = new (Ctx) IntegerLiteralExpr(E->getDigitsText(),
                                           E->getSourceRange().End);
   if (E->isNegative())
@@ -871,7 +876,9 @@
   return res;
 }
 
-static LiteralExpr *shallowCloneImpl(const FloatLiteralExpr *E, ASTContext &Ctx) {
+static LiteralExpr *
+shallowCloneImpl(const FloatLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   auto res = new (Ctx) FloatLiteralExpr(E->getDigitsText(),
                                         E->getSourceRange().End);
   if (E->isNegative())
@@ -879,26 +886,30 @@
   return res;
 }
 static LiteralExpr *
-shallowCloneImpl(const BooleanLiteralExpr *E, ASTContext &Ctx) {
+shallowCloneImpl(const BooleanLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   return new (Ctx) BooleanLiteralExpr(E->getValue(), E->getLoc());
 }
-static LiteralExpr *shallowCloneImpl(const StringLiteralExpr *E, ASTContext &Ctx) {
+static LiteralExpr *
+shallowCloneImpl(const StringLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   auto res = new (Ctx) StringLiteralExpr(E->getValue(), E->getSourceRange());
   res->setEncoding(E->getEncoding());
   return res;
 }
 
 static LiteralExpr *
-shallowCloneImpl(const InterpolatedStringLiteralExpr *E, ASTContext &Ctx) {
+shallowCloneImpl(const InterpolatedStringLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   auto res = new (Ctx) InterpolatedStringLiteralExpr(E->getLoc(),
                 const_cast<InterpolatedStringLiteralExpr*>(E)->getSegments());
   res->setSemanticExpr(E->getSemanticExpr());
   return res;
 }
 
-
 static LiteralExpr *
-shallowCloneImpl(const MagicIdentifierLiteralExpr *E, ASTContext &Ctx) {
+shallowCloneImpl(const MagicIdentifierLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
   auto res = new (Ctx) MagicIdentifierLiteralExpr(E->getKind(),
                                                   E->getSourceRange().End);
   if (res->isString())
@@ -907,36 +918,38 @@
 }
 
 static LiteralExpr *
-shallowCloneImpl(const ObjectLiteralExpr *E, ASTContext &Ctx) {
-  auto res = ObjectLiteralExpr::create(Ctx, E->getStartLoc(),
-                                       E->getLiteralKind(),
-                                       E->getArg(), E->isImplicit());
+shallowCloneImpl(const ObjectLiteralExpr *E, ASTContext &Ctx,
+                 llvm::function_ref<Type(const Expr *)> getType) {
+  auto res =
+      ObjectLiteralExpr::create(Ctx, E->getStartLoc(), E->getLiteralKind(),
+                                E->getArg(), E->isImplicit(), getType);
   res->setSemanticExpr(E->getSemanticExpr());
   return res;
 }
 
 // Make an exact copy of this AST node.
-LiteralExpr *LiteralExpr::shallowClone(ASTContext &Ctx) const {
+LiteralExpr *LiteralExpr::shallowClone(
+    ASTContext &Ctx, llvm::function_ref<Type(const Expr *)> getType) const {
   LiteralExpr *Result = nullptr;
   switch (getKind()) {
   default: llvm_unreachable("Unknown literal type!");
-#define DISPATCH_CLONE(KIND) \
-  case ExprKind::KIND: \
-    Result = shallowCloneImpl(cast<KIND##Expr>(this), Ctx); \
+#define DISPATCH_CLONE(KIND)                                                   \
+  case ExprKind::KIND:                                                         \
+    Result = shallowCloneImpl(cast<KIND##Expr>(this), Ctx, getType);           \
     break;
 
-  DISPATCH_CLONE(NilLiteral)
-  DISPATCH_CLONE(IntegerLiteral)
-  DISPATCH_CLONE(FloatLiteral)
-  DISPATCH_CLONE(BooleanLiteral)
-  DISPATCH_CLONE(StringLiteral)
-  DISPATCH_CLONE(InterpolatedStringLiteral)
-  DISPATCH_CLONE(ObjectLiteral)
-  DISPATCH_CLONE(MagicIdentifierLiteral)
+    DISPATCH_CLONE(NilLiteral)
+    DISPATCH_CLONE(IntegerLiteral)
+    DISPATCH_CLONE(FloatLiteral)
+    DISPATCH_CLONE(BooleanLiteral)
+    DISPATCH_CLONE(StringLiteral)
+    DISPATCH_CLONE(InterpolatedStringLiteral)
+    DISPATCH_CLONE(ObjectLiteral)
+    DISPATCH_CLONE(MagicIdentifierLiteral)
 #undef DISPATCH_CLONE
   }
-  
-  Result->setType(getType());
+
+  Result->setType(getType(this));
   Result->setImplicit(isImplicit());
   return Result;
 }
@@ -1011,10 +1024,13 @@
       unicode::isSingleExtendedGraphemeCluster(Val);
 }
 
-static ArrayRef<Identifier>
-getArgumentLabelsFromArgument(Expr *arg, SmallVectorImpl<Identifier> &scratch,
-                              SmallVectorImpl<SourceLoc> *sourceLocs = nullptr,
-                              bool *hasTrailingClosure = nullptr){
+static ArrayRef<Identifier> getArgumentLabelsFromArgument(
+    Expr *arg, SmallVectorImpl<Identifier> &scratch,
+    SmallVectorImpl<SourceLoc> *sourceLocs = nullptr,
+    bool *hasTrailingClosure = nullptr,
+    llvm::function_ref<Type(const Expr *)> getType = [](const Expr *E) -> Type {
+      return E->getType();
+    }) {
   if (sourceLocs) sourceLocs->clear();
   if (hasTrailingClosure) *hasTrailingClosure = false;
 
@@ -1045,7 +1061,7 @@
   }
 
   // Otherwise, use the type information.
-  auto type = arg->getType();
+  auto type = getType(arg);
   if (isa<ParenType>(type.getPointer())) {
     scratch.clear();
     scratch.push_back(Identifier());
@@ -1067,15 +1083,16 @@
 }
 
 /// Compute the type of an argument to a call (or call-like) AST
-static void computeSingleArgumentType(ASTContext &ctx, Expr *arg,
-                                      bool implicit) {
+static void
+computeSingleArgumentType(ASTContext &ctx, Expr *arg, bool implicit,
+                          llvm::function_ref<Type(const Expr *)> getType) {
   // Propagate 'implicit' to the argument.
   if (implicit)
     arg->setImplicit(true);
 
   // Handle parenthesized expressions.
   if (auto paren = dyn_cast<ParenExpr>(arg)) {
-    if (auto type = paren->getSubExpr()->getType()) {
+    if (auto type = getType(paren->getSubExpr())) {
       arg->setType(ParenType::get(ctx, type));
     }
     return;
@@ -1085,7 +1102,7 @@
   auto tuple = dyn_cast<TupleExpr>(arg);
   SmallVector<TupleTypeElt, 4> typeElements;
   for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) {
-    auto type = tuple->getElement(i)->getType();
+    auto type = getType(tuple->getElement(i));
     if (!type) return;
 
     typeElements.push_back(TupleTypeElt(type, tuple->getElementName(i)));
@@ -1101,17 +1118,15 @@
 ///
 /// \param argLabelLocs The argument label locations, which might be updated by
 /// this function.
-static Expr *packSingleArgument(
-    ASTContext &ctx,
-    SourceLoc lParenLoc,
-    ArrayRef<Expr *> args,
-    ArrayRef<Identifier> &argLabels,
-    ArrayRef<SourceLoc> &argLabelLocs,
-    SourceLoc rParenLoc,
-    Expr *trailingClosure,
-    bool implicit,
-    SmallVectorImpl<Identifier> &argLabelsScratch,
-    SmallVectorImpl<SourceLoc> &argLabelLocsScratch) {
+static Expr *
+packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef<Expr *> args,
+                   ArrayRef<Identifier> &argLabels,
+                   ArrayRef<SourceLoc> &argLabelLocs, SourceLoc rParenLoc,
+                   Expr *trailingClosure, bool implicit,
+                   SmallVectorImpl<Identifier> &argLabelsScratch,
+                   SmallVectorImpl<SourceLoc> &argLabelLocsScratch,
+                   llvm::function_ref<Type(const Expr *)> getType =
+                       [](const Expr *E) -> Type { return E->getType(); }) {
   // Clear out our scratch space.
   argLabelsScratch.clear();
   argLabelLocsScratch.clear();
@@ -1122,7 +1137,7 @@
     if (args.size() == 1 && (argLabels.empty() || argLabels[0].empty())) {
       auto arg = new (ctx) ParenExpr(lParenLoc, args[0], rParenLoc,
                                      /*hasTrailingClosure=*/false);
-      computeSingleArgumentType(ctx, arg, implicit);
+      computeSingleArgumentType(ctx, arg, implicit, getType);
       argLabelsScratch.push_back(Identifier());
       argLabels = argLabelsScratch;
       argLabelLocs = { };
@@ -1144,7 +1159,7 @@
     auto arg = TupleExpr::create(ctx, lParenLoc, args, argLabels, argLabelLocs,
                                  rParenLoc, /*HasTrailingClosure=*/false,
                                  /*Implicit=*/false);
-    computeSingleArgumentType(ctx, arg, implicit);
+    computeSingleArgumentType(ctx, arg, implicit, getType);
     return arg;
   }
 
@@ -1153,7 +1168,7 @@
   if (args.size() == 0) {
     auto arg = new (ctx) ParenExpr(lParenLoc, trailingClosure, rParenLoc,
                                    /*hasTrailingClosure=*/true);
-    computeSingleArgumentType(ctx, arg, implicit);
+    computeSingleArgumentType(ctx, arg, implicit, getType);
     argLabelsScratch.push_back(Identifier());
     argLabels = argLabelsScratch;
     argLabelLocs = { };
@@ -1189,7 +1204,7 @@
                                argLabelLocs, rParenLoc,
                                /*HasTrailingClosure=*/true,
                                /*Implicit=*/false);
-  computeSingleArgumentType(ctx, arg, implicit);
+  computeSingleArgumentType(ctx, arg, implicit, getType);
 
   return arg;
 }
@@ -1210,11 +1225,10 @@
   initializeCallArguments(argLabels, argLabelLocs, hasTrailingClosure);  
 }
 
-ObjectLiteralExpr *ObjectLiteralExpr::create(ASTContext &ctx,
-                                             SourceLoc poundLoc,
-                                             LiteralKind kind,
-                                             Expr *arg,
-                                             bool implicit) {
+ObjectLiteralExpr *
+ObjectLiteralExpr::create(ASTContext &ctx, SourceLoc poundLoc, LiteralKind kind,
+                          Expr *arg, bool implicit,
+                          llvm::function_ref<Type(const Expr *)> getType) {
   // Inspect the argument to dig out the argument labels, their location, and
   // whether there is a trailing closure.
   SmallVector<Identifier, 4> argLabelsScratch;
@@ -1222,7 +1236,8 @@
   bool hasTrailingClosure = false;
   auto argLabels = getArgumentLabelsFromArgument(arg, argLabelsScratch,
                                                  &argLabelLocs,
-                                                 &hasTrailingClosure);
+                                                 &hasTrailingClosure,
+                                                 getType);
 
   size_t size = totalSizeToAlloc(argLabels, argLabelLocs, hasTrailingClosure);
 
@@ -1483,9 +1498,11 @@
   initializeCallArguments(argLabels, argLabelLocs, hasTrailingClosure);
 }
 
-SubscriptExpr *SubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index,
-                                     ConcreteDeclRef decl, bool implicit,
-                                     AccessSemantics semantics) {
+SubscriptExpr *
+SubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index,
+                      ConcreteDeclRef decl, bool implicit,
+                      AccessSemantics semantics,
+                      llvm::function_ref<Type(const Expr *)> getType) {
   // Inspect the argument to dig out the argument labels, their location, and
   // whether there is a trailing closure.
   SmallVector<Identifier, 4> argLabelsScratch;
@@ -1493,7 +1510,8 @@
   bool hasTrailingClosure = false;
   auto argLabels = getArgumentLabelsFromArgument(index, argLabelsScratch,
                                                  &argLabelLocs,
-                                                 &hasTrailingClosure);
+                                                 &hasTrailingClosure,
+                                                 getType);
 
   size_t size = totalSizeToAlloc(argLabels, argLabelLocs, hasTrailingClosure);
 
@@ -1548,7 +1566,8 @@
 
 DynamicSubscriptExpr *
 DynamicSubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index,
-                             ConcreteDeclRef decl, bool implicit) {
+                             ConcreteDeclRef decl, bool implicit,
+                             llvm::function_ref<Type(const Expr *)> getType) {
   // Inspect the argument to dig out the argument labels, their location, and
   // whether there is a trailing closure.
   SmallVector<Identifier, 4> argLabelsScratch;
@@ -1556,7 +1575,8 @@
   bool hasTrailingClosure = false;
   auto argLabels = getArgumentLabelsFromArgument(index, argLabelsScratch,
                                                  &argLabelLocs,
-                                                 &hasTrailingClosure);
+                                                 &hasTrailingClosure,
+                                                 getType);
 
   size_t size = totalSizeToAlloc(argLabels, argLabelLocs, hasTrailingClosure);
 
@@ -1697,8 +1717,8 @@
 CallExpr *CallExpr::create(ASTContext &ctx, Expr *fn, Expr *arg,
                            ArrayRef<Identifier> argLabels,
                            ArrayRef<SourceLoc> argLabelLocs,
-                           bool hasTrailingClosure,
-                           bool implicit, Type type) {
+                           bool hasTrailingClosure, bool implicit, Type type,
+                           llvm::function_ref<Type(const Expr *)> getType) {
   SmallVector<Identifier, 4> argLabelsScratch;
   SmallVector<SourceLoc, 4> argLabelLocsScratch;
   if (argLabels.empty()) {
@@ -1706,7 +1726,8 @@
     // whether there is a trailing closure.
     argLabels = getArgumentLabelsFromArgument(arg, argLabelsScratch,
                                               &argLabelLocsScratch,
-                                              &hasTrailingClosure);
+                                              &hasTrailingClosure,
+                                              getType);
     argLabelLocs = argLabelLocsScratch;
   }
 
@@ -1717,14 +1738,13 @@
                                hasTrailingClosure, type);
 }
 
-CallExpr *CallExpr::create(ASTContext &ctx, Expr *fn,
-                           SourceLoc lParenLoc,
+CallExpr *CallExpr::create(ASTContext &ctx, Expr *fn, SourceLoc lParenLoc,
                            ArrayRef<Expr *> args,
                            ArrayRef<Identifier> argLabels,
                            ArrayRef<SourceLoc> argLabelLocs,
-                           SourceLoc rParenLoc,
-                           Expr *trailingClosure,
-                           bool implicit) {
+                           SourceLoc rParenLoc, Expr *trailingClosure,
+                           bool implicit,
+                           llvm::function_ref<Type(const Expr *)> getType) {
   SmallVector<Identifier, 4> argLabelsScratch;
   SmallVector<SourceLoc, 4> argLabelLocsScratch;
   Expr *arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs,
@@ -1899,15 +1919,15 @@
 // The type of a TypeExpr is always a metatype type.  Return the instance
 // type or null if not set yet.
 Type TypeExpr::getInstanceType(
-    llvm::function_ref<bool(const Expr &)> hasType,
-    llvm::function_ref<Type(const Expr &)> getType) const {
-  if (!hasType(*this))
+    llvm::function_ref<bool(const Expr *)> hasType,
+    llvm::function_ref<Type(const Expr *)> getType) const {
+  if (!hasType(this))
     return Type();
 
-  if (auto metaType = getType(*this)->getAs<MetatypeType>())
+  if (auto metaType = getType(this)->getAs<MetatypeType>())
     return metaType->getInstanceType();
 
-  return ErrorType::get(getType(*this)->getASTContext());
+  return ErrorType::get(getType(this)->getASTContext());
 }
 
 
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index a9cd136..49635fc 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -44,7 +44,9 @@
           "${ICU_UC_LIBDIR}"
           "${ICU_I18N_LIBDIR}"
         OUTPUT
-          "${SWIFTSTATICLIB_DIR}/${linkfile}")
+          "${SWIFTSTATICLIB_DIR}/${linkfile}"
+        DEPENDS
+          "${SWIFT_SOURCE_DIR}/utils/gen-static-stdlib-link-args")
 
       list(APPEND static_stdlib_lnk_file_list ${swift_static_stdlib_${sdk}_args})
       swift_install_in_component(stdlib
diff --git a/lib/SILGen/Cleanup.cpp b/lib/SILGen/Cleanup.cpp
index 85b05f2..9542537 100644
--- a/lib/SILGen/Cleanup.cpp
+++ b/lib/SILGen/Cleanup.cpp
@@ -232,3 +232,32 @@
     cleanup.setState(stateToRestore);
   }
 }
+
+llvm::raw_ostream &Lowering::operator<<(llvm::raw_ostream &os,
+                                        CleanupState state) {
+  switch (state) {
+  case CleanupState::Dormant:
+    return os << "Dormant";
+  case CleanupState::Dead:
+    return os << "Dead";
+  case CleanupState::Active:
+    return os << "Active";
+  case CleanupState::PersistentlyActive:
+    return os << "PersistentlyActive";
+  }
+}
+
+void CleanupManager::dump() const {
+#ifndef NDEBUG
+  auto begin = Stack.stable_begin();
+  auto end = Stack.stable_end();
+  while (begin != end) {
+    auto iter = Stack.find(begin);
+    const Cleanup &stackCleanup = *iter;
+    llvm::errs() << "CLEANUP DEPTH: " << begin.getDepth() << "\n";
+    stackCleanup.dump();
+    begin = Stack.stabilize(++iter);
+    Stack.checkIterator(begin);
+  }
+#endif
+}
diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h
index 2cd4684..7b79bbf 100644
--- a/lib/SILGen/Cleanup.h
+++ b/lib/SILGen/Cleanup.h
@@ -14,20 +14,25 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef CLEANUP_H
-#define CLEANUP_H
+#ifndef SWIFT_SILGEN_CLEANUP_H
+#define SWIFT_SILGEN_CLEANUP_H
 
 #include "swift/Basic/DiverseStack.h"
 #include "swift/SIL/SILLocation.h"
+#include "llvm/ADT/SmallVector.h"
 
 namespace swift {
-  class SILBasicBlock;
-  class SILFunction;
-  class SILValue;
-  
+
+class SILBasicBlock;
+class SILFunction;
+class SILValue;
+
 namespace Lowering {
-  class JumpDest;
-  class SILGenFunction;
+
+class JumpDest;
+class SILGenFunction;
+class ManagedValue;
+class BorrowedManagedValue;
 
 /// The valid states that a cleanup can be in.
 enum class CleanupState {
@@ -47,6 +52,8 @@
   PersistentlyActive
 };
 
+llvm::raw_ostream &operator<<(raw_ostream &os, CleanupState state);
+
 class LLVM_LIBRARY_VISIBILITY Cleanup {
   unsigned allocatedSize;
   CleanupState state;
@@ -67,6 +74,7 @@
   bool isDead() const { return state == CleanupState::Dead; }
 
   virtual void emit(SILGenFunction &Gen, CleanupLocation L) = 0;
+  virtual void dump() const = 0;
 };
 
 /// A cleanup depth is generally used to denote the set of cleanups
@@ -112,7 +120,8 @@
   void setCleanupState(Cleanup &cleanup, CleanupState state);
 
   friend class CleanupStateRestorationScope;
-  
+  friend class BorrowedManagedValue;
+
 public:
   CleanupManager(SILGenFunction &Gen)
     : Gen(Gen), InnermostScope(Stack.stable_end()) {
@@ -192,6 +201,9 @@
   /// True if there are any active cleanups in the scope between the specified
   /// cleanup handle and the current top of stack.
   bool hasAnyActiveCleanups(CleanupsDepth from);
+
+  /// Dump the output of each cleanup on this stack.
+  void dump() const;
 };
 
 /// An RAII object that allows the state of a cleanup to be
diff --git a/lib/SILGen/ManagedValue.cpp b/lib/SILGen/ManagedValue.cpp
index 0a7a88e..560b499 100644
--- a/lib/SILGen/ManagedValue.cpp
+++ b/lib/SILGen/ManagedValue.cpp
@@ -104,3 +104,78 @@
   gen.emitSemanticStore(loc, getValue(), address, addrTL,
                         IsNotInitialization);
 }
+
+ManagedValue ManagedValue::borrow(SILGenFunction &gen, SILLocation loc) const {
+  assert(getValue() && "cannot borrow an invalid or in-context value");
+  if (isLValue())
+    return *this;
+  if (getType().isAddress())
+    return ManagedValue::forUnmanaged(getValue());
+  return gen.emitManagedBeginBorrow(loc, getValue());
+}
+
+void BorrowedManagedValue::cleanupImpl() {
+  if (!gen.B.hasValidInsertionPoint()) {
+    handle.reset();
+    return;
+  }
+
+  // We had a trivial or an address value so there isn't anything to
+  // cleanup. Still be sure to unset borrowedValue though.
+  if (!handle.hasValue()) {
+    borrowedValue = ManagedValue();
+    return;
+  }
+
+  assert(borrowedValue && "already cleaned up this object!?");
+
+  CleanupHandle handleValue = handle.getValue();
+  CleanupLocation cleanupLoc = CleanupLocation::get(loc);
+
+  auto iter = gen.Cleanups.Stack.find(handleValue);
+  assert(iter != gen.Cleanups.Stack.end() &&
+         "can't change end of cleanups stack");
+
+  Cleanup &cleanup = *iter;
+  assert(cleanup.isActive() && "Cleanup emitted out of order?!");
+
+  CleanupState newState =
+      (cleanup.getState() == CleanupState::Active ? CleanupState::Dead
+                                                  : CleanupState::Dormant);
+  cleanup.emit(gen, cleanupLoc);
+  gen.Cleanups.setCleanupState(cleanup, newState);
+
+  borrowedValue = ManagedValue();
+  handle.reset();
+}
+
+BorrowedManagedValue::BorrowedManagedValue(SILGenFunction &gen,
+                                           ManagedValue originalValue,
+                                           SILLocation loc)
+    : gen(gen), borrowedValue(), handle(), loc(loc) {
+  if (!originalValue)
+    return;
+  auto &lowering = gen.F.getTypeLowering(originalValue.getType());
+  assert(lowering.getLoweredType().getObjectType() ==
+         originalValue.getType().getObjectType());
+
+  if (lowering.isTrivial()) {
+    borrowedValue = ManagedValue::forUnmanaged(originalValue.getValue());
+    return;
+  }
+
+  if (originalValue.getOwnershipKind() == ValueOwnershipKind::Guaranteed) {
+    borrowedValue = ManagedValue::forUnmanaged(originalValue.getValue());
+    return;
+  }
+
+  if (originalValue.getType().isAddress()) {
+    borrowedValue = ManagedValue::forUnmanaged(originalValue.getValue());
+    return;
+  }
+
+  SILValue borrowed = gen.B.createBeginBorrow(loc, originalValue.getValue());
+  if (borrowed->getType().isObject())
+    handle = gen.enterEndBorrowCleanup(originalValue.getValue(), borrowed);
+  borrowedValue = ManagedValue(borrowed, CleanupHandle::invalid());
+}
diff --git a/lib/SILGen/ManagedValue.h b/lib/SILGen/ManagedValue.h
index 5af4e05..b383694 100644
--- a/lib/SILGen/ManagedValue.h
+++ b/lib/SILGen/ManagedValue.h
@@ -31,6 +31,8 @@
 
 namespace Lowering {
 
+class SILGenFunction;
+
 /// ManagedValue - represents a singular SIL value and an optional cleanup.
 /// Ownership of the ManagedValue can be "forwarded" to disable its cleanup when
 /// the rvalue is consumed. A ManagedValue can also represent an LValue used as
@@ -253,9 +255,10 @@
   /// An l-value is borrowed as itself.  A +1 r-value is borrowed as a
   /// +0 r-value, with the assumption that the original ManagedValue
   /// will not be forwarded until the borrowed value is fully used.
-  ManagedValue borrow() const {
-    assert(getValue() && "cannot borrow an invalid or in-context value");
-    return (isLValue() ? *this : ManagedValue::forUnmanaged(getValue()));
+  ManagedValue borrow(SILGenFunction &gen, SILLocation loc) const;
+
+  ManagedValue unmanagedBorrow() const {
+    return isLValue() ? *this : ManagedValue::forUnmanaged(getValue());
   }
 
   /// Disable the cleanup for this value.
@@ -358,8 +361,41 @@
     return { asUnmanagedValue(), CastConsumptionKind::CopyOnSuccess };
   }
 };
-  
-} // end namespace Lowering
+
+/// An RAII object that allows a user to borrow a value without a specific scope
+/// that ensures that the object is cleaned up before other scoped cleanups
+/// occur. The way cleanup is triggered is by calling:
+///
+///   std::move(value).cleanup();
+class BorrowedManagedValue {
+  SILGenFunction &gen;
+  ManagedValue borrowedValue;
+  Optional<CleanupHandle> handle;
+  SILLocation loc;
+
+public:
+  BorrowedManagedValue(SILGenFunction &gen, ManagedValue originalValue,
+                       SILLocation loc);
+  ~BorrowedManagedValue() {
+    assert(!borrowedValue &&
+           "Did not manually cleanup borrowed managed value?!");
+  }
+  BorrowedManagedValue(const BorrowedManagedValue &) = delete;
+  BorrowedManagedValue(BorrowedManagedValue &&) = delete;
+  BorrowedManagedValue &operator=(const BorrowedManagedValue &) = delete;
+  BorrowedManagedValue &operator=(BorrowedManagedValue &&) = delete;
+
+  void cleanup() && { cleanupImpl(); }
+  operator ManagedValue() const { return borrowedValue; }
+
+private:
+  void cleanupImpl();
+};
+
+} // namespace Lowering
+} // namespace swift
+
+namespace swift {
 
 template <typename To> inline bool isa(const Lowering::ManagedValue &M) {
   return isa<To>(M.getValue());
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 111cbb3..cc406e5 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -3805,6 +3805,14 @@
   void emit(SILGenFunction &gen, CleanupLocation l) override {
     gen.B.createDeallocBox(l, box);
   }
+
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "DeallocateUninitializedBox "
+                 << "State:" << getState() << " "
+                 << "Box: " << box << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
@@ -4423,7 +4431,7 @@
                              uncurriedArgs.end());
           uncurriedArgs[foreignSelf.getSelfIndex()] = selfArg;
         }
-        
+
         // Emit the uncurried call.
         
         // Special case for superclass method calls.
@@ -4922,6 +4930,14 @@
     void emit(SILGenFunction &gen, CleanupLocation l) override {
       gen.emitUninitializedArrayDeallocation(l, Array);
     }
+
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "DeallocateUninitializedArray "
+                   << "State:" << getState() << " "
+                   << "Array:" << Array << "\n";
+#endif
+    }
   };
 } // end anonymous namespace
 
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index 5f8a2c2..94668c8 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -111,10 +111,9 @@
 
   // Call the witness.
   SILType resultTy = gen.getLoweredType(objcType);
-  SILValue bridgedValue = gen.B.createApply(loc, witnessRef, witnessFnTy,
-                                            resultTy, substitutions,
-                                            swiftValue.borrow()
-                                              .getUnmanagedValue());
+  SILValue bridgedValue =
+      gen.B.createApply(loc, witnessRef, witnessFnTy, resultTy, substitutions,
+                        swiftValue.borrow(gen, loc).getValue());
   return gen.emitManagedRValueWithCleanup(bridgedValue);
 }
 
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 573ee54..3b9f0a4 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -120,6 +120,13 @@
     void emit(SILGenFunction &gen, CleanupLocation l) override {
       gen.B.emitDestroyValueOperation(l, closure);
     }
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "CleanupClosureConstant\n"
+                   << "State:" << getState() << "\n"
+                   << "closure:" << closure << "\n";
+#endif
+    }
   };
 } // end anonymous namespace
 
@@ -214,6 +221,15 @@
   void emit(SILGenFunction &gen, CleanupLocation l) override {
     gen.B.createEndBorrow(l, borrowed, original);
   }
+
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "EndBorrowCleanup "
+                 << "State:" << getState() << "\n"
+                 << "original:" << original << "\n"
+                 << "borrowed:" << borrowed << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
@@ -229,6 +245,14 @@
     else
       gen.B.emitDestroyValueOperation(l, v);
   }
+
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "ReleaseValueCleanup\n"
+                 << "State:" << getState() << "\n"
+                 << "Value:" << v << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
@@ -242,6 +266,14 @@
   void emit(SILGenFunction &gen, CleanupLocation l) override {
     gen.B.createDeallocStack(l, Addr);
   }
+
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "DeallocStackCleanup\n"
+                 << "State:" << getState() << "\n"
+                 << "Addr:" << Addr << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
@@ -255,6 +287,15 @@
   void emit(SILGenFunction &gen, CleanupLocation l) override {
     gen.destroyLocalVariable(l, Var);
   }
+
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "DestroyLocalVariable\n"
+                 << "State:" << getState() << "\n";
+    // TODO: Make sure we dump var.
+    llvm::errs() << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
@@ -268,6 +309,15 @@
   void emit(SILGenFunction &gen, CleanupLocation l) override {
     gen.deallocateUninitializedLocalVariable(l, Var);
   }
+
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "DeallocateUninitializedLocalVariable\n"
+                 << "State:" << getState() << "\n";
+    // TODO: Make sure we dump var.
+    llvm::errs() << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
@@ -1196,6 +1246,14 @@
         break;
       }
     }
+
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "DeinitExistentialCleanup\n"
+                   << "State:" << getState() << "\n"
+                   << "Value:" << existentialAddr << "\n";
+#endif
+    }
   };
 } // end anonymous namespace
 
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 33dfcdd..b934489 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -93,6 +93,13 @@
     void emit(SILGenFunction &gen, CleanupLocation loc) override {
       gen.getWritebackStack()[Depth].performWriteback(gen, /*isFinal*/ false);
     }
+
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "LValueWritebackCleanup\n"
+                   << "State: " << getState() << "Depth: " << Depth << "\n";
+#endif
+    }
   };
 } // end anonymous namespace
 
@@ -230,20 +237,21 @@
 
   // Otherwise, we need to emit a get and set.  Borrow the base for
   // the getter.
-  ManagedValue getterBase = (base ? base.borrow() : ManagedValue());
+  BorrowedManagedValue borrowedBase(gen, base, loc);
 
   // Clone anything else about the component that we might need in the
   // writeback.
   auto clonedComponent = clone(gen, loc);
 
-  // Emit a 'get' into a temporary.
-  ManagedValue temporary = emitGetIntoTemporary(gen, loc, getterBase,
-                                                std::move(*this));
+  // Emit a 'get' into a temporary and then pop the borrow of base.
+  ManagedValue temporary =
+      emitGetIntoTemporary(gen, loc, borrowedBase, std::move(*this));
+  std::move(borrowedBase).cleanup();
 
   // Push a writeback for the temporary.
   pushWriteback(gen, loc, std::move(clonedComponent), base,
                 MaterializedLValue(temporary));
-  return temporary.borrow();
+  return temporary.unmanagedBorrow();
 }
 
 void LogicalPathComponent::writeback(SILGenFunction &gen, SILLocation loc,
@@ -865,7 +873,7 @@
 
       // If the base is a +1 r-value, just borrow it for materializeForSet.
       // prepareAccessorArgs will copy it if necessary.
-      ManagedValue borrowedBase = (base ? base.borrow() : ManagedValue());
+      BorrowedManagedValue borrowedBase(gen, base, loc);
 
       // Clone the component without cloning the indices.  We don't actually
       // consume them in writeback().
@@ -912,6 +920,11 @@
             gen.B.createMarkDependence(loc, temporary, base.getValue()));
       }
 
+      // Now that we have emitted the materializeForSet and created a dependence
+      // on the base from the temporary value, we can end the shared borrow of
+      // the base scope if we performed one.
+      std::move(borrowedBase).cleanup();
+
       // TODO: maybe needsWriteback should be a thin function pointer
       // to which we pass the base?  That would let us use direct
       // access for stored properties with didSet.
@@ -1714,8 +1727,10 @@
   assert(!entry.HasBeenConsumed && "opaque value already consumed");
   entry.HasBeenConsumed = true;
 
+  RegularLocation loc(e);
   LValue lv;
-  lv.add<ValueComponent>(entry.Value.borrow(), getValueTypeData(gen, e));
+  lv.add<ValueComponent>(entry.Value.borrow(gen, loc),
+                         getValueTypeData(gen, e));
   return lv;
 }
 
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index 6fa6a18..b18277e 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -746,6 +746,12 @@
     void emit(SILGenFunction &gen, CleanupLocation loc) override {
       gen.B.createDeallocValueBuffer(loc, ValueType, Buffer);
     }
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "DeallocateValueBuffer\n"
+                   << "State: " << getState() << "Buffer: " << Buffer << "\n";
+#endif
+    }
   }; 
 } // end anonymous namespace
 
diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp
index e7ad809..017240d 100644
--- a/lib/SILGen/SILGenProlog.cpp
+++ b/lib/SILGen/SILGenProlog.cpp
@@ -64,6 +64,12 @@
   void emit(SILGenFunction &gen, CleanupLocation l) override {
     gen.B.emitDestroyValueOperation(l, box);
   }
+  void dump() const override {
+#ifndef NDEBUG
+    llvm::errs() << "DeallocateValueBuffer\n"
+                 << "State: " << getState() << "box: " << box << "\n";
+#endif
+  }
 };
 } // end anonymous namespace
 
diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp
index dc215c5..63d762d 100644
--- a/lib/SILGen/SILGenStmt.cpp
+++ b/lib/SILGen/SILGenStmt.cpp
@@ -405,6 +405,12 @@
     void emit(SILGenFunction &SGF, CleanupLocation l) override {
       assert(false && "Sema didn't catch exit out of a defer?");
     }
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "DeferEscapeCheckerCleanup\n"
+                   << "State: " << getState() << "\n";
+#endif
+    }
   };
 } // end anonymous namespace
 
@@ -425,6 +431,12 @@
       if (SGF.B.hasValidInsertionPoint())
         SGF.Cleanups.setCleanupState(TheCleanup, CleanupState::Dead);
     }
+    void dump() const override {
+#ifndef NDEBUG
+      llvm::errs() << "DeferCleanup\n"
+                   << "State: " << getState() << "\n";
+#endif
+    }
   };
 } // end anonymous namespace
 
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 6fe33e5..c34fba9 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,3 +1,8 @@
+
+if (SWIFT_FORCE_OPTIMIZED_TYPECHECKER)
+  set(EXTRA_TYPECHECKER_FLAGS "FORCE_BUILD_OPTIMIZED")
+endif()
+
 add_swift_library(swiftSema STATIC
   CSApply.cpp
   CSDiag.cpp
@@ -44,5 +49,7 @@
   TypeChecker.cpp
   LINK_LIBRARIES
     swiftParse
-    swiftAST)
+    swiftAST
+  ${EXTRA_TYPECHECKER_FLAGS}
+)
 
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 8a6a59a..10f4fbf 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -265,17 +265,17 @@
 }
 
 bool ConstraintSystem::isTypeReference(Expr *E) {
-  return E->isTypeReference([&](const Expr &E) -> Type { return getType(&E); });
+  return E->isTypeReference([&](const Expr *E) -> Type { return getType(E); });
 }
 
 bool ConstraintSystem::isStaticallyDerivedMetatype(Expr *E) {
   return E->isStaticallyDerivedMetatype(
-      [&](const Expr &E) -> Type { return getType(&E); });
+      [&](const Expr *E) -> Type { return getType(E); });
 }
 
 Type ConstraintSystem::getInstanceType(TypeExpr *E) {
-  return E->getInstanceType([&](const Expr &E) -> bool { return hasType(&E); },
-                            [&](const Expr &E) -> Type { return getType(&E); });
+  return E->getInstanceType([&](const Expr *E) -> bool { return hasType(E); },
+                            [&](const Expr *E) -> Type { return getType(E); });
 }
 
 namespace {
@@ -968,6 +968,7 @@
           apply->setImplicit();
         }
       }
+
       return finishApply(apply, openedType, locator);
     }
     
@@ -1280,6 +1281,10 @@
       if (!index)
         return nullptr;
 
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
       // Form the subscript expression.
 
       // Handle dynamic lookup.
@@ -1293,7 +1298,7 @@
         // TODO: diagnose if semantics != AccessSemantics::Ordinary?
         auto subscriptExpr = DynamicSubscriptExpr::create(tc.Context, base,
                                                           index, subscript,
-                                                          isImplicit);
+                                                          isImplicit, getType);
         cs.setType(subscriptExpr, resultTy);
         Expr *result = subscriptExpr;
         closeExistential(result, locator);
@@ -1323,12 +1328,10 @@
           return nullptr;
 
         // Form the generic subscript expression.
-        auto subscriptExpr
-          = SubscriptExpr::create(tc.Context, base, index,
-                                  ConcreteDeclRef(tc.Context, subscript,
-                                                  substitutions),
-                                  isImplicit,
-                                  semantics);
+        auto subscriptExpr = SubscriptExpr::create(
+            tc.Context, base, index,
+            ConcreteDeclRef(tc.Context, subscript, substitutions), isImplicit,
+            semantics, getType);
         cs.setType(subscriptExpr, resultTy);
         subscriptExpr->setIsSuper(isSuper);
 
@@ -1349,9 +1352,8 @@
         return nullptr;
 
       // Form a normal subscript.
-      auto *subscriptExpr
-        = SubscriptExpr::create(tc.Context, base, index, subscript,
-                                isImplicit, semantics);
+      auto *subscriptExpr = SubscriptExpr::create(
+          tc.Context, base, index, subscript, isImplicit, semantics, getType);
       cs.setType(subscriptExpr, resultTy);
       subscriptExpr->setIsSuper(isSuper);
       Expr *result = subscriptExpr;
@@ -1418,10 +1420,17 @@
       ConcreteDeclRef fnDeclRef(fn);
       auto fnRef = new (tc.Context) DeclRefExpr(fnDeclRef, DeclNameLoc(loc),
                                                 /*Implicit=*/true);
-      fnRef->setType(fn->getInterfaceType());
+      cs.setType(fnRef, fn->getInterfaceType());
       fnRef->setFunctionRefKind(FunctionRefKind::SingleApply);
-      cs.setExprTypes(value);
-      Expr *call = CallExpr::createImplicit(tc.Context, fnRef, { value }, { });
+
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
+      Expr *call = CallExpr::createImplicit(tc.Context, fnRef, { value }, { },
+                                            getType);
+      cs.cacheSubExprTypes(call);
+      cs.setSubExprTypes(call);
       if (tc.typeCheckExpressionShallow(call, dc))
         return nullptr;
 
@@ -1506,11 +1515,15 @@
                                                 AccessSemantics::Ordinary,
                                                 bridgeFnTy);
 
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
       fnRef->setFunctionRefKind(FunctionRefKind::SingleApply);
       Expr *call = CallExpr::createImplicit(tc.Context, fnRef, valueParen,
-                                            { Identifier() });
+                                            { Identifier() }, getType);
       cs.setType(call, bridgeTy);
-      cs.cacheSubExprTypes(call);
+      cs.cacheExprTypes(call);
       return call;
     }
 
@@ -1605,19 +1618,23 @@
       // Form the arguments.
       Expr *args[2] = {
         object,
-        cs.cacheType(new (tc.Context) DotSelfExpr(
-                         cs.cacheType(
+        new (tc.Context) DotSelfExpr(
                              TypeExpr::createImplicitHack(object->getLoc(),
                                                           valueType,
-                                                          tc.Context)),
-                         object->getLoc(), object->getLoc(),
-                         MetatypeType::get(valueType)))
+                                                          tc.Context),
+                             object->getLoc(), object->getLoc(),
+                             MetatypeType::get(valueType))
       };
       args[1]->setImplicit();
 
       // Form the call and type-check it.
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
       Expr *call = CallExpr::createImplicit(tc.Context, fnRef, args,
-                                            { Identifier(), Identifier() });
+                                            { Identifier(), Identifier() },
+                                            getType);
       cs.cacheSubExprTypes(call);
       cs.setSubExprTypes(call);
 
@@ -2064,9 +2081,9 @@
 
       // Build a reference to the init(stringInterpolation:) initializer.
       // FIXME: This location info is bogus.
-      auto *typeRef =
-        cs.cacheType(TypeExpr::createImplicitHack(expr->getStartLoc(),
-                                                  type, tc.Context));
+      auto *typeRef = TypeExpr::createImplicitHack(expr->getStartLoc(), type,
+                                                   tc.Context);
+
       Expr *memberRef =
         new (tc.Context) MemberRefExpr(typeRef,
                                        expr->getStartLoc(),
@@ -2084,17 +2101,23 @@
       SmallVector<Expr *, 4> segments;
       SmallVector<Identifier, 4> names;
       ConstraintLocatorBuilder locatorBuilder(cs.getConstraintLocator(expr));
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
       for (auto segment : expr->getSegments()) {
         ApplyExpr *apply =
           CallExpr::createImplicit(
             tc.Context, typeRef,
             { segment },
-            { tc.Context.Id_stringInterpolationSegment });
-        cs.cacheType(apply->getArg());
+            { tc.Context.Id_stringInterpolationSegment }, getType);
+        cs.cacheSubExprTypes(apply);
 
         Expr *convertedSegment = apply;
+        cs.setSubExprTypes(convertedSegment);
         if (tc.typeCheckExpressionShallow(convertedSegment, cs.DC))
           continue;
+        cs.cacheExprTypes(convertedSegment);
 
         segments.push_back(convertedSegment);
 
@@ -2111,8 +2134,8 @@
 
       // Call the init(stringInterpolation:) initializer with the arguments.
       ApplyExpr *apply = CallExpr::createImplicit(tc.Context, memberRef,
-                                                  segments, names);
-      cs.cacheSubExprTypes(apply);
+                                                  segments, names, getType);
+      cs.cacheExprTypes(apply);
       expr->setSemanticExpr(finishApply(apply, openedType, locatorBuilder));
       return expr;
     }
@@ -2164,10 +2187,9 @@
                               ConformanceCheckFlags::InExpression);
       assert(conformance && "object literal type conforms to protocol");
 
-      Expr *base =
-        cs.cacheType(TypeExpr::createImplicitHack(expr->getLoc(),
-                                                  conformingType,
-                                                  ctx));
+      Expr *base = TypeExpr::createImplicitHack(expr->getLoc(), conformingType,
+                                                ctx);
+      cs.cacheExprTypes(base);
         
       SmallVector<Expr *, 4> args;
       if (!isa<TupleExpr>(expr->getArg()))
@@ -2327,9 +2349,9 @@
 
       // The base expression is simply the metatype of the base type.
       // FIXME: This location info is bogus.
-      auto base =
-        cs.cacheType(TypeExpr::createImplicitHack(expr->getDotLoc(),
-                                                  baseTy, tc.Context));
+      auto base = TypeExpr::createImplicitHack(expr->getDotLoc(), baseTy,
+                                               tc.Context);
+      cs.cacheExprTypes(base);
 
       // Build the member reference.
       bool isDynamic
@@ -2348,13 +2370,16 @@
       if (!result)
         return nullptr;
 
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
       // If there was an argument, apply it.
       if (auto arg = expr->getArgument()) {
-        ApplyExpr *apply = CallExpr::create(tc.Context, result, arg,
-                                            expr->getArgumentLabels(),
-                                            expr->getArgumentLabelLocs(),
-                                            expr->hasTrailingClosure(),
-                                            /*implicit=*/false);
+        ApplyExpr *apply = CallExpr::create(
+            tc.Context, result, arg, expr->getArgumentLabels(),
+            expr->getArgumentLabelLocs(), expr->hasTrailingClosure(),
+            /*implicit=*/false, Type(), getType);
         result = finishApply(apply, Type(), cs.getConstraintLocator(expr));
       }
 
@@ -2493,9 +2518,9 @@
                                               baseMetaTy->getInstanceType());
           
           // FIXME: We're dropping side effects in the base here!
-          base =
-            cs.cacheType(TypeExpr::createImplicitHack(base->getLoc(), classTy,
-                                                      tc.Context));
+          base = TypeExpr::createImplicitHack(base->getLoc(), classTy,
+                                              tc.Context);
+          cs.cacheExprTypes(base);
         } else {
           // Bridge the base to its corresponding Objective-C object.
           base = bridgeToObjectiveC(base);
@@ -2628,9 +2653,10 @@
       // be nicer to re-use them.
 
       // FIXME: This location info is bogus.
-      Expr *typeRef =
-        cs.cacheType(TypeExpr::createImplicitHack(expr->getLoc(),
-                                                  arrayTy, tc.Context));
+      Expr *typeRef = TypeExpr::createImplicitHack(expr->getLoc(), arrayTy,
+                                                   tc.Context);
+      cs.cacheExprTypes(typeRef);
+
       DeclName name(tc.Context, tc.Context.Id_init,
                     { tc.Context.Id_arrayLiteral });
 
@@ -2706,9 +2732,9 @@
       // It would be nicer to re-use them.
       // FIXME: Cache the name.
       // FIXME: This location info is bogus.
-      Expr *typeRef =
-        cs.cacheType(TypeExpr::createImplicitHack(expr->getLoc(),
-                                                  dictionaryTy, tc.Context));
+      Expr *typeRef = TypeExpr::createImplicitHack(expr->getLoc(), dictionaryTy,
+                                                   tc.Context);
+      cs.cacheExprTypes(typeRef);
 
       DeclName name(tc.Context, tc.Context.Id_init,
                     { tc.Context.Id_dictionaryLiteral });
@@ -3276,13 +3302,13 @@
       // Warn about NSNumber and NSValue bridging coercions we accepted in
       // Swift 3 but which can fail at runtime.
       if (tc.Context.LangOpts.isSwiftVersion3()
-          && tc.typeCheckCheckedCast(sub->getType(), toInstanceType,
+          && tc.typeCheckCheckedCast(cs.getType(sub), toInstanceType,
                                      CheckedCastContextKind::None,
                                      dc, SourceLoc(), sub, SourceRange())
                == CheckedCastKind::Swift3BridgingDowncast) {
         tc.diagnose(expr->getLoc(),
                     diag::missing_forced_downcast_swift3_compat_warning,
-                    sub->getType(), toInstanceType)
+                    cs.getType(sub), toInstanceType)
           .fixItReplace(expr->getAsLoc(), "as!");
       }
       
@@ -3547,8 +3573,13 @@
       StringRef msg = "attempt to evaluate editor placeholder";
       Expr *argExpr = new (ctx) StringLiteralExpr(msg, E->getLoc(),
                                                   /*implicit*/true);
+
+      auto getType = [&](const Expr *E) -> Type {
+        return cs.getType(E);
+      };
+
       Expr *callExpr = CallExpr::createImplicit(ctx, fnRef, { argExpr },
-                                                { Identifier() });
+                                                { Identifier() }, getType);
 
       bool invalid = tc.typeCheckExpression(callExpr, cs.DC,
                                             TypeLoc::withoutLoc(valueType),
@@ -3867,6 +3898,9 @@
           .fixItInsert(cast->getStartLoc(), "(")
           .fixItInsertAfter(cast->getEndLoc(), ")");
       }
+
+      // Set the final types on the expression.
+      cs.setExprTypes(result);
     }
 
     /// Diagnose an optional injection that is probably not what the
@@ -5927,14 +5961,18 @@
                                    Diag<> brokenBuiltinProtocolDiag) {
   auto &tc = cs.getTypeChecker();
 
+  auto getType = [&](const Expr *E) -> Type {
+    return cs.getType(E);
+  };
+
   // If coercing a literal to an unresolved type, we don't try to look up the
   // witness members, just do it.
   if (type->is<UnresolvedType>()) {
     // Instead of updating the literal expr in place, allocate a new node.  This
     // avoids issues where Builtin types end up on expr nodes and pollute
     // diagnostics.
-    literal = cast<LiteralExpr>(literal)->shallowClone(tc.Context);
-    
+    literal = cast<LiteralExpr>(literal)->shallowClone(tc.Context, getType);
+
     // The literal expression has this type.
     cs.setType(literal, type);
     return literal;
@@ -5968,7 +6006,7 @@
     // Instead of updating the literal expr in place, allocate a new node.  This
     // avoids issues where Builtin types end up on expr nodes and pollute
     // diagnostics.
-    literal = cast<LiteralExpr>(literal)->shallowClone(tc.Context);
+    literal = cast<LiteralExpr>(literal)->shallowClone(tc.Context, getType);
 
     // The literal expression has this type.
     cs.setType(literal, argType);
@@ -6066,14 +6104,18 @@
                                           Diag<> brokenBuiltinProtocolDiag) {
   auto &tc = cs.getTypeChecker();
 
+  auto getType = [&](const Expr *E) -> Type {
+    return cs.getType(E);
+  };
+
   // If coercing a literal to an unresolved type, we don't try to look up the
   // witness members, just do it.
   if (type->is<UnresolvedType>()) {
     // Instead of updating the literal expr in place, allocate a new node.  This
     // avoids issues where Builtin types end up on expr nodes and pollute
     // diagnostics.
-    literal = cast<LiteralExpr>(literal)->shallowClone(tc.Context);
-    
+    literal = cast<LiteralExpr>(literal)->shallowClone(tc.Context, getType);
+
     // The literal expression has this type.
     cs.setType(literal, type);
     return literal;
@@ -6097,9 +6139,9 @@
 
     // Form a reference to the builtin conversion function.
     // FIXME: Bogus location info.
-    Expr *base =
-      cs.cacheType(TypeExpr::createImplicitHack(literal->getLoc(), type,
-                                                tc.Context));
+    Expr *base = TypeExpr::createImplicitHack(literal->getLoc(), type,
+                                              tc.Context);
+
     Expr *unresolvedDot = new (tc.Context) UnresolvedDotExpr(
                                              base, SourceLoc(),
                                              witness->getFullName(),
@@ -6162,9 +6204,9 @@
 
   // Form a reference to the conversion function.
   // FIXME: Bogus location info.
-  Expr *base =
-    cs.cacheType(TypeExpr::createImplicitHack(literal->getLoc(), type,
-                                              tc.Context));
+  Expr *base = TypeExpr::createImplicitHack(literal->getLoc(), type,
+                                            tc.Context);
+
   Expr *unresolvedDot = new (tc.Context) UnresolvedDotExpr(
                                            base, SourceLoc(),
                                            witness->getFullName(),
@@ -6297,11 +6339,14 @@
         auto escapable = new (tc.Context)
           OpaqueValueExpr(apply->getFn()->getLoc(), Type());
         cs.setType(escapable, escapableType);
-        
-        auto callSubExpr = CallExpr::create(tc.Context, body, escapable,
-                                            {}, {},
+
+        auto getType = [&](const Expr *E) -> Type {
+          return cs.getType(E);
+        };
+
+        auto callSubExpr = CallExpr::create(tc.Context, body, escapable, {}, {},
                                             /*trailing closure*/ false,
-                                            /*implicit*/ true);
+                                            /*implicit*/ true, Type(), getType);
         cs.setType(callSubExpr, resultType);
         
         auto replacement = new (tc.Context)
@@ -7149,6 +7194,10 @@
                                   FunctionRefKind::DoubleApply,
                                   dotLocator);
 
+  auto getType = [&](const Expr *E) -> Type {
+    return cs.getType(E);
+  };
+
   // Form the call argument.
   // FIXME: Standardize all callers to always provide all argument names,
   // rather than hack around this.
@@ -7157,9 +7206,9 @@
   if (arguments.size() == 1 &&
       (isVariadicWitness(witness) ||
        argumentNamesMatch(arguments[0]->getType(), argLabels))) {
-    call = CallExpr::create(Context, unresolvedDot, arguments[0], { },
-                            { }, /*hasTrailingClosure=*/false,
-                            /*implicit=*/true);
+    call = CallExpr::create(Context, unresolvedDot, arguments[0], {}, {},
+                            /*hasTrailingClosure=*/false,
+                            /*implicit=*/true, Type(), getType);
   } else {
     // The tuple should have the source range enclosing its arguments unless
     // they are invalid or there are no arguments.
@@ -7174,12 +7223,10 @@
       }
     }
 
-    call = CallExpr::create(Context, unresolvedDot,
-                            TupleStartLoc,
-                            arguments, argLabels, { },
-                            TupleEndLoc,
+    call = CallExpr::create(Context, unresolvedDot, TupleStartLoc, arguments,
+                            argLabels, {}, TupleEndLoc,
                             /*trailingClosure=*/nullptr,
-                            /*implicit=*/true);
+                            /*implicit=*/true, getType);
   }
 
   // Add the conversion from the argument to the function parameter type.
@@ -7276,7 +7323,11 @@
   (void)failed;
 
   // Call the builtin method.
-  expr = CallExpr::createImplicit(ctx, memberRef, { }, { });
+  auto getType = [&](const Expr *E) -> Type {
+    return cs.getType(E);
+  };
+
+  expr = CallExpr::createImplicit(ctx, memberRef, { }, { }, getType);
   cs.cacheSubExprTypes(expr);
   cs.setSubExprTypes(expr);
   failed = tc.typeCheckExpressionShallow(expr, cs.DC);
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index e5d530b..a44e642 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -102,7 +102,9 @@
       "${SWIFT_SOURCE_DIR}/utils/${lowercase}/static-executable-args.lnk"
       "${SWIFTSTATICLIB_DIR}/${linkfile}"
     OUTPUT
-      "${SWIFTSTATICLIB_DIR}/${linkfile}")
+      "${SWIFTSTATICLIB_DIR}/${linkfile}"
+    DEPENDS
+      "${SWIFT_SOURCE_DIR}/utils/${lowercase}/static-executable-args.lnk")
 
   list(APPEND static_binary_lnk_file_list ${swift_static_binary_${sdk}_args})
   swift_install_in_component(stdlib
@@ -161,16 +163,10 @@
     set(section_magic_begin_obj "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/section_magic_begin-${arch_suffix}.dir/swift_sections.S${CMAKE_C_OUTPUT_EXTENSION}")
     set(section_magic_end_obj "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/section_magic_end-${arch_suffix}.dir/swift_sections.S${CMAKE_C_OUTPUT_EXTENSION}")
 
-    if(SWIFT_ENABLE_GOLD_LINKER)
-      set(LD_COMMAND "gold")
-    else()
-      set(LD_COMMAND "ld")
-    endif()
-
     add_custom_command_target(section_magic_${arch_suffix}_begin_object
       COMMAND
           # Merge ImageInspectionInit.o + swift_sections.S(BEGIN) => swift_begin.o
-          ${LD_COMMAND} -r -o "${SWIFTLIB_DIR}/${arch_subdir}/swift_begin.o"
+          ${CMAKE_LINKER} -r -o "${SWIFTLIB_DIR}/${arch_subdir}/swift_begin.o"
           "${section_magic_begin_obj}" "${section_magic_loader_obj}"
       OUTPUT
           "${SWIFTLIB_DIR}/${arch_subdir}/swift_begin.o"
diff --git a/test/SILGen/accessors.swift b/test/SILGen/accessors.swift
index ea80410..7d4e39a 100644
--- a/test/SILGen/accessors.swift
+++ b/test/SILGen/accessors.swift
@@ -26,7 +26,7 @@
   ref.array[index0()] = ref.array[index1()]
 }
 // CHECK: sil hidden @_T09accessors5test0yAA1ACF : $@convention(thin) (@owned A) -> () {
-// CHECK: bb0(%0 : $A):
+// CHECK: bb0([[ARG:%.*]] : $A):
 // CHECK-NEXT: debug_value
 //   Formal evaluation of LHS.
 // CHECK-NEXT: // function_ref accessors.index0 () -> Swift.Int
@@ -38,8 +38,8 @@
 // CHECK-NEXT: [[INDEX1:%.*]] = apply [[T0]]()
 //   Formal access to RHS.
 // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $OrdinarySub
-// CHECK-NEXT: [[T0:%.*]] = class_method %0 : $A, #A.array!getter.1
-// CHECK-NEXT: [[T1:%.*]] = apply [[T0]](%0)
+// CHECK-NEXT: [[T0:%.*]] = class_method [[ARG]] : $A, #A.array!getter.1
+// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[ARG]])
 // CHECK-NEXT: store [[T1]] to [init] [[TEMP]]
 // CHECK-NEXT: [[T0:%.*]] = load [take] [[TEMP]]
 // CHECK-NEXT: // function_ref accessors.OrdinarySub.subscript.getter : (Swift.Int) -> Swift.Int
@@ -49,17 +49,20 @@
 //   Formal access to LHS.
 // CHECK-NEXT: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
 // CHECK-NEXT: [[BUFFER:%.*]] = alloc_stack $OrdinarySub
+// CHECK-NEXT: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
 // CHECK-NEXT: [[T0:%.*]] = address_to_pointer [[BUFFER]]
-// CHECK-NEXT: [[T1:%.*]] = class_method %0 : $A, #A.array!materializeForSet.1
-// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE]], %0)
+// CHECK-NEXT: [[T1:%.*]] = class_method [[BORROWED_ARG]] : $A, #A.array!materializeForSet.1
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE]], [[BORROWED_ARG]])
 // CHECK-NEXT: [[T3:%.*]] = tuple_extract [[T2]] {{.*}}, 0
 // CHECK-NEXT: [[OPT_CALLBACK:%.*]] = tuple_extract [[T2]] {{.*}}, 1
 // CHECK-NEXT: [[T4:%.*]] = pointer_to_address [[T3]]
 // CHECK-NEXT: [[ADDR:%.*]] = mark_dependence [[T4]] : $*OrdinarySub on %0 : $A
+// CHECK-NEXT: end_borrow [[BORROWED_ARG]] from [[ARG]]
 // CHECK-NEXT: // function_ref accessors.OrdinarySub.subscript.setter : (Swift.Int) -> Swift.Int
 // CHECK-NEXT: [[T0:%.*]] = function_ref @_T09accessors11OrdinarySubV9subscriptSiSicfs
 // CHECK-NEXT: apply [[T0]]([[VALUE]], [[INDEX0]], [[ADDR]])
 // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+
 // CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer):
 // CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout A, @thick A.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $A
@@ -69,6 +72,7 @@
 // CHECK-NEXT: apply [[CALLBACK]]([[T1]], [[STORAGE]], [[TEMP2]], [[T0]])
 // CHECK-NEXT: dealloc_stack [[TEMP2]]
 // CHECK-NEXT: br [[CONT]]
+
 // CHECK:    [[CONT]]:
 // CHECK-NEXT: dealloc_stack [[BUFFER]]
 // CHECK-NEXT: dealloc_stack [[STORAGE]]
@@ -92,7 +96,7 @@
   ref.array[index0()] = ref.array[index1()]
 }
 // CHECK-LABEL: sil hidden @_T09accessors5test1yAA1BCF : $@convention(thin) (@owned B) -> () {
-// CHECK:    bb0(%0 : $B):
+// CHECK:    bb0([[ARG:%.*]] : $B):
 // CHECK-NEXT: debug_value
 //   Formal evaluation of LHS.
 // CHECK-NEXT: // function_ref accessors.index0 () -> Swift.Int
@@ -105,17 +109,20 @@
 //   Formal access to RHS.
 // CHECK-NEXT: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
 // CHECK-NEXT: [[BUFFER:%.*]] = alloc_stack $MutatingSub
+// CHECK-NEXT: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
 // CHECK-NEXT: [[T0:%.*]] = address_to_pointer [[BUFFER]]
-// CHECK-NEXT: [[T1:%.*]] = class_method %0 : $B, #B.array!materializeForSet.1
-// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE]], %0)
+// CHECK-NEXT: [[T1:%.*]] = class_method [[BORROWED_ARG]] : $B, #B.array!materializeForSet.1
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE]], [[BORROWED_ARG]])
 // CHECK-NEXT: [[T3:%.*]] = tuple_extract [[T2]] {{.*}}, 0
 // CHECK-NEXT: [[OPT_CALLBACK:%.*]] = tuple_extract [[T2]] {{.*}}, 1
 // CHECK-NEXT: [[T4:%.*]] = pointer_to_address [[T3]]
 // CHECK-NEXT: [[ADDR:%.*]] = mark_dependence [[T4]] : $*MutatingSub on %0 : $B
+// CHECK-NEXT: end_borrow [[BORROWED_ARG]] from [[ARG]]
 // CHECK-NEXT: // function_ref accessors.MutatingSub.subscript.getter : (Swift.Int) -> Swift.Int
 // CHECK-NEXT: [[T0:%.*]] = function_ref @_T09accessors11MutatingSubV9subscriptSiSicfg : $@convention(method) (Int, @inout MutatingSub) -> Int 
 // CHECK-NEXT: [[VALUE:%.*]] = apply [[T0]]([[INDEX1]], [[ADDR]])
 // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+//
 // CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer):
 // CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
@@ -125,21 +132,25 @@
 // CHECK-NEXT: apply [[CALLBACK]]([[T1]], [[STORAGE]], [[TEMP2]], [[T0]])
 // CHECK-NEXT: dealloc_stack [[TEMP2]]
 // CHECK-NEXT: br [[CONT]]
+//
 // CHECK:    [[CONT]]:
 //   Formal access to LHS.
 // CHECK-NEXT: [[STORAGE2:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
 // CHECK-NEXT: [[BUFFER2:%.*]] = alloc_stack $MutatingSub
+// CHECK-NEXT: [[BORROWED_ARG_2:%.*]] = begin_borrow [[ARG]]
 // CHECK-NEXT: [[T0:%.*]] = address_to_pointer [[BUFFER2]]
-// CHECK-NEXT: [[T1:%.*]] = class_method %0 : $B, #B.array!materializeForSet.1
-// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE2]], %0)
+// CHECK-NEXT: [[T1:%.*]] = class_method [[BORROWED_ARG_2]] : $B, #B.array!materializeForSet.1
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE2]], [[BORROWED_ARG_2]])
 // CHECK-NEXT: [[T3:%.*]] = tuple_extract [[T2]] {{.*}}, 0
 // CHECK-NEXT: [[OPT_CALLBACK:%.*]] = tuple_extract [[T2]] {{.*}}, 1
 // CHECK-NEXT: [[T4:%.*]] = pointer_to_address [[T3]]
 // CHECK-NEXT: [[ADDR:%.*]] = mark_dependence [[T4]] : $*MutatingSub on %0 : $B
+// CHECK-NEXT: end_borrow [[BORROWED_ARG_2]] from [[ARG]]
 // CHECK-NEXT: // function_ref accessors.MutatingSub.subscript.setter : (Swift.Int) -> Swift.Int
 // CHECK-NEXT: [[T0:%.*]] = function_ref @_T09accessors11MutatingSubV9subscriptSiSicfs : $@convention(method) (Int, Int, @inout MutatingSub) -> () 
 // CHECK-NEXT: apply [[T0]]([[VALUE]], [[INDEX0]], [[ADDR]])
 // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+//
 // CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer):
 // CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
@@ -149,6 +160,7 @@
 // CHECK-NEXT: apply [[CALLBACK]]([[T1]], [[STORAGE2]], [[TEMP2]], [[T0]])
 // CHECK-NEXT: dealloc_stack [[TEMP2]]
 // CHECK-NEXT: br [[CONT]]
+//
 // CHECK:    [[CONT]]:
 // CHECK-NEXT: dealloc_stack [[BUFFER2]]
 // CHECK-NEXT: dealloc_stack [[STORAGE2]]
diff --git a/test/SILGen/foreign_errors.swift b/test/SILGen/foreign_errors.swift
index 7dee4f8..2ad9a68 100644
--- a/test/SILGen/foreign_errors.swift
+++ b/test/SILGen/foreign_errors.swift
@@ -91,17 +91,25 @@
   @objc func badDescription() throws -> String {
     throw NSError(domain: "", code: 1, userInfo: [:])
   }
-// CHECK-LABEL: sil hidden [thunk] @_TToFE14foreign_errorsCSo8NSObject14badDescription{{.*}} : $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, NSObject) -> @autoreleased Optional<NSString>
+// CHECK-LABEL: sil hidden [thunk] @_TToFE14foreign_errorsCSo8NSObject14badDescription{{.*}} : $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, NSObject) -> @autoreleased Optional<NSString> {
+// CHECK: bb0([[UNOWNED_ARG0:%.*]] : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, [[UNOWNED_ARG1:%.*]] : $NSObject):
+// CHECK: [[ARG1:%.*]] = copy_value [[UNOWNED_ARG1]]
 // CHECK: [[T0:%.*]] = function_ref @_TFE14foreign_errorsCSo8NSObject14badDescription{{.*}} : $@convention(method) (@guaranteed NSObject) -> (@owned String, @error Error)
-// CHECK: try_apply [[T0]](
-// CHECK: bb1([[RESULT:%.*]] : $String):
+// CHECK: try_apply [[T0]]([[ARG1]]) : $@convention(method) (@guaranteed NSObject) -> (@owned String, @error Error), normal [[NORMAL_BB:bb[0-9][0-9]*]], error [[ERROR_BB:bb[0-9][0-9]*]]
+//
+// CHECK: [[NORMAL_BB]]([[RESULT:%.*]] : $String):
 // CHECK:   [[T0:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString : $@convention(method) (@guaranteed String) -> @owned NSString
-// CHECK:   [[T1:%.*]] = apply [[T0]]([[RESULT]])
+// CHECK:   [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[BORROWED_RESULT]])
 // CHECK:   [[T2:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[T1]] : $NSString
+// CHECK:   end_borrow [[BORROWED_RESULT]] from [[RESULT]]
+// CHECK:   destroy_value [[RESULT]]  
 // CHECK:   br bb6([[T2]] : $Optional<NSString>)
-// CHECK: bb2([[ERR:%.*]] : $Error):
-// CHECK:   switch_enum %0 : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb4
-// CHECK: bb3([[UNWRAPPED_OUT:%.+]] : $AutoreleasingUnsafeMutablePointer<Optional<NSError>>):
+//
+// CHECK: [[ERROR_BB]]([[ERR:%.*]] : $Error):
+// CHECK:   switch_enum [[UNOWNED_ARG0]] : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9][0-9]*]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9][0-9]*]]
+//
+// CHECK: [[SOME_BB]]([[UNWRAPPED_OUT:%.+]] : $AutoreleasingUnsafeMutablePointer<Optional<NSError>>):
 // CHECK:   [[T0:%.*]] = function_ref @swift_convertErrorToNSError : $@convention(thin) (@owned Error) -> @owned NSError
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[ERR]])
 // CHECK:   [[OBJCERR:%.*]] = enum $Optional<NSError>, #Optional.some!enumelt.1, [[T1]] : $NSError
@@ -111,9 +119,11 @@
 // CHECK:   apply [[SETTER]]<Optional<NSError>>([[TEMP]], [[UNWRAPPED_OUT]])
 // CHECK:   dealloc_stack [[TEMP]]
 // CHECK:   br bb5
-// CHECK: bb4:
+//
+// CHECK: [[NONE_BB]]:
 // CHECK:   destroy_value [[ERR]] : $Error
 // CHECK:   br bb5
+//
 // CHECK: bb5:
 // CHECK:   [[T0:%.*]] = enum $Optional<NSString>, #Optional.none!enumelt
 // CHECK:   br bb6([[T0]] : $Optional<NSString>)
diff --git a/test/SILGen/lifetime.swift b/test/SILGen/lifetime.swift
index 94e7d42..1792014 100644
--- a/test/SILGen/lifetime.swift
+++ b/test/SILGen/lifetime.swift
@@ -362,9 +362,10 @@
   // CHECK: [[R2:%[0-9]+]] = load [copy] [[PR]]
   // CHECK: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
   // CHECK: [[ALEPH_PROP_TEMP:%[0-9]+]] = alloc_stack $Aleph
+  // CHECK: [[BORROWED_R2:%.*]] = begin_borrow [[R2]]
   // CHECK: [[T0:%.*]] = address_to_pointer [[ALEPH_PROP_TEMP]]
-  // CHECK: [[MATERIALIZE_METHOD:%[0-9]+]] = class_method {{.*}} : $RefWithProp, #RefWithProp.aleph_prop!materializeForSet.1 :
-  // CHECK: [[MATERIALIZE:%.*]] = apply [[MATERIALIZE_METHOD]]([[T0]], [[STORAGE]], [[R2]])
+  // CHECK: [[MATERIALIZE_METHOD:%[0-9]+]] = class_method [[BORROWED_R2]] : $RefWithProp, #RefWithProp.aleph_prop!materializeForSet.1 :
+  // CHECK: [[MATERIALIZE:%.*]] = apply [[MATERIALIZE_METHOD]]([[T0]], [[STORAGE]], [[BORROWED_R2]])
   // CHECK: [[PTR:%.*]] = tuple_extract [[MATERIALIZE]] : {{.*}}, 0
   // CHECK: [[OPTCALLBACK:%.*]] = tuple_extract [[MATERIALIZE]] : {{.*}}, 1
   // CHECK: [[ADDR:%.*]] = pointer_to_address [[PTR]]
diff --git a/test/SILGen/objc_bridging.swift b/test/SILGen/objc_bridging.swift
index df2b9c8..79703a5 100644
--- a/test/SILGen/objc_bridging.swift
+++ b/test/SILGen/objc_bridging.swift
@@ -226,7 +226,10 @@
   // CHECK:   [[PROP_COPY:%.*]] = apply [[PROPIMPL]]([[THIS_COPY]]) : $@convention(method) (@guaranteed Bas) -> @owned String
   // CHECK:   destroy_value [[THIS_COPY]]
   // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
-  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[PROP_COPY]])
+  // CHECK:   [[BORROWED_PROP_COPY:%.*]] = begin_borrow [[PROP_COPY]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_PROP_COPY]])
+  // CHECK:   end_borrow [[BORROWED_PROP_COPY]] from [[PROP_COPY]]
+  // CHECK:   destroy_value [[PROP_COPY]]
   // CHECK:   return [[NSSTR]]
   // CHECK: }
 
@@ -267,7 +270,9 @@
   // CHECK:   [[STR:%.*]] = apply [[GETTER]]([[THIS_COPY]])
   // CHECK:   destroy_value [[THIS_COPY]]
   // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
-  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[STR]])
+  // CHECK:   [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_STR]])
+  // CHECK:   end_borrow [[BORROWED_STR]] from [[STR]]
   // CHECK:   destroy_value [[STR]]
   // CHECK:   return [[NSSTR]]
   // CHECK: }
@@ -309,7 +314,9 @@
   // CHECK:   [[STR:%.*]] = apply [[METHOD]]([[THIS_COPY]])
   // CHECK:   destroy_value [[THIS_COPY]]
   // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
-  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[STR]])
+  // CHECK:   [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_STR]])
+  // CHECK:   end_borrow [[BORROWED_STR]] from [[STR]]
   // CHECK:   destroy_value [[STR]]
   // CHECK:   return [[NSSTR]]
   // CHECK: }
@@ -364,7 +371,9 @@
   // CHECK:   [[ARRAY:%[0-9]+]] = apply [[SWIFT_FN]]([[SELF_COPY]]) : $@convention(method) (@guaranteed Bas) -> @owned Array<AnyObject>
   // CHECK:   destroy_value [[SELF_COPY]]
   // CHECK:   [[CONV_FN:%[0-9]+]] = function_ref @_TFE10FoundationSa19_bridgeToObjectiveCfT_CSo7NSArray
-  // CHECK:   [[NSARRAY:%[0-9]+]] = apply [[CONV_FN]]<AnyObject>([[ARRAY]]) : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> @owned NSArray
+  // CHECK:   [[BORROWED_ARRAY:%.*]] = begin_borrow [[ARRAY]]
+  // CHECK:   [[NSARRAY:%[0-9]+]] = apply [[CONV_FN]]<AnyObject>([[BORROWED_ARRAY]]) : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> @owned NSArray
+  // CHECK:   end_borrow [[BORROWED_ARRAY]] from [[ARRAY]]
   // CHECK:   destroy_value [[ARRAY]]
   // CHECK:   return [[NSARRAY]]
   func arrayResult() -> [AnyObject] { return [] }
@@ -381,12 +390,14 @@
   // CHECK:   [[BLOCK_COPY_COPY:%.*]] = copy_value [[BLOCK_COPY]]
   // CHECK:   [[STRING_COPY:%.*]] = copy_value [[STRING]]
   // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
-  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[STRING_COPY]])
+  // CHECK:   [[BORROWED_STRING_COPY:%.*]] = begin_borrow [[STRING_COPY]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_STRING_COPY]]) : $@convention(method) (@guaranteed String)
   // CHECK:   [[RESULT_NSSTR:%.*]] = apply [[BLOCK_COPY_COPY]]([[NSSTR]]) : $@convention(block) (NSString) -> @autoreleased NSString
   // CHECK:   [[FINAL_BRIDGE:%.*]] = function_ref @_TZFE10FoundationSS36_unconditionallyBridgeFromObjectiveCfGSqCSo8NSString_SS
   // CHECK:   [[OPTIONAL_NSSTR:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[RESULT_NSSTR]]
   // CHECK:   [[RESULT:%.*]] = apply [[FINAL_BRIDGE]]([[OPTIONAL_NSSTR]], {{.*}}) : $@convention(method) (@owned Optional<NSString>, @thin String.Type) -> @owned String
   // CHECK:   destroy_value [[NSSTR]]
+  // CHECK:   end_borrow [[BORROWED_STRING_COPY]] from [[STRING_COPY]]
   // CHECK:   destroy_value [[STRING_COPY]]
   // CHECK:   destroy_value [[BLOCK_COPY_COPY]]
   // CHECK:   destroy_value [[STRING]]
@@ -483,16 +494,22 @@
   // +=
   // CHECK: [[PLUS_EQ:%[0-9]+]] = function_ref @_TFsoi2peFTRSdSd_T_
 
+  // Borrowed home
+  // CHECK: [[BORROWED_HOME:%.*]] = begin_borrow [[HOME]]
+
   // Temporary fridge
   // CHECK: [[TEMP_FRIDGE:%[0-9]+]]  = alloc_stack $Refrigerator
 
   // Get operation
-  // CHECK: [[GETTER:%[0-9]+]] = class_method [volatile] [[HOME]] : $APPHouse, #APPHouse.fridge!getter.1.foreign
-  // CHECK: [[OBJC_FRIDGE:%[0-9]+]] = apply [[GETTER]]([[HOME]])
+  // CHECK: [[GETTER:%[0-9]+]] = class_method [volatile] [[BORROWED_HOME]] : $APPHouse, #APPHouse.fridge!getter.1.foreign
+  // CHECK: [[OBJC_FRIDGE:%[0-9]+]] = apply [[GETTER]]([[BORROWED_HOME]])
   // CHECK: [[BRIDGE_FROM_FN:%[0-9]+]] = function_ref @_TZFV10Appliances12Refrigerator36_unconditionallyBridgeFromObjectiveC
   // CHECK: [[REFRIGERATOR_META:%[0-9]+]] = metatype $@thin Refrigerator.Type
   // CHECK: [[FRIDGE:%[0-9]+]] = apply [[BRIDGE_FROM_FN]]([[OBJC_FRIDGE]], [[REFRIGERATOR_META]])
 
+  // End the borrow from the get operation.
+  // CHECK: end_borrow [[BORROWED_HOME]] from [[HOME]]
+
   // Addition
   // CHECK: [[TEMP:%[0-9]+]] = struct_element_addr [[TEMP_FRIDGE]] : $*Refrigerator, #Refrigerator.temperature
   // CHECK: apply [[PLUS_EQ]]([[TEMP]], [[DELTA]])
@@ -502,6 +519,8 @@
   // CHECK: [[SETTER:%[0-9]+]] = class_method [volatile] [[HOME]] : $APPHouse, #APPHouse.fridge!setter.1.foreign
   // CHECK: [[BRIDGE_TO_FN:%[0-9]+]] = function_ref @_TFV10Appliances12Refrigerator19_bridgeToObjectiveCfT_CSo15APPRefrigerator
   // CHECK: [[OBJC_ARG:%[0-9]+]] = apply [[BRIDGE_TO_FN]]([[FRIDGE]])
-  // CHECK: apply [[SETTER]]([[OBJC_ARG]], [[HOME]])
+  // CHECK: apply [[SETTER]]([[OBJC_ARG]], [[HOME]]) : $@convention(objc_method) (APPRefrigerator, APPHouse) -> ()
+  // CHECK: destroy_value [[OBJC_ARG]]
+  // CHECK: destroy_value [[HOME]]
   home.fridge.temperature += delta
 }
diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift
index 5c9a086..45d80bb 100644
--- a/test/SILGen/objc_bridging_any.swift
+++ b/test/SILGen/objc_bridging_any.swift
@@ -42,10 +42,12 @@
   // CHECK:   [[METHOD:%.*]] = class_method [volatile] [[SELF]]
   // CHECK:   [[STRING_COPY:%.*]] = copy_value [[STRING]]
   // CHECK:   [[BRIDGE_STRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveC
-  // CHECK:   [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[STRING_COPY]])
+  // CHECK:   [[BORROWED_STRING_COPY:%.*]] = begin_borrow [[STRING_COPY]]
+  // CHECK:   [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[BORROWED_STRING_COPY]])
   // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[BRIDGED]] : $NSString : $NSString, $AnyObject
   // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
   // CHECK:   destroy_value [[BRIDGED]]
+  // CHECK:   end_borrow [[BORROWED_STRING_COPY]] from [[STRING_COPY]]
   // CHECK:   destroy_value [[STRING_COPY]]
   receiver.takesId(string)
 
@@ -237,10 +239,14 @@
   // CHECK: [[METHOD:%.*]] = class_method [volatile] [[SELF]]
   // CHECK: [[STRING_COPY:%.*]] = copy_value [[STRING]]
   // CHECK: [[BRIDGE_STRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveC
-  // CHECK: [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[STRING_COPY]])
+  // CHECK: [[BORROWED_STRING_COPY:%.*]] = begin_borrow [[STRING_COPY]]
+  // CHECK: [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[BORROWED_STRING_COPY]])
   // CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[BRIDGED]] : $NSString : $NSString, $AnyObject
   // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
   // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  // CHECK: destroy_value [[BRIDGED]]
+  // CHECK: end_borrow [[BORROWED_STRING_COPY]] from [[STRING_COPY]]
+  // CHECK: destroy_value [[STRING_COPY]]
   receiver.takesNullableId(string)
 
   // CHECK: [[METHOD:%.*]] = class_method [volatile] [[SELF]] : $NSIdLover,
diff --git a/test/SILGen/objc_dictionary_bridging.swift b/test/SILGen/objc_dictionary_bridging.swift
index c9cd86e..79288f7 100644
--- a/test/SILGen/objc_dictionary_bridging.swift
+++ b/test/SILGen/objc_dictionary_bridging.swift
@@ -37,7 +37,9 @@
     // CHECK:   destroy_value [[SELF_COPY]]
 
     // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @_T0s10DictionaryV10FoundationE19_bridgeToObjectiveCSo12NSDictionaryCyF
-    // CHECK:   [[NSDICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[DICT]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+    // CHECK:   [[BORROWED_DICT:%.*]] = begin_borrow [[DICT]]
+    // CHECK:   [[NSDICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[BORROWED_DICT]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+    // CHECK:   end_borrow [[BORROWED_DICT]] from [[DICT]]
     // CHECK:   destroy_value [[DICT]]
     // CHECK:   return [[NSDICT]] : $NSDictionary
   }
@@ -53,7 +55,9 @@
   // CHECK:   [[DICT:%[0-9]+]] = apply [[GETTER]]([[SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
   // CHECK:   destroy_value [[SELF_COPY]]
   // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @_T0s10DictionaryV10FoundationE19_bridgeToObjectiveCSo12NSDictionaryCyF
-  // CHECK:   [[NSDICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[DICT]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+  // CHECK:   [[BORROWED_DICT:%.*]] = begin_borrow [[DICT]]
+  // CHECK:   [[NSDICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[BORROWED_DICT]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+  // CHECK:   end_borrow [[BORROWED_DICT]] from [[DICT]]
   // CHECK:   destroy_value [[DICT]]
   // CHECK:   return [[NSDICT]] : $NSDictionary
   // CHECK: } // end sil function '_T024objc_dictionary_bridging3FooC8propertys10DictionaryVyAcCGfgTo'
diff --git a/test/SILGen/objc_set_bridging.swift b/test/SILGen/objc_set_bridging.swift
index 61dc602..ba3c95a 100644
--- a/test/SILGen/objc_set_bridging.swift
+++ b/test/SILGen/objc_set_bridging.swift
@@ -35,7 +35,9 @@
     // CHECK:   [[SET:%[0-9]+]] = apply [[SWIFT_FN]]([[SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Set<Foo>
     // CHECK:   destroy_value [[SELF_COPY]]
     // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @_T0s3SetV10FoundationE19_bridgeToObjectiveCSo5NSSetCyF
-    // CHECK:   [[NSSET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[SET]]) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned NSSet
+    // CHECK:   [[BORROWED_SET:%.*]] = begin_borrow [[SET]]
+    // CHECK:   [[NSSET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[BORROWED_SET]]) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned NSSet
+    // CHECK:   end_borrow [[BORROWED_SET]] from [[SET]]
     // CHECK:   destroy_value [[SET]]
     // CHECK:   return [[NSSET]] : $NSSet
   }
@@ -51,7 +53,9 @@
   // CHECK:   [[SET:%[0-9]+]] = apply [[GETTER]]([[SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Set<Foo>
   // CHECK:   destroy_value [[SELF_COPY]]
   // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @_T0s3SetV10FoundationE19_bridgeToObjectiveCSo5NSSetCyF
-  // CHECK:   [[NSSET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[SET]]) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned NSSet
+  // CHECK:   [[BORROWED_SET:%.*]] = begin_borrow [[SET]]
+  // CHECK:   [[NSSET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[BORROWED_SET]]) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned NSSet
+  // CHECK:   end_borrow [[BORROWED_SET]] from [[SET]]
   // CHECK:   destroy_value [[SET]]
   // CHECK:   return [[NSSET]] : $NSSet
   // CHECK: } // end sil function '_T017objc_set_bridging3FooC8property{{[_0-9a-zA-Z]*}}fgTo'
diff --git a/test/SILGen/objc_thunks.swift b/test/SILGen/objc_thunks.swift
index 993afc7..f8377df 100644
--- a/test/SILGen/objc_thunks.swift
+++ b/test/SILGen/objc_thunks.swift
@@ -336,7 +336,9 @@
   // CHECK-NEXT:   destroy_value [[SELF_COPY]] : $Wotsit<T>
   // CHECK-NEXT:   // function_ref
   // CHECK-NEXT:   [[BRIDGE:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
-  // CHECK-NEXT:   [[NSRESULT:%.*]] = apply [[BRIDGE]]([[RESULT]]) : $@convention(method) (@guaranteed String) -> @owned NSString
+  // CHECK-NEXT:   [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK-NEXT:   [[NSRESULT:%.*]] = apply [[BRIDGE]]([[BORROWED_RESULT]]) : $@convention(method) (@guaranteed String) -> @owned NSString
+  // CHECK-NEXT:   end_borrow [[BORROWED_RESULT]] from [[RESULT]]
   // CHECK-NEXT:   destroy_value [[RESULT]]
   // CHECK-NEXT:   return [[NSRESULT]] : $NSString
   // CHECK-NEXT: }
diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift
index 200936c..414f44a 100644
--- a/test/SILGen/properties.swift
+++ b/test/SILGen/properties.swift
@@ -190,13 +190,15 @@
   // -- val.ref.val_prop
   // CHECK: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
   // CHECK: [[VAL_REF_VAL_PROP_TEMP:%.*]] = alloc_stack $Val
+  // CHECK: [[VAL_REF_BORROWED:%.*]] = begin_borrow [[VAL_REF]]
   // CHECK: [[T0:%.*]] = address_to_pointer [[VAL_REF_VAL_PROP_TEMP]] : $*Val to $Builtin.RawPointer
   // CHECK: [[MAT_VAL_PROP_METHOD:%[0-9]+]] = class_method {{.*}} : $Ref, #Ref.val_prop!materializeForSet.1 : (Ref) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)
-  // CHECK: [[MAT_RESULT:%[0-9]+]] = apply [[MAT_VAL_PROP_METHOD]]([[T0]], [[STORAGE]], [[VAL_REF]])
+  // CHECK: [[MAT_RESULT:%[0-9]+]] = apply [[MAT_VAL_PROP_METHOD]]([[T0]], [[STORAGE]], [[VAL_REF_BORROWED]])
   // CHECK: [[T0:%.*]] = tuple_extract [[MAT_RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>), 0
   // CHECK: [[OPT_CALLBACK:%.*]] = tuple_extract [[MAT_RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>), 1  
   // CHECK: [[T1:%[0-9]+]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Val
   // CHECK: [[VAL_REF_VAL_PROP_MAT:%.*]] = mark_dependence [[T1]] : $*Val on [[VAL_REF]]
+  // CHECK: end_borrow [[VAL_REF_BORROWED]] from [[VAL_REF]]
   // CHECK: [[V_R_VP_Z_TUPLE_MAT:%[0-9]+]] = alloc_stack $(Int, Int)
   // CHECK: [[LD:%[0-9]+]] = load [copy] [[VAL_REF_VAL_PROP_MAT]]
   // -- val.ref.val_prop.z_tuple
diff --git a/utils/build-script b/utils/build-script
index 9e9f4d8..9294811 100755
--- a/utils/build-script
+++ b/utils/build-script
@@ -2059,6 +2059,11 @@
                         help="Enable the SIL ownership model",
                         action='store_true')
 
+    parser.add_argument("--force-optimized-typechecker",
+                        help="Force the type checker to be built with "
+                        "optimization",
+                        action='store_true')
+
     parser.add_argument(
         # Explicitly unavailable options here.
         "--build-jobs",
diff --git a/utils/swift_build_support/swift_build_support/products/swift.py b/utils/swift_build_support/swift_build_support/products/swift.py
index a1af113..203b113 100644
--- a/utils/swift_build_support/swift_build_support/products/swift.py
+++ b/utils/swift_build_support/swift_build_support/products/swift.py
@@ -36,6 +36,10 @@
         # Generate the compile db.
         self.cmake_options.extend(self._compile_db_flags)
 
+        # Add the flag if we are supposed to force the typechecker to compile
+        # with optimization.
+        self.cmake_options.extend(self._force_optimized_typechecker_flags)
+
     @property
     def _runtime_sanitizer_flags(self):
         sanitizer_list = []
@@ -108,3 +112,9 @@
     @property
     def _compile_db_flags(self):
         return ['-DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE']
+
+    @property
+    def _force_optimized_typechecker_flags(self):
+        if not self.args.force_optimized_typechecker:
+            return ['-DSWIFT_FORCE_OPTIMIZED_TYPECHECKER=FALSE']
+        return ['-DSWIFT_FORCE_OPTIMIZED_TYPECHECKER=TRUE']
diff --git a/utils/swift_build_support/tests/products/test_swift.py b/utils/swift_build_support/tests/products/test_swift.py
index 9378379..0400038 100644
--- a/utils/swift_build_support/tests/products/test_swift.py
+++ b/utils/swift_build_support/tests/products/test_swift.py
@@ -55,7 +55,8 @@
             benchmark=False,
             benchmark_num_onone_iterations=3,
             benchmark_num_o_iterations=3,
-            enable_sil_ownership=False)
+            enable_sil_ownership=False,
+            force_optimized_typechecker=False)
 
         # Setup shell
         shell.dry_run = True
@@ -84,7 +85,8 @@
             build_dir='/path/to/build')
         self.assertEqual(set(swift.cmake_options), set([
                          '-DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE',
-                         '-DSWIFT_STDLIB_ENABLE_SIL_OWNERSHIP=FALSE']))
+                         '-DSWIFT_STDLIB_ENABLE_SIL_OWNERSHIP=FALSE',
+                         '-DSWIFT_FORCE_OPTIMIZED_TYPECHECKER=FALSE']))
 
     def test_swift_runtime_tsan(self):
         self.args.enable_tsan_runtime = True
@@ -96,7 +98,8 @@
         self.assertEqual(set(swift.cmake_options),
                          set(['-DSWIFT_RUNTIME_USE_SANITIZERS=Thread',
                               '-DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE',
-                              '-DSWIFT_STDLIB_ENABLE_SIL_OWNERSHIP=FALSE']))
+                              '-DSWIFT_STDLIB_ENABLE_SIL_OWNERSHIP=FALSE',
+                              '-DSWIFT_FORCE_OPTIMIZED_TYPECHECKER=FALSE']))
 
     def test_swift_compiler_vendor_flags(self):
         self.args.compiler_vendor = "none"
@@ -281,3 +284,15 @@
             ['-DSWIFT_STDLIB_ENABLE_SIL_OWNERSHIP=TRUE'],
             [x for x in swift.cmake_options
              if 'SWIFT_STDLIB_ENABLE_SIL_OWNERSHIP' in x])
+
+    def test_force_optimized_typechecker_flags(self):
+        self.args.force_optimized_typechecker = True
+        swift = Swift(
+            args=self.args,
+            toolchain=self.toolchain,
+            source_dir='/path/to/src',
+            build_dir='/path/to/build')
+        self.assertEqual(
+            ['-DSWIFT_FORCE_OPTIMIZED_TYPECHECKER=TRUE'],
+            [x for x in swift.cmake_options
+             if 'SWIFT_FORCE_OPTIMIZED_TYPECHECKER' in x])