Merge pull request #7768 from kconner/fix-omitted-word-in-ownership-manifesto

Fix an omitted word in the Ownership Manifesto
diff --git a/.pep8 b/.pep8
index 8d2e668..8d7296d 100644
--- a/.pep8
+++ b/.pep8
@@ -1,2 +1,2 @@
 [flake8]
-filename = *.py,80+-check,backtrace-check,Benchmark_Driver,Benchmark_DTrace.in,Benchmark_GuardMalloc.in,Benchmark_RuntimeLeaksRunner.in,build-script,check-incremental,clang++,coverage-build-db,coverage-generate-data,coverage-query-db,coverage-touch-tests,gyb,ld,line-directive,mock-distcc,ns-html2rst,PathSanitizingFileCheck,recursive-lipo,rth,run-test,scale-test,submit-benchmark-results,update-checkout,viewcfg,symbolicate-linux-fatal
+filename = *.py,80+-check,backtrace-check,Benchmark_Driver,Benchmark_DTrace.in,Benchmark_GuardMalloc.in,Benchmark_RuntimeLeaksRunner.in,build-script,check-incremental,clang++,coverage-build-db,coverage-generate-data,coverage-query-db,coverage-touch-tests,gyb,ld,line-directive,mock-distcc,ns-html2rst,PathSanitizingFileCheck,python-lint,recursive-lipo,round-trip-syntax-test,rth,run-test,scale-test,submit-benchmark-results,update-checkout,viewcfg,symbolicate-linux-fatal
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 196afd7..f91a13f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 
 | Contents               |
 | :--------------------- |
+| [Swift 4.0](#swift-40) |
 | [Swift 3.1](#swift-31) |
 | [Swift 3.0](#swift-30) |
 | [Swift 2.2](#swift-22) |
@@ -17,6 +18,28 @@
 
 </details>
 
+Swift 4.0
+---------
+
+* [SE-0148][]:
+
+  Subscript declarations can now be defined to have generic parameter lists.
+  Example:
+
+  ```
+  extension JSON {
+    subscript<T>(key: String) -> T?
+        where T : JSONConvertible {
+      // ...
+    }
+  }
+  ```
+
+* [SE-0110][]:
+
+  In Swift 4 mode, Swift's type system properly distinguishes between functions that
+  take one tuple argument, and functions that take multiple arguments.
+
 * More types of C macros which define integer constants are supported by the
   importer. Specifically the `+, -, *, /, ^, >>, ==, <, <=, >, >=` operators
   are now recognized, and the previously-supported `<<, &&, ||, &, |`
@@ -6408,3 +6431,11 @@
 [SE-0145]: <https://github.com/apple/swift-evolution/blob/master/proposals/0145-package-manager-version-pinning.md>
 [SE-0146]: <https://github.com/apple/swift-evolution/blob/master/proposals/0146-package-manager-product-definitions.md>
 [SE-0147]: <https://github.com/apple/swift-evolution/blob/master/proposals/0147-move-unsafe-initialize-from.md>
+[SE-0148]: <https://github.com/apple/swift-evolution/blob/master/proposals/0148-generic-subscripts.md>
+[SE-0149]: <https://github.com/apple/swift-evolution/blob/master/proposals/0149-package-manager-top-of-tree.md>
+[SE-0150]: <https://github.com/apple/swift-evolution/blob/master/proposals/0150-package-manager-branch-support.md>
+[SE-0151]: <https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md>
+[SE-0152]: <https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md>
+[SE-0153]: <https://github.com/apple/swift-evolution/blob/master/proposals/0153-compensate-for-the-inconsistency-of-nscopyings-behaviour.md>
+[SE-0154]: <https://github.com/apple/swift-evolution/blob/master/proposals/0154-dictionary-key-and-value-collections.md>
+[SE-0155]: <https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b47c464..cacf882 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -270,6 +270,10 @@
     "Build the standard libraries and overlays with resilience enabled; see docs/LibraryEvolution.rst"
     FALSE)
 
+option(SWIFT_STDLIB_USE_NONATOMIC_RC
+    "Build the standard libraries and overlays with nonatomic reference count operations enabled"
+    FALSE)
+
 option(SWIFT_STDLIB_ENABLE_SIL_OWNERSHIP
   "Build the standard libraries and overlays with sil ownership enabled."
   FALSE)
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index 82b7755..6d87720 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -48,6 +48,7 @@
     single-source/GlobalClass
     single-source/Hanoi
     single-source/Hash
+    single-source/HashQuadratic
     single-source/Histogram
     single-source/Integrate
     single-source/IterateData
diff --git a/benchmark/scripts/generate_harness/CMakeLists.txt_template b/benchmark/scripts/generate_harness/CMakeLists.txt_template
index 79eba3b..d4f0abb 100644
--- a/benchmark/scripts/generate_harness/CMakeLists.txt_template
+++ b/benchmark/scripts/generate_harness/CMakeLists.txt_template
@@ -67,9 +67,18 @@
   set(SWIFT_LIBRARY_PATH "${tmp_dir}/lib/swift")
 endif()
 
-runcmd(COMMAND "xcrun" "-toolchain" "${SWIFT_DARWIN_XCRUN_TOOLCHAIN}" "-f" "clang"
-       VARIABLE CLANG_EXEC
-       ERROR "Unable to find Clang driver")
+# If the CMAKE_C_COMPILER is already clang, don't find it again,
+# thus allowing the --host-cc build-script argument to work here.
+get_filename_component(c_compiler ${CMAKE_C_COMPILER} NAME)
+
+if(${c_compiler} STREQUAL "clang")
+  set(CLANG_EXEC ${CMAKE_C_COMPILER})
+else()
+  runcmd(COMMAND "xcrun" "-toolchain" "${SWIFT_DARWIN_XCRUN_TOOLCHAIN}" "-f" "clang"
+         VARIABLE CLANG_EXEC
+         ERROR "Unable to find Clang driver")
+endif()
+
 
 # You have to delete CMakeCache.txt in the swift build to force a
 # reconfiguration.
diff --git a/benchmark/single-source/HashQuadratic.swift b/benchmark/single-source/HashQuadratic.swift
new file mode 100644
index 0000000..0895aad
--- /dev/null
+++ b/benchmark/single-source/HashQuadratic.swift
@@ -0,0 +1,33 @@
+//===--- HashQuadratic.swift ----------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+import TestsUtils
+
+let size = 3_000_000
+
+@inline(never)
+public func run_HashQuadratic(_ N: Int) {
+    for _ in 1...N {
+        var dict1: [Int: Int] = [:]
+        for i in 0..<size {
+            dict1[i] = i * 2
+        }
+
+        var dict2: [Int: Int] = [:]
+        for (k, v) in dict1 {
+            dict2[k] = v
+        }
+    
+        CheckResults(dict1[size/2] == dict2[size/2],
+            "Incorrect results in HashQuadratic")
+    }
+}
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index a716acd..d21cb0c 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -53,6 +53,7 @@
 import GlobalClass
 import Hanoi
 import Hash
+import HashQuadratic
 import Histogram
 import Integrate
 import IterateData
@@ -113,21 +114,19 @@
   "Array2D": run_Array2D,
   "ArrayAppend": run_ArrayAppend,
   "ArrayAppendArrayOfInt": run_ArrayAppendArrayOfInt,
+  "ArrayAppendAscii": run_ArrayAppendAscii,
   "ArrayAppendFromGeneric": run_ArrayAppendFromGeneric,
   "ArrayAppendGenericStructs": run_ArrayAppendGenericStructs,
+  "ArrayAppendLatin1": run_ArrayAppendLatin1,
   "ArrayAppendLazyMap": run_ArrayAppendLazyMap,
   "ArrayAppendOptionals": run_ArrayAppendOptionals,
   "ArrayAppendRepeatCol": run_ArrayAppendRepeatCol,
   "ArrayAppendReserved": run_ArrayAppendReserved,
   "ArrayAppendSequence": run_ArrayAppendSequence,
   "ArrayAppendStrings": run_ArrayAppendStrings,
-  "ArrayAppendASCII": run_ArrayAppendAscii,  
-  "ArrayAppendLatin1": run_ArrayAppendLatin1,  
-  "ArrayAppendUTF16": run_ArrayAppendUTF16,  
   "ArrayAppendToFromGeneric": run_ArrayAppendToFromGeneric,
   "ArrayAppendToGeneric": run_ArrayAppendToGeneric,
-  "ArrayPlusEqualSingleElementCollection": run_ArrayPlusEqualSingleElementCollection,
-  "ArrayPlusEqualFiveElementCollection": run_ArrayPlusEqualFiveElementCollection,
+  "ArrayAppendUTF16": run_ArrayAppendUTF16,
   "ArrayInClass": run_ArrayInClass,
   "ArrayLiteral": run_ArrayLiteral,
   "ArrayOfGenericPOD": run_ArrayOfGenericPOD,
@@ -135,6 +134,8 @@
   "ArrayOfPOD": run_ArrayOfPOD,
   "ArrayOfRef": run_ArrayOfRef,
   "ArrayPlusEqualArrayOfInt": run_ArrayPlusEqualArrayOfInt,
+  "ArrayPlusEqualFiveElementCollection": run_ArrayPlusEqualFiveElementCollection,
+  "ArrayPlusEqualSingleElementCollection": run_ArrayPlusEqualSingleElementCollection,
   "ArraySubscript": run_ArraySubscript,
   "ArrayValueProp": run_ArrayValueProp,
   "ArrayValueProp2": run_ArrayValueProp2,
@@ -164,6 +165,7 @@
   "ErrorHandling": run_ErrorHandling,
   "GlobalClass": run_GlobalClass,
   "Hanoi": run_Hanoi,
+  "HashQuadratic": run_HashQuadratic,
   "HashTest": run_HashTest,
   "Histogram": run_Histogram,
   "Integrate": run_Integrate,
@@ -172,15 +174,16 @@
   "LinkedList": run_LinkedList,
   "MapReduce": run_MapReduce,
   "MapReduceAnyCollection": run_MapReduceAnyCollection,
-  "MapReduceShort": run_MapReduceShort,
-  "MapReduceSequence": run_MapReduceSequence,
-  "MapReduceLazySequence": run_MapReduceLazySequence,
-  "MapReduceLazyCollection": run_MapReduceLazyCollection,
-  "MapReduceLazyCollectionShort": run_MapReduceLazyCollectionShort,
-  "MapReduceString": run_MapReduceString,
-  "MapReduceShortString": run_MapReduceShortString,
+  "MapReduceAnyCollectionShort": run_MapReduceAnyCollectionShort,
   "MapReduceClass": run_MapReduceClass,
   "MapReduceClassShort": run_MapReduceClassShort,
+  "MapReduceLazyCollection": run_MapReduceLazyCollection,
+  "MapReduceLazyCollectionShort": run_MapReduceLazyCollectionShort,
+  "MapReduceLazySequence": run_MapReduceLazySequence,
+  "MapReduceSequence": run_MapReduceSequence,
+  "MapReduceShort": run_MapReduceShort,
+  "MapReduceShortString": run_MapReduceShortString,
+  "MapReduceString": run_MapReduceString,
   "Memset": run_Memset,
   "MonteCarloE": run_MonteCarloE,
   "MonteCarloPi": run_MonteCarloPi,
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 993c156..0acbd41 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -241,6 +241,8 @@
     list(APPEND result "-D_CRT_USE_WINAPI_FAMILY_DESKTOP_APP")
     # TODO(compnerd) handle /MT
     list(APPEND result "-D_DLL")
+    # NOTE: We assume that we are using VS 2015 U2+
+    list(APPEND result "-D_ENABLE_ATOMIC_ALIGNMENT_FIX")
   endif()
 
   if(CFLAGS_ENABLE_ASSERTIONS)
diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake
index a4b4ff1..39b0d2b 100644
--- a/cmake/modules/SwiftConfigureSDK.cmake
+++ b/cmake/modules/SwiftConfigureSDK.cmake
@@ -22,6 +22,13 @@
   message(STATUS "  Triple name: ${SWIFT_SDK_${prefix}_TRIPLE_NAME}")
   message(STATUS "  Architectures: ${SWIFT_SDK_${prefix}_ARCHITECTURES}")
   message(STATUS "  Object Format: ${SWIFT_SDK_${prefix}_OBJECT_FORMAT}")
+  foreach(arch ${SWIFT_SDK_${prefix}_ARCHITECTURES})
+    if(${SWIFT_SDK_${prefix}_ARCH_${arch}_LINKER})
+      message(STATUS "  Linker (${arch}): ${SWIFT_SDK_${prefix}_ARCH_${arch}_LINKER}")
+    else()
+      message(STATUS "  Linker (${arch}): ${CMAKE_LINKER}")
+    endif()
+  endforeach()
 
   foreach(arch ${SWIFT_SDK_${prefix}_ARCHITECTURES})
     message(STATUS
diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake
index a9bb87e..bb20246 100644
--- a/cmake/modules/SwiftSource.cmake
+++ b/cmake/modules/SwiftSource.cmake
@@ -239,6 +239,10 @@
     list(APPEND swift_flags "-Xfrontend" "-enable-resilience")
   endif()
 
+  if(SWIFT_STDLIB_USE_NONATOMIC_RC)
+    list(APPEND swift_flags "-Xfrontend" "-assume-single-threaded")
+  endif()
+
   if(SWIFT_STDLIB_ENABLE_SIL_OWNERSHIP AND SWIFTFILE_IS_STDLIB)
     list(APPEND swift_flags "-Xfrontend" "-enable-sil-ownership")
   endif()
diff --git a/docs/HighLevelSILOptimizations.rst b/docs/HighLevelSILOptimizations.rst
index 7cb9e45..3178b4c 100644
--- a/docs/HighLevelSILOptimizations.rst
+++ b/docs/HighLevelSILOptimizations.rst
@@ -349,6 +349,11 @@
   @_semantics("optimize.sil.never")
   func miscompile() { ... }
 
+sil.specialize.generic.never
+
+   The sil optimizer should never create generic specializations of this function. 
+
+
 Availability checks
 ~~~~~~~~~~~~~~~~~~~
 
diff --git a/docs/SIL.rst b/docs/SIL.rst
index 0ee207f..6e45602 100644
--- a/docs/SIL.rst
+++ b/docs/SIL.rst
@@ -3743,6 +3743,7 @@
   
   * `init_existential_opaque`_
   * `open_existential_opaque`_
+  * `deinit_existential_opaque`_
 
 - **Class existential containers**: If a protocol type is constrained by one or
   more class protocols, then the existential container for that type is
@@ -3847,6 +3848,22 @@
 ``init_existential_addr`` but haven't had their contained value initialized.
 A fully initialized existential must be destroyed with ``destroy_addr``.
 
+deinit_existential_opaque
+`````````````````````````
+::
+
+  sil-instruction ::= 'deinit_existential_opaque' sil-operand
+
+  deinit_existential_opaque %0 : $P
+  // %0 must be of a $P opaque type for non-class protocol or protocol
+  // composition type P
+
+Undoes the partial initialization performed by
+``init_existential_opaque``.  ``deinit_existential_opaque`` is only valid for
+existential containers that have been partially initialized by
+``init_existential_opaque`` but haven't had their contained value initialized.
+A fully initialized existential must be destroyed with ``destroy_value``.
+
 open_existential_addr
 `````````````````````
 ::
diff --git a/docs/Testing.rst b/docs/Testing.rst
index ffc1183..b7fd2a5 100644
--- a/docs/Testing.rst
+++ b/docs/Testing.rst
@@ -431,7 +431,7 @@
 * ``swift_ast_verifier``: present if the AST verifier is enabled in this build.
 
 * When writing a test specific to x86, if possible, prefer ``REQUIRES:
-  CPU=i386 || CPU=x86_64`` over ``REQUIRES: CPU=x86_64``.
+  CPU=i386_or_x86_64`` to ``REQUIRES: CPU=x86_64``.
 
 * ``swift_test_mode_optimize[_unchecked|none]`` and
   ``swift_test_mode_optimize[_unchecked|none]_<CPUNAME>``: specify a test mode
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 1fddf63..fc285c4 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -24,9 +24,11 @@
 #include "swift/AST/DefaultArgumentKind.h"
 #include "swift/AST/GenericSignature.h"
 #include "swift/AST/GenericParamKey.h"
+#include "swift/AST/IfConfigClause.h"
 #include "swift/AST/LayoutConstraint.h"
 #include "swift/AST/LazyResolver.h"
 #include "swift/AST/TypeAlignments.h"
+#include "swift/AST/TypeWalker.h"
 #include "swift/AST/Witness.h"
 #include "swift/Basic/Compiler.h"
 #include "swift/Basic/OptionalEnum.h"
@@ -238,11 +240,15 @@
     /// \brief Whether this declaration is currently being validated.
     unsigned BeingValidated : 1;
 
+    /// \brief Whether we have started validating the declaration; this *isn't*
+    /// reset after finishing it.
+    unsigned ValidationStarted : 1;
+
     /// \brief Whether this declaration was added to the surrounding
     /// DeclContext of an active #if config clause.
     unsigned EscapedFromIfConfig : 1;
   };
-  enum { NumDeclBits = 12 };
+  enum { NumDeclBits = 13 };
   static_assert(NumDeclBits <= 32, "fits in an unsigned");
 
   class PatternBindingDeclBitfields {
@@ -423,13 +429,8 @@
   class TypeAliasDeclBitfields {
     friend class TypeAliasDecl;
     unsigned : NumGenericTypeDeclBits;
-
-    /// Whether we have completed validation of the typealias.
-    /// This is necessary because unlike other declarations, a
-    /// typealias will not get an interface type right away.
-    unsigned HasCompletedValidation : 1;
   };
-  enum { NumTypeAliasDeclBits = NumGenericTypeDeclBits + 1 };
+  enum { NumTypeAliasDeclBits = NumGenericTypeDeclBits };
   static_assert(NumTypeAliasDeclBits <= 32, "fits in an unsigned");
 
   class NominalTypeDeclBitFields {
@@ -577,9 +578,6 @@
     /// FIXME: Is this too fine-grained?
     unsigned CheckedInheritanceClause : 1;
 
-    /// Whether this extension has already been validated.
-    unsigned Validated : 1;
-
     /// An encoding of the default and maximum access level for this extension.
     ///
     /// This is encoded as (1 << (maxAccess-1)) | (1 << (defaultAccess-1)),
@@ -590,7 +588,7 @@
     /// Whether there is are lazily-loaded conformances for this extension.
     unsigned HasLazyConformances : 1;
   };
-  enum { NumExtensionDeclBits = NumDeclBits + 6 };
+  enum { NumExtensionDeclBits = NumDeclBits + 5 };
   static_assert(NumExtensionDeclBits <= 32, "fits in an unsigned");
 
   class IfConfigDeclBitfields {
@@ -659,6 +657,7 @@
     DeclBits.FromClang = false;
     DeclBits.EarlyAttrValidation = false;
     DeclBits.BeingValidated = false;
+    DeclBits.ValidationStarted = false;
     DeclBits.EscapedFromIfConfig = false;
   }
 
@@ -815,8 +814,19 @@
   void setIsBeingValidated(bool ibv = true) {
     assert(DeclBits.BeingValidated != ibv);
     DeclBits.BeingValidated = ibv;
+    if (ibv) {
+      DeclBits.ValidationStarted = true;
+    }
   }
 
+  bool hasValidationStarted() const { return DeclBits.ValidationStarted; }
+
+  /// Manually indicate that validation has started for the declaration.
+  ///
+  /// This is implied by setIsBeingValidated(true) (i.e. starting validation)
+  /// and so rarely needs to be called directly.
+  void setValidationStarted() { DeclBits.ValidationStarted = true; }
+
   bool escapedFromIfConfig() const {
     return DeclBits.EscapedFromIfConfig;
   }
@@ -1644,19 +1654,9 @@
 
   void setInherited(MutableArrayRef<TypeLoc> i) { Inherited = i; }
 
-  /// Whether we started validating this extension.
-  bool validated() const {
-    return ExtensionDeclBits.Validated;
-  }
-
-  /// Set whether we have validated this extension.
-  void setValidated(bool validated = true) {
-    ExtensionDeclBits.Validated = validated;
-  }
-
   /// Whether we have fully checked the extension.
   bool hasValidSignature() const {
-    return validated() && !isBeingValidated();
+    return hasValidationStarted() && !isBeingValidated();
   }
 
   /// Whether we already type-checked the inheritance clause.
@@ -2017,28 +2017,6 @@
   }
 };
 
-/// This represents one part of a #if block.  If the condition field is
-/// non-null, then this represents a #if or a #elseif, otherwise it represents
-/// an #else block.
-struct IfConfigDeclClause {
-  /// The location of the #if, #elseif, or #else keyword.
-  SourceLoc Loc;
-  
-  /// The condition guarding this #if or #elseif block.  If this is null, this
-  /// is a #else clause.
-  Expr *Cond;
-
-  ArrayRef<Decl*> Members;
-
-  /// True if this is the active clause of the #if block.
-  bool isActive;
-
-  IfConfigDeclClause(SourceLoc Loc, Expr *Cond, ArrayRef<Decl*> Members,
-                     bool isActive)
-    : Loc(Loc), Cond(Cond), Members(Members), isActive(isActive) {}
-};
-  
-  
 /// IfConfigDecl - This class represents the declaration-side representation of
 /// #if/#else/#endif blocks. Active and inactive block members are stored
 /// separately, with the intention being that active members will be handed
@@ -2046,21 +2024,21 @@
 class IfConfigDecl : public Decl {
   /// An array of clauses controlling each of the #if/#elseif/#else conditions.
   /// The array is ASTContext allocated.
-  ArrayRef<IfConfigDeclClause> Clauses;
+  ArrayRef<IfConfigClause<Decl *>> Clauses;
   SourceLoc EndLoc;
 public:
   
-  IfConfigDecl(DeclContext *Parent, ArrayRef<IfConfigDeclClause> Clauses,
+  IfConfigDecl(DeclContext *Parent, ArrayRef<IfConfigClause<Decl *>> Clauses,
                SourceLoc EndLoc, bool HadMissingEnd)
     : Decl(DeclKind::IfConfig, Parent), Clauses(Clauses), EndLoc(EndLoc)
   {
     IfConfigDeclBits.HadMissingEnd = HadMissingEnd;
   }
 
-  ArrayRef<IfConfigDeclClause> getClauses() const { return Clauses; }
+  ArrayRef<IfConfigClause<Decl *>> getClauses() const { return Clauses; }
 
   /// Return the active clause, or null if there is no active one.
-  const IfConfigDeclClause *getActiveClause() const {
+  const IfConfigClause<Decl *> *getActiveClause() const {
     for (auto &Clause : Clauses)
       if (Clause.isActive) return &Clause;
     return nullptr;
@@ -2068,7 +2046,7 @@
 
   const ArrayRef<Decl*> getActiveMembers() const {
     if (auto *Clause = getActiveClause())
-      return Clause->Members;
+      return Clause->Elements;
     return {};
   }
   
@@ -2442,14 +2420,6 @@
   /// aliases.
   void setUnderlyingType(Type type);
 
-  bool hasCompletedValidation() const {
-    return TypeAliasDeclBits.HasCompletedValidation;
-  }
-
-  void setHasCompletedValidation() {
-    TypeAliasDeclBits.HasCompletedValidation = 1;
-  }
-
   /// For generic typealiases, return the unbound generic type.
   UnboundGenericType *getUnboundGenericType() const;
 
@@ -2583,14 +2553,19 @@
   /// The default definition.
   TypeLoc DefaultDefinition;
 
+  /// The where clause attached to the associated type.
+  TrailingWhereClause *TrailingWhere;
+
   LazyMemberLoader *Resolver = nullptr;
   uint64_t ResolverContextData;
 
 public:
   AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
-                     SourceLoc nameLoc, TypeLoc defaultDefinition);
+                     SourceLoc nameLoc, TypeLoc defaultDefinition,
+                     TrailingWhereClause *trailingWhere);
   AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
-                     SourceLoc nameLoc, LazyMemberLoader *definitionResolver,
+                     SourceLoc nameLoc, TrailingWhereClause *trailingWhere,
+                     LazyMemberLoader *definitionResolver,
                      uint64_t resolverData);
 
   /// Get the protocol in which this associated type is declared.
@@ -2608,6 +2583,14 @@
     return const_cast<AssociatedTypeDecl *>(this)->getDefaultDefinitionLoc();
   }
 
+  /// Retrieve the trailing where clause for this associated type, if any.
+  TrailingWhereClause *getTrailingWhereClause() const { return TrailingWhere; }
+
+  /// Set the trailing where clause for this associated type.
+  void setTrailingWhereClause(TrailingWhereClause *trailingWhereClause) {
+    TrailingWhere = trailingWhereClause;
+  }
+
   /// computeType - Compute the type (and declared type) of this associated
   /// type; can only be called after the alias type has been resolved.
   void computeType();
@@ -3413,6 +3396,19 @@
   /// Retrieve the set of protocols inherited from this protocol.
   llvm::TinyPtrVector<ProtocolDecl *> getInheritedProtocols() const;
 
+  /// Walk all of the protocols inherited by this protocol, transitively,
+  /// invoking the callback function for each protocol.
+  ///
+  /// \param fn The callback function that will be invoked for each inherited
+  /// protocol. It can return \c Continue to continue the traversal,
+  /// \c SkipChildren to avoid visiting the children of the given protocol
+  /// but continue the search, and \c Stop to halt the search.
+  ///
+  /// \returns \c true if \c fn returned \c Stop for any protocol, \c false
+  /// otherwise.
+  bool walkInheritedProtocols(
+               llvm::function_ref<TypeWalker::Action(ProtocolDecl *)> fn) const;
+
   /// \brief Determine whether this protocol inherits from the given ("super")
   /// protocol.
   bool inheritsFrom(const ProtocolDecl *Super) const;
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index a1dd113..c5e2979 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -208,6 +208,9 @@
 ERROR(enum_case_dot_prefix,none,
       "extraneous '.' in enum 'case' declaration", ())
 
+ERROR(associatedtype_where_swift_3,none,
+      "where clauses on associated types are fragile; use '-swift-version 4' to experiment.", ())
+
 
 // Variable getters/setters
 ERROR(static_var_decl_global_scope,none,
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 377c8b6..42e442f 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -164,6 +164,9 @@
 ERROR(cannot_match_expr_pattern_with_value,none,
       "expression pattern of type %0 cannot match values of type %1",
       (Type, Type))
+ERROR(cannot_match_unresolved_expr_pattern_with_value,none,
+      "pattern cannot match values of type %0",
+      (Type))
 
 ERROR(cannot_reference_compare_types,none,
       "cannot check reference equality of functions; operands here have types "
@@ -1562,9 +1565,6 @@
 ERROR(requires_generic_param_made_equal_to_concrete,none,
       "same-type requirement makes generic parameter %0 non-generic",
       (Type))
-ERROR(requires_superclass_conflict,none,
-      "%select{generic parameter |protocol |}0%1 cannot be a subclass of both "
-      "%2 and %3", (unsigned, Type, Type, Type))
 ERROR(recursive_type_reference,none,
       "%0 %1 references itself", (DescriptiveDeclKind, Identifier))
 ERROR(recursive_requirement_reference,none,
@@ -1586,9 +1586,17 @@
       (Identifier, Type, Type))
 WARNING(redundant_same_type_to_concrete,none,
         "redundant same-type constraint %0 == %1", (Type, Type))
-NOTE(redundancy_here,none,
+NOTE(same_type_redundancy_here,none,
      "same-type constraint %1 == %2 %select{written here|implied here}0",
      (bool, Type, Type))
+ERROR(requires_superclass_conflict,none,
+      "%select{generic parameter |protocol |}0%1 cannot be a subclass of both "
+      "%2 and %3", (unsigned, Type, Type, Type))
+WARNING(redundant_superclass_constraint,none,
+        "redundant superclass constraint %0 : %1", (Type, Type))
+NOTE(superclass_redundancy_here,none,
+     "superclass constraint %1 : %2 %select{written here|implied here}0",
+     (bool, Type, Type))
 
 ERROR(mutiple_layout_constraints,none,
       "multiple layout constraints cannot be used at the same time: %0 and %1",
diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h
index 8c7721d..a859f92 100644
--- a/include/swift/AST/GenericSignature.h
+++ b/include/swift/AST/GenericSignature.h
@@ -114,8 +114,9 @@
   /// \param substitutions The generic parameter -> generic argument
   /// substitutions that will have been applied to these types.
   /// These are used to produce the "parameter = argument" bindings in the test.
-  std::string gatherGenericParamBindingsText(
-      ArrayRef<Type> types, const TypeSubstitutionMap &substitutions) const;
+  std::string
+  gatherGenericParamBindingsText(ArrayRef<Type> types,
+                                 TypeSubstitutionFn substitutions) const;
 
   /// Retrieve the requirements.
   ArrayRef<Requirement> getRequirements() const {
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index d6aef4f..ed575c4 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -21,6 +21,7 @@
 #define SWIFT_GENERICSIGNATUREBUILDER_H
 
 #include "swift/AST/Decl.h"
+#include "swift/AST/DiagnosticEngine.h"
 #include "swift/AST/Identifier.h"
 #include "swift/AST/Types.h"
 #include "swift/AST/TypeLoc.h"
@@ -31,6 +32,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Support/TrailingObjects.h"
 #include <functional>
 #include <memory>
 
@@ -50,17 +52,428 @@
 class RequirementRepr;
 class SILModule;
 class SourceLoc;
+class SubstitutionMap;
 class Type;
 class TypeRepr;
 class ASTContext;
 class DiagnosticEngine;
 
+/// \brief Collects a set of requirements of generic parameters, both explicitly
+/// stated and inferred, and determines the set of archetypes for each of
+/// the generic parameters.
+class GenericSignatureBuilder {
+public:
+  /// Describes a potential archetype, which stands in for a generic parameter
+  /// type or some type derived from it.
+  class PotentialArchetype;
+
+  using UnresolvedType = llvm::PointerUnion<PotentialArchetype *, Type>;
+  struct ResolvedType;
+
+  using RequirementRHS =
+      llvm::PointerUnion3<Type, PotentialArchetype *, LayoutConstraint>;
+
+  class RequirementSource;
+
+  class FloatingRequirementSource;
+
+  /// Describes a constraint that is bounded on one side by a concrete type.
+  struct ConcreteConstraint {
+    PotentialArchetype *archetype;
+    Type concreteType;
+    const RequirementSource *source;
+  };
+
+  /// Describes an equivalence class of potential archetypes.
+  struct EquivalenceClass {
+    /// Concrete type to which this equivalence class is equal.
+    ///
+    /// This is the semantic concrete type; the constraints as written
+    /// (or implied) are stored in \c concreteTypeConstraints;
+    Type concreteType;
+
+    /// The same-type-to-concrete constraints written within this
+    /// equivalence class.
+    std::vector<ConcreteConstraint> concreteTypeConstraints;
+
+    /// Superclass constraint, which requires that the type fulfilling the
+    /// requirements of this equivalence class to be the same as or a subtype
+    /// of this superclass.
+    Type superclass;
+
+    /// Superclass constraints written within this equivalence class.
+    std::vector<ConcreteConstraint> superclassConstraints;
+
+    /// The members of the equivalence class.
+    TinyPtrVector<PotentialArchetype *> members;
+
+    /// Construct a new equivalence class containing only the given
+    /// potential archetype (which represents itself).
+    EquivalenceClass(PotentialArchetype *representative);
+
+    /// Find a source of the same-type constraint that maps a potential
+    /// archetype in this equivalence class to a concrete type along with
+    /// that concrete type as written.
+    Optional<ConcreteConstraint>
+    findAnyConcreteConstraintAsWritten(
+                              PotentialArchetype *preferredPA = nullptr) const;
+
+    /// Find a source of the superclass constraint in this equivalence class
+    /// that has a type equivalence to \c superclass, along with that
+    /// superclass type as written.
+    Optional<ConcreteConstraint>
+    findAnySuperclassConstraintAsWritten(
+                              PotentialArchetype *preferredPA = nullptr) const;
+};
+
+  friend class RequirementSource;
+
+private:
+  class InferRequirementsWalker;
+  friend class InferRequirementsWalker;
+  friend class GenericSignature;
+
+  ASTContext &Context;
+  DiagnosticEngine &Diags;
+  struct Implementation;
+  std::unique_ptr<Implementation> Impl;
+
+  GenericSignatureBuilder(const GenericSignatureBuilder &) = delete;
+  GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete;
+
+  /// Update an existing constraint source reference when another constraint
+  /// source was found to produce the same constraint. Only the better
+  /// constraint source will be kept.
+  ///
+  /// \returns true if the new constraint source was better, false otherwise.
+  bool updateRequirementSource(const RequirementSource *&existingSource,
+                               const RequirementSource *newSource);
+
+  /// Retrieve the constraint source conformance for the superclass constraint
+  /// of the given potential archetype (if present) to the given protocol.
+  ///
+  /// \param pa The potential archetype whose superclass constraint is being
+  /// queried.
+  ///
+  /// \param proto The protocol to which we are establishing conformance.
+  ///
+  /// \param protoSource The requirement source for the conformance to the
+  /// given protocol.
+  const RequirementSource *resolveSuperConformance(
+                            GenericSignatureBuilder::PotentialArchetype *pa,
+                            ProtocolDecl *proto,
+                            const RequirementSource *&protoSource);
+
+  /// \brief Add a new conformance requirement specifying that the given
+  /// potential archetype conforms to the given protocol.
+  bool addConformanceRequirement(PotentialArchetype *T,
+                                 ProtocolDecl *Proto,
+                                 const RequirementSource *Source);
+
+  bool addConformanceRequirement(PotentialArchetype *T,
+                                 ProtocolDecl *Proto,
+                                 const RequirementSource *Source,
+                                llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
+
+public:
+  /// \brief Add a new same-type requirement between two fully resolved types
+  /// (output of \c GenericSignatureBuilder::resolve).
+  ///
+  /// If the types refer to two concrete types that are fundamentally
+  /// incompatible (e.g. \c Foo<Bar<T>> and \c Foo<Baz>), \c diagnoseMismatch is
+  /// called with the two types that don't match (\c Bar<T> and \c Baz for the
+  /// previous example).
+  bool
+  addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
+                         FloatingRequirementSource Source,
+                         llvm::function_ref<void(Type, Type)> diagnoseMismatch);
+
+  /// \brief Add a new same-type requirement between two fully resolved types
+  /// (output of GenericSignatureBuilder::resolve).
+  ///
+  /// The two types must not be incompatible concrete types.
+  bool addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
+                              FloatingRequirementSource Source);
+
+  /// \brief Add a new same-type requirement between two unresolved types.
+  ///
+  /// The types are resolved with \c GenericSignatureBuilder::resolve, and must
+  /// not be incompatible concrete types.
+  bool addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
+                              FloatingRequirementSource Source);
+
+  /// \brief Add a new same-type requirement between two unresolved types.
+  ///
+  /// The types are resolved with \c GenericSignatureBuilder::resolve. \c
+  /// diagnoseMismatch is called if the two types refer to incompatible concrete
+  /// types.
+  bool
+  addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
+                         FloatingRequirementSource Source,
+                         llvm::function_ref<void(Type, Type)> diagnoseMismatch);
+
+  /// Update the superclass for the equivalence class of \c T.
+  ///
+  /// This assumes that the constraint has already been recorded
+  bool updateSuperclass(PotentialArchetype *T,
+                        Type superclass,
+                        const RequirementSource *source);
+
+private:
+  /// \brief Add a new superclass requirement specifying that the given
+  /// potential archetype has the given type as an ancestor.
+  bool addSuperclassRequirement(PotentialArchetype *T,
+                                Type Superclass,
+                                const RequirementSource *Source);
+
+  /// \brief Add a new conformance requirement specifying that the given
+  /// potential archetypes are equivalent.
+  bool addSameTypeRequirementBetweenArchetypes(PotentialArchetype *T1,
+                                               PotentialArchetype *T2,
+                                               const RequirementSource *Source);
+  
+  /// \brief Add a new conformance requirement specifying that the given
+  /// potential archetype is bound to a concrete type.
+  bool addSameTypeRequirementToConcrete(PotentialArchetype *T,
+                                        Type Concrete,
+                                        const RequirementSource *Source);
+
+  /// \brief Add a new same-type requirement specifying that the given two
+  /// types should be the same.
+  ///
+  /// \param diagnoseMismatch Callback invoked when the types in the same-type
+  /// requirement mismatch.
+  bool addSameTypeRequirementBetweenConcrete(
+      Type T1, Type T2, FloatingRequirementSource Source,
+      llvm::function_ref<void(Type, Type)> diagnoseMismatch);
+
+  /// Add the requirements placed on the given type parameter
+  /// to the given potential archetype.
+  bool addInheritedRequirements(TypeDecl *decl, PotentialArchetype *pa,
+                                const RequirementSource *parentSource,
+                                llvm::SmallPtrSetImpl<ProtocolDecl *> &visited);
+
+  /// Visit all of the potential archetypes.
+  template<typename F>
+  void visitPotentialArchetypes(F f);
+
+  void markPotentialArchetypeRecursive(PotentialArchetype *pa,
+                                       ProtocolDecl *proto,
+                                       const RequirementSource *source);
+
+public:
+  /// Construct a new generic signature builder.
+  ///
+  /// \param lookupConformance Conformance-lookup routine that will be used
+  /// to satisfy conformance requirements for concrete types.
+  explicit GenericSignatureBuilder(ASTContext &ctx,
+                            std::function<GenericFunction> lookupConformance);
+
+  GenericSignatureBuilder(GenericSignatureBuilder &&);
+  ~GenericSignatureBuilder();
+
+  /// Retrieve the AST context.
+  ASTContext &getASTContext() const { return Context; }
+
+  /// Retrieve the conformance-lookup function used by this generic signature builder.
+  std::function<GenericFunction> getLookupConformanceFn() const;
+
+  /// Retrieve the lazy resolver, if there is one.
+  LazyResolver *getLazyResolver() const;
+
+  /// Enumerate the requirements that describe the signature of this
+  /// generic signature builder.
+  ///
+  /// \param f A function object that will be passed each requirement
+  /// and requirement source.
+  void enumerateRequirements(llvm::function_ref<
+                      void (RequirementKind kind,
+                            PotentialArchetype *archetype,
+                            RequirementRHS constraint,
+                            const RequirementSource *source)> f);
+
+public:
+  /// \brief Add a new generic parameter for which there may be requirements.
+  void addGenericParameter(GenericTypeParamDecl *GenericParam);
+
+  /// Add the requirements placed on the given abstract type parameter
+  /// to the given potential archetype.
+  ///
+  /// \returns true if an error occurred, false otherwise.
+  bool addGenericParameterRequirements(GenericTypeParamDecl *GenericParam);
+
+  /// \brief Add a new generic parameter for which there may be requirements.
+  void addGenericParameter(GenericTypeParamType *GenericParam);
+  
+  /// \brief Add a new requirement.
+  ///
+  /// \returns true if this requirement makes the set of requirements
+  /// inconsistent, in which case a diagnostic will have been issued.
+  bool addRequirement(const RequirementRepr *Req,
+                      const RequirementSource *source = nullptr,
+                      const SubstitutionMap *subMap = nullptr);
+
+  /// \brief Add an already-checked requirement.
+  ///
+  /// Adding an already-checked requirement cannot fail. This is used to
+  /// re-inject requirements from outer contexts.
+  ///
+  /// \returns true if this requirement makes the set of requirements
+  /// inconsistent, in which case a diagnostic will have been issued.
+  bool addRequirement(const Requirement &req, FloatingRequirementSource source);
+
+  bool addRequirement(const Requirement &req, FloatingRequirementSource source,
+                      llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
+
+  /// \brief Add a new requirement.
+  ///
+  /// \returns true if this requirement makes the set of requirements
+  /// inconsistent, in which case a diagnostic will have been issued.
+
+  bool addLayoutRequirement(PotentialArchetype *PAT,
+                            LayoutConstraint Layout,
+                            const RequirementSource *Source);
+
+  /// \brief Add all of a generic signature's parameters and requirements.
+  void addGenericSignature(GenericSignature *sig);
+
+  /// \brief Build the generic signature.
+  GenericSignature *getGenericSignature();
+
+  /// Infer requirements from the given type, recursively.
+  ///
+  /// This routine infers requirements from a type that occurs within the
+  /// signature of a generic function. For example, given:
+  ///
+  /// \code
+  /// func f<K, V>(dict : Dictionary<K, V>) { ... }
+  /// \endcode
+  ///
+  /// where \c Dictionary requires that its key type be \c Hashable,
+  /// the requirement \c K : Hashable is inferred from the parameter type,
+  /// because the type \c Dictionary<K,V> cannot be formed without it.
+  void inferRequirements(TypeLoc type);
+
+  /// Infer requirements from the given pattern, recursively.
+  ///
+  /// This routine infers requirements from a type that occurs within the
+  /// signature of a generic function. For example, given:
+  ///
+  /// \code
+  /// func f<K, V>(dict : Dictionary<K, V>) { ... }
+  /// \endcode
+  ///
+  /// where \c Dictionary requires that its key type be \c Hashable,
+  /// the requirement \c K : Hashable is inferred from the parameter type,
+  /// because the type \c Dictionary<K,V> cannot be formed without it.
+  void inferRequirements(ParameterList *params,GenericParamList *genericParams);
+
+  /// Finalize the set of requirements, performing any remaining checking
+  /// required before generating archetypes.
+  ///
+  /// \param allowConcreteGenericParams If true, allow generic parameters to
+  /// be made concrete.
+  void finalize(SourceLoc loc,
+                ArrayRef<GenericTypeParamType *> genericParams,
+                bool allowConcreteGenericParams=false);
+
+  /// Diagnose any remaining renames.
+  ///
+  /// \returns \c true if there were any remaining renames to diagnose.
+  bool diagnoseRemainingRenames(SourceLoc loc,
+                                ArrayRef<GenericTypeParamType *> genericParams);
+
+private:
+  /// Describes the relationship between a given constraint and
+  /// the canonical constraint of the equivalence class.
+  enum class ConstraintRelation {
+    /// The constraint is unrelated.
+    ///
+    /// This is a conservative result that can be used when, for example,
+    /// we have incomplete information to make a determination.
+    Unrelated,
+    /// The constraint is redundant and can be removed without affecting the
+    /// semantics.
+    Redundant,
+    /// The constraint conflicts, meaning that the signature is erroneous.
+    Conflicting,
+  };
+
+  /// Check a list of concrete constraints, removing self-derived constraints
+  /// and diagnosing redundant constraints.
+  ///
+  /// \param isSuitableRepresentative Determines whether the given constraint
+  /// is a suitable representative.
+  ///
+  /// \param checkConstraint Checks the given constraint against the
+  /// canonical constraint to determine which diagnostics (if any) should be
+  /// emitted.
+  ///
+  /// \returns the representative constraint.
+  ConcreteConstraint checkConstraintList(
+                           ArrayRef<GenericTypeParamType *> genericParams,
+                           std::vector<ConcreteConstraint> &constraints,
+                           llvm::function_ref<bool(const ConcreteConstraint &)>
+                             isSuitableRepresentative,
+                           llvm::function_ref<ConstraintRelation(Type)>
+                             checkConstraint,
+                           Optional<Diag<unsigned, Type, Type, Type>>
+                             conflictingDiag,
+                           Diag<Type, Type> redundancyDiag,
+                           Diag<bool, Type, Type> otherNoteDiag);
+
+  /// Check for redundant concrete type constraints within the equivalence
+  /// class of the given potential archetype.
+  void checkRedundantConcreteTypeConstraints(
+                            ArrayRef<GenericTypeParamType *> genericParams,
+                            PotentialArchetype *pa);
+
+  /// Check for redundant superclass constraints within the equivalence
+  /// class of the given potential archetype.
+  void checkRedundantSuperclassConstraints(
+                            ArrayRef<GenericTypeParamType *> genericParams,
+                            PotentialArchetype *pa);
+
+public:
+  /// \brief Resolve the given type to the potential archetype it names.
+  ///
+  /// This routine will synthesize nested types as required to refer to a
+  /// potential archetype, even in cases where no requirement specifies the
+  /// requirement for such an archetype. FIXME: The failure to include such a
+  /// requirement will be diagnosed at some point later (when the types in the
+  /// signature are fully resolved).
+  ///
+  /// For any type that cannot refer to an archetype, this routine returns null.
+  PotentialArchetype *resolveArchetype(Type type);
+
+  /// \brief Resolve the given type as far as this Builder knows how.
+  ///
+  /// This returns either a non-typealias potential archetype or a Type, if \c
+  /// type is concrete.
+  // FIXME: the hackTypeFromGenericTypeAlias is just temporarily patching over
+  // problems with generic typealiases (see the comment on the ResolvedType
+  // function)
+  ResolvedType resolve(UnresolvedType type,
+                       bool hackTypeFromGenericTypeAlias = false);
+
+  /// \brief Dump all of the requirements, both specified and inferred.
+  LLVM_ATTRIBUTE_DEPRECATED(
+      void dump(),
+      "only for use within the debugger");
+
+  /// Dump all of the requirements to the given output stream.
+  void dump(llvm::raw_ostream &out);
+};
+
 /// Describes how a generic signature determines a requirement, from its origin
 /// in some requirement written in the source, inferred through a path of
 /// other implications (e.g., introduced by a particular protocol).
 ///
 /// Requirement sources are uniqued within a generic signature builder.
-class RequirementSource : public llvm::FoldingSetNode {
+class GenericSignatureBuilder::RequirementSource final
+  : public llvm::FoldingSetNode,
+    private llvm::TrailingObjects<RequirementSource, PotentialArchetype *> {
+
 public:
   enum Kind : uint8_t {
     /// A requirement stated explicitly, e.g., in a where clause or type
@@ -126,11 +539,12 @@
 private:
   /// The kind of storage we have.
   enum class StorageKind : uint8_t {
-    None,
+    RootArchetype,
     TypeRepr,
     RequirementRepr,
     ProtocolDecl,
     ProtocolConformance,
+    AssociatedTypeDecl,
   };
 
   /// The kind of storage we have.
@@ -138,6 +552,9 @@
 
   /// The actual storage, described by \c storageKind.
   union {
+    /// The root archetype.
+    PotentialArchetype *rootArchetype;
+
     /// The type representation describing where the requirement came from.
     const TypeRepr *typeRepr;
 
@@ -149,8 +566,32 @@
 
     /// A protocol conformance used to satisfy the requirement.
     ProtocolConformance *conformance;
+
+    /// An associated type to which a requirement is being applied.
+    AssociatedTypeDecl *assocType;
   } storage;
 
+  friend TrailingObjects;
+
+  /// The trailing potential archetype, for
+  size_t numTrailingObjects(OverloadToken<PotentialArchetype *>) const {
+    switch (kind) {
+    case RequirementSignatureSelf:
+      return 1;
+
+    case Explicit:
+    case Inferred:
+      return storageKind == StorageKind::RootArchetype ? 0 : 1;
+
+    case NestedTypeNameMatch:
+    case ProtocolRequirement:
+    case Superclass:
+    case Parent:
+    case Concrete:
+      return 0;
+    }
+  }
+
   /// Determines whether we have been provided with an acceptable storage kind
   /// for the given requirement source kind.
   static bool isAcceptableStorageKind(Kind kind, StorageKind storageKind);
@@ -158,6 +599,10 @@
   /// Retrieve the opaque storage as a single pointer, for use in uniquing.
   const void *getOpaqueStorage() const;
 
+  /// Retrieve the extra opaque storage as a single pointer, for use in
+  /// uniquing.
+  const void *getExtraOpaqueStorage() const;
+
   /// Whether this kind of requirement source is a root.
   static bool isRootKind(Kind kind) {
     switch (kind) {
@@ -182,15 +627,15 @@
   /// requirement source with one of the "root" kinds.
   const RequirementSource * const parent;
 
-  RequirementSource(Kind kind, const RequirementSource *parent)
-    : kind(kind), storageKind(StorageKind::None), parent(parent) {
+  RequirementSource(Kind kind, const RequirementSource *parent,
+                    PotentialArchetype *rootArchetype)
+    : kind(kind), storageKind(StorageKind::RootArchetype), parent(parent) {
     assert((static_cast<bool>(parent) != isRootKind(kind)) &&
            "Root RequirementSource should not have parent (or vice versa)");
     assert(isAcceptableStorageKind(kind, storageKind) &&
            "RequirementSource kind/storageKind mismatch");
 
-    // Prevent uninitialized memory.
-    storage.typeRepr = nullptr;
+    storage.rootArchetype = rootArchetype;
   }
 
   RequirementSource(Kind kind, const RequirementSource *parent,
@@ -216,7 +661,7 @@
   }
 
   RequirementSource(Kind kind, const RequirementSource *parent,
-                   ProtocolDecl *protocol)
+                    ProtocolDecl *protocol)
     : kind(kind), storageKind(StorageKind::ProtocolDecl), parent(parent) {
     assert((static_cast<bool>(parent) != isRootKind(kind)) &&
            "Root RequirementSource should not have parent (or vice versa)");
@@ -227,7 +672,7 @@
   }
 
   RequirementSource(Kind kind, const RequirementSource *parent,
-                   ProtocolConformance *conformance)
+                    ProtocolConformance *conformance)
     : kind(kind), storageKind(StorageKind::ProtocolConformance),
       parent(parent) {
     assert((static_cast<bool>(parent) != isRootKind(kind)) &&
@@ -238,35 +683,48 @@
     storage.conformance = conformance;
   }
 
+  RequirementSource(Kind kind, const RequirementSource *parent,
+                    AssociatedTypeDecl *assocType)
+    : kind(kind), storageKind(StorageKind::AssociatedTypeDecl),
+      parent(parent) {
+    assert((static_cast<bool>(parent) != isRootKind(kind)) &&
+           "Root RequirementSource should not have parent (or vice versa)");
+    assert(isAcceptableStorageKind(kind, storageKind) &&
+           "RequirementSource kind/storageKind mismatch");
+
+    storage.assocType = assocType;
+  }
+
 public:
   /// Retrieve an abstract requirement source.
-  static const RequirementSource *forAbstract(GenericSignatureBuilder &builder);
+  static const RequirementSource *forAbstract(PotentialArchetype *root);
 
   /// Retrieve a requirement source representing an explicit requirement
   /// stated in an 'inheritance' clause.
-  static const RequirementSource *forExplicit(GenericSignatureBuilder &builder,
+  static const RequirementSource *forExplicit(PotentialArchetype *root,
                                               const TypeRepr *typeRepr);
 
   /// Retrieve a requirement source representing an explicit requirement
   /// stated in an 'where' clause.
-  static const RequirementSource *forExplicit(GenericSignatureBuilder &builder,
+  static const RequirementSource *forExplicit(
+                                        PotentialArchetype *root,
                                         const RequirementRepr *requirementRepr);
 
   /// Retrieve a requirement source representing a requirement that is
   /// inferred from some part of a generic declaration's signature, e.g., the
   /// parameter or result type of a generic function.
-  static const RequirementSource *forInferred(GenericSignatureBuilder &builder,
+  static const RequirementSource *forInferred(PotentialArchetype *root,
                                               const TypeRepr *typeRepr);
 
   /// Retrieve a requirement source representing the requirement signature
   /// computation for a protocol.
   static const RequirementSource *forRequirementSignature(
-                                              GenericSignatureBuilder &builder,
-                                              ProtocolDecl *protocol);
+                                                      PotentialArchetype *root,
+                                                      ProtocolDecl *protocol);
 
-  /// Retrieve an requirement source for nested type name matches.
+  /// Retrieve a requirement source for nested type name matches.
   static const RequirementSource *forNestedTypeNameMatch(
-                                              GenericSignatureBuilder &builder);
+                                     PotentialArchetype *root);
 
   /// A requirement source that describes that a requirement comes from a
   /// requirement of the given protocol described by the parent.
@@ -287,7 +745,13 @@
 
   /// A constraint source that describes that a constraint that is resolved
   /// for a nested type via a constraint on its parent.
-  const RequirementSource *viaParent(GenericSignatureBuilder &builder) const;
+  ///
+  /// \param assocType the associated type that
+  const RequirementSource *viaParent(GenericSignatureBuilder &builder,
+                                     AssociatedTypeDecl *assocType) const;
+
+  /// Retrieve the potential archetype at the root.
+  PotentialArchetype *getRootPotentialArchetype() const;
 
   /// Whether the requirement can be derived from something in its path.
   ///
@@ -301,6 +765,13 @@
   /// to a protocol.
   bool isDerivedViaConcreteConformance() const;
 
+  /// Determine whether the given derived requirement \c source, when rooted at
+  /// the potential archetype \c pa, is actually derived from the same
+  /// requirement. Such "self-derived" requirements do not make the original
+  /// requirement redundant, because without said original requirement, the
+  /// derived requirement ceases to hold.
+  bool isSelfDerivedSource(PotentialArchetype *pa) const;
+
   /// Retrieve a source location that corresponds to the requirement.
   SourceLoc getLoc() const;
 
@@ -333,17 +804,26 @@
     return storage.conformance;
   }
 
+  /// Retrieve the associated type declaration for this requirement, if there
+  /// is one.
+  AssociatedTypeDecl *getAssociatedType() const {
+    if (storageKind != StorageKind::AssociatedTypeDecl) return nullptr;
+    return storage.assocType;
+  }
+
   /// Profiling support for \c FoldingSet.
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, kind, parent, getOpaqueStorage());
+    Profile(ID, kind, parent, getOpaqueStorage(), getExtraOpaqueStorage());
   }
 
   /// Profiling support for \c FoldingSet.
   static void Profile(llvm::FoldingSetNodeID &ID, Kind kind,
-                      const RequirementSource *parent, const void *storage) {
+                      const RequirementSource *parent, const void *storage,
+                      const void *extraStorage) {
     ID.AddInteger(kind);
     ID.AddPointer(parent);
     ID.AddPointer(storage);
+    ID.AddPointer(extraStorage);
   }
 
   LLVM_ATTRIBUTE_DEPRECATED(
@@ -362,313 +842,56 @@
   void print(llvm::raw_ostream &out, SourceManager *SrcMgr) const;
 };
 
-/// \brief Collects a set of requirements of generic parameters, both explicitly
-/// stated and inferred, and determines the set of archetypes for each of
-/// the generic parameters.
-class GenericSignatureBuilder {
-public:
-  /// Describes a potential archetype, which stands in for a generic parameter
-  /// type or some type derived from it.
-  class PotentialArchetype;
+/// A requirement source that potentially lacks a root \c PotentialArchetype.
+/// The root will be supplied as soon as the appropriate dependent type is
+/// resolved.
+class GenericSignatureBuilder::FloatingRequirementSource {
+  enum Kind {
+    /// A fully-resolved requirement source, which does not need a root.
+    Resolved,
+    /// An explicit requirement source lacking a root.
+    Explicit,
+    /// An inferred requirement source lacking a root.
+    Inferred
+  } kind;
 
-  using UnresolvedType = llvm::PointerUnion<PotentialArchetype *, Type>;
-  struct ResolvedType;
+  using Storage =
+    llvm::PointerUnion3<const RequirementSource *, const TypeRepr *,
+                        const RequirementRepr *>;
 
-  using RequirementRHS =
-      llvm::PointerUnion3<Type, PotentialArchetype *, LayoutConstraint>;
+  Storage storage;
 
-  /// Describes an equivalence class of potential archetypes.
-  struct EquivalenceClass {
-    /// Concrete type to which this equivalence class is equal.
-    Type concreteType;
-
-    /// The members of the equivalence class.
-    TinyPtrVector<PotentialArchetype *> members;
-
-    /// Construct a new equivalence class containing only the given
-    /// potential archetype (which represents itself).
-    EquivalenceClass(PotentialArchetype *representative);
-  };
-
-  friend class RequirementSource;
-
-private:
-  class InferRequirementsWalker;
-  friend class InferRequirementsWalker;
-  friend class GenericSignature;
-
-  ASTContext &Context;
-  DiagnosticEngine &Diags;
-  struct Implementation;
-  std::unique_ptr<Implementation> Impl;
-
-  GenericSignatureBuilder(const GenericSignatureBuilder &) = delete;
-  GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete;
-
-  /// Update an existing constraint source reference when another constraint
-  /// source was found to produce the same constraint. Only the better
-  /// constraint source will be kept.
-  ///
-  /// \returns true if the new constraint source was better, false otherwise.
-  bool updateRequirementSource(const RequirementSource *&existingSource,
-                               const RequirementSource *newSource);
-
-  /// Retrieve the constraint source conformance for the superclass constraint
-  /// of the given potential archetype (if present) to the given protocol.
-  ///
-  /// \param pa The potential archetype whose superclass constraint is being
-  /// queried.
-  ///
-  /// \param proto The protocol to which we are establishing conformance.
-  ///
-  /// \param protoSource The requirement source for the conformance to the
-  /// given protocol.
-  const RequirementSource *resolveSuperConformance(
-                            GenericSignatureBuilder::PotentialArchetype *pa,
-                            ProtocolDecl *proto,
-                            const RequirementSource *&protoSource);
-
-  /// \brief Add a new conformance requirement specifying that the given
-  /// potential archetype conforms to the given protocol.
-  bool addConformanceRequirement(PotentialArchetype *T,
-                                 ProtocolDecl *Proto,
-                                 const RequirementSource *Source);
-
-  bool addConformanceRequirement(PotentialArchetype *T,
-                                 ProtocolDecl *Proto,
-                                 const RequirementSource *Source,
-                                llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
+  FloatingRequirementSource(Kind kind, Storage storage)
+    : kind(kind), storage(storage) { }
 
 public:
-  /// \brief Add a new same-type requirement between two fully resolved types
-  /// (output of \c GenericSignatureBuilder::resolve).
-  ///
-  /// If the types refer to two concrete types that are fundamentally
-  /// incompatible (e.g. \c Foo<Bar<T>> and \c Foo<Baz>), \c diagnoseMismatch is
-  /// called with the two types that don't match (\c Bar<T> and \c Baz for the
-  /// previous example).
-  bool
-  addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
-                         const RequirementSource *Source,
-                         llvm::function_ref<void(Type, Type)> diagnoseMismatch);
+  /// Implicit conversion from a resolved requirement source.
+  FloatingRequirementSource(const RequirementSource *source)
+    : FloatingRequirementSource(Resolved, source) { }
 
-  /// \brief Add a new same-type requirement between two fully resolved types
-  /// (output of GenericSignatureBuilder::resolve).
-  ///
-  /// The two types must not be incompatible concrete types.
-  bool addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
-                              const RequirementSource *Source);
+  static FloatingRequirementSource forAbstract() {
+    return { Explicit, Storage() };
+  }
 
-  /// \brief Add a new same-type requirement between two unresolved types.
-  ///
-  /// The types are resolved with \c GenericSignatureBuilder::resolve, and must
-  /// not be incompatible concrete types.
-  bool addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
-                              const RequirementSource *Source);
+  static FloatingRequirementSource forExplicit(const TypeRepr *typeRepr) {
+    return { Explicit, typeRepr };
+  }
 
-  /// \brief Add a new same-type requirement between two unresolved types.
-  ///
-  /// The types are resolved with \c GenericSignatureBuilder::resolve. \c
-  /// diagnoseMismatch is called if the two types refer to incompatible concrete
-  /// types.
-  bool
-  addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
-                         const RequirementSource *Source,
-                         llvm::function_ref<void(Type, Type)> diagnoseMismatch);
+  static FloatingRequirementSource forExplicit(
+                                     const RequirementRepr *requirementRepr) {
+    return { Explicit, requirementRepr };
+  }
 
-private:
-  /// \brief Add a new superclass requirement specifying that the given
-  /// potential archetype has the given type as an ancestor.
-  bool addSuperclassRequirement(PotentialArchetype *T,
-                                Type Superclass,
-                                const RequirementSource *Source);
+  static FloatingRequirementSource forInferred(const TypeRepr *typeRepr) {
+    return { Inferred, typeRepr };
+  }
 
-  /// \brief Add a new conformance requirement specifying that the given
-  /// potential archetypes are equivalent.
-  bool addSameTypeRequirementBetweenArchetypes(PotentialArchetype *T1,
-                                               PotentialArchetype *T2,
-                                               const RequirementSource *Source);
-  
-  /// \brief Add a new conformance requirement specifying that the given
-  /// potential archetype is bound to a concrete type.
-  bool addSameTypeRequirementToConcrete(PotentialArchetype *T,
-                                        Type Concrete,
-                                        const RequirementSource *Source);
+  /// Retrieve the complete requirement source rooted at the given potential
+  /// archetype.
+  const RequirementSource *getSource(PotentialArchetype *pa) const;
 
-  /// \brief Add a new same-type requirement specifying that the given two
-  /// types should be the same.
-  ///
-  /// \param diagnoseMismatch Callback invoked when the types in the same-type
-  /// requirement mismatch.
-  bool addSameTypeRequirementBetweenConcrete(
-      Type T1, Type T2, const RequirementSource *Source,
-      llvm::function_ref<void(Type, Type)> diagnoseMismatch);
-
-  /// Add the requirements placed on the given type parameter
-  /// to the given potential archetype.
-  bool addInheritedRequirements(TypeDecl *decl, PotentialArchetype *pa,
-                                const RequirementSource *parentSource,
-                                llvm::SmallPtrSetImpl<ProtocolDecl *> &visited);
-
-  /// Visit all of the potential archetypes.
-  template<typename F>
-  void visitPotentialArchetypes(F f);
-
-  void markPotentialArchetypeRecursive(PotentialArchetype *pa,
-                                       ProtocolDecl *proto,
-                                       const RequirementSource *source);
-
-public:
-  /// Construct a new generic signature builder.
-  ///
-  /// \param lookupConformance Conformance-lookup routine that will be used
-  /// to satisfy conformance requirements for concrete types.
-  explicit GenericSignatureBuilder(ASTContext &ctx,
-                            std::function<GenericFunction> lookupConformance);
-
-  GenericSignatureBuilder(GenericSignatureBuilder &&);
-  ~GenericSignatureBuilder();
-
-  /// Retrieve the AST context.
-  ASTContext &getASTContext() const { return Context; }
-
-  /// Retrieve the conformance-lookup function used by this generic signature builder.
-  std::function<GenericFunction> getLookupConformanceFn() const;
-
-  /// Retrieve the lazy resolver, if there is one.
-  LazyResolver *getLazyResolver() const;
-
-  /// Enumerate the requirements that describe the signature of this
-  /// generic signature builder.
-  ///
-  /// \param f A function object that will be passed each requirement
-  /// and requirement source.
-  void enumerateRequirements(llvm::function_ref<
-                      void (RequirementKind kind,
-                            PotentialArchetype *archetype,
-                            RequirementRHS constraint,
-                            const RequirementSource *source)> f);
-
-public:
-  /// \brief Add a new generic parameter for which there may be requirements.
-  void addGenericParameter(GenericTypeParamDecl *GenericParam);
-
-  /// Add the requirements placed on the given abstract type parameter
-  /// to the given potential archetype.
-  ///
-  /// \returns true if an error occurred, false otherwise.
-  bool addGenericParameterRequirements(GenericTypeParamDecl *GenericParam);
-
-  /// \brief Add a new generic parameter for which there may be requirements.
-  void addGenericParameter(GenericTypeParamType *GenericParam);
-  
-  /// \brief Add a new requirement.
-  ///
-  /// \returns true if this requirement makes the set of requirements
-  /// inconsistent, in which case a diagnostic will have been issued.
-  bool addRequirement(const RequirementRepr *Req);
-
-  /// \brief Add an already-checked requirement.
-  ///
-  /// Adding an already-checked requirement cannot fail. This is used to
-  /// re-inject requirements from outer contexts.
-  ///
-  /// \returns true if this requirement makes the set of requirements
-  /// inconsistent, in which case a diagnostic will have been issued.
-  bool addRequirement(const Requirement &req, const RequirementSource *source);
-
-  bool addRequirement(const Requirement &req, const RequirementSource *source,
-                      llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
-
-  bool addLayoutRequirement(PotentialArchetype *PAT,
-                            LayoutConstraint Layout,
-                            const RequirementSource *Source);
-
-  /// \brief Add all of a generic signature's parameters and requirements.
-  void addGenericSignature(GenericSignature *sig);
-
-  /// \brief Build the generic signature.
-  GenericSignature *getGenericSignature();
-
-  /// Infer requirements from the given type, recursively.
-  ///
-  /// This routine infers requirements from a type that occurs within the
-  /// signature of a generic function. For example, given:
-  ///
-  /// \code
-  /// func f<K, V>(dict : Dictionary<K, V>) { ... }
-  /// \endcode
-  ///
-  /// where \c Dictionary requires that its key type be \c Hashable,
-  /// the requirement \c K : Hashable is inferred from the parameter type,
-  /// because the type \c Dictionary<K,V> cannot be formed without it.
-  void inferRequirements(TypeLoc type, unsigned minDepth, unsigned maxDepth);
-
-  /// Infer requirements from the given pattern, recursively.
-  ///
-  /// This routine infers requirements from a type that occurs within the
-  /// signature of a generic function. For example, given:
-  ///
-  /// \code
-  /// func f<K, V>(dict : Dictionary<K, V>) { ... }
-  /// \endcode
-  ///
-  /// where \c Dictionary requires that its key type be \c Hashable,
-  /// the requirement \c K : Hashable is inferred from the parameter type,
-  /// because the type \c Dictionary<K,V> cannot be formed without it.
-  void inferRequirements(ParameterList *params,GenericParamList *genericParams);
-
-  /// Finalize the set of requirements, performing any remaining checking
-  /// required before generating archetypes.
-  ///
-  /// \param allowConcreteGenericParams If true, allow generic parameters to
-  /// be made concrete.
-  void finalize(SourceLoc loc,
-                ArrayRef<GenericTypeParamType *> genericParams,
-                bool allowConcreteGenericParams=false);
-
-  /// Diagnose any remaining renames.
-  ///
-  /// \returns \c true if there were any remaining renames to diagnose.
-  bool diagnoseRemainingRenames(SourceLoc loc,
-                                ArrayRef<GenericTypeParamType *> genericParams);
-
-private:
-  /// Check for redundant concrete type constraints within the equivalence
-  /// class of the given potential archetype.
-  void checkRedundantConcreteTypeConstraints(
-                            ArrayRef<GenericTypeParamType *> genericParams,
-                            PotentialArchetype *pa);
-
-public:
-  /// \brief Resolve the given type to the potential archetype it names.
-  ///
-  /// This routine will synthesize nested types as required to refer to a
-  /// potential archetype, even in cases where no requirement specifies the
-  /// requirement for such an archetype. FIXME: The failure to include such a
-  /// requirement will be diagnosed at some point later (when the types in the
-  /// signature are fully resolved).
-  ///
-  /// For any type that cannot refer to an archetype, this routine returns null.
-  PotentialArchetype *resolveArchetype(Type type);
-
-  /// \brief Resolve the given type as far as this Builder knows how.
-  ///
-  /// This returns either a non-typealias potential archetype or a Type, if \c
-  /// type is concrete.
-  // FIXME: the hackTypeFromGenericTypeAlias is just temporarily patching over
-  // problems with generic typealiases (see the comment on the ResolvedType
-  // function)
-  ResolvedType resolve(UnresolvedType type,
-                       bool hackTypeFromGenericTypeAlias = false);
-
-  /// \brief Dump all of the requirements, both specified and inferred.
-  LLVM_ATTRIBUTE_DEPRECATED(
-      void dump(),
-      "only for use within the debugger");
-
-  /// Dump all of the requirements to the given output stream.
-  void dump(llvm::raw_ostream &out);
+  /// Retrieve the source location for this requirement.
+  SourceLoc getLoc() const;
 };
 
 class GenericSignatureBuilder::PotentialArchetype {
@@ -713,12 +936,6 @@
   llvm::MapVector<PotentialArchetype *, const RequirementSource *>
     SameTypeConstraints;
 
-  /// \brief The superclass of this archetype, if specified.
-  Type Superclass;
-
-  /// The source of the superclass requirement.
-  const RequirementSource *SuperclassSource = nullptr;
-
   /// \brief The list of protocols to which this archetype will conform.
   llvm::MapVector<ProtocolDecl *, const RequirementSource *> ConformsTo;
 
@@ -736,16 +953,6 @@
   llvm::MapVector<Identifier, llvm::TinyPtrVector<PotentialArchetype *>>
     NestedTypes;
 
-  /// The concrete types to which this potential archetype has been
-  /// constrained.
-  ///
-  /// This vector runs parallel to ConcreteTypeSources.
-  llvm::TinyPtrVector<Type> concreteTypes;
-
-  /// The source of the concrete type requirements that were written on
-  /// this potential archetype.
-  llvm::TinyPtrVector<const RequirementSource *> concreteTypeSources;
-
   /// Whether this is an unresolved nested type.
   unsigned isUnresolvedNestedType : 1;
 
@@ -910,12 +1117,12 @@
                       GenericSignatureBuilder &builder);
 
   /// Retrieve the superclass of this archetype.
-  Type getSuperclass() const { return Superclass; }
-
-  /// Retrieve the requirement source for the superclass requirement.
-  const RequirementSource *getSuperclassSource() const {
-    return SuperclassSource;
-  } 
+  Type getSuperclass() const {
+    if (auto equiv = getEquivalenceClassIfPresent())
+      return equiv->superclass;
+    
+    return nullptr;
+  }
 
   /// Retrieve the layout constraint of this archetype.
   LayoutConstraint getLayout() const { return Layout; }
@@ -973,22 +1180,6 @@
                             SameTypeConstraints.end());
   }
 
-  /// Retrieve the concrete types as written on this potential archetype.
-  const llvm::TinyPtrVector<Type>& getConcreteTypesAsWritten() const {
-    return concreteTypes;
-  }
-
-  /// Retrieve the concrete type sources as written on this potential archetype.
-  ArrayRef<const RequirementSource *> getConcreteTypeSourcesAsWritten() const {
-    return concreteTypeSources;
-  }
-
-  /// Find a source of the same-type constraint that maps this potential
-  /// archetype to a concrete type somewhere in the equivalence class of this
-  /// type along with the concrete type that was written there.
-  Optional<std::pair<Type, const RequirementSource *>>
-  findAnyConcreteTypeSourceAsWritten() const;
-
   /// \brief Retrieve (or create) a nested type with the given name.
   PotentialArchetype *getNestedType(Identifier Name,
                                     GenericSignatureBuilder &builder);
diff --git a/include/swift/AST/IfConfigClause.h b/include/swift/AST/IfConfigClause.h
new file mode 100644
index 0000000..7c8c1cf
--- /dev/null
+++ b/include/swift/AST/IfConfigClause.h
@@ -0,0 +1,52 @@
+//===--- IfConfigClause.h ---------------------------------------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the IfConfigClause.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_AST_IFCONFIGCLAUSE_H
+#define SWIFT_AST_IFCONFIGCLAUSE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace swift {
+  class Expr;
+  class SourceLoc;
+
+/// This represents one part of a #if block.  If the condition field is
+/// non-null, then this represents a #if or a #elseif, otherwise it represents
+/// an #else block.
+template <typename ElemTy>
+struct IfConfigClause {
+  /// The location of the #if, #elseif, or #else keyword.
+  SourceLoc Loc;
+  
+  /// The condition guarding this #if or #elseif block.  If this is null, this
+  /// is a #else clause.
+  Expr *Cond;
+  
+  /// Elements inside the clause
+  ArrayRef<ElemTy> Elements;
+
+  /// True if this is the active clause of the #if block.
+  bool isActive;
+
+  IfConfigClause<ElemTy>(SourceLoc Loc, Expr *Cond,
+                         ArrayRef<ElemTy> Elements, bool isActive)
+    : Loc(Loc), Cond(Cond), Elements(Elements), isActive(isActive) {
+  }
+};
+
+} // end namespace swift
+
+#endif
diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h
index 3c561ce..5100365 100644
--- a/include/swift/AST/Pattern.h
+++ b/include/swift/AST/Pattern.h
@@ -492,7 +492,7 @@
   SourceLoc DotLoc;
   SourceLoc NameLoc;
   Identifier Name;
-  EnumElementDecl *ElementDecl;
+  PointerUnion<EnumElementDecl *, Expr*> ElementDeclOrUnresolvedOriginalExpr;
   Pattern /*nullable*/ *SubPattern;
   
 public:
@@ -501,10 +501,25 @@
                      Pattern *SubPattern, Optional<bool> Implicit = None)
     : Pattern(PatternKind::EnumElement),
       ParentType(ParentType), DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
-      ElementDecl(Element), SubPattern(SubPattern) {
+      ElementDeclOrUnresolvedOriginalExpr(Element),
+      SubPattern(SubPattern) {
     if (Implicit.hasValue() && *Implicit)
       setImplicit();
   }
+  
+  /// Create an unresolved EnumElementPattern for a `.foo` pattern relying on
+  /// contextual type.
+  EnumElementPattern(SourceLoc DotLoc,
+                     SourceLoc NameLoc,
+                     Identifier Name,
+                     Pattern *SubPattern,
+                     Expr *UnresolvedOriginalExpr)
+    : Pattern(PatternKind::EnumElement),
+      ParentType(), DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
+      ElementDeclOrUnresolvedOriginalExpr(UnresolvedOriginalExpr),
+      SubPattern(SubPattern) {
+    
+  }
 
   bool hasSubPattern() const { return SubPattern; }
   
@@ -524,8 +539,19 @@
   
   Identifier getName() const { return Name; }
   
-  EnumElementDecl *getElementDecl() const { return ElementDecl; }
-  void setElementDecl(EnumElementDecl *d) { ElementDecl = d; }
+  EnumElementDecl *getElementDecl() const {
+    return ElementDeclOrUnresolvedOriginalExpr.dyn_cast<EnumElementDecl*>();
+  }
+  void setElementDecl(EnumElementDecl *d) {
+    ElementDeclOrUnresolvedOriginalExpr = d;
+  }
+  
+  Expr *getUnresolvedOriginalExpr() const {
+    return ElementDeclOrUnresolvedOriginalExpr.get<Expr*>();
+  }
+  bool hasUnresolvedOriginalExpr() const {
+    return ElementDeclOrUnresolvedOriginalExpr.is<Expr*>();
+  }
   
   SourceLoc getNameLoc() const { return NameLoc; }
   SourceLoc getLoc() const { return NameLoc; }
diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h
index 928da0f..9a6adf5 100644
--- a/include/swift/AST/Stmt.h
+++ b/include/swift/AST/Stmt.h
@@ -20,6 +20,7 @@
 #include "swift/AST/Availability.h"
 #include "swift/AST/AvailabilitySpec.h"
 #include "swift/AST/ASTNode.h"
+#include "swift/AST/IfConfigClause.h"
 #include "swift/AST/TypeAlignments.h"
 #include "swift/Basic/NullablePtr.h"
 #include "llvm/Support/TrailingObjects.h"
@@ -653,41 +654,17 @@
   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Guard; }
 };
 
-  
-/// This represents one part of a #if block.  If the condition field is
-/// non-null, then this represents a #if or a #elseif, otherwise it represents
-/// an #else block.
-struct IfConfigStmtClause {
-  /// The location of the #if, #elseif, or #else keyword.
-  SourceLoc Loc;
-  
-  /// The condition guarding this #if or #elseif block.  If this is null, this
-  /// is a #else clause.
-  Expr *Cond;
-  
-  /// Elements inside the clause
-  ArrayRef<ASTNode> Elements;
-
-  /// True if this is the active clause of the #if block.
-  bool isActive;
-
-  IfConfigStmtClause(SourceLoc Loc, Expr *Cond,
-                     ArrayRef<ASTNode> Elements, bool isActive)
-    : Loc(Loc), Cond(Cond), Elements(Elements), isActive(isActive) {
-  }
-};
-
 /// IfConfigStmt - This class models the statement-side representation of
 /// #if/#else/#endif blocks.
 class IfConfigStmt : public Stmt {
   /// An array of clauses controlling each of the #if/#elseif/#else conditions.
   /// The array is ASTContext allocated.
-  ArrayRef<IfConfigStmtClause> Clauses;
+  ArrayRef<IfConfigClause<ASTNode>> Clauses;
   SourceLoc EndLoc;
   bool HadMissingEnd;
 
 public:
-  IfConfigStmt(ArrayRef<IfConfigStmtClause> Clauses, SourceLoc EndLoc,
+  IfConfigStmt(ArrayRef<IfConfigClause<ASTNode>> Clauses, SourceLoc EndLoc,
                bool HadMissingEnd)
   : Stmt(StmtKind::IfConfig, /*implicit=*/false),
     Clauses(Clauses), EndLoc(EndLoc), HadMissingEnd(HadMissingEnd) {}
@@ -699,7 +676,9 @@
 
   bool hadMissingEnd() const { return HadMissingEnd; }
   
-  const ArrayRef<IfConfigStmtClause> &getClauses() const { return Clauses; }
+  const ArrayRef<IfConfigClause<ASTNode>> &getClauses() const {
+    return Clauses;
+  }
 
   ArrayRef<ASTNode> getActiveClauseElements() const {
     for (auto &Clause : Clauses)
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index 26fdde0..5d3fb2a 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -361,7 +361,6 @@
                                               OptionalTypeKind &kind);
   static CanType getReferenceStorageReferentImpl(CanType type);
   static CanType getLValueOrInOutObjectTypeImpl(CanType type);
-  static ClassDecl *getClassBoundImpl(CanType type);
 
 public:
   explicit CanType(TypeBase *P = 0) : Type(P) {
@@ -438,15 +437,6 @@
   /// it returns an empty LayoutConstraint.
   LayoutConstraint getLayoutConstraint() const;
 
-  /// \brief Retrieve the most-specific class bound of this type,
-  /// which is either a class, a bound-generic class, or a class-bounded
-  /// archetype.
-  ///
-  /// Returns nil if this is an archetype with a non-specific class bound.
-  ClassDecl *getClassBound() const {
-    return getClassBoundImpl(*this);
-  }
-
   CanType getAnyOptionalObjectType() const {
     OptionalTypeKind kind;
     return getAnyOptionalObjectTypeImpl(*this, kind);
diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h
index 5bdebfd..166bc0e 100644
--- a/include/swift/AST/TypeRepr.h
+++ b/include/swift/AST/TypeRepr.h
@@ -283,6 +283,9 @@
   SimpleIdentTypeRepr(SourceLoc Loc, Identifier Id)
     : ComponentIdentTypeRepr(TypeReprKind::SimpleIdent, Loc, Id) {}
 
+  SimpleIdentTypeRepr(const SimpleIdentTypeRepr &repr)
+    : SimpleIdentTypeRepr(repr.getLoc(), repr.getIdentifier()) {}
+
   static bool classof(const TypeRepr *T) {
     return T->getKind() == TypeReprKind::SimpleIdent;
   }
@@ -846,6 +849,9 @@
   FixedTypeRepr(Type Ty, SourceLoc Loc)
     : TypeRepr(TypeReprKind::Fixed), Ty(Ty), Loc(Loc) {}
 
+  FixedTypeRepr(const FixedTypeRepr& repr)
+    : FixedTypeRepr(repr.Ty, repr.Loc) {}
+
   /// Retrieve the location.
   SourceLoc getLoc() const { return Loc; }
 
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 77f492e..743761b 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -606,13 +606,6 @@
                            LazyResolver *resolver,
                            DeclContext *gpContext = nullptr);
 
-  /// \brief Determine whether the given type is "generic", meaning that
-  /// it involves generic types for which generic arguments have not been
-  /// provided.
-  /// For example, the type Vector and Vector<Int>.InnerGeneric are both
-  /// unspecialized generic, but the type Vector<Int> is not.
-  bool isUnspecializedGeneric();
-
   /// \brief Determine whether this type is a legal, lowered SIL type.
   ///
   /// A type is SIL-illegal if it is:
@@ -882,13 +875,15 @@
   /// Get the substitutions to apply to the type of the given member as seen
   /// from this base type.
   ///
-  /// If the member has its own generic parameters, they will remain unchanged
-  /// by the substitution.
+  /// \param genericEnv If non-null, generic parameters of the member are
+  /// mapped to context archetypes of this generic environment.
   SubstitutionMap getMemberSubstitutionMap(ModuleDecl *module,
-                                           const ValueDecl *member);
+                                           const ValueDecl *member,
+                                           GenericEnvironment *genericEnv=nullptr);
 
   /// Deprecated version of the above.
-  TypeSubstitutionMap getMemberSubstitutions(const ValueDecl *member);
+  TypeSubstitutionMap getMemberSubstitutions(const ValueDecl *member,
+                                             GenericEnvironment *genericEnv=nullptr);
 
   /// Retrieve the type of the given member as seen through the given base
   /// type, substituting generic arguments where necessary.
@@ -4471,6 +4466,8 @@
 inline Type TypeBase::getNominalParent() {
   if (auto classType = getAs<NominalType>()) {
     return classType->getParent();
+  } else if (auto unboundType = getAs<UnboundGenericType>()) {
+    return unboundType->getParent();
   } else {
     return castTo<BoundGenericType>()->getParent();
   }
diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h
index cd5f872..82a1cee 100644
--- a/include/swift/Basic/LangOptions.h
+++ b/include/swift/Basic/LangOptions.h
@@ -29,6 +29,20 @@
 #include <vector>
 
 namespace swift {
+
+  /// Kind of implicit platform conditions.
+  enum class PlatformConditionKind {
+    /// The active os target (OSX, iOS, Linux, etc.)
+    OS,
+    /// The active arch target (x86_64, i386, arm, arm64, etc.)
+    Arch,
+    /// The active endianness target (big or little)
+    Endianness,
+    /// Runtime support (_ObjC or _Native)
+    Runtime,
+  };
+  enum { NumPlatformConditionKind = 4 };
+
   /// \brief A collection of options that affect the language dialect and
   /// provide compiler debugging facilities.
   class LangOptions {
@@ -114,6 +128,10 @@
     /// solver should be debugged.
     unsigned DebugConstraintSolverAttempt = 0;
 
+    /// \brief Enable the experimental constraint propagation in the
+    /// type checker.
+    bool EnableConstraintPropagation = false;
+
     /// \brief Enable the iterative type checker.
     bool IterativeTypeChecker = false;
 
@@ -198,14 +216,9 @@
     }
 
     /// Sets an implicit platform condition.
-    ///
-    /// There are currently three supported platform conditions:
-    /// - os: The active os target (OSX or iOS)
-    /// - arch: The active arch target (x86_64, i386, arm, arm64)
-    /// - _runtime: Runtime support (_ObjC or _Native)
-    void addPlatformConditionValue(StringRef Name, StringRef Value) {
-      assert(!Name.empty() && !Value.empty());
-      PlatformConditionValues.emplace_back(Name, Value);
+    void addPlatformConditionValue(PlatformConditionKind Kind, StringRef Value) {
+      assert(!Value.empty());
+      PlatformConditionValues.emplace_back(Kind, Value);
     }
 
     /// Removes all values added with addPlatformConditionValue.
@@ -214,7 +227,7 @@
     }
     
     /// Returns the value for the given platform condition or an empty string.
-    StringRef getPlatformConditionValue(StringRef Name) const;
+    StringRef getPlatformConditionValue(PlatformConditionKind Kind) const;
 
     /// Explicit conditional compilation flags, initialized via the '-D'
     /// compiler flag.
@@ -226,7 +239,7 @@
     /// Determines if a given conditional compilation flag has been set.
     bool isCustomConditionalCompilationFlagSet(StringRef Name) const;
 
-    ArrayRef<std::pair<std::string, std::string>>
+    ArrayRef<std::pair<PlatformConditionKind, std::string>>
     getPlatformConditionValues() const {
       return PlatformConditionValues;
     }
@@ -240,35 +253,18 @@
       return EffectiveLanguageVersion.isVersion3();
     }
 
-    /// Returns true if the 'os' platform condition argument represents
+    /// Returns true if the given platform condition argument represents
     /// a supported target operating system.
     ///
-    /// Note that this also canonicalizes the OS name if the check returns
-    /// true.
-    ///
     /// \param suggestions Populated with suggested replacements
     /// if a match is not found.
-    static bool checkPlatformConditionOS(
-      StringRef &OSName, std::vector<StringRef> &suggestions);
-
-    /// Returns true if the 'arch' platform condition argument represents
-    /// a supported target architecture.
-    ///
-    /// \param suggestions Populated with suggested replacements
-    /// if a match is not found.
-    static bool isPlatformConditionArchSupported(
-      StringRef ArchName, std::vector<StringRef> &suggestions);
-
-    /// Returns true if the 'endian' platform condition argument represents
-    /// a supported target endianness.
-    ///
-    /// \param suggestions Populated with suggested replacements
-    /// if a match is not found.
-    static bool isPlatformConditionEndiannessSupported(
-      StringRef endianness, std::vector<StringRef> &suggestions);
+    static bool checkPlatformConditionSupported(
+      PlatformConditionKind Kind, StringRef Value,
+      std::vector<StringRef> &suggestions);
 
   private:
-    llvm::SmallVector<std::pair<std::string, std::string>, 3>
+    llvm::SmallVector<std::pair<PlatformConditionKind, std::string>,
+                      NumPlatformConditionKind>
         PlatformConditionValues;
     llvm::SmallVector<std::string, 2> CustomConditionalCompilationFlags;
   };
diff --git a/include/swift/Basic/OwnedString.h b/include/swift/Basic/OwnedString.h
index f4240b2..8745de6 100644
--- a/include/swift/Basic/OwnedString.h
+++ b/include/swift/Basic/OwnedString.h
@@ -2,7 +2,7 @@
 //
 // This source file is part of the Swift.org open source project
 //
-// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
 // Licensed under Apache License v2.0 with Runtime Library Exception
 //
 // See https://swift.org/LICENSE.txt for license information
diff --git a/include/swift/Basic/Timer.h b/include/swift/Basic/Timer.h
index 8558cd2..20f199c 100644
--- a/include/swift/Basic/Timer.h
+++ b/include/swift/Basic/Timer.h
@@ -33,8 +33,7 @@
   public:
     explicit SharedTimer(StringRef name) {
       if (CompilationTimersEnabled == State::Enabled)
-        Timer.emplace(name, StringRef("Swift compilation"), StringRef("swift"),
-                      StringRef("swift related timers"));
+        Timer.emplace(name, name, "swift", "Swift compilation");
       else
         CompilationTimersEnabled = State::Skipped;
     }
diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h
index 242f075..c0881c9 100644
--- a/include/swift/ClangImporter/ClangImporter.h
+++ b/include/swift/ClangImporter/ClangImporter.h
@@ -260,8 +260,7 @@
   /// The return value may be an empty identifier, in which case the enum would
   /// not be imported.
   ///
-  /// This is mostly an implementation detail of the importer, but is also
-  /// used by the debugger.
+  /// This is not used by the importer itself, but is used by the debugger.
   Identifier getEnumConstantName(const clang::EnumConstantDecl *enumConstant);
 
   /// Writes the mangled name of \p clangDecl to \p os.
diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h
index a3ed69b..11d3a38 100644
--- a/include/swift/ClangImporter/ClangModule.h
+++ b/include/swift/ClangImporter/ClangModule.h
@@ -17,6 +17,7 @@
 #define SWIFT_CLANGIMPORTER_CLANGMODULE_H
 
 #include "swift/AST/Module.h"
+#include "swift/ClangImporter/ClangImporter.h"
 
 namespace clang {
   class ASTContext;
@@ -26,12 +27,11 @@
 namespace swift {
 
 class ASTContext;
-class ClangImporter;
 class ModuleLoader;
 
 /// \brief Represents a Clang module that has been imported into Swift.
 class ClangModuleUnit final : public LoadedFile {
-  ClangImporter &owner;
+  ClangImporter::Implementation &owner;
   const clang::Module *clangModule;
   llvm::PointerIntPair<ModuleDecl *, 1, bool> adapterModule;
   mutable ArrayRef<ModuleDecl::ImportedModule> importedModulesForLookup;
@@ -42,7 +42,7 @@
   /// True if the given Module contains an imported Clang module unit.
   static bool hasClangModule(ModuleDecl *M);
 
-  ClangModuleUnit(ModuleDecl &M, ClangImporter &owner,
+  ClangModuleUnit(ModuleDecl &M, ClangImporter::Implementation &owner,
                   const clang::Module *clangModule);
 
   /// \brief Retrieve the underlying Clang module.
diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h
index c472f12..633e77f 100644
--- a/include/swift/IDE/Utils.h
+++ b/include/swift/IDE/Utils.h
@@ -307,7 +307,7 @@
   unsigned commonPartsCount(DeclNameViewer &Other) const;
 };
 
-/// This provide a utility for writing to a underlying string buffer multiple
+/// This provide a utility for writing to an underlying string buffer mulitiple
 /// string pieces and retrieve them later when the underlying buffer is stable.
 class DelayedStringRetriever : public raw_ostream {
     SmallVectorImpl<char> &OS;
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index cd1111b..260b898 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -139,6 +139,9 @@
 def debug_constraints_attempt : Separate<["-"], "debug-constraints-attempt">,
   HelpText<"Debug the constraint solver at a given attempt">;
 
+def propagate_constraints : Flag<["-"], "propagate-constraints">,
+  HelpText<"Enable constraint propagation in the type checker">;
+
 def iterative_type_checker : Flag<["-"], "iterative-type-checker">,
   HelpText<"Enable the iterative type checker">;
 
diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h
index 5496801..ea69199 100644
--- a/include/swift/Parse/Parser.h
+++ b/include/swift/Parse/Parser.h
@@ -750,6 +750,9 @@
                                            DeclAttributes &Attributes);
   ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
                                 SourceLoc *classRequirementLoc);
+  ParserStatus parseDeclItem(bool &PreviousHadSemi,
+                             Parser::ParseDeclOptions Options,
+                             llvm::function_ref<void(Decl*)> handler);
   bool parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
                      Diag<> ErrorDiag, ParseDeclOptions Options,
                      llvm::function_ref<void(Decl*)> handler);
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index 8097ab5..a2fcbcd 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -869,6 +869,8 @@
       return {true, metadataPointer};
     }
     }
+
+    swift_runtime_unreachable("Unhandled IsaEncodingKind in switch.");
   }
 
   /// Read the parent type metadata from a nested nominal type metadata.
diff --git a/include/swift/Runtime/HeapObject.h b/include/swift/Runtime/HeapObject.h
index e21d417..cfb6fba 100644
--- a/include/swift/Runtime/HeapObject.h
+++ b/include/swift/Runtime/HeapObject.h
@@ -510,6 +510,16 @@
 void swift_unownedRelease(HeapObject *value)
     SWIFT_CC(RegisterPreservingCC);
 
+/// Increment the unowned retain count.
+SWIFT_RT_ENTRY_VISIBILITY
+void swift_nonatomic_unownedRetain(HeapObject *value)
+    SWIFT_CC(RegisterPreservingCC);
+
+/// Decrement the unowned retain count.
+SWIFT_RT_ENTRY_VISIBILITY
+void swift_nonatomic_unownedRelease(HeapObject *value)
+    SWIFT_CC(RegisterPreservingCC);
+
 /// Increment the unowned retain count by n.
 SWIFT_RT_ENTRY_VISIBILITY
 void swift_unownedRetain_n(HeapObject *value, int n)
@@ -520,12 +530,28 @@
 void swift_unownedRelease_n(HeapObject *value, int n)
     SWIFT_CC(RegisterPreservingCC);
 
+/// Increment the unowned retain count by n.
+SWIFT_RT_ENTRY_VISIBILITY
+void swift_nonatomic_unownedRetain_n(HeapObject *value, int n)
+    SWIFT_CC(RegisterPreservingCC);
+
+/// Decrement the unowned retain count by n.
+SWIFT_RT_ENTRY_VISIBILITY
+void swift_nonatomic_unownedRelease_n(HeapObject *value, int n)
+    SWIFT_CC(RegisterPreservingCC);
+
 /// Increment the strong retain count of an object, aborting if it has
 /// been deallocated.
 SWIFT_RT_ENTRY_VISIBILITY
 void swift_unownedRetainStrong(HeapObject *value)
     SWIFT_CC(RegisterPreservingCC);
 
+/// Increment the strong retain count of an object, aborting if it has
+/// been deallocated.
+SWIFT_RT_ENTRY_VISIBILITY
+void swift_nonatomic_unownedRetainStrong(HeapObject *value)
+    SWIFT_CC(RegisterPreservingCC);
+
 /// Increment the strong retain count of an object which may have been
 /// deallocated, aborting if it has been deallocated, and decrement its
 /// unowned reference count.
@@ -533,6 +559,13 @@
 void swift_unownedRetainStrongAndRelease(HeapObject *value)
     SWIFT_CC(RegisterPreservingCC);
 
+/// Increment the strong retain count of an object which may have been
+/// deallocated, aborting if it has been deallocated, and decrement its
+/// unowned reference count.
+SWIFT_RT_ENTRY_VISIBILITY
+void swift_nonatomic_unownedRetainStrongAndRelease(HeapObject *value)
+    SWIFT_CC(RegisterPreservingCC);
+
 /// Aborts if the object has been deallocated.
 SWIFT_RUNTIME_EXPORT
 void swift_unownedCheck(HeapObject *value);
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 555a2b0..4a8ceb0 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -769,6 +769,8 @@
   value_witness_types::storeExtraInhabitant *storeExtraInhabitant;
   value_witness_types::getExtraInhabitantIndex *getExtraInhabitantIndex;
 
+#define SET_WITNESS(NAME) base.NAME,
+
   constexpr ExtraInhabitantsValueWitnessTable()
     : ValueWitnessTable{}, extraInhabitantFlags(),
       storeExtraInhabitant(nullptr),
@@ -778,9 +780,15 @@
                             value_witness_types::extraInhabitantFlags eif,
                             value_witness_types::storeExtraInhabitant *sei,
                             value_witness_types::getExtraInhabitantIndex *geii)
-    : ValueWitnessTable(base), extraInhabitantFlags(eif),
+    : ValueWitnessTable{
+      FOR_ALL_FUNCTION_VALUE_WITNESSES(SET_WITNESS)
+      base.size,
+      base.flags,
+      base.stride
+    }, extraInhabitantFlags(eif),
       storeExtraInhabitant(sei),
       getExtraInhabitantIndex(geii) {}
+#undef SET_WITNESS
 
   static bool classof(const ValueWitnessTable *table) {
     return table->flags.hasExtraInhabitants();
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index 9c82868..2be2880 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -369,6 +369,20 @@
          ARGS(RefCountedPtrTy),
          ATTRS(NoUnwind))
 
+// void swift_nonatomic_unownedRetain(void *ptr);
+FUNCTION(NonAtomicNativeUnownedRetain, swift_nonatomic_unownedRetain,
+         RegisterPreservingCC,
+         RETURNS(VoidTy),
+         ARGS(RefCountedPtrTy),
+         ATTRS(NoUnwind))
+
+// void swift_nonatomic_unownedRelease(void *ptr);
+FUNCTION(NonAtomicNativeUnownedRelease, swift_nonatomic_unownedRelease,
+         RegisterPreservingCC,
+         RETURNS(VoidTy),
+         ARGS(RefCountedPtrTy),
+         ATTRS(NoUnwind))
+
 // void swift_unownedRetain_n(void *ptr, int32_t n);
 FUNCTION(UnownedRetainN, swift_unownedRetain_n,
          RegisterPreservingCC,
@@ -383,12 +397,33 @@
          ARGS(RefCountedPtrTy, Int32Ty),
          ATTRS(NoUnwind))
 
+// void swift_nonatomic_unownedRetain_n(void *ptr, int32_t n);
+FUNCTION(NonAtomicUnownedRetainN, swift_nonatomic_unownedRetain_n,
+         RegisterPreservingCC,
+         RETURNS(VoidTy),
+         ARGS(RefCountedPtrTy, Int32Ty),
+         ATTRS(NoUnwind))
+
+// void swift_nonatomic_unownedRelease_n(void *ptr, int32_t n);
+FUNCTION(NonAtomicUnownedReleaseN, swift_nonatomic_unownedRelease_n,
+         RegisterPreservingCC,
+         RETURNS(VoidTy),
+         ARGS(RefCountedPtrTy, Int32Ty),
+         ATTRS(NoUnwind))
+
 // void swift_unownedRetainStrong(void *ptr);
 FUNCTION(NativeStrongRetainUnowned, swift_unownedRetainStrong, RegisterPreservingCC,
          RETURNS(VoidTy),
          ARGS(RefCountedPtrTy),
          ATTRS(NoUnwind))
 
+// void swift_nonatomic_unownedRetainStrong(void *ptr);
+FUNCTION(NonAtomicNativeStrongRetainUnowned, swift_nonatomic_unownedRetainStrong,
+         RegisterPreservingCC,
+         RETURNS(VoidTy),
+         ARGS(RefCountedPtrTy),
+         ATTRS(NoUnwind))
+
 // void swift_unownedRetainStrongAndRelease(void *ptr);
 FUNCTION(NativeStrongRetainAndUnownedRelease,
          swift_unownedRetainStrongAndRelease, RegisterPreservingCC,
@@ -396,6 +431,13 @@
          ARGS(RefCountedPtrTy),
          ATTRS(NoUnwind))
 
+// void swift_nonatomic_unownedRetainStrongAndRelease(void *ptr);
+FUNCTION(NonAtomicNativeStrongRetainAndUnownedRelease,
+         swift_nonatomic_unownedRetainStrongAndRelease, RegisterPreservingCC,
+         RETURNS(VoidTy),
+         ARGS(RefCountedPtrTy),
+         ATTRS(NoUnwind))
+
 // void swift_weakDestroy(WeakReference *object);
 FUNCTION(NativeWeakDestroy, swift_weakDestroy, DefaultCC,
          RETURNS(VoidTy),
diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h
index 831abb1..b50ac0f 100644
--- a/include/swift/SIL/PatternMatch.h
+++ b/include/swift/SIL/PatternMatch.h
@@ -369,6 +369,7 @@
 UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialOpaqueInst)
 UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialRefInst)
 UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialAddrInst)
+UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialOpaqueInst)
 UNARY_OP_MATCH_WITH_ARG_MATCHER(ProjectBlockStorageInst)
 UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongRetainInst)
 UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongReleaseInst)
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index 79821fb..1088268 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -479,7 +479,8 @@
   /// non-address values.
   SILValue emitLoadValueOperation(SILLocation Loc, SILValue LV,
                                   LoadOwnershipQualifier Qualifier) {
-    assert(LV->getType().isLoadable(F.getModule()));
+    assert(!SILModuleConventions(F.getModule()).useLoweredAddresses()
+           || LV->getType().isLoadable(F.getModule()));
     const auto &lowering = getTypeLowering(LV->getType());
     return lowering.emitLoad(*this, Loc, LV, Qualifier);
   }
@@ -819,17 +820,19 @@
   }
 
   UnmanagedRetainValueInst *createUnmanagedRetainValue(SILLocation Loc,
-                                                       SILValue operand) {
+                                                       SILValue operand,
+                                                       Atomicity atomicity) {
     assert(F.hasQualifiedOwnership());
     return insert(new (F.getModule()) UnmanagedRetainValueInst(
-        getSILDebugLocation(Loc), operand));
+        getSILDebugLocation(Loc), operand, atomicity));
   }
 
   UnmanagedReleaseValueInst *createUnmanagedReleaseValue(SILLocation Loc,
-                                                         SILValue operand) {
+                                                         SILValue operand,
+                                                         Atomicity atomicity) {
     assert(F.hasQualifiedOwnership());
     return insert(new (F.getModule()) UnmanagedReleaseValueInst(
-        getSILDebugLocation(Loc), operand));
+        getSILDebugLocation(Loc), operand, atomicity));
   }
 
   CopyValueInst *createCopyValue(SILLocation Loc, SILValue operand) {
@@ -856,9 +859,10 @@
   }
 
   UnmanagedAutoreleaseValueInst *
-  createUnmanagedAutoreleaseValue(SILLocation Loc, SILValue operand) {
+  createUnmanagedAutoreleaseValue(SILLocation Loc, SILValue operand,
+                                  Atomicity atomicity) {
     return insert(new (F.getModule()) UnmanagedAutoreleaseValueInst(
-                      getSILDebugLocation(Loc), operand));
+                      getSILDebugLocation(Loc), operand, atomicity));
   }
 
   SetDeallocatingInst *createSetDeallocating(SILLocation Loc,
@@ -1175,6 +1179,12 @@
         getSILDebugLocation(Loc), Existential));
   }
 
+  DeinitExistentialOpaqueInst *
+  createDeinitExistentialOpaque(SILLocation Loc, SILValue Existential) {
+    return insert(new (F.getModule()) DeinitExistentialOpaqueInst(
+        getSILDebugLocation(Loc), Existential));
+  }
+
   ProjectBlockStorageInst *createProjectBlockStorage(SILLocation Loc,
                                                      SILValue Storage) {
     auto CaptureTy = Storage->getType()
@@ -1529,6 +1539,11 @@
   // Memory management helpers
   //===--------------------------------------------------------------------===//
 
+  /// Returns the default atomicity of the module.
+  Atomicity getDefaultAtomicity() {
+    return getModule().isDefaultAtomic() ? Atomicity::Atomic : Atomicity::NonAtomic;
+  }
+
   /// Try to fold a destroy_addr operation into the previous instructions, or
   /// generate an explicit one if that fails.  If this inserts a new
   /// instruction, it returns it, otherwise it returns null.
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 1308eba..9184783 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -143,28 +143,43 @@
   
   SILType getTypeInClonedContext(SILType Ty) {
     // Substitute opened existential types, if we have any.
-    if (!OpenedExistentialSubs.empty()) {
-      auto &F = getBuilder().getFunction();
-      Ty = Ty.subst(F.getModule(),
-                    QueryTypeSubstitutionMap{OpenedExistentialSubs},
-                    MakeAbstractConformanceForGenericType());
-    }
-
-    return Ty;
+    return SILType::getPrimitiveObjectType(
+      getASTTypeInClonedContext(Ty.getSwiftRValueType()))
+      .copyCategory(Ty);
   }
   SILType getOpType(SILType Ty) {
     Ty = getTypeInClonedContext(Ty);
     return asImpl().remapType(Ty);
   }
-  
+
   CanType getASTTypeInClonedContext(CanType ty) {
-    // Substitute opened existential types, if we have any.
-    if (!OpenedExistentialSubs.empty()) {
-      ty = ty.subst(QueryTypeSubstitutionMap{OpenedExistentialSubs},
-                    MakeAbstractConformanceForGenericType())
-          ->getCanonicalType();
-    }
-    return ty;
+    // Do not substitute opened existential types, if we do not have any.
+    if (!ty->hasOpenedExistential())
+      return ty;
+    // Do not substitute opened existential types, if it is not required.
+    // This is often the case when cloning basic blocks inside the same
+    // function.
+    if (OpenedExistentialSubs.empty())
+      return ty;
+
+    return ty.transform(
+      [&](Type t) -> Type {
+        if (t->isOpenedExistential()) {
+          auto found = OpenedExistentialSubs.find(
+            t->castTo<ArchetypeType>());
+          // If an opened existential is supposed to be
+          // remapped, it is guaranteed by construction
+          // to be in the OpenedExistentialSubs, because
+          // a cloner always processes definitions of
+          // opened existentials before their uses and
+          // adds found opened existentials definitions
+          // to the map.
+          if (found != OpenedExistentialSubs.end())
+            return found->second;
+          return t;
+        }
+        return t;
+      })->getCanonicalType();
   }
   CanType getOpASTType(CanType ty) {
     ty = getASTTypeInClonedContext(ty);
@@ -1176,7 +1191,8 @@
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   doPostProcess(
       Inst, getBuilder().createUnmanagedRetainValue(
-                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
+                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()),
+                  Inst->getAtomicity()));
 }
 
 template <typename ImplClass>
@@ -1211,7 +1227,8 @@
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   doPostProcess(
       Inst, getBuilder().createUnmanagedReleaseValue(
-                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
+                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()),
+                  Inst->getAtomicity()));
 }
 
 template <typename ImplClass>
@@ -1238,7 +1255,8 @@
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   doPostProcess(
       Inst, getBuilder().createUnmanagedAutoreleaseValue(
-                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
+                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()),
+                  Inst->getAtomicity()));
 }
 
 template<typename ImplClass>
@@ -1645,6 +1663,15 @@
                                          getOpValue(Inst->getOperand())));
 }
 
+template <typename ImplClass>
+void SILCloner<ImplClass>::visitDeinitExistentialOpaqueInst(
+    DeinitExistentialOpaqueInst *Inst) {
+  getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+  doPostProcess(
+      Inst, getBuilder().createDeinitExistentialOpaque(
+                getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
+}
+
 template<typename ImplClass>
 void
 SILCloner<ImplClass>::visitCopyBlockInst(CopyBlockInst *Inst) {
diff --git a/include/swift/SIL/SILFunctionConventions.h b/include/swift/SIL/SILFunctionConventions.h
index 182db02..615fc12 100644
--- a/include/swift/SIL/SILFunctionConventions.h
+++ b/include/swift/SIL/SILFunctionConventions.h
@@ -148,6 +148,12 @@
   /// Get the error result type.
   SILType getSILErrorType() { return getSILType(funcTy->getErrorResult()); }
 
+  /// Returns an array of result info.
+  /// Provides convenient access to the underlying SILFunctionType.
+  ArrayRef<SILResultInfo> getResults() const {
+    return funcTy->getResults();
+  }
+
   /// Get the number of SIL results passed as address-typed arguments.
   unsigned getNumIndirectSILResults() const {
     return silConv.loweredAddresses ? funcTy->getNumIndirectFormalResults() : 0;
@@ -243,7 +249,7 @@
   /// SILFunctionType.
   unsigned getNumParameters() const { return funcTy->getNumParameters(); }
 
-  /// Returns an array if parameter info, not including indirect
+  /// Returns an array of parameter info, not including indirect
   /// results. Provides convenient access to the underlying SILFunctionType.
   ArrayRef<SILParameterInfo> getParameters() const {
     return funcTy->getParameters();
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index d8c47ec..77766a7 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -3021,8 +3021,11 @@
                                   /*HasValue*/ false> {
   friend SILBuilder;
 
-  UnmanagedRetainValueInst(SILDebugLocation DebugLoc, SILValue operand)
-      : UnaryInstructionBase(DebugLoc, operand) {}
+  UnmanagedRetainValueInst(SILDebugLocation DebugLoc, SILValue operand,
+                           Atomicity atomicity)
+      : UnaryInstructionBase(DebugLoc, operand) {
+    setAtomicity(atomicity);
+  }
 };
 
 /// Destroys a loadable value in an unmanaged, unbalanced way. Only meant for
@@ -3034,8 +3037,11 @@
                                   /*HasValue*/ false> {
   friend SILBuilder;
 
-  UnmanagedReleaseValueInst(SILDebugLocation DebugLoc, SILValue operand)
-      : UnaryInstructionBase(DebugLoc, operand) {}
+  UnmanagedReleaseValueInst(SILDebugLocation DebugLoc, SILValue operand,
+                            Atomicity atomicity)
+      : UnaryInstructionBase(DebugLoc, operand) {
+    setAtomicity(atomicity);
+  }
 };
 
 /// Transfers ownership of a loadable value to the current autorelease
@@ -3046,8 +3052,11 @@
                                                 /*HasValue*/ false> {
   friend SILBuilder;
 
-  UnmanagedAutoreleaseValueInst(SILDebugLocation DebugLoc, SILValue operand)
-      : UnaryInstructionBase(DebugLoc, operand) {}
+  UnmanagedAutoreleaseValueInst(SILDebugLocation DebugLoc, SILValue operand,
+                                Atomicity atomicity)
+      : UnaryInstructionBase(DebugLoc, operand) {
+    setAtomicity(atomicity);
+  }
 };
 
 /// Transfers ownership of a loadable value to the current autorelease pool.
@@ -4167,6 +4176,15 @@
       : UnaryInstructionBase(DebugLoc, Existential) {}
 };
 
+class DeinitExistentialOpaqueInst
+    : public UnaryInstructionBase<ValueKind::DeinitExistentialOpaqueInst,
+                                  SILInstruction, /*HAS_RESULT*/ false> {
+  friend SILBuilder;
+
+  DeinitExistentialOpaqueInst(SILDebugLocation DebugLoc, SILValue Existential)
+      : UnaryInstructionBase(DebugLoc, Existential) {}
+};
+
 /// Projects the capture storage address from a @block_storage address.
 class ProjectBlockStorageInst
   : public UnaryInstructionBase<ValueKind::ProjectBlockStorageInst,
diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h
index f4ed80f..f184c9b 100644
--- a/include/swift/SIL/SILModule.h
+++ b/include/swift/SIL/SILModule.h
@@ -642,6 +642,11 @@
 
   /// Returns true if the builtin or intrinsic is no-return.
   bool isNoReturnBuiltinOrIntrinsic(Identifier Name);
+
+  /// Returns true if the default atomicity of the module is Atomic.
+  bool isDefaultAtomic() const {
+    return ! getOptions().AssumeSingleThreaded;
+  }
 };
 
 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILModule &M){
diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def
index 63e796d..770fec1 100644
--- a/include/swift/SIL/SILNodes.def
+++ b/include/swift/SIL/SILNodes.def
@@ -227,6 +227,8 @@
   INST(InitExistentialOpaqueInst, SILInstruction, init_existential_opaque, MayWrite, DoesNotRelease)
   INST(DeinitExistentialAddrInst, SILInstruction, deinit_existential_addr, MayHaveSideEffects,
        DoesNotRelease)
+  INST(DeinitExistentialOpaqueInst, SILInstruction, deinit_existential_opaque, MayHaveSideEffects,
+       DoesNotRelease)
   INST(OpenExistentialAddrInst, SILInstruction, open_existential_addr, MayRead, DoesNotRelease)
   INST(InitExistentialRefInst, SILInstruction, init_existential_ref, None, DoesNotRelease)
   INST(OpenExistentialRefInst, SILInstruction, open_existential_ref, None, DoesNotRelease)
diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h
index 1bdd049..cb46848 100644
--- a/include/swift/SIL/SILType.h
+++ b/include/swift/SIL/SILType.h
@@ -127,12 +127,6 @@
     return SILType(T, SILValueCategory::Address);
   }
 
-  ///  Apply a substitution to the function type.
-  static CanSILFunctionType substFuncType(SILModule &silModule,
-                                          const SubstitutionMap &subs,
-                                          CanSILFunctionType SrcTy,
-                                          bool dropGenerics);
-
   bool isNull() const { return value.getPointer() == nullptr; }
   explicit operator bool() const { return bool(value.getPointer()); }
 
@@ -166,15 +160,6 @@
   CanType getSwiftRValueType() const {
     return CanType(value.getPointer());
   }
-
-  /// Returns the Swift type equivalent to this SIL type. If the SIL type is
-  /// an address type, returns an InOutType.
-  CanType getSwiftType() const {
-    CanType rvalueTy = getSwiftRValueType();
-    if (isAddress())
-      return CanInOutType::get(rvalueTy);
-    return rvalueTy;
-  }
   
   /// Returns the AbstractCC of a function type.
   /// The SILType must refer to a function type.
@@ -436,9 +421,14 @@
   SILType substGenericArgs(SILModule &M,
                            SubstitutionList Subs) const;
 
+  /// If the original type is generic, pass the signature as genericSig.
+  ///
+  /// If the replacement types are generic, you must push a generic context
+  /// first.
   SILType subst(SILModule &silModule,
                 TypeSubstitutionFn subs,
-                LookupConformanceFn conformances) const;
+                LookupConformanceFn conformances,
+                CanGenericSignature genericSig=CanGenericSignature()) const;
 
   SILType subst(SILModule &silModule, const SubstitutionMap &subs) const;
 
diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h
index 6c2f784..dd42035 100644
--- a/include/swift/SIL/TypeLowering.h
+++ b/include/swift/SIL/TypeLowering.h
@@ -622,7 +622,8 @@
   CanSILFunctionType
   getMaterializeForSetCallbackType(AbstractStorageDecl *storage,
                                    CanGenericSignature genericSig,
-                                   Type selfType);
+                                   Type selfType,
+                                   SILFunctionTypeRepresentation rep);
 
   /// Return the SILFunctionType for a native function value of the
   /// given type.
@@ -675,13 +676,6 @@
   SILConstantInfo getConstantOverrideInfo(SILDeclRef constant,
                                           SILDeclRef base);
 
-  /// Substitute the given function type so that it implements the
-  /// given substituted type.
-  CanSILFunctionType substFunctionType(CanSILFunctionType origFnType,
-                                 CanAnyFunctionType origLoweredType,
-                                 CanAnyFunctionType substLoweredInterfaceType,
-                         const Optional<ForeignErrorConvention> &foreignError);
-  
   /// Get the empty tuple type as a SILType.
   SILType getEmptyTupleType() {
     return getLoweredType(TupleType::getEmpty(Context));
diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h
index e8ff184..234016d 100644
--- a/include/swift/SIL/TypeSubstCloner.h
+++ b/include/swift/SIL/TypeSubstCloner.h
@@ -97,12 +97,12 @@
   }
 
   Substitution remapSubstitution(Substitution sub) {
-    sub = sub.subst(SwiftMod, SubsMap);
-
     // Remap opened archetypes into the cloned context.
-    return Substitution(getASTTypeInClonedContext(sub.getReplacement()
-                                                    ->getCanonicalType()),
-                        sub.getConformances());
+    sub = Substitution(
+        getASTTypeInClonedContext(sub.getReplacement()->getCanonicalType()),
+        sub.getConformances());
+    // Now remap the substitution. 
+    return sub.subst(SwiftMod, SubsMap);
   }
 
   ProtocolConformanceRef remapConformance(CanType type,
diff --git a/include/swift/SILOptimizer/Utils/Devirtualize.h b/include/swift/SILOptimizer/Utils/Devirtualize.h
index dfcfe5e..44bede7 100644
--- a/include/swift/SILOptimizer/Utils/Devirtualize.h
+++ b/include/swift/SILOptimizer/Utils/Devirtualize.h
@@ -54,9 +54,7 @@
                                                SILValue ClassInstance);
 DevirtualizationResult tryDevirtualizeClassMethod(FullApplySite AI,
                                                   SILValue ClassInstance);
-DevirtualizationResult tryDevirtualizeWitnessMethod(ApplySite AI); 
-/// Check if an upcast is legal.
-bool isLegalUpcast(SILType FromTy, SILType ToTy);
+DevirtualizationResult tryDevirtualizeWitnessMethod(ApplySite AI);
 }
 
 #endif
diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h
index caf0480..6ca651c 100644
--- a/include/swift/SILOptimizer/Utils/Local.h
+++ b/include/swift/SILOptimizer/Utils/Local.h
@@ -110,22 +110,10 @@
 /// - a type of the return value is a subclass of the expected return type.
 /// - actual return type and expected return type differ in optionality.
 /// - both types are tuple-types and some of the elements need to be casted.
-///
-/// If CheckOnly flag is set, then this function only checks if the
-/// required casting is possible. If it is not possible, then None
-/// is returned.
-/// If CheckOnly is not set, then a casting code is generated and the final
-/// casted value is returned.
-Optional<SILValue> castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
-                                                SILValue Value,
-                                                SILType SrcTy,
-                                                SILType DestTy,
-                                                bool CheckOnly = false);
-
-/// Check if the optimizer can cast a value into the expected,
-/// ABI compatible type if necessary.
-bool canCastValueToABICompatibleType(SILModule &M,
-                                     SILType SrcTy, SILType DestTy);
+SILValue castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
+                                      SILValue Value,
+                                      SILType SrcTy,
+                                      SILType DestTy);
 
 /// Returns a project_box if it is the next instruction after \p ABI and
 /// and has \p ABI as operand. Otherwise it creates a new project_box right
diff --git a/include/swift/Sema/Semantics.h b/include/swift/Sema/Semantics.h
index c399df2..524a2b5 100644
--- a/include/swift/Sema/Semantics.h
+++ b/include/swift/Sema/Semantics.h
@@ -1,4 +1,4 @@
-//===--- Semantics.h - Swift Container for Semantic Info ----*- C++ -*-===//
+//===--- Semantics.h - Swift Container for Semantic Info --------*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index fd084f9..e790e71 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
 /// in source control, you should also update the comment to briefly
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 320; // Last change: inherited protocols
+const uint16_t VERSION_MINOR = 321; // Last change: restrict to extension
 
 using DeclID = PointerEmbeddedInt<unsigned, 31>;
 using DeclIDField = BCFixed<31>;
@@ -1181,7 +1181,7 @@
   using XRefTypePathPieceLayout = BCRecordLayout<
     XREF_TYPE_PATH_PIECE,
     IdentifierIDField, // name
-    BCFixed<1>         // only in nominal
+    BCFixed<1>         // restrict to protocol extension
   >;
 
   using XRefValuePathPieceLayout = BCRecordLayout<
diff --git a/include/swift/Syntax/DeclSyntax.h b/include/swift/Syntax/DeclSyntax.h
index f826ed4..eb936fa 100644
--- a/include/swift/Syntax/DeclSyntax.h
+++ b/include/swift/Syntax/DeclSyntax.h
@@ -1,4 +1,4 @@
-//===--- DeclSyntax.cpp - Declaration Syntax Interface ----------*- C++ -*-===//
+//===--- DeclSyntax.h - Declaration Syntax Interface ------------*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -25,6 +25,7 @@
 #include "swift/Syntax/SyntaxData.h"
 #include "swift/Syntax/TokenSyntax.h"
 #include "swift/Syntax/TypeSyntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 #include "llvm/ADT/BitVector.h"
 
@@ -56,7 +57,7 @@
 
 #pragma mark - unknown-declaration Data
 
-class UnknownDeclSyntaxData : public DeclSyntaxData {
+class UnknownDeclSyntaxData : public UnknownSyntaxData {
   UnknownDeclSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
                         CursorIndex IndexInParent = 0);
 public:
@@ -71,7 +72,7 @@
 
 #pragma mark - unknown-declaration API
 
-class UnknownDeclSyntax : public DeclSyntax {
+class UnknownDeclSyntax : public UnknownSyntax {
   friend class SyntaxData;
   friend class UnknownStmtSyntaxData;
   friend class LegacyASTTransformer;
diff --git a/include/swift/Syntax/ExprSyntax.h b/include/swift/Syntax/ExprSyntax.h
index 2873c65..5dbebda 100644
--- a/include/swift/Syntax/ExprSyntax.h
+++ b/include/swift/Syntax/ExprSyntax.h
@@ -1,4 +1,4 @@
-//===--- ExprSyntax.h - Swift Expression Syntax Interface --------*- C++ -*-===//
+//===--- ExprSyntax.h - Swift Expression Syntax Interface -------*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -23,12 +23,16 @@
 #include "swift/Syntax/Syntax.h"
 #include "swift/Syntax/SyntaxData.h"
 #include "swift/Syntax/TokenSyntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 using llvm::Optional;
 
 namespace swift {
 namespace syntax {
 
+class GenericArgumentClauseSyntax;
+class GenericArgumentClauseSyntaxData;
+
 class ExprSyntaxData : public SyntaxData {
 protected:
   ExprSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
@@ -58,7 +62,7 @@
 
 #pragma mark - unknown-expression Data
 
-class UnknownExprSyntaxData : public ExprSyntaxData {
+class UnknownExprSyntaxData : public UnknownSyntaxData {
   UnknownExprSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
                         CursorIndex IndexInParent = 0);
 public:
@@ -73,17 +77,17 @@
 
 #pragma mark - unknown-expression API
 
-class UnknownExprSyntax : public ExprSyntax {
+class UnknownExprSyntax : public UnknownSyntax {
   friend class SyntaxData;
   friend class UnknownExprSyntaxData;
   friend class LegacyASTTransformer;
 
   using DataType = UnknownExprSyntaxData;
 
+public:
   UnknownExprSyntax(const RC<SyntaxData> Root,
                     const UnknownExprSyntaxData *Data);
 
-public:
   static bool classof(const Syntax *S) {
     return S->getKind() == SyntaxKind::UnknownExpr;
   }
@@ -144,6 +148,329 @@
   }
 };
 
+#pragma mark - symbolic-reference Data
+
+class SymbolicReferenceExprSyntaxData : public ExprSyntaxData {
+  friend class SymbolicReferenceExprSyntax;
+  friend class SyntaxData;
+  friend struct SyntaxFactory;
+
+  RC<GenericArgumentClauseSyntaxData> CachedGenericArgClause;
+
+  SymbolicReferenceExprSyntaxData(RC<RawSyntax> Raw,
+                                  const SyntaxData *Parent = nullptr,
+                                  CursorIndex IndexInParent = 0);
+
+  static RC<SymbolicReferenceExprSyntaxData>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0);
+
+  static RC<SymbolicReferenceExprSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *S) {
+    return S->getKind() == SyntaxKind::SymbolicReferenceExpr;
+  }
+};
+
+#pragma mark - symbolic-reference API
+
+/// symbolic-reference-expression -> identifier generic-argument-clause?
+///
+/// This is shown as primary-expression -> identifier generic-argument-clause?
+/// in the grammar. It can be just an identifier referring to some
+/// declaration, or it could perhaps be a constructor call to `Array<Int>`.
+class SymbolicReferenceExprSyntax : public ExprSyntax {
+
+  using DataType = SymbolicReferenceExprSyntaxData;
+
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class Syntax;
+  friend class SymbolicReferenceExprSyntaxData;
+
+  enum class Cursor : CursorIndex {
+    Identifier,
+    GenericArgumentClause
+  };
+
+  SymbolicReferenceExprSyntax(const RC<SyntaxData> Root,
+                              const DataType *Data);
+
+public:
+
+  /// Get the identifier for the symbol to which this expression refers.
+  RC<TokenSyntax> getIdentifier() const;
+
+  /// Return a new `SymbolicReferenceExprSyntax` with the given identifier.
+  SymbolicReferenceExprSyntax
+  withIdentifier(RC<TokenSyntax> NewIdentifier) const;
+
+  /// Return the generic arguments this symbolic reference has, if it has one.
+  llvm::Optional<GenericArgumentClauseSyntax> getGenericArgumentClause() const;
+
+  /// Return a new `SymbolicReferenceExprSyntax` with the given generic
+  /// arguments.
+  SymbolicReferenceExprSyntax
+  withGenericArgumentClause(GenericArgumentClauseSyntax NewGenericArgs) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::SymbolicReferenceExpr;
+  }
+};
+
+#pragma mark - function-call-argument Data
+
+class FunctionCallArgumentSyntaxData : public SyntaxData {
+  friend struct SyntaxFactory;
+  friend class FunctionCallArgumentSyntax;
+  friend class SyntaxData;
+
+  RC<ExprSyntaxData> CachedExpression;
+
+  FunctionCallArgumentSyntaxData(RC<RawSyntax> Raw,
+                           const SyntaxData *Parent = nullptr,
+                           CursorIndex IndexInParent = 0);
+
+  static RC<FunctionCallArgumentSyntaxData>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0);
+
+  static RC<FunctionCallArgumentSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *S) {
+    return S->getKind() == SyntaxKind::FunctionCallArgument;
+  }
+};
+
+#pragma mark - function-call-argument API
+
+/// function-call-argument -> label? ':'? (expression | operator) ','?
+class FunctionCallArgumentSyntax : public Syntax {
+
+  using DataType = FunctionCallArgumentSyntaxData;
+
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class Syntax;
+  friend class FunctionCallArgumentSyntaxData;
+  friend class FunctionCallArgumentListSyntax;
+
+  enum class Cursor {
+    Label,
+    Colon,
+    Expression,
+    Comma,
+  };
+
+  FunctionCallArgumentSyntax(const RC<SyntaxData> Root,
+                             const DataType *Data);
+
+public:
+
+  /// Return the label identifier for this argument, if it has one.
+  RC<TokenSyntax> getLabel() const;
+
+  /// Return a new `FunctionCallArgumentSyntax` with the given label.
+  FunctionCallArgumentSyntax withLabel(RC<TokenSyntax> NewLabel) const;
+
+  /// Get the colon ':' token in between the label and argument,
+  /// if there is one.
+  RC<TokenSyntax> getColonToken() const;
+
+  /// Return a new `FunctionCallArgumentSyntax` with the given colon ':' token.
+  FunctionCallArgumentSyntax withColonToken(RC<TokenSyntax> NewColon) const;
+
+  /// Returns the expression of the argument.
+  llvm::Optional<ExprSyntax> getExpression() const;
+
+  /// Return a new `FunctionCallArgumentSyntax` with the given expression
+  /// argument.
+  FunctionCallArgumentSyntax withExpression(ExprSyntax NewExpression) const;
+
+  /// Get the comma ',' token immediately following this argument, if there
+  /// is one.
+  RC<TokenSyntax> getTrailingComma() const;
+
+  /// Return a new `FunctionCallArgumentSyntax` with the given comma attached
+  /// to the end of the argument.
+  FunctionCallArgumentSyntax
+  withTrailingComma(RC<TokenSyntax> NewTrailingComma) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionCallArgument;
+  }
+};
+
+#pragma mark - function-call-argument-list Data
+
+class FunctionCallArgumentListSyntaxData : public SyntaxData {
+  friend struct SyntaxFactory;
+  friend class FunctionCallArgumentListSyntax;
+  friend class FunctionCallExprSyntaxBuilder;
+  friend class SyntaxData;
+
+  std::vector<RC<FunctionCallArgumentSyntaxData>> CachedArguments;
+
+  FunctionCallArgumentListSyntaxData(const RC<RawSyntax> Raw,
+                                     const SyntaxData *Parent = nullptr,
+                                     CursorIndex IndexInParent = 0);
+
+  static RC<FunctionCallArgumentListSyntaxData>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0);
+
+  static RC<FunctionCallArgumentListSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *S) {
+    return S->getKind() == SyntaxKind::FunctionCallArgumentList;
+  }
+};
+
+#pragma mark - function-call-argument-list API
+
+/// function-call-argument-list -> function-call-argument
+///                                function-call-argument-list?
+class FunctionCallArgumentListSyntax : public Syntax {
+  friend struct SyntaxFactory;
+  friend class FunctionCallArgumentListSyntaxData;
+  friend class FunctionCallExprSyntax;
+  friend class Syntax;
+  friend class SyntaxData;
+
+  using DataType = FunctionCallArgumentListSyntaxData;
+
+  FunctionCallArgumentListSyntax(const RC<SyntaxData> Root,
+                                 const DataType *Data);
+
+public:
+  /// Return the number of arguments in this list.
+  size_t getNumArguments() const;
+
+  /// Get the argument at the given Index.
+  FunctionCallArgumentSyntax getArgument(size_t n) const;
+
+  /// Returns a new `FunctionCallArgumentListSyntax` with the given
+  /// argument added to the end.
+  FunctionCallArgumentListSyntax
+  withAdditionalArgument(FunctionCallArgumentSyntax AdditionalArgument) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionCallArgumentList;
+  }
+};
+
+#pragma mark - function-call-expression Data
+
+class FunctionCallExprSyntaxData : public ExprSyntaxData {
+  friend struct SyntaxFactory;
+  friend class FunctionCallExprSyntax;
+  friend class FunctionCallExprSyntaxBuilder;
+  friend class SyntaxData;
+
+  RC<ExprSyntaxData> CachedCalledExpression;
+  RC<FunctionCallArgumentListSyntaxData> CachedArgumentList;
+
+  FunctionCallExprSyntaxData(RC<RawSyntax> Raw,
+                                 const SyntaxData *Parent = nullptr,
+                                 CursorIndex IndexInParent = 0);
+
+  static RC<FunctionCallExprSyntaxData>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0);
+
+  static RC<FunctionCallExprSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *S) {
+    return S->getKind() == SyntaxKind::FunctionCallExpr;
+  }
+};
+
+#pragma mark - function-call-expression API
+
+class FunctionCallExprSyntax : public ExprSyntax {
+  using DataType = FunctionCallExprSyntaxData;
+  friend struct SyntaxFactory;
+  friend class FunctionCallExprSyntaxData;
+  friend class FunctionCallExprSyntaxBuilder;
+  friend class Syntax;
+  friend class SyntaxData;
+
+  enum class Cursor: CursorIndex {
+    CalledExpression,
+    LeftParen,
+    ArgumentList,
+    RightParen,
+  };
+
+  FunctionCallExprSyntax(const RC<SyntaxData> Root, const DataType *Data);
+
+public:
+
+  /// Get the base expression getting called.
+  ExprSyntax getCalledExpression() const;
+
+  /// Return a new `FunctionCallExprSyntax` with the given base expression
+  /// to be called.
+  FunctionCallExprSyntax
+  withCalledExpression(ExprSyntax NewBaseExpression) const;
+
+  /// Return the left parenthesis '(' token in this call.
+  RC<TokenSyntax> getLeftParen() const;
+
+  /// Return a new `FunctionCallExprSyntax` with the given left parenthesis '('
+  /// token.
+  FunctionCallExprSyntax withLeftParen(RC<TokenSyntax> NewLeftParen) const;
+
+  /// Get the list of arguments in this call expression.
+  FunctionCallArgumentListSyntax getArgumentList() const;
+
+  /// Return a new `FunctionCallExprSyntax` with the given argument list.
+  FunctionCallExprSyntax
+  withArgumentList(FunctionCallArgumentListSyntax NewArgumentList) const;
+
+  /// Return the right parenthesis ')' token in this call.
+  RC<TokenSyntax> getRightParen() const;
+
+  /// Return a new `FunctionCallExprSyntax` with the given right parenthesis ')'
+  /// token.
+  FunctionCallExprSyntax withRightParen(RC<TokenSyntax> NewLeftParen) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionCallExpr;
+  }
+};
+
+#pragma mark - function-call-argument-list-builder
+class FunctionCallExprSyntaxBuilder {
+  RawSyntax::LayoutList CallLayout;
+  RawSyntax::LayoutList ListLayout;
+public:
+
+  /// Start the builder with all elements marked as missing or empty.
+  FunctionCallExprSyntaxBuilder();
+
+  /// Use the given expression as the call target.
+  FunctionCallExprSyntaxBuilder &
+  useCalledExpression(ExprSyntax CalledExpression);
+
+  /// Use the given left parenthesis '(' token in the function call.
+  FunctionCallExprSyntaxBuilder &useLeftParen(RC<TokenSyntax> LeftParen);
+
+  /// Add an additional argument to the layout.
+  FunctionCallExprSyntaxBuilder &
+  appendArgument(FunctionCallArgumentSyntax AdditionalArgument);
+
+  /// Use the given right parenthesis ')' token in the function call.
+  FunctionCallExprSyntaxBuilder &useRightParen(RC<TokenSyntax> RightParen);
+
+  /// Return a `FunctionCallExprSyntax` with the arguments added so far.
+  FunctionCallExprSyntax build() const;
+};
+
 } // end namespace syntax
 } // end namespace swift
 
diff --git a/include/swift/Syntax/Format.h b/include/swift/Syntax/Format.h
index ca89034..b6cd188 100644
--- a/include/swift/Syntax/Format.h
+++ b/include/swift/Syntax/Format.h
@@ -1,4 +1,4 @@
-//===--- Format.cpp - Declaration Syntax Formatting Interface ---*- C++ -*-===//
+//===--- Format.h - Declaration Syntax Formatting Interface -----*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/include/swift/Syntax/GenericSyntax.h b/include/swift/Syntax/GenericSyntax.h
index e31eec9..753018e 100644
--- a/include/swift/Syntax/GenericSyntax.h
+++ b/include/swift/Syntax/GenericSyntax.h
@@ -1,4 +1,4 @@
-//===--- GenericSyntax.cpp - Swift Generic Syntax Interface -----*- C++ -*-===//
+//===--- GenericSyntax.h - Swift Generic Syntax Interface -------*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -433,7 +433,9 @@
 class GenericArgumentClauseSyntax : public Syntax {
   friend struct SyntaxFactory;
   friend class GenericArgumentClauseBuilder;
+  friend class SymbolicReferenceExprSyntax;
   friend class SyntaxData;
+  friend class Syntax;
 
   using DataType = GenericArgumentClauseSyntaxData;
 
diff --git a/include/swift/Syntax/RawSyntax.h b/include/swift/Syntax/RawSyntax.h
index 1b58de0..40a53c3 100644
--- a/include/swift/Syntax/RawSyntax.h
+++ b/include/swift/Syntax/RawSyntax.h
@@ -235,6 +235,18 @@
     return Kind >= SyntaxKind::First_Expr && Kind <= SyntaxKind::Last_Expr;
   }
 
+  /// Return true if this raw syntax node is a token.
+  bool isToken() const {
+    return Kind == SyntaxKind::Token;
+  }
+
+  bool isUnknown() const {
+    return Kind == SyntaxKind::Unknown ||
+           Kind == SyntaxKind::UnknownDecl ||
+           Kind == SyntaxKind::UnknownExpr ||
+           Kind == SyntaxKind::UnknownStmt;
+  }
+
   /// Get the absolute position of this raw syntax: its offset, line,
   /// and column.
   AbsolutePosition getAbsolutePosition(RC<RawSyntax> Root) const;
diff --git a/include/swift/Syntax/Rewriter.h b/include/swift/Syntax/Rewriter.h
index bdebab2..224373d 100644
--- a/include/swift/Syntax/Rewriter.h
+++ b/include/swift/Syntax/Rewriter.h
@@ -27,6 +27,7 @@
 #include "swift/Syntax/ExprSyntax.h"
 #include "swift/Syntax/StmtSyntax.h"
 #include "swift/Syntax/Syntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 namespace swift {
 namespace syntax {
diff --git a/include/swift/Syntax/StmtSyntax.h b/include/swift/Syntax/StmtSyntax.h
index 523133f..d4c93a5 100644
--- a/include/swift/Syntax/StmtSyntax.h
+++ b/include/swift/Syntax/StmtSyntax.h
@@ -22,6 +22,7 @@
 #include "swift/Syntax/References.h"
 #include "swift/Syntax/Syntax.h"
 #include "swift/Syntax/SyntaxData.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 using llvm::Optional;
 
@@ -66,7 +67,7 @@
 
 #pragma mark - unknown-statement Data
 
-class UnknownStmtSyntaxData : public StmtSyntaxData {
+class UnknownStmtSyntaxData : public UnknownSyntaxData {
   UnknownStmtSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
                         CursorIndex IndexInParent = 0);
 public:
@@ -81,12 +82,12 @@
 
 #pragma mark - unknown-statement API
 
-class UnknownStmtSyntax : public StmtSyntax {
+class UnknownStmtSyntax : public UnknownSyntax {
   friend class SyntaxData;
   friend class UnknownStmtSyntaxData;
   friend class LegacyASTTransformer;
 
-  using DataType = UnknownExprSyntaxData;
+  using DataType = UnknownStmtSyntaxData;
 
   UnknownStmtSyntax(const RC<SyntaxData> Root,
                     const UnknownStmtSyntaxData *Data);
diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h
index 3528fb2..7be6fd9 100644
--- a/include/swift/Syntax/Syntax.h
+++ b/include/swift/Syntax/Syntax.h
@@ -39,7 +39,6 @@
 const auto NoParent = llvm::None;
 
 class SyntaxData;
-class UnknownSyntaxData;
 
 /// The main handle for syntax nodes - subclasses contain all public
 /// structured editing APIs.
@@ -138,6 +137,9 @@
   /// Returns true if this syntax node represents a type.
   bool isType() const;
 
+  /// Returns true if this syntax is of some "unknown" kind.
+  bool isUnknown() const;
+
   /// Print the syntax node with full fidelity to the given output stream.
   void print(llvm::raw_ostream &OS) const;
 
@@ -155,19 +157,6 @@
   // TODO: hasSameStructureAs ?
 };
 
-/// A chunk of "unknown" syntax - effectively a sequence of tokens.
-class UnknownSyntax final : public Syntax {
-  friend struct SyntaxFactory;
-
-  UnknownSyntax(const RC<SyntaxData> Root, UnknownSyntaxData *Data);
-  static UnknownSyntax make(RC<RawSyntax> Raw);
-
-public:
-  static bool classof(const Syntax *S) {
-    return S->getKind() == SyntaxKind::Unknown;
-  }
-};
-
 } // end namespace syntax
 } // end namespace swift
 
diff --git a/include/swift/Syntax/SyntaxData.h b/include/swift/Syntax/SyntaxData.h
index c048dcc..f27e59e 100644
--- a/include/swift/Syntax/SyntaxData.h
+++ b/include/swift/Syntax/SyntaxData.h
@@ -242,28 +242,14 @@
   /// Returns true if the data node represents expression syntax.
   bool isExpr() const;
 
+  /// Returns true if this syntax is of some "unknown" kind.
+  bool isUnknown() const;
+
   /// Dump a debug description of the syntax data for debugging to
   /// standard error.
   void dump(llvm::raw_ostream &OS) const;
 };
 
-class UnknownSyntaxData final : public SyntaxData {
-  friend class SyntaxData;
-  friend class UnknownSyntax;
-  friend struct SyntaxFactory;
-  friend class LegacyASTTransformer;
-
-  UnknownSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
-                    CursorIndex IndexInParent = 0)
-    : SyntaxData(Raw, Parent, IndexInParent) {}
-
-  static RC<UnknownSyntaxData> make(RC<RawSyntax> Raw,
-                                    const SyntaxData *Parent = nullptr,
-                                    CursorIndex IndexInParent = 0);
-public:
-  static bool classof(const SyntaxData *SD);
-};
-
 } // end namespace syntax
 } // end namespace swift
 
diff --git a/include/swift/Syntax/SyntaxFactory.h b/include/swift/Syntax/SyntaxFactory.h
index 4f09467..d1d74c8 100644
--- a/include/swift/Syntax/SyntaxFactory.h
+++ b/include/swift/Syntax/SyntaxFactory.h
@@ -129,6 +129,43 @@
   /// as missing.
   static IntegerLiteralExprSyntax makeBlankIntegerLiteralExpr();
 
+  /// Make a symbolic reference with the given identifier and optionally a
+  /// generic argument clause.
+  static SymbolicReferenceExprSyntax
+  makeSymbolicReferenceExpr(RC<TokenSyntax> Identifier,
+    llvm::Optional<GenericArgumentClauseSyntax> GenericArgs);
+
+  /// Make a symbolic reference expression with the identifier and
+  /// generic argument clause marked as missing.
+  static SymbolicReferenceExprSyntax makeBlankSymbolicReferenceExpr();
+
+  /// Make a function call argument with all elements marked as missing.
+  static FunctionCallArgumentSyntax makeBlankFunctionCallArgument();
+
+  /// Make a function call argument based on an expression with the
+  /// given elements.
+  static FunctionCallArgumentSyntax
+  makeFunctionCallArgument(RC<TokenSyntax> Label, RC<TokenSyntax> Colon,
+                           ExprSyntax ExpressionArgument,
+                           RC<TokenSyntax> TrailingComma);
+
+  /// Make a function call argument list with the given arguments.
+  static FunctionCallArgumentListSyntax
+  makeFunctionCallArgumentList(
+    std::vector<FunctionCallArgumentSyntax> Arguments);
+
+  /// Make a function call argument list with no arguments.
+  static FunctionCallArgumentListSyntax makeBlankFunctionCallArgumentList();
+
+  /// Make a function call expression with the given elements.
+  static FunctionCallExprSyntax
+  makeFunctionCallExpr(ExprSyntax CalledExpr, RC<TokenSyntax> LeftParen,
+                       FunctionCallArgumentListSyntax Arguments,
+                       RC<TokenSyntax> RightParen);
+
+  /// Make a function call expression with all elements marked as missing.
+  static FunctionCallExprSyntax makeBlankFunctionCallExpr();
+
 #pragma mark - Tokens
 
   /// Make a 'fallthrough' keyword with the specified leading and
@@ -353,7 +390,7 @@
   /// Make a metatype type with all elements marked as missing.
   static MetatypeTypeSyntax makeBlankMetatypeType();
 
-  /// Make an sugared Array type, as in `[MyType]`.
+  /// Make a sugared Array type, as in `[MyType]`.
   static ArrayTypeSyntax makeArrayType(RC<TokenSyntax> LeftSquareBracket,
                                        TypeSyntax ElementType,
                                        RC<TokenSyntax> RightSquareBracket);
diff --git a/include/swift/Syntax/SyntaxKinds.def b/include/swift/Syntax/SyntaxKinds.def
index e5b0c70..941d50d 100644
--- a/include/swift/Syntax/SyntaxKinds.def
+++ b/include/swift/Syntax/SyntaxKinds.def
@@ -1,4 +1,4 @@
-//===--- SyntaxKinds.def - Swift Syntax Node Metaprogramming -------------===//
+//===--- SyntaxKinds.def - Swift Syntax Node Metaprogramming --------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -86,13 +86,18 @@
   MISSING_SYNTAX(MissingExpr, ExprSyntax)
   SYNTAX(UnknownExpr, ExprSyntax)
   SYNTAX(IntegerLiteralExpr, ExprSyntax)
-SYNTAX_RANGE(Expr, MissingExpr, IntegerLiteralExpr)
+  SYNTAX(FunctionCallExpr, ExprSyntax)
+  SYNTAX(SymbolicReferenceExpr, ExprSyntax)
+SYNTAX_RANGE(Expr, MissingExpr, SymbolicReferenceExpr)
 
+// Other stuff
 SYNTAX(BalancedTokens, Syntax)
 SYNTAX(TypeAttribute, Syntax)
 SYNTAX(TypeAttributes, Syntax)
 SYNTAX(TupleTypeElement, Syntax)
 SYNTAX(FunctionTypeArgument, Syntax)
+SYNTAX(FunctionCallArgumentList, Syntax)
+SYNTAX(FunctionCallArgument, Syntax)
 
 #undef ABSTRACT_SYNTAX
 #undef DECL
diff --git a/include/swift/Syntax/TypeSyntax.h b/include/swift/Syntax/TypeSyntax.h
index 5afb0ed..07bf362 100644
--- a/include/swift/Syntax/TypeSyntax.h
+++ b/include/swift/Syntax/TypeSyntax.h
@@ -32,8 +32,7 @@
 class GenericParameterClauseSyntax;
 class GenericParameterClauseSyntaxData;
 
-#pragma mark -
-#pragma mark balanced-tokens Data
+#pragma mark - balanced-tokens Data
 
 class BalancedTokensSyntaxData final : public SyntaxData {
   friend class SyntaxData;
@@ -52,8 +51,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark balanced-tokens API
+#pragma mark - balanced-tokens API
 
 /// balanced-tokens -> Any identifier, keyword, literal, or operator
 ///                  | Any punctuation except (, ), [, ], {, or }
@@ -77,8 +75,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-attribute Data
+#pragma mark - type-attribute Data
 
 class TypeAttributeSyntaxData final : public SyntaxData {
   friend class SyntaxData;
@@ -99,8 +96,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-attribute API
+#pragma mark - type-attribute API
 
 /// type-attribute -> '@' identifier attribute-argument-clause?
 /// attribute-argument-clause -> '(' balanced-tokens ')'
@@ -162,8 +158,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-attributes Data
+#pragma mark - type-attributes Data
 
 class TypeAttributesSyntaxData final : public SyntaxData {
   friend class SyntaxData;
@@ -183,8 +178,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-attributes API
+#pragma mark - type-attributes API
 
 /// type-attributes -> type-attribute
 ///                  | type-attribute type-attributes
@@ -208,8 +202,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-syntax Data
+#pragma mark - type-syntax Data
 
 class TypeSyntaxData : public SyntaxData {
   friend class SyntaxData;
@@ -226,8 +219,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-syntax API
+#pragma mark - type-syntax API
 
 /// type -> array-type
 ///       | dictionary-type
@@ -251,8 +243,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-identifier Data
+#pragma mark - type-identifier Data
 
 class TypeIdentifierSyntaxData final : public TypeSyntaxData {
   friend struct SyntaxFactory;
@@ -276,8 +267,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-identifier API
+#pragma mark - type-identifier API
 
 /// type-identifier -> type-name generic-argument-clause?
 ///                  | type-name generic-argument-clause '.' type-identifier
@@ -320,8 +310,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark type-argument-list Data
+#pragma mark - type-argument-list Data
 
 class TypeArgumentListSyntaxData final : public SyntaxData {
   friend class SyntaxData;
@@ -342,8 +331,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark tuple-type-element Data
+#pragma mark - tuple-type-element Data
 
 class TupleTypeElementSyntaxData final : public SyntaxData {
   friend class SyntaxData;
@@ -362,8 +350,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark tuple-type-element API
+#pragma mark - tuple-type-element API
 
 /// tuple-type-element -> (identifier ':')? type-attributes? 'inout'? type
 ///
@@ -425,8 +412,7 @@
 };
 
 
-#pragma mark -
-#pragma mark type-argument-list API
+#pragma mark - type-argument-list API
 
 /// type-argument-list
 ///   -> function-type-argument
@@ -451,8 +437,8 @@
   }
 };
 
-#pragma mark -
-#pragma mark tuple-type Data
+#pragma mark - tuple-type Data
+
 class TupleTypeSyntaxData final : public TypeSyntaxData {
   friend class SyntaxData;
   friend struct SyntaxFactory;
@@ -472,8 +458,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark tuple-type API
+#pragma mark - tuple-type API
 
 /// tuple-type -> '(' tuple-type-element-list ')'
 class TupleTypeSyntax final : public TypeSyntax {
@@ -513,8 +498,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark tuple-type Builder
+#pragma mark - tuple-type Builder
 
 /// Incrementally builds tuple type syntax.
 class TupleTypeSyntaxBuilder final {
@@ -543,8 +527,7 @@
   TupleTypeSyntax build() const;
 };
 
-#pragma mark -
-#pragma mark metatype-type Data
+#pragma mark - metatype-type Data
 
 class MetatypeTypeSyntaxData final : public TypeSyntaxData {
   friend struct SyntaxFactory;
@@ -562,8 +545,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark metatype-type API
+#pragma mark - metatype-type API
 
 /// metatype-type -> type '.' 'Type'
 ///                | type '.' 'Protocol'
@@ -605,8 +587,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark optional-type Data
+#pragma mark - optional-type Data
 
 class OptionalTypeSyntaxData final : public TypeSyntaxData {
   friend class SyntaxData;
@@ -624,8 +605,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark optional-type API
+#pragma mark - optional-type API
 
 /// optional-type -> type '?'
 class OptionalTypeSyntax final : public TypeSyntax {
@@ -661,8 +641,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark implicitly-unwrapped-optional-type Data
+#pragma mark - implicitly-unwrapped-optional-type Data
 
 class ImplicitlyUnwrappedOptionalTypeSyntaxData final : public TypeSyntaxData {
   friend struct SyntaxFactory;
@@ -682,8 +661,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark implicitly-unwrapped-optional-type API
+#pragma mark - implicitly-unwrapped-optional-type API
 
 /// implicitly-unwrapped-optional-type -> type '!'
 class ImplicitlyUnwrappedOptionalTypeSyntax final : public TypeSyntax {
@@ -722,8 +700,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark array-type Data
+#pragma mark - array-type Data
 
 class ArrayTypeSyntaxData final : public TypeSyntaxData {
   friend class SyntaxData;
@@ -744,8 +721,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark array-type API
+#pragma mark - array-type API
 
 // array-type -> '[' type ']'
 class ArrayTypeSyntax final : public TypeSyntax {
@@ -788,8 +764,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark dictionary-type Data
+#pragma mark - dictionary-type Data
 
 class DictionaryTypeSyntaxData final : public TypeSyntaxData {
   friend class SyntaxData;
@@ -813,8 +788,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark dictionary-type API
+#pragma mark - dictionary-type API
 
 // dictionary-type -> '[' type ':' type ']'
 class DictionaryTypeSyntax final : public TypeSyntax {
@@ -875,8 +849,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark function-type-argument Data
+#pragma mark - function-type-argument Data
 
 class FunctionTypeArgumentSyntaxData final : public SyntaxData {
   friend class SyntaxData;
@@ -897,8 +870,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark function-type-argument API
+#pragma mark - function-type-argument API
 
 class FunctionTypeArgumentSyntax final : public Syntax {
   friend struct SyntaxFactory;
@@ -925,8 +897,7 @@
 };
 
 
-#pragma mark -
-#pragma mark function-type Data
+#pragma mark - function-type Data
 
 class FunctionTypeSyntaxData final : public TypeSyntaxData {
   friend class SyntaxData;
@@ -947,8 +918,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark function-type API
+#pragma mark - function-type API
 
 /// function-type ->
 ///   type-attributes? function-type-argument-clause 'throws'? '->' type
@@ -1045,8 +1015,7 @@
   }
 };
 
-#pragma mark -
-#pragma mark function-type Builder
+#pragma mark - function-type Builder
 
 /// Incrementally builds function type syntax.
 class FunctionTypeSyntaxBuilder final {
diff --git a/include/swift/Syntax/UnknownSyntax.h b/include/swift/Syntax/UnknownSyntax.h
new file mode 100644
index 0000000..7158e03
--- /dev/null
+++ b/include/swift/Syntax/UnknownSyntax.h
@@ -0,0 +1,89 @@
+//===--- UnknownSyntax.h - Swift Unknown Syntax Interface -----------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_SYNTAX_UNKNOWNSYNTAX_H
+#define SWIFT_SYNTAX_UNKNOWNSYNTAX_H
+
+#include "swift/Syntax/SyntaxData.h"
+#include "swift/Syntax/Syntax.h"
+
+#include <vector>
+
+namespace swift {
+namespace syntax {
+
+#pragma mark unknown-syntax Data
+
+class UnknownSyntaxData : public SyntaxData {
+  friend class SyntaxData;
+  friend class UnknownSyntax;
+  friend struct SyntaxFactory;
+  friend class LegacyASTTransformer;
+
+protected:
+  std::vector<RC<SyntaxData>> CachedChildren;
+
+  UnknownSyntaxData(const RC<RawSyntax> Raw,
+                    const SyntaxData *Parent = nullptr,
+                    const CursorIndex IndexInParent = 0);
+public:
+
+  static RC<UnknownSyntaxData> make(RC<RawSyntax> Raw,
+                                    const SyntaxData *Parent = nullptr,
+                                    CursorIndex IndexInParent = 0);
+
+  size_t getNumChildren() const {
+    return CachedChildren.size();
+  }
+
+  /// Get the child at the given Index.
+  ///
+  /// Precondition: Index <= getNumChildren();
+  Syntax getChild(size_t Index) const;
+
+  static bool classof(const SyntaxData *SD) {
+    return SD->isUnknown();
+  }
+};
+
+#pragma mark unknown-syntax API
+
+/// A chunk of "unknown" syntax.
+///
+/// Effectively wraps a tree of RawSyntax.
+///
+/// This should not be vended by SyntaxFactory.
+class UnknownSyntax : public Syntax {
+  friend struct SyntaxFactory;
+  friend class Syntax;
+
+  using DataType = UnknownSyntaxData;
+
+public:
+  UnknownSyntax(const RC<SyntaxData> Root, const UnknownSyntaxData *Data);
+
+  /// Get the number of child nodes in this piece of syntax, not including
+  /// tokens.
+  size_t getNumChildren() const;
+
+  /// Get the Nth child of this piece of syntax.
+  Syntax getChild(const size_t N) const;
+
+  static bool classof(const Syntax *S) {
+    return S->isUnknown();
+  }
+};
+
+} // end namespace syntax
+} // end namespace swift
+
+#endif // SWIFT_SYNTAX_UNKNOWNSYNTAX_H
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 0f7e463..7be8ea7 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -365,11 +365,11 @@
 //===----------------------------------------------------------------------===//
 
 // Print a name.
-static void printName(raw_ostream &os, Identifier name) {
-  if (name.empty())
+static void printName(raw_ostream &os, DeclName name) {
+  if (!name)
     os << "<anonymous>";
   else
-    os << name.str();
+    os << name;
 }
 
 namespace {
@@ -1004,7 +1004,7 @@
           OS << "#else:\n";
         }
 
-        for (auto D : Clause.Members) {
+        for (auto D : Clause.Elements) {
           OS << '\n';
           printRec(D);
         }
@@ -1148,7 +1148,7 @@
         break;
       }
     }
-    os << "extension";
+    os << " extension";
     break;
 
   case DeclContextKind::Initializer:
@@ -1166,18 +1166,12 @@
     os << "top-level code";
     break;
 
-  case DeclContextKind::AbstractFunctionDecl: {
-    auto *AFD = cast<AbstractFunctionDecl>(dc);
-    if (isa<FuncDecl>(AFD))
-      os << "func decl";
-    if (isa<ConstructorDecl>(AFD))
-      os << "init";
-    if (isa<DestructorDecl>(AFD))
-      os << "deinit";
+  case DeclContextKind::AbstractFunctionDecl:
+    printName(os, cast<AbstractFunctionDecl>(dc)->getFullName());
     break;
-  }
+
   case DeclContextKind::SubscriptDecl:
-    os << "subscript decl";
+    printName(os, cast<SubscriptDecl>(dc)->getFullName());
     break;
   }
 }
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b6eeb2b..c57b4cf 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -622,6 +622,20 @@
   if (auto genericSig = GenericSigOrEnv.dyn_cast<GenericSignature *>())
     return genericSig;
 
+  // The signature of a Protocol is trivial (Self: TheProtocol) so let's compute
+  // it.
+  if (auto PD = dyn_cast<ProtocolDecl>(this)) {
+    auto self = PD->getSelfInterfaceType()->castTo<GenericTypeParamType>();
+    auto req =
+        Requirement(RequirementKind::Conformance, self, PD->getDeclaredType());
+    GenericTypeParamType *params[] = {self};
+    Requirement reqs[] = {req};
+
+    auto &ctx = getASTContext();
+    return GenericSignature::get(ctx.AllocateCopy(params),
+                                 ctx.AllocateCopy(reqs));
+  }
+
   return nullptr;
 }
 
@@ -808,7 +822,6 @@
     ExtendedType(extendedType),
     Inherited(inherited)
 {
-  ExtensionDeclBits.Validated = false;
   ExtensionDeclBits.CheckedInheritanceClause = false;
   ExtensionDeclBits.DefaultAndMaxAccessLevel = 0;
   ExtensionDeclBits.HasLazyConformances = false;
@@ -2006,7 +2019,7 @@
         selfTy, const_cast<AssociatedTypeDecl *>(ATD));
   }
 
-  Type interfaceType = getInterfaceType();
+  Type interfaceType = hasInterfaceType() ? getInterfaceType() : nullptr;
   if (interfaceType.isNull() || interfaceType->is<ErrorType>())
     return interfaceType;
 
@@ -2261,10 +2274,7 @@
                              Identifier Name, SourceLoc NameLoc,
                              GenericParamList *GenericParams, DeclContext *DC)
   : GenericTypeDecl(DeclKind::TypeAlias, DC, Name, NameLoc, {}, GenericParams),
-    TypeAliasLoc(TypeAliasLoc),
-    EqualLoc(EqualLoc) {
-  TypeAliasDeclBits.HasCompletedValidation = false;
-}
+    TypeAliasLoc(TypeAliasLoc), EqualLoc(EqualLoc) {}
 
 SourceRange TypeAliasDecl::getSourceRange() const {
   if (UnderlyingTy.hasLocation())
@@ -2273,7 +2283,7 @@
 }
 
 void TypeAliasDecl::setUnderlyingType(Type underlying) {
-  setHasCompletedValidation();
+  setValidationStarted();
 
   // lldb creates global typealiases containing archetypes
   // sometimes...
@@ -2342,19 +2352,20 @@
 
 AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
                                        Identifier name, SourceLoc nameLoc,
-                                       TypeLoc defaultDefinition)
-  : AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
-    KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition)
-{ }
+                                       TypeLoc defaultDefinition,
+                                       TrailingWhereClause *trailingWhere)
+    : AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
+      KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition),
+      TrailingWhere(trailingWhere) {}
 
 AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
                                        Identifier name, SourceLoc nameLoc,
+                                       TrailingWhereClause *trailingWhere,
                                        LazyMemberLoader *definitionResolver,
                                        uint64_t resolverData)
-  : AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
-    KeywordLoc(keywordLoc), Resolver(definitionResolver),
-    ResolverContextData(resolverData)
-{
+    : AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
+      KeywordLoc(keywordLoc), TrailingWhere(trailingWhere),
+      Resolver(definitionResolver), ResolverContextData(resolverData) {
   assert(Resolver && "missing resolver");
 }
 
@@ -2725,6 +2736,41 @@
   return result;
 }
 
+bool ProtocolDecl::walkInheritedProtocols(
+              llvm::function_ref<TypeWalker::Action(ProtocolDecl *)> fn) const {
+  auto self = const_cast<ProtocolDecl *>(this);
+
+  // Visit all of the inherited protocols.
+  SmallPtrSet<ProtocolDecl *, 8> visited;
+  SmallVector<ProtocolDecl *, 4> stack;
+  stack.push_back(self);
+  visited.insert(self);
+  while (!stack.empty()) {
+    // Pull the next protocol off the stack.
+    auto proto = stack.back();
+    stack.pop_back();
+
+    switch (fn(proto)) {
+    case TypeWalker::Action::Stop:
+      return true;
+
+    case TypeWalker::Action::Continue:
+      // Add inherited protocols to the stack.
+      for (auto inherited : proto->getInheritedProtocols()) {
+        if (visited.insert(inherited).second)
+          stack.push_back(inherited);
+      }
+      break;
+
+    case TypeWalker::Action::SkipChildren:
+      break;
+    }
+  }
+
+  return false;
+
+}
+
 bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
   if (this == super)
     return false;
@@ -2735,26 +2781,27 @@
 }
 
 bool ProtocolDecl::requiresClassSlow() {
-  if (!isRequirementSignatureComputed()) return false;
+  ProtocolDeclBits.RequiresClass =
+    walkInheritedProtocols([&](ProtocolDecl *proto) {
+      // If the 'requires class' bit is valid, we don't need to search any
+      // further.
+      if (proto->ProtocolDeclBits.RequiresClassValid) {
+        // If this protocol has a class requirement, we're done.
+        if (proto->ProtocolDeclBits.RequiresClass)
+          return TypeWalker::Action::Stop;
 
-  ProtocolDeclBits.RequiresClass = false;
+        return TypeWalker::Action::SkipChildren;
+      }
 
-  // Ensure that the result cannot change in future.
+      // Quick check: @objc indicates that it requires a class.
+      if (proto->getAttrs().hasAttribute<ObjCAttr>() || proto->isObjC())
+        return TypeWalker::Action::Stop;
 
-  if (getAttrs().hasAttribute<ObjCAttr>() || isObjC()) {
-    ProtocolDeclBits.RequiresClass = true;
-    return true;
-  }
+      // Keep looking.
+      return TypeWalker::Action::Continue;
+    });
 
-  // Check inherited protocols for class-ness.
-  for (auto *proto : getInheritedProtocols()) {
-    if (proto->requiresClass()) {
-      ProtocolDeclBits.RequiresClass = true;
-      return true;
-    }
-  }
-
-  return false;
+  return ProtocolDeclBits.RequiresClass;
 }
 
 bool ProtocolDecl::existentialConformsToSelfSlow() {
@@ -2787,7 +2834,6 @@
 
   // Check whether any of the inherited protocols fail to conform to
   // themselves.
-  // FIXME: does this need a resolver?
   for (auto proto : getInheritedProtocols()) {
     if (!proto->existentialConformsToSelf()) {
       ProtocolDeclBits.ExistentialConformsToSelf = false;
@@ -3058,9 +3104,10 @@
   GenericSignatureBuilder builder(getASTContext(),
                                   LookUpConformanceInModule(module));
   builder.addGenericParameter(selfType);
-  builder.addRequirement(requirement,
-                         RequirementSource::forRequirementSignature(builder,
-                                                                    this));
+  builder.addRequirement(
+         requirement,
+         GenericSignatureBuilder::RequirementSource
+          ::forRequirementSignature(builder.resolveArchetype(selfType), this));
   builder.finalize(SourceLoc(), { selfType });
   
   RequirementSignature = builder.getGenericSignature();
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 0a3bebe..56747a6 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -79,7 +79,7 @@
 }
 
 std::string GenericSignature::gatherGenericParamBindingsText(
-    ArrayRef<Type> types, const TypeSubstitutionMap &substitutions) const {
+    ArrayRef<Type> types, TypeSubstitutionFn substitutions) const {
   llvm::SmallPtrSet<GenericTypeParamType *, 2> knownGenericParams;
   for (auto type : types) {
     type.visit([&](Type type) {
@@ -106,11 +106,11 @@
     result += gp->getName().str();
     result += " = ";
 
-    auto found = substitutions.find(canonGP);
-    if (found == substitutions.end())
+    auto type = substitutions(canonGP);
+    if (!type)
       return "";
 
-    result += found->second.getString();
+    result += type.getString();
   }
 
   result += "]";
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index c039407..b3f69c4 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -39,7 +39,11 @@
 using llvm::DenseMap;
 
 namespace {
+  typedef GenericSignatureBuilder::RequirementSource RequirementSource;
+  typedef GenericSignatureBuilder::FloatingRequirementSource
+    FloatingRequirementSource;
   typedef GenericSignatureBuilder::PotentialArchetype PotentialArchetype;
+  typedef GenericSignatureBuilder::ConcreteConstraint ConcreteConstraint;
   typedef GenericSignatureBuilder::EquivalenceClass EquivalenceClass;
 
 } // end anonymous namespace
@@ -78,38 +82,53 @@
   switch (kind) {
   case Explicit:
     switch (storageKind) {
-    case StorageKind::None:
+    case StorageKind::RootArchetype:
     case StorageKind::TypeRepr:
     case StorageKind::RequirementRepr:
       return true;
 
     case StorageKind::ProtocolDecl:
     case StorageKind::ProtocolConformance:
+    case StorageKind::AssociatedTypeDecl:
       return false;
     }
 
   case Inferred:
     switch (storageKind) {
-    case StorageKind::None:
+    case StorageKind::RootArchetype:
     case StorageKind::TypeRepr:
       return true;
 
     case StorageKind::ProtocolDecl:
     case StorageKind::ProtocolConformance:
     case StorageKind::RequirementRepr:
+    case StorageKind::AssociatedTypeDecl:
       return false;
     }
 
   case NestedTypeNameMatch:
-  case Parent:
     switch (storageKind) {
-    case StorageKind::None:
+    case StorageKind::RootArchetype:
         return true;
 
     case StorageKind::TypeRepr:
     case StorageKind::ProtocolDecl:
     case StorageKind::ProtocolConformance:
     case StorageKind::RequirementRepr:
+    case StorageKind::AssociatedTypeDecl:
+      return false;
+    }
+
+  case Parent:
+    switch (storageKind) {
+    case StorageKind::AssociatedTypeDecl:
+        return true;
+
+    case StorageKind::RootArchetype:
+    case StorageKind::TypeRepr:
+    case StorageKind::ProtocolDecl:
+    case StorageKind::ProtocolConformance:
+    case StorageKind::RequirementRepr:
       return false;
     }
 
@@ -119,10 +138,11 @@
     case StorageKind::ProtocolDecl:
       return true;
 
-    case StorageKind::None:
+    case StorageKind::RootArchetype:
     case StorageKind::TypeRepr:
     case StorageKind::ProtocolConformance:
     case StorageKind::RequirementRepr:
+    case StorageKind::AssociatedTypeDecl:
       return false;
     }
 
@@ -132,10 +152,11 @@
     case StorageKind::ProtocolConformance:
       return true;
 
-    case StorageKind::None:
+    case StorageKind::RootArchetype:
     case StorageKind::ProtocolDecl:
     case StorageKind::TypeRepr:
     case StorageKind::RequirementRepr:
+    case StorageKind::AssociatedTypeDecl:
       return false;
     }
   }
@@ -143,9 +164,8 @@
 
 const void *RequirementSource::getOpaqueStorage() const {
   switch (storageKind) {
-  case StorageKind::None:
-    // Note: always null.
-    return storage.typeRepr;
+  case StorageKind::RootArchetype:
+    return storage.rootArchetype;
 
   case StorageKind::TypeRepr:
     return storage.typeRepr;
@@ -158,9 +178,19 @@
 
   case StorageKind::ProtocolDecl:
     return storage.protocol;
+
+  case StorageKind::AssociatedTypeDecl:
+    return storage.assocType;
   }
 }
 
+const void *RequirementSource::getExtraOpaqueStorage() const {
+  if (numTrailingObjects(OverloadToken<PotentialArchetype *>()) == 1)
+    return getTrailingObjects<PotentialArchetype *>()[0];
+
+  return nullptr;
+}
+
 bool RequirementSource::isDerivedRequirement() const {
   switch (kind) {
   case Explicit:
@@ -204,23 +234,60 @@
   return false;
 }
 
-#define REQUIREMENT_SOURCE_FACTORY_BODY(SourceKind, Parent, Storage)       \
-  llvm::FoldingSetNodeID nodeID;                                           \
-  Profile(nodeID, Kind::SourceKind, Parent, Storage);                      \
-                                                                           \
-  void *insertPos = nullptr;                                               \
-  if (auto known =                                                         \
-        builder.Impl->RequirementSources.FindNodeOrInsertPos(nodeID,       \
-                                                            insertPos))    \
-    return known;                                                          \
-                                                                           \
-  auto result = new RequirementSource(Kind::SourceKind, Parent, Storage);  \
-  builder.Impl->RequirementSources.InsertNode(result, insertPos);          \
-  return result
+bool RequirementSource::isSelfDerivedSource(PotentialArchetype *pa) const {
+  // If it's not a derived requirement, it's not self-derived.
+  if (!isDerivedRequirement()) return false;
 
-#define REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(SourceKind, Parent)      \
+  // Collect the path of associated types from the root pa.
+  SmallVector<AssociatedTypeDecl *, 4> assocTypes;
+  PotentialArchetype *currentPA = nullptr;
+  for (auto source = this; source; source = source->parent) {
+    switch (source->kind) {
+    case RequirementSource::Parent:
+      assocTypes.push_back(source->getAssociatedType());
+      break;
+
+    case RequirementSource::NestedTypeNameMatch:
+      return false;
+
+    case RequirementSource::Explicit:
+    case RequirementSource::Inferred:
+    case RequirementSource::RequirementSignatureSelf:
+      currentPA = source->getRootPotentialArchetype();
+      break;
+
+    case RequirementSource::Concrete:
+    case RequirementSource::ProtocolRequirement:
+    case RequirementSource::Superclass:
+      break;
+    }
+  }
+
+  assert(currentPA && "Missing root potential archetype");
+
+  // Check whether anything of the potential archetypes in the path are
+  // equivalent to the end of the path.
+  auto rep = pa->getRepresentative();
+  for (auto assocType : reversed(assocTypes)) {
+    // Check whether this potential archetype is in the same equivalence class.
+    if (currentPA->getRepresentative() == rep) return true;
+
+    // Get the next nested type, but only if we've seen it before.
+    // FIXME: Feels hacky.
+    auto knownNested = currentPA->NestedTypes.find(assocType->getName());
+    if (knownNested == currentPA->NestedTypes.end()) return false;
+    currentPA = knownNested->second.front();
+  }
+
+  // FIXME: currentPA == pa?
+  return false;
+}
+
+#define REQUIREMENT_SOURCE_FACTORY_BODY(                                   \
+          SourceKind, Parent, Storage, ExtraStorage,                       \
+          NumPotentialArchetypes)                                          \
   llvm::FoldingSetNodeID nodeID;                                           \
-  Profile(nodeID, Kind::SourceKind, Parent, nullptr);                      \
+  Profile(nodeID, Kind::SourceKind, Parent, Storage, ExtraStorage);        \
                                                                            \
   void *insertPos = nullptr;                                               \
   if (auto known =                                                         \
@@ -228,73 +295,113 @@
                                                             insertPos))    \
     return known;                                                          \
                                                                            \
-  auto result = new RequirementSource(Kind::SourceKind, Parent);           \
+  unsigned size =                                                          \
+    totalSizeToAlloc<PotentialArchetype *>(NumPotentialArchetypes);        \
+  void *mem = malloc(size);                                                \
+  auto result = new (mem) RequirementSource(Kind::SourceKind, Parent,      \
+                                            Storage);                      \
+  if (NumPotentialArchetypes > 0)                                          \
+    result->getTrailingObjects<PotentialArchetype *>()[0] = ExtraStorage;  \
   builder.Impl->RequirementSources.InsertNode(result, insertPos);          \
   return result
 
 const RequirementSource *RequirementSource::forAbstract(
-                                             GenericSignatureBuilder &builder) {
-  REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(Explicit, nullptr);
+                                                    PotentialArchetype *root) {
+  auto &builder = *root->getBuilder();
+  REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, root, nullptr, 0);
 }
 
 const RequirementSource *RequirementSource::forExplicit(
-                                             GenericSignatureBuilder &builder,
+                                             PotentialArchetype *root,
                                              const TypeRepr *typeRepr) {
-  REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, typeRepr);
+  // If the type representation is NULL, we have an abstract requirement
+  // source.
+  if (!typeRepr)
+    return forAbstract(root);
+
+  auto &builder = *root->getBuilder();
+  REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, typeRepr, root, 1);
 }
 
 const RequirementSource *RequirementSource::forExplicit(
-                                      GenericSignatureBuilder &builder,
+                                      PotentialArchetype *root,
                                       const RequirementRepr *requirementRepr) {
-  REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, requirementRepr);
+  // If the requirement representation is NULL, we have an abstract requirement
+  // source.
+  if (!requirementRepr)
+    return forAbstract(root);
+
+  auto &builder = *root->getBuilder();
+  REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, requirementRepr, root, 1);
 }
 
 const RequirementSource *RequirementSource::forInferred(
-                                              GenericSignatureBuilder &builder,
+                                              PotentialArchetype *root,
                                               const TypeRepr *typeRepr) {
-  REQUIREMENT_SOURCE_FACTORY_BODY(Inferred, nullptr, typeRepr);
+  auto &builder = *root->getBuilder();
+  REQUIREMENT_SOURCE_FACTORY_BODY(Inferred, nullptr, typeRepr, root, 1);
 }
 
 const RequirementSource *RequirementSource::forRequirementSignature(
-                                              GenericSignatureBuilder &builder,
+                                              PotentialArchetype *root,
                                               ProtocolDecl *protocol) {
-  REQUIREMENT_SOURCE_FACTORY_BODY(RequirementSignatureSelf, nullptr, protocol);
+  auto &builder = *root->getBuilder();
+  REQUIREMENT_SOURCE_FACTORY_BODY(RequirementSignatureSelf, nullptr, protocol,
+                                  root, 1);
 }
 
 const RequirementSource *RequirementSource::forNestedTypeNameMatch(
-                                             GenericSignatureBuilder &builder) {
-  REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(NestedTypeNameMatch, nullptr);
+                                             PotentialArchetype *root) {
+  auto &builder = *root->getBuilder();
+  REQUIREMENT_SOURCE_FACTORY_BODY(NestedTypeNameMatch, nullptr, root, nullptr,
+                                  0);
 }
 
 const RequirementSource *RequirementSource::viaAbstractProtocolRequirement(
                                                GenericSignatureBuilder &builder,
                                                ProtocolDecl *protocol) const {
-  REQUIREMENT_SOURCE_FACTORY_BODY(ProtocolRequirement, this, protocol);
+  REQUIREMENT_SOURCE_FACTORY_BODY(ProtocolRequirement, this, protocol,
+                                  nullptr, 0);
 }
 
 const RequirementSource *RequirementSource::viaSuperclass(
                                       GenericSignatureBuilder &builder,
                                       ProtocolConformance *conformance) const {
-  REQUIREMENT_SOURCE_FACTORY_BODY(Superclass, this, conformance);
+  REQUIREMENT_SOURCE_FACTORY_BODY(Superclass, this, conformance, nullptr, 0);
 }
 
 const RequirementSource *RequirementSource::viaConcrete(
                                       GenericSignatureBuilder &builder,
                                       ProtocolConformance *conformance) const {
-  REQUIREMENT_SOURCE_FACTORY_BODY(Concrete, this, conformance);
+  REQUIREMENT_SOURCE_FACTORY_BODY(Concrete, this, conformance, nullptr, 0);
 }
 
 const RequirementSource *RequirementSource::viaParent(
-                                      GenericSignatureBuilder &builder) const {
-  REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(Parent, this);
+                                      GenericSignatureBuilder &builder,
+                                      AssociatedTypeDecl *assocType) const {
+  REQUIREMENT_SOURCE_FACTORY_BODY(Parent, this, assocType, nullptr, 0);
 }
 
-#undef REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE
 #undef REQUIREMENT_SOURCE_FACTORY_BODY
 
+PotentialArchetype *RequirementSource::getRootPotentialArchetype() const {
+  /// Find the root.
+  auto root = this;
+  while (auto parent = root->parent)
+    root = parent;
+
+  // If the root archetype is in extra storage, grab it from there.
+  if (root->numTrailingObjects(OverloadToken<PotentialArchetype *>()) == 1)
+    return root->getTrailingObjects<PotentialArchetype *>()[0];
+
+  // Otherwise, it's in inline storage.
+  assert(storageKind == StorageKind::RootArchetype);
+  return storage.rootArchetype;
+}
+
 ProtocolDecl *RequirementSource::getProtocolDecl() const {
   switch (storageKind) {
-  case StorageKind::None:
+  case StorageKind::RootArchetype:
   case StorageKind::TypeRepr:
   case StorageKind::RequirementRepr:
     return nullptr;
@@ -307,6 +414,9 @@
       return storage.conformance->getProtocol();
 
     return nullptr;
+
+  case StorageKind::AssociatedTypeDecl:
+    return storage.assocType->getProtocol();
   }
 }
 
@@ -365,6 +475,9 @@
   if (parent) {
     parent->print(out, srcMgr);
     out << " -> ";
+  } else {
+    auto pa = getRootPotentialArchetype();
+    out << pa->getDebugName() << ": ";
   }
 
   switch (kind) {
@@ -413,7 +526,7 @@
   };
 
   switch (storageKind) {
-  case StorageKind::None:
+  case StorageKind::RootArchetype:
     break;
 
   case StorageKind::TypeRepr:
@@ -432,9 +545,53 @@
           << storage.conformance->getProtocol()->getName() << ")";
     }
     break;
+
+  case StorageKind::AssociatedTypeDecl:
+    out << " (" << storage.assocType->getProtocol()->getName()
+        << "::" << storage.assocType->getName() << ")";
+    break;
   }
 }
 
+const RequirementSource *FloatingRequirementSource::getSource(
+                                                PotentialArchetype *pa) const {
+  switch (kind) {
+  case Resolved:
+      return storage.get<const RequirementSource *>();
+
+  case Explicit:
+    if (auto requirementRepr = storage.dyn_cast<const RequirementRepr *>())
+      return RequirementSource::forExplicit(pa, requirementRepr);
+    if (auto typeRepr = storage.dyn_cast<const TypeRepr *>())
+      return RequirementSource::forExplicit(pa, typeRepr);
+    return RequirementSource::forAbstract(pa);
+
+  case Inferred:
+    return RequirementSource::forInferred(pa, storage.get<const TypeRepr *>());
+  }
+}
+
+SourceLoc FloatingRequirementSource::getLoc() const {
+  if (auto source = storage.dyn_cast<const RequirementSource *>())
+    return source->getLoc();
+
+  if (auto typeRepr = storage.dyn_cast<const TypeRepr *>())
+    return typeRepr->getLoc();
+
+  if (auto requirementRepr = storage.dyn_cast<const RequirementRepr *>()) {
+    switch (requirementRepr->getKind()) {
+    case RequirementReprKind::LayoutConstraint:
+    case RequirementReprKind::TypeConstraint:
+      return requirementRepr->getColonLoc();
+
+    case RequirementReprKind::SameType:
+      return requirementRepr->getEqualLoc();
+    }
+  }
+
+  return SourceLoc();
+}
+
 GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() {
   for (const auto &nested : NestedTypes) {
     for (auto pa : nested.second) {
@@ -501,38 +658,44 @@
   --builder.Impl->NumUnresolvedNestedTypes;
 }
 
-Optional<std::pair<Type, const RequirementSource *>>
-PotentialArchetype::findAnyConcreteTypeSourceAsWritten() const {
-  using Result = std::pair<Type, const RequirementSource *>;
-
-  // Local function to look for a source in the given potential archetype.
-  auto lookInPA = [](const PotentialArchetype *pa) -> Optional<Result> {
-    for (unsigned i : indices(pa->concreteTypeSources)) {
-      auto source = pa->concreteTypeSources[i];
-      if (source->getLoc().isValid())
-        return Result(pa->concreteTypes[i], source);
-    }
-
-    return None;
-  };
-
-  // If we have a concrete type source with location information, use that.
-  if (auto result = lookInPA(this))
-    return result;
-
+Optional<ConcreteConstraint>
+EquivalenceClass::findAnyConcreteConstraintAsWritten(
+                                      PotentialArchetype *preferredPA) const {
   // If we don't have a concrete type, there's no source.
-  auto rep = getRepresentative();
-  if (!rep->isConcreteType()) return None;
+  if (!concreteType) return None;
 
-  // Otherwise, go look for the source.
-  for (auto pa : rep->getEquivalenceClassMembers()) {
-    if (pa != this) {
-      if (auto result = lookInPA(pa))
+  // Go look for a source with source-location information.
+  Optional<ConcreteConstraint> result;
+  for (const auto &constraint : concreteTypeConstraints) {
+    if (constraint.source->getLoc().isValid()) {
+      result = constraint;
+      if (!preferredPA || constraint.archetype == preferredPA)
         return result;
     }
   }
 
-  return None;
+  return result;
+}
+
+Optional<ConcreteConstraint>
+EquivalenceClass::findAnySuperclassConstraintAsWritten(
+                                      PotentialArchetype *preferredPA) const {
+  // If we don't have a superclass, there's no source.
+  if (!superclass) return None;
+
+  // Go look for a source with source-location information.
+  Optional<ConcreteConstraint> result;
+  for (const auto &constraint : superclassConstraints) {
+    if (constraint.source->getLoc().isValid() &&
+        constraint.concreteType->isEqual(superclass)) {
+      result = constraint;
+
+      if (!preferredPA || constraint.archetype == preferredPA)
+        return result;
+    }
+  }
+
+  return result;
 }
 
 bool GenericSignatureBuilder::updateRequirementSource(
@@ -570,8 +733,16 @@
 
   // Conformance to this protocol is redundant; update the requirement source
   // appropriately.
-  auto superclassSource =
-    pa->getSuperclassSource()->viaSuperclass(*this, conformance->getConcrete());
+  auto paEquivClass = pa->getOrCreateEquivalenceClass();
+  const RequirementSource *superclassSource;
+  if (auto writtenSource =
+        paEquivClass->findAnySuperclassConstraintAsWritten(pa))
+    superclassSource = writtenSource->source;
+  else
+    superclassSource = paEquivClass->superclassConstraints.front().source;
+
+  superclassSource =
+    superclassSource->viaSuperclass(*this, conformance->getConcrete());
   updateRequirementSource(protoSource, superclassSource);
   return superclassSource;
 }
@@ -603,7 +774,6 @@
 
   static ResolvedType forNewTypeAlias(PotentialArchetype *pa) {
     assert(pa->getParent() && pa->getTypeAliasDecl() &&
-           pa->concreteTypes.empty() &&
            pa->getEquivalenceClassMembers().size() == 1 &&
            "not a new typealias");
     return ResolvedType(pa);
@@ -635,7 +805,7 @@
   if (!concreteType) return;
 
   // Add the same-type constraint.
-  auto nestedSource = superSource->viaParent(builder);
+  auto nestedSource = superSource->viaParent(builder, assocType);
   concreteType = superConformance->getDeclContext()
       ->mapTypeOutOfContext(concreteType);
 
@@ -709,7 +879,8 @@
     // and make it equivalent to the first potential archetype we encountered.
     auto otherPA = new PotentialArchetype(this, assocType);
     known->second.push_back(otherPA);
-    auto sameNamedSource = RequirementSource::forNestedTypeNameMatch(builder);
+    auto sameNamedSource = RequirementSource::forNestedTypeNameMatch(
+                                                        known->second.front());
     builder.addSameTypeRequirement(known->second.front(), otherPA,
                                    sameNamedSource);
 
@@ -921,11 +1092,12 @@
 
   // These requirements are all implied based on the parent's concrete
   // conformance.
-  auto source = parentConcreteSource->viaConcrete(builder, /*FIXME: */nullptr)
-    ->viaParent(builder);
   auto assocType = nestedPA->getResolvedAssociatedType();
   if (!assocType) return;
 
+  auto source = parentConcreteSource->viaConcrete(builder, /*FIXME: */nullptr)
+    ->viaParent(builder, assocType);
+
   // FIXME: Get the conformance from the parent.
   auto conformance = lookupConformance(assocType->getProtocol());
 
@@ -964,9 +1136,6 @@
   if (rep != this)
     repNested = rep->getNestedType(nestedName, builder);
 
-  auto sameNestedTypeSource =
-    RequirementSource::forNestedTypeNameMatch(builder);
-
   // Attempt to resolve this nested type to an associated type
   // of one of the protocols to which the parent potential
   // archetype conforms.
@@ -1032,9 +1201,11 @@
           ProtocolConformanceRef(proto));
         type = type.subst(subMap, SubstFlags::UseErrorType);
 
-        builder.addSameTypeRequirement(ResolvedType::forNewTypeAlias(pa),
-                                       builder.resolve(type),
-                                       sameNestedTypeSource, diagnoseMismatch);
+        builder.addSameTypeRequirement(
+                                 ResolvedType::forNewTypeAlias(pa),
+                                 builder.resolve(type),
+                                 RequirementSource::forNestedTypeNameMatch(pa),
+                                 diagnoseMismatch);
       } else
         continue;
 
@@ -1047,14 +1218,18 @@
 
         // Produce a same-type constraint between the two same-named
         // potential archetypes.
-        builder.addSameTypeRequirement(pa, nested.front(), sameNestedTypeSource,
-                                       diagnoseMismatch);
+        builder.addSameTypeRequirement(
+                                 pa, nested.front(),
+                                 RequirementSource::forNestedTypeNameMatch(pa),
+                                 diagnoseMismatch);
       } else {
         nested.push_back(pa);
 
         if (repNested) {
-          builder.addSameTypeRequirement(pa, repNested, sameNestedTypeSource,
-                                         diagnoseMismatch);
+          builder.addSameTypeRequirement(
+                                 pa, repNested,
+                                 RequirementSource::forNestedTypeNameMatch(pa),
+                                 diagnoseMismatch);
         }
       }
 
@@ -1081,7 +1256,8 @@
   if (isConcreteType()) {
     for (auto equivT : rep->getEquivalenceClassMembers()) {
       concretizeNestedTypeFromConcreteParent(
-          equivT, sameNestedTypeSource, nestedPA, builder,
+          equivT, RequirementSource::forNestedTypeNameMatch(nestedPA),
+          nestedPA, builder,
           [&](ProtocolDecl *proto) -> ProtocolConformanceRef {
             auto depTy = nestedPA->getDependentType({},
                                                     /*allowUnresolved=*/true)
@@ -1109,7 +1285,7 @@
   // somewhere else.
   bool failed = builder.addConformanceRequirement(
                   this, assocType->getProtocol(),
-                  RequirementSource::forInferred(builder, nullptr));
+                  RequirementSource::forInferred(this, nullptr));
   (void)failed;
 
   // Trigger the construction of nested types with this name.
@@ -1341,31 +1517,40 @@
   else
     Out.indent(Indent) << getNestedName();
 
+  auto equivClass = getEquivalenceClassIfPresent();
+
   // Print superclass.
-  if (Superclass) {
-    Out << " : ";
-    Superclass.print(Out);
-    Out << " ";
-    if (!SuperclassSource->isDerivedRequirement())
-      Out << "*";
-    Out << "[";
-    SuperclassSource->print(Out, SrcMgr);
-    Out << "]";
+  if (equivClass && equivClass->superclass) {
+    for (const auto &constraint : equivClass->superclassConstraints) {
+      if (constraint.archetype != this) continue;
+
+      Out << " : ";
+      constraint.concreteType.print(Out);
+
+      Out << " ";
+      if (!constraint.source->isDerivedRequirement())
+        Out << "*";
+      Out << "[";
+      constraint.source->print(Out, SrcMgr);
+      Out << "]";
+    }
   }
 
   // Print concrete type.
-  for (unsigned i : indices(concreteTypes)) {
-    auto concreteType = concreteTypes[i];
-    Out << " == ";
-    concreteType.print(Out);
+  if (equivClass && equivClass->concreteType) {
+    for (const auto &constraint : equivClass->concreteTypeConstraints) {
+      if (constraint.archetype != this) continue;
 
-    auto concreteTypeSource = concreteTypeSources[i];
-    Out << " ";
-    if (!concreteTypeSource->isDerivedRequirement())
-      Out << "*";
-    Out << "[";
-    concreteTypeSource->print(Out, SrcMgr);
-    Out << "]";
+      Out << " == ";
+      constraint.concreteType.print(Out);
+
+      Out << " ";
+      if (!constraint.source->isDerivedRequirement())
+        Out << "*";
+      Out << "[";
+      constraint.source->print(Out, SrcMgr);
+      Out << "]";
+    }
   }
 
   // Print requirements.
@@ -1595,19 +1780,19 @@
     Visited.erase(Proto);
   };
 
+  auto concreteSelf = T->getDependentType({}, /*allowUnresolved=*/true);
+  auto protocolSubMap = SubstitutionMap::getProtocolSubstitutions(
+      Proto, concreteSelf, ProtocolConformanceRef(Proto));
+
   // Use the requirement signature to avoid rewalking the entire protocol.  This
   // cannot compute the requirement signature directly, because that may be
   // infinitely recursive: this code is also used to construct it.
   if (Proto->isRequirementSignatureComputed()) {
     auto reqSig = Proto->getRequirementSignature();
 
-    auto concreteSelf = T->getDependentType({}, /*allowUnresolved=*/true);
-    auto subMap = SubstitutionMap::getProtocolSubstitutions(
-        Proto, concreteSelf, ProtocolConformanceRef(Proto));
-
     auto innerSource = Source->viaAbstractProtocolRequirement(*this, Proto);
     for (auto rawReq : reqSig->getRequirements()) {
-      auto req = rawReq.subst(subMap);
+      auto req = rawReq.subst(protocolSubMap);
       assert(req && "substituting Self in requirement shouldn't fail");
       if (addRequirement(*req, innerSource, Visited))
         return true;
@@ -1633,6 +1818,12 @@
         if (addInheritedRequirements(AssocType, AssocPA, Source, Visited))
           return true;
       }
+      if (auto WhereClause = AssocType->getTrailingWhereClause()) {
+        auto innerSource = Source->viaAbstractProtocolRequirement(*this, Proto);
+        for (auto &req : WhereClause->getRequirements()) {
+          addRequirement(&req, innerSource, &protocolSubMap);
+        }
+      }
     } else if (auto TypeAlias = dyn_cast<TypeAliasDecl>(Member)) {
         // FIXME: this should check that the typealias is makes sense (e.g. has
         // the same/compatible type as typealiases in parent protocols) and
@@ -1642,8 +1833,6 @@
         // unresolved PA that prints an error later.
       (void)TypeAlias;
     }
-
-    // FIXME: Requirement declarations.
   }
 
   return false;
@@ -1677,28 +1866,11 @@
   return false;
 }
 
-bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T,
-                                                Type Superclass,
-                                                const RequirementSource *Source) {
-  T = T->getRepresentative();
-
-  // Make sure the concrete type fulfills the superclass requirement
-  // of the archetype.
-  if (T->isConcreteType()) {
-    Type concrete = T->getConcreteType();
-    if (!Superclass->isExactSuperclassOf(concrete, getLazyResolver())) {
-      if (auto source = T->findAnyConcreteTypeSourceAsWritten()) {
-        Diags.diagnose(source->second->getLoc(), diag::type_does_not_inherit,
-                       T->getDependentType(/*FIXME:*/{ },
-                                           /*allowUnresolved=*/true),
-                       source->first, Superclass)
-          .highlight(Source->getLoc());
-      }
-      return true;
-    }
-
-    return false;
-  }
+bool GenericSignatureBuilder::updateSuperclass(
+                                           PotentialArchetype *T,
+                                           Type superclass,
+                                           const RequirementSource *source) {
+  auto equivClass = T->getOrCreateEquivalenceClass();
 
   // Local function to handle the update of superclass conformances
   // when the superclass constraint changes.
@@ -1724,73 +1896,49 @@
     }
   };
 
-  // If T already has a superclass, make sure it's related.
-  if (T->Superclass) {
-    // TODO: In principle, this could be isBindableToSuperclassOf instead of
-    // isExactSubclassOf. If you had:
-    //
-    //   class Foo<T>
-    //   class Bar: Foo<Int>
-    //
-    //   func foo<T, U where U: Foo<T>, U: Bar>(...) { ... }
-    //
-    // then the second constraint should be allowed, constraining U to Bar
-    // and secondarily imposing a T == Int constraint.
-    if (T->Superclass->isExactSuperclassOf(Superclass, nullptr)) {
-      T->Superclass = Superclass;
-
-      // We've strengthened the bound, so update superclass conformances.
-      updateSuperclassConformances();
-    // TODO: Similar to the above, a more general isBindableToSuperclassOf
-    // base class constraint could potentially introduce secondary constraints.
-    // If you had:
-    //
-    //   class Foo<T>
-    //   class Bar: Foo<Int>
-    //
-    //   func foo<T, U where U: Bar, U: Foo<T>>(...) { ... }
-    //
-    // then the second `U: Foo<T>` constraint introduces a `T == Int`
-    // constraint.
-    } else if (!Superclass->isExactSuperclassOf(T->Superclass, nullptr)) {
-      if (Source->getLoc().isValid()) {
-        // Figure out what kind of subject we have; it will affect the
-        // diagnostic.
-        auto subjectType = T->getDependentType(/*FIXME: */{ }, true);
-        unsigned kind;
-        if (auto gp = subjectType->getAs<GenericTypeParamType>()) {
-          if (gp->getDecl() &&
-              isa<ProtocolDecl>(gp->getDecl()->getDeclContext())) {
-            kind = 1;
-            subjectType = cast<ProtocolDecl>(gp->getDecl()->getDeclContext())
-                            ->getDeclaredInterfaceType();
-          } else {
-            kind = 0;
-          }
-        } else {
-          kind = 2;
-        }
-
-        Diags.diagnose(Source->getLoc(), diag::requires_superclass_conflict,
-                       kind, subjectType, T->Superclass, Superclass)
-          .highlight(T->SuperclassSource->getLoc());
-      }
-      return true;
-    }
-
-    updateRequirementSource(T->SuperclassSource, Source);
+  // If we haven't yet recorded a superclass constraint for this equivalence
+  // class, do so now.
+  if (!equivClass->superclass) {
+    equivClass->superclass = superclass;
+    updateSuperclassConformances();
     return false;
   }
 
-  // Set the superclass.
-  T->Superclass = Superclass;
-  T->SuperclassSource = Source;
+  // T already has a superclass; make sure it's related.
+  auto existingSuperclass = equivClass->superclass;
+  // TODO: In principle, this could be isBindableToSuperclassOf instead of
+  // isExactSubclassOf. If you had:
+  //
+  //   class Foo<T>
+  //   class Bar: Foo<Int>
+  //
+  //   func foo<T, U where U: Foo<T>, U: Bar>(...) { ... }
+  //
+  // then the second constraint should be allowed, constraining U to Bar
+  // and secondarily imposing a T == Int constraint.
+  if (existingSuperclass->isExactSuperclassOf(superclass, nullptr)) {
+    equivClass->superclass = superclass;
 
-  // Update based on these conformances.
-  updateSuperclassConformances();
+    // We've strengthened the bound, so update superclass conformances.
+    updateSuperclassConformances();
+    return false;
+  }
+
   return false;
 }
 
+bool GenericSignatureBuilder::addSuperclassRequirement(
+                                            PotentialArchetype *T,
+                                            Type superclass,
+                                            const RequirementSource *source) {
+  // Record the constraint.
+  T->getOrCreateEquivalenceClass()->superclassConstraints
+    .push_back(ConcreteConstraint{T, superclass, source});
+
+  // Update the equivalence class with the constraint.
+  return updateSuperclass(T, superclass, source);
+}
+
 void GenericSignatureBuilder::PotentialArchetype::addSameTypeConstraint(
                                              PotentialArchetype *otherPA,
                                              const RequirementSource *source) {
@@ -1831,8 +1979,10 @@
   // Decide which potential archetype is to be considered the representative.
   // It doesn't specifically matter which we use, but it's a minor optimization
   // to prefer the canonical type.
-  if (compareDependentTypes(&T2, &T1) < 0)
+  if (compareDependentTypes(&T2, &T1) < 0) {
     std::swap(T1, T2);
+    std::swap(OrigT1, OrigT2);
+  }
 
   // Merge any concrete constraints.
   Type concrete1 = T1->getConcreteType();
@@ -1882,17 +2032,35 @@
     delete equivClass2;
   };
 
+  // Same-type-to-concrete requirements.
+  if (equivClass2 && equivClass2->concreteType) {
+    if (!equivClass->concreteType)
+      equivClass->concreteType = equivClass2->concreteType;
+
+    equivClass->concreteTypeConstraints.insert(
+                                 equivClass->concreteTypeConstraints.end(),
+                                 equivClass2->concreteTypeConstraints.begin(),
+                                 equivClass2->concreteTypeConstraints.end());
+  }
+
   // Make T1 the representative of T2, merging the equivalence classes.
   T2->representativeOrEquivClass = T1;
 
-  // Same-type-to-concrete requirement.
-  if (equivClass2 && equivClass2->concreteType && !equivClass->concreteType)
-    equivClass->concreteType = equivClass2->concreteType;
-
   // Superclass requirements.
-  if (T2->Superclass) {
-    addSuperclassRequirement(T1, T2->getSuperclass(),
-                             T2->getSuperclassSource());
+  if (equivClass2 && equivClass2->superclass) {
+    const RequirementSource *source2;
+    if (auto existingSource2 =
+          equivClass2->findAnySuperclassConstraintAsWritten(OrigT2))
+      source2 = existingSource2->source;
+    else
+      source2 = equivClass2->superclassConstraints.front().source;
+
+    (void)updateSuperclass(T1, equivClass2->superclass, source2);
+
+    equivClass->superclassConstraints.insert(
+                                   equivClass->concreteTypeConstraints.end(),
+                                   equivClass2->superclassConstraints.begin(),
+                                   equivClass2->superclassConstraints.end());
   }
 
   // Add all of the protocol conformance requirements of T2 to T1.
@@ -1902,13 +2070,13 @@
   }
 
   // Recursively merge the associated types of T2 into T1.
-  auto sameNestedTypeSource = RequirementSource::forNestedTypeNameMatch(*this);
   for (auto equivT2 : equivClass2Members) {
     for (auto T2Nested : equivT2->NestedTypes) {
       auto T1Nested = T1->getNestedType(T2Nested.first, *this);
-      if (addSameTypeRequirement(T1Nested, T2Nested.second.front(),
-                                 sameNestedTypeSource,
-                                 [&](Type type1, Type type2) {
+      if (addSameTypeRequirement(
+                           T1Nested, T2Nested.second.front(),
+                           RequirementSource::forNestedTypeNameMatch(T1Nested),
+                           [&](Type type1, Type type2) {
             Diags.diagnose(Source->getLoc(),
                            diag::requires_same_type_conflict,
                            T1Nested->isGenericParam(),
@@ -1926,21 +2094,25 @@
        PotentialArchetype *T,
        Type Concrete,
        const RequirementSource *Source) {
+  auto rep = T->getRepresentative();
+  auto equivClass = rep->getOrCreateEquivalenceClass();
+
   // Record the concrete type and its source.
-  T->concreteTypes.push_back(Concrete);
-  T->concreteTypeSources.push_back(Source);
+  equivClass->concreteTypeConstraints.push_back(
+                                      ConcreteConstraint{T, Concrete, Source});
 
   // If we've already been bound to a type, match that type.
-  if (auto oldConcrete = T->getConcreteType()) {
+  if (equivClass->concreteType) {
     bool mismatch = addSameTypeRequirement(
-        oldConcrete, Concrete, Source, [&](Type type1, Type type2) {
-          Diags.diagnose(Source->getLoc(),
-                         diag::requires_same_type_conflict,
-                         T->isGenericParam(),
-                         T->getDependentType(/*FIXME: */{ }, true), type1,
-                         type2);
+            equivClass->concreteType, Concrete, Source,
+            [&](Type type1, Type type2) {
+            Diags.diagnose(Source->getLoc(),
+                           diag::requires_same_type_conflict,
+                           T->isGenericParam(),
+                           T->getDependentType(/*FIXME: */{ }, true), type1,
+                           type2);
 
-        });
+          });
 
     if (mismatch) return true;
 
@@ -1949,10 +2121,7 @@
   }
 
   // Record the requirement.
-  auto rep = T->getRepresentative();
-  auto equivClass = rep->getOrCreateEquivalenceClass();
-  if (!equivClass->concreteType)
-    equivClass->concreteType = Concrete;
+  equivClass->concreteType = Concrete;
 
   // Make sure the concrete type fulfills the requirements on the archetype.
   // FIXME: Move later...
@@ -1986,24 +2155,6 @@
     updateRequirementSource(conforms.second, concreteSource);
   }
 
-  // Make sure the concrete type fulfills the superclass requirement
-  // of the archetype.
-  if (rep->Superclass) {
-    if (!rep->Superclass->isExactSuperclassOf(Concrete, getLazyResolver())) {
-      Diags.diagnose(Source->getLoc(), diag::type_does_not_inherit,
-                     rep->getDependentType(/*FIXME: */{ },
-                                         /*allowUnresolved=*/true),
-                     Concrete, rep->Superclass)
-        .highlight(rep->SuperclassSource->getLoc());
-      return true;
-    }
-
-    // The superclass requirement is made redundant by the concrete type
-    // assignment.
-    auto concreteSource = Source->viaConcrete(*this, nullptr);
-    updateRequirementSource(rep->SuperclassSource, concreteSource);
-  }
-
   // Eagerly resolve any existing nested types to their concrete forms (others
   // will be "concretized" as they are constructed, in getNestedType).
   for (auto equivT : rep->getEquivalenceClassMembers()) {
@@ -2020,17 +2171,18 @@
 }
 
 bool GenericSignatureBuilder::addSameTypeRequirementBetweenConcrete(
-    Type type1, Type type2, const RequirementSource *source,
+    Type type1, Type type2, FloatingRequirementSource source,
     llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
   // Local class to handle matching the two sides of the same-type constraint.
   class ReqTypeMatcher : public TypeMatcher<ReqTypeMatcher> {
     GenericSignatureBuilder &builder;
-    const RequirementSource *source;
+    FloatingRequirementSource source;
     Type outerType1, outerType2;
     llvm::function_ref<void(Type, Type)> diagnoseMismatch;
 
   public:
-    ReqTypeMatcher(GenericSignatureBuilder &builder, const RequirementSource *source,
+    ReqTypeMatcher(GenericSignatureBuilder &builder,
+                   FloatingRequirementSource source,
                    Type outerType1, Type outerType2,
                    llvm::function_ref<void(Type, Type)> diagnoseMismatch)
         : builder(builder), source(source), outerType1(outerType1),
@@ -2056,29 +2208,31 @@
   return !matcher.match(type1, type2);
 }
 
-bool GenericSignatureBuilder::addSameTypeRequirement(UnresolvedType paOrT1,
-                                                     UnresolvedType paOrT2,
-                                                     const RequirementSource *source) {
+bool GenericSignatureBuilder::addSameTypeRequirement(
+                                             UnresolvedType paOrT1,
+                                             UnresolvedType paOrT2,
+                                             FloatingRequirementSource source) {
   return addSameTypeRequirement(resolve(paOrT1), resolve(paOrT2), source);
 }
 bool GenericSignatureBuilder::addSameTypeRequirement(
-    UnresolvedType paOrT1, UnresolvedType paOrT2, const RequirementSource *source,
+    UnresolvedType paOrT1, UnresolvedType paOrT2,
+    FloatingRequirementSource source,
     llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
   return addSameTypeRequirement(resolve(paOrT1), resolve(paOrT2), source,
                                 diagnoseMismatch);
 }
 bool GenericSignatureBuilder::addSameTypeRequirement(ResolvedType paOrT1,
                                                      ResolvedType paOrT2,
-                                                     const RequirementSource *source) {
+                                                     FloatingRequirementSource source) {
   return addSameTypeRequirement(paOrT1, paOrT2, source,
                                 [&](Type type1, Type type2) {
-    Diags.diagnose(source->getLoc(), diag::requires_same_concrete_type,
+    Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
                    type1, type2);
   });
 }
 
 bool GenericSignatureBuilder::addSameTypeRequirement(
-    ResolvedType paOrT1, ResolvedType paOrT2, const RequirementSource *source,
+    ResolvedType paOrT1, ResolvedType paOrT2, FloatingRequirementSource source,
     llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
   auto pa1 = paOrT1.getPotentialArchetype();
   auto pa2 = paOrT2.getPotentialArchetype();
@@ -2087,12 +2241,13 @@
 
   // If both sides of the requirement are type parameters, equate them.
   if (pa1 && pa2) {
-    return addSameTypeRequirementBetweenArchetypes(pa1, pa2, source);
+    return addSameTypeRequirementBetweenArchetypes(pa1, pa2,
+                                                   source.getSource(pa1));
     // If just one side is a type parameter, map it to a concrete type.
   } else if (pa1) {
-    return addSameTypeRequirementToConcrete(pa1, t2, source);
+    return addSameTypeRequirementToConcrete(pa1, t2, source.getSource(pa1));
   } else if (pa2) {
-    return addSameTypeRequirementToConcrete(pa2, t1, source);
+    return addSameTypeRequirementToConcrete(pa2, t1, source.getSource(pa2));
   } else {
     return addSameTypeRequirementBetweenConcrete(t1, t2, source,
                                                  diagnoseMismatch);
@@ -2155,10 +2310,10 @@
 
       // Explicit requirement.
       if (typeRepr)
-        return RequirementSource::forExplicit(*this, typeRepr);
+        return RequirementSource::forExplicit(pa, typeRepr);
 
       // An abstract explicit requirement.
-      return RequirementSource::forAbstract(*this);
+      return RequirementSource::forAbstract(pa);
     };
 
     // Protocol requirement.
@@ -2184,13 +2339,23 @@
   });
 }
 
-bool GenericSignatureBuilder::addRequirement(const RequirementRepr *Req) {
-  auto source = RequirementSource::forExplicit(*this, Req);
+bool GenericSignatureBuilder::addRequirement(const RequirementRepr *Req,
+                                             const RequirementSource *source,
+                                             const SubstitutionMap *subMap) {
+  auto localSource = source ? FloatingRequirementSource(source)
+                            : FloatingRequirementSource::forExplicit(Req);
+
+  auto subst = [&](Type t) {
+    if (subMap)
+      return t.subst(*subMap);
+
+    return t;
+  };
 
   switch (Req->getKind()) {
   case RequirementReprKind::LayoutConstraint: {
     // FIXME: Need to do something here.
-    PotentialArchetype *PA = resolveArchetype(Req->getSubject());
+    PotentialArchetype *PA = resolveArchetype(subst(Req->getSubject()));
     if (!PA) {
       // FIXME: Poor location information.
       // FIXME: Delay diagnostic until after type validation?
@@ -2199,14 +2364,15 @@
       return true;
     }
 
-    if (addLayoutRequirement(PA, Req->getLayoutConstraint(), source))
+    if (addLayoutRequirement(PA, Req->getLayoutConstraint(),
+                             localSource.getSource(PA)))
       return true;
 
     return false;
   }
 
   case RequirementReprKind::TypeConstraint: {
-    PotentialArchetype *PA = resolveArchetype(Req->getSubject());
+    PotentialArchetype *PA = resolveArchetype(subst(Req->getSubject()));
     if (!PA) {
       // FIXME: Poor location information.
       // FIXME: Delay diagnostic until after type validation?
@@ -2217,7 +2383,8 @@
 
     // Check whether this is a supertype requirement.
     if (Req->getConstraint()->getClassOrBoundGenericClass()) {
-      return addSuperclassRequirement(PA, Req->getConstraint(), source);
+      return addSuperclassRequirement(PA, Req->getConstraint(),
+                                      localSource.getSource(PA));
     }
 
     SmallVector<ProtocolDecl *, 4> ConformsTo;
@@ -2228,7 +2395,7 @@
 
     // Add each of the protocols.
     for (auto Proto : ConformsTo)
-      if (addConformanceRequirement(PA, Proto, source))
+      if (addConformanceRequirement(PA, Proto, localSource.getSource(PA)))
         return true;
 
     return false;
@@ -2246,22 +2413,22 @@
     }
 
     return addRequirement(Requirement(RequirementKind::SameType,
-                                      Req->getFirstType(),
-                                      Req->getSecondType()),
-                          source);
+                                      subst(Req->getFirstType()),
+                                      subst(Req->getSecondType())),
+                          localSource);
   }
 
   llvm_unreachable("Unhandled requirement?");
 }
 
 bool GenericSignatureBuilder::addRequirement(const Requirement &req,
-                                      const RequirementSource *source) {
+                                             FloatingRequirementSource source) {
   llvm::SmallPtrSet<ProtocolDecl *, 8> Visited;
   return addRequirement(req, source, Visited);
 }
 
 bool GenericSignatureBuilder::addRequirement(
-    const Requirement &req, const RequirementSource *source,
+    const Requirement &req, FloatingRequirementSource source,
     llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
   switch (req.getKind()) {
   case RequirementKind::Superclass: {
@@ -2270,7 +2437,8 @@
     if (!pa) return false;
 
     assert(req.getSecondType()->getClassOrBoundGenericClass());
-    return addSuperclassRequirement(pa, req.getSecondType(), source);
+    return addSuperclassRequirement(pa, req.getSecondType(),
+                                    source.getSource(pa));
   }
 
   case RequirementKind::Layout: {
@@ -2278,7 +2446,8 @@
     PotentialArchetype *pa = resolveArchetype(req.getFirstType());
     if (!pa) return false;
 
-    return addLayoutRequirement(pa, req.getLayoutConstraint(), source);
+    return addLayoutRequirement(pa, req.getLayoutConstraint(),
+                                source.getSource(pa));
   }
 
   case RequirementKind::Conformance: {
@@ -2292,10 +2461,11 @@
     // Add each of the protocols.
     for (auto proto : conformsTo) {
       if (Visited.count(proto)) {
-        markPotentialArchetypeRecursive(pa, proto, source);
+        markPotentialArchetypeRecursive(pa, proto, source.getSource(pa));
         continue;
       }
-      if (addConformanceRequirement(pa, proto, source, Visited)) return true;
+      if (addConformanceRequirement(pa, proto, source.getSource(pa), Visited))
+        return true;
     }
 
     return false;
@@ -2305,8 +2475,8 @@
     return addSameTypeRequirement(
         req.getFirstType(), req.getSecondType(), source,
         [&](Type type1, Type type2) {
-          if (source->getLoc().isValid())
-            Diags.diagnose(source->getLoc(), diag::requires_same_concrete_type,
+          if (source.getLoc().isValid())
+            Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
                            type1, type2);
         });
   }
@@ -2318,25 +2488,11 @@
 class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
   GenericSignatureBuilder &Builder;
   TypeRepr *typeRepr;
-  unsigned MinDepth;
-  unsigned MaxDepth;
-
-  /// We cannot add requirements to archetypes from outer generic parameter
-  /// lists.
-  bool isOuterArchetype(PotentialArchetype *PA) {
-    unsigned ParamDepth = PA->getRootGenericParamKey().Depth;
-    assert(ParamDepth <= MaxDepth);
-    (void) MaxDepth;
-    return ParamDepth < MinDepth;
-  }
 
 public:
   InferRequirementsWalker(GenericSignatureBuilder &builder,
-                          TypeRepr *typeRepr,
-                          unsigned MinDepth,
-                          unsigned MaxDepth)
-    : Builder(builder), typeRepr(typeRepr), MinDepth(MinDepth),
-      MaxDepth(MaxDepth) { }
+                          TypeRepr *typeRepr)
+    : Builder(builder), typeRepr(typeRepr) { }
 
   Action walkToTypePost(Type ty) override {
     auto boundGeneric = ty->getAs<BoundGenericType>();
@@ -2364,7 +2520,7 @@
 
     // Handle the requirements.
     // FIXME: Inaccurate TypeReprs.
-    auto source = RequirementSource::forInferred(Builder, typeRepr);
+    auto source = FloatingRequirementSource::forInferred(typeRepr);
     for (const auto &rawReq : genericSig->getRequirements()) {
       if (auto req = rawReq.subst(getTypeSubstitution,
                                   Builder.getLookupConformanceFn()))
@@ -2375,14 +2531,11 @@
   }
 };
 
-void GenericSignatureBuilder::inferRequirements(TypeLoc type,
-                                         unsigned minDepth,
-                                         unsigned maxDepth) {
+void GenericSignatureBuilder::inferRequirements(TypeLoc type) {
   if (!type.getType())
     return;
   // FIXME: Crummy source-location information.
-  InferRequirementsWalker walker(*this, type.getTypeRepr(),
-                                 minDepth, maxDepth);
+  InferRequirementsWalker walker(*this, type.getTypeRepr());
   type.getType().walk(walker);
 }
 
@@ -2391,11 +2544,8 @@
   if (genericParams == nullptr)
     return;
 
-  unsigned depth = genericParams->getDepth();
   for (auto P : *params)
-    inferRequirements(P->getTypeLoc(),
-                      /*minDepth=*/depth,
-                      /*maxDepth=*/depth);
+    inferRequirements(P->getTypeLoc());
 }
 
 /// Perform typo correction on the given nested type, producing the
@@ -2548,15 +2698,17 @@
   visitPotentialArchetypes([&](PotentialArchetype *archetype) {
     if (archetype != archetype->getRepresentative()) return;
 
-    if (archetype->isConcreteType()) {
+    auto equivClass = archetype->getOrCreateEquivalenceClass();
+    if (equivClass->concreteType) {
       // Check for recursive same-type bindings.
       if (isRecursiveConcreteType(archetype, /*isSuperclass=*/false)) {
-        if (auto source = archetype->findAnyConcreteTypeSourceAsWritten()) {
-          Diags.diagnose(source->second->getLoc(),
+        if (auto constraint =
+              equivClass->findAnyConcreteConstraintAsWritten()) {
+          Diags.diagnose(constraint->source->getLoc(),
                          diag::recursive_same_type_constraint,
                          archetype->getDependentType(genericParams,
                                                      /*allowUnresolved=*/true),
-                         source->first);
+                         constraint->concreteType);
         }
 
         archetype->RecursiveConcreteType = true;
@@ -2566,25 +2718,29 @@
     }
 
     // Check for recursive superclass bindings.
-    if (archetype->getSuperclass()) {
+    if (equivClass->superclass) {
       if (isRecursiveConcreteType(archetype, /*isSuperclass=*/true)) {
-        if (archetype->SuperclassSource->getLoc().isValid())
-          Diags.diagnose(archetype->SuperclassSource->getLoc(),
+        if (auto source = equivClass->findAnySuperclassConstraintAsWritten()) {
+          Diags.diagnose(source->source->getLoc(),
                          diag::recursive_superclass_constraint,
-                         archetype->getDependentType(genericParams,
+                         source->archetype->getDependentType(
+                                                     genericParams,
                                                      /*allowUnresolved=*/true),
-                         archetype->getSuperclass());
+                         equivClass->superclass);
+        }
 
         archetype->RecursiveSuperclassType = true;
+      } else {
+        checkRedundantSuperclassConstraints(genericParams, archetype);
       }
     }
   });
 
-  SmallPtrSet<PotentialArchetype *, 4> visited;
-
   // Check for generic parameters which have been made concrete or equated
   // with each other.
   if (!allowConcreteGenericParams) {
+    SmallPtrSet<PotentialArchetype *, 4> visited;
+    
     unsigned depth = 0;
     for (const auto &gp : Impl->GenericParams)
       depth = std::max(depth, gp->getDepth());
@@ -2600,9 +2756,10 @@
 
       // Don't allow a generic parameter to be equivalent to a concrete type,
       // because then we don't actually have a parameter.
-      if (rep->getConcreteType()) {
-        if (auto source = rep->findAnyConcreteTypeSourceAsWritten())
-          Diags.diagnose(source->second->getLoc(),
+      auto equivClass = rep->getOrCreateEquivalenceClass();
+      if (equivClass->concreteType) {
+        if (auto constraint = equivClass->findAnyConcreteConstraintAsWritten())
+          Diags.diagnose(constraint->source->getLoc(),
                          diag::requires_generic_param_made_equal_to_concrete,
                          rep->getDependentType(genericParams,
                                                /*allowUnresolved=*/true));
@@ -2667,7 +2824,7 @@
                                 *this);
       addSameTypeRequirement(
           pa, replacement,
-          RequirementSource::forNestedTypeNameMatch(*this));
+          RequirementSource::forNestedTypeNameMatch(pa));
     });
   }
 }
@@ -2690,101 +2847,97 @@
   return invalid;
 }
 
-namespace {
-  /// Describes a concrete constraint on a potential archetype.
-  struct ConcreteConstraint {
-    PotentialArchetype *archetype;
-    Type concreteType;
-    const RequirementSource *source;
+namespace swift {
+  bool operator<(const ConcreteConstraint &lhs, const ConcreteConstraint &rhs) {
+    auto lhsPA = lhs.archetype;
+    auto rhsPA = rhs.archetype;
+    if (int result = compareDependentTypes(&lhsPA, &rhsPA))
+      return result < 0;
 
-    friend bool operator<(const ConcreteConstraint &lhs,
-                          const ConcreteConstraint &rhs) {
-      auto lhsPA = lhs.archetype;
-      auto rhsPA = rhs.archetype;
-      if (int result = compareDependentTypes(&lhsPA, &rhsPA))
-        return result < 0;
+    if (int result = lhs.source->compare(rhs.source))
+      return result < 0;
 
-      if (int result = lhs.source->compare(rhs.source))
-        return result < 0;
-
-      return false;
-    }
-
-    friend bool operator==(const ConcreteConstraint &lhs,
-                           const ConcreteConstraint &rhs) {
-      return lhs.archetype == rhs.archetype &&
-             lhs.concreteType->isEqual(rhs.concreteType) &&
-             lhs.source == rhs.source;
-    }
-  };
-}
-
-void GenericSignatureBuilder::checkRedundantConcreteTypeConstraints(
-                                 ArrayRef<GenericTypeParamType *> genericParams,
-                                 PotentialArchetype *representative) {
-  Type concreteType = representative->getConcreteType();
-  assert(concreteType && "No concrete type to check");
-
-  Optional<ConcreteConstraint> representativeConstraint;
-
-  // Gather the concrete constraints within this equivalence class.
-  SmallVector<ConcreteConstraint, 4> concreteConstraints;
-  for (auto pa : representative->getEquivalenceClassMembers()) {
-    auto types = pa->getConcreteTypesAsWritten();
-    auto sources = pa->getConcreteTypeSourcesAsWritten();
-    for (unsigned i : indices(types)) {
-      auto source = sources[i];
-
-      // Save this constraint.
-      auto constraint = ConcreteConstraint{pa, types[i], source};
-      concreteConstraints.push_back(constraint);
-
-      // Check whether this constraint is better than the best we've seen so far
-      // at being the representative constraint against which others will be
-      // compared.
-      if (!representativeConstraint) {
-        representativeConstraint = constraint;
-        continue;
-      }
-
-      // We prefer derived constraints to non-derived constraints.
-      bool thisIsDerived = source->isDerivedRequirement();
-      bool representativeIsDerived =
-        representativeConstraint->source->isDerivedRequirement();
-      if (thisIsDerived != representativeIsDerived) {
-        if (thisIsDerived)
-          representativeConstraint = constraint;
-
-        continue;
-      }
-
-      // We prefer constraints with locations to constraints without locations.
-      bool thisHasValidSourceLoc = source->getLoc().isValid();
-      bool representativeHasValidSourceLoc =
-        representativeConstraint->source->getLoc().isValid();
-      if (thisHasValidSourceLoc != representativeHasValidSourceLoc) {
-        if (thisHasValidSourceLoc)
-          representativeConstraint = constraint;
-
-        continue;
-      }
-
-      // Otherwise, order via the constraint itself.
-      if (constraint < *representativeConstraint)
-        representativeConstraint = constraint;
-    }
+    return false;
   }
 
-  // Sort the concrete constraints, so we get deterministic ordering of
-  // diagnostics.
-  llvm::array_pod_sort(concreteConstraints.begin(), concreteConstraints.end());
+  bool operator==(const ConcreteConstraint &lhs, const ConcreteConstraint &rhs){
+    return lhs.archetype == rhs.archetype &&
+           lhs.concreteType->isEqual(rhs.concreteType) &&
+           lhs.source == rhs.source;
+  }
+}
 
-  // Local function to provide a note desribing the representative constraint.
+ConcreteConstraint GenericSignatureBuilder::checkConstraintList(
+                           ArrayRef<GenericTypeParamType *> genericParams,
+                           std::vector<ConcreteConstraint> &constraints,
+                           llvm::function_ref<bool(const ConcreteConstraint &)>
+                             isSuitableRepresentative,
+                           llvm::function_ref<ConstraintRelation(Type)>
+                             checkConstraint,
+                           Optional<Diag<unsigned, Type, Type, Type>>
+                             conflictingDiag,
+                           Diag<Type, Type> redundancyDiag,
+                           Diag<bool, Type, Type> otherNoteDiag) {
+  // Remove self-derived constraints.
+  constraints.erase(
+    std::remove_if(constraints.begin(), constraints.end(),
+                   [&](const ConcreteConstraint &constraint) {
+                     return constraint.source->isSelfDerivedSource(
+                              constraint.archetype);
+                   }),
+    constraints.end());
+
+  // Sort the constraints, so we get a deterministic ordering of diagnostics.
+  llvm::array_pod_sort(constraints.begin(), constraints.end());
+
+  // Find a representative constraint.
+  Optional<ConcreteConstraint> representativeConstraint;
+  for (const auto &constraint : constraints) {
+    // If this isn't a suitable representative constraint, ignore it.
+    if (!isSuitableRepresentative(constraint))
+      continue;
+
+    // Check whether this constraint is better than the best we've seen so far
+    // at being the representative constraint against which others will be
+    // compared.
+    if (!representativeConstraint) {
+      representativeConstraint = constraint;
+      continue;
+    }
+
+    // We prefer derived constraints to non-derived constraints.
+    bool thisIsDerived = constraint.source->isDerivedRequirement();
+    bool representativeIsDerived =
+      representativeConstraint->source->isDerivedRequirement();
+    if (thisIsDerived != representativeIsDerived) {
+      if (thisIsDerived)
+        representativeConstraint = constraint;
+
+      continue;
+    }
+
+    // We prefer constraints with locations to constraints without locations.
+    bool thisHasValidSourceLoc = constraint.source->getLoc().isValid();
+    bool representativeHasValidSourceLoc =
+      representativeConstraint->source->getLoc().isValid();
+    if (thisHasValidSourceLoc != representativeHasValidSourceLoc) {
+      if (thisHasValidSourceLoc)
+        representativeConstraint = constraint;
+
+      continue;
+    }
+
+    // Otherwise, order via the constraint itself.
+    if (constraint < *representativeConstraint)
+      representativeConstraint = constraint;
+  }
+
+  // Local function to provide a note describing the representative constraint.
   auto noteRepresentativeConstraint = [&] {
     if (representativeConstraint->source->getLoc().isInvalid()) return;
 
     Diags.diagnose(representativeConstraint->source->getLoc(),
-                   diag::redundancy_here,
+                   otherNoteDiag,
                    representativeConstraint->source->isDerivedRequirement(),
                    representativeConstraint->archetype->
                      getDependentType(genericParams, /*allowUnresolved=*/true),
@@ -2792,26 +2945,193 @@
   };
 
   // Go through the concrete constraints looking for redundancies.
-  for (const auto &constraint : concreteConstraints) {
+  bool diagnosedConflictingRepresentative = false;
+  for (const auto &constraint : constraints) {
     // Leave the representative alone.
     if (constraint == *representativeConstraint) continue;
 
-    // Note: this is conservative. There might be redundant constraints that
-    // don't get diagnosed here.
-    if (!concreteType->isEqual(constraint.concreteType)) continue;
+    switch (checkConstraint(constraint.concreteType)) {
+    case ConstraintRelation::Unrelated:
+      continue;
 
-    // If this requirement is not derived (but has a useful location),
-    // complain that it is redundant.
-    if (!constraint.source->isDerivedRequirement() &&
-        constraint.source->getLoc().isValid()) {
-      Diags.diagnose(constraint.source->getLoc(),
-                     diag::redundant_same_type_to_concrete,
-                     constraint.archetype->getDependentType(
-                                                  /*FIXME:*/{ },
+    case ConstraintRelation::Conflicting: {
+      // Figure out what kind of subject we have; it will affect the
+      // diagnostic.
+      auto getSubjectType =
+        [&](PotentialArchetype *T) -> std::pair<unsigned, Type> {
+          auto subjectType = T->getDependentType(genericParams, true);
+          unsigned kind;
+          if (auto gp = subjectType->getAs<GenericTypeParamType>()) {
+            if (gp->getDecl() &&
+                isa<ProtocolDecl>(gp->getDecl()->getDeclContext())) {
+              kind = 1;
+              subjectType = cast<ProtocolDecl>(gp->getDecl()->getDeclContext())
+                              ->getDeclaredInterfaceType();
+            } else {
+              kind = 0;
+            }
+          } else {
+            kind = 2;
+          }
+
+          return std::make_pair(kind, subjectType);
+        };
+
+
+      // The requirement conflicts. If this constraint has a location, complain
+      // about it.
+      if (constraint.source->getLoc().isValid()) {
+        auto subject = getSubjectType(constraint.archetype);
+        Diags.diagnose(constraint.source->getLoc(), *conflictingDiag,
+                       subject.first, subject.second,
+                       constraint.concreteType,
+                       representativeConstraint->concreteType);
+
+        noteRepresentativeConstraint();
+        break;
+      }
+
+      // If the representative itself conflicts and we haven't diagnosed it yet,
+      // do so now.
+      if (!diagnosedConflictingRepresentative &&
+          representativeConstraint->source->getLoc().isValid()) {
+        auto subject = getSubjectType(representativeConstraint->archetype);
+        Diags.diagnose(representativeConstraint->source->getLoc(),
+                       *conflictingDiag,
+                       subject.first, subject.second,
+                       representativeConstraint->concreteType,
+                       constraint.concreteType);
+
+        diagnosedConflictingRepresentative = true;
+        break;
+      }
+      break;
+    }
+
+    case ConstraintRelation::Redundant:
+      // If this requirement is not derived (but has a useful location),
+      // complain that it is redundant.
+      if (!constraint.source->isDerivedRequirement() &&
+          constraint.source->getLoc().isValid()) {
+        Diags.diagnose(constraint.source->getLoc(),
+                       redundancyDiag,
+                       constraint.archetype->getDependentType(
+                         genericParams, /*allowUnresolved=*/true),
+                       constraint.concreteType);
+
+        noteRepresentativeConstraint();
+      }
+      break;
+    }
+  }
+
+  return *representativeConstraint;
+}
+
+void GenericSignatureBuilder::checkRedundantConcreteTypeConstraints(
+                                 ArrayRef<GenericTypeParamType *> genericParams,
+                                 PotentialArchetype *representative) {
+  auto equivClass = representative->getOrCreateEquivalenceClass();
+  assert(equivClass->concreteType && "No concrete type to check");
+
+  checkConstraintList(
+    genericParams, equivClass->concreteTypeConstraints,
+    [](const ConcreteConstraint &constraint) {
+      return true;
+    },
+    [&](Type concreteType) {
+      // If the concrete type is equivalent, the constraint is redundant.
+      // FIXME: Should check this constraint after substituting in the
+      // archetype anchors for each dependent type.
+      if (concreteType->isEqual(equivClass->concreteType))
+        return ConstraintRelation::Redundant;
+
+      // Call this unrelated.
+      return ConstraintRelation::Unrelated;
+    },
+    None,
+    diag::redundant_same_type_to_concrete,
+    diag::same_type_redundancy_here);
+}
+
+void GenericSignatureBuilder::checkRedundantSuperclassConstraints(
+                                 ArrayRef<GenericTypeParamType *> genericParams,
+                                 PotentialArchetype *representative) {
+  auto equivClass = representative->getOrCreateEquivalenceClass();
+  assert(equivClass->superclass && "No superclass constraint?");
+
+  // FIXME: We should be substituting in the canonical type in context so
+  // we can resolve superclass requirements, e.g., if you had:
+  //
+  //   class Foo<T>
+  //   class Bar: Foo<Int>
+  //
+  //   func foo<T, U where U: Bar, U: Foo<T>>(...) { ... }
+  //
+  // then the second `U: Foo<T>` constraint introduces a `T == Int`
+  // constraint, and we will need to perform that substitution for this final
+  // check.
+
+  auto representativeConstraint =
+    checkConstraintList(
+      genericParams, equivClass->superclassConstraints,
+      [&](const ConcreteConstraint &constraint) {
+        return constraint.concreteType->isEqual(equivClass->superclass);
+      },
+      [&](Type superclass) {
+        // If this class is a superclass of the "best"
+        if (superclass->isExactSuperclassOf(equivClass->superclass, nullptr))
+          return ConstraintRelation::Redundant;
+
+        // Otherwise, it conflicts.
+        return ConstraintRelation::Conflicting;
+      },
+      diag::requires_superclass_conflict,
+      diag::redundant_superclass_constraint,
+      diag::superclass_redundancy_here);
+
+  // If we have a concrete type, check it.
+  // FIXME: Substitute into the concrete type.
+  if (equivClass->concreteType) {
+    // Make sure the concrete type fulfills the superclass requirement.
+    if (!equivClass->superclass->isExactSuperclassOf(equivClass->concreteType,
+                                                     nullptr)) {
+      if (auto existing = equivClass->findAnyConcreteConstraintAsWritten(
+                            representativeConstraint.archetype)) {
+        Diags.diagnose(existing->source->getLoc(), diag::type_does_not_inherit,
+                       existing->archetype->getDependentType(
+                                                   genericParams,
+                                                   /*allowUnresolved=*/true),
+                       existing->concreteType, equivClass->superclass);
+
+        // FIXME: Note the representative constraint.
+      } else if (representativeConstraint.source->getLoc().isValid()) {
+        Diags.diagnose(representativeConstraint.source->getLoc(),
+                       diag::type_does_not_inherit,
+                       representativeConstraint.archetype->getDependentType(
+                                                    genericParams,
+                                                    /*allowUnresolved=*/true),
+                       equivClass->concreteType, equivClass->superclass);
+      }
+    } else if (representativeConstraint.source->getLoc().isValid()) {
+      // It does fulfill the requirement; diagnose the redundancy.
+      Diags.diagnose(representativeConstraint.source->getLoc(),
+                     diag::redundant_superclass_constraint,
+                     representativeConstraint.archetype->getDependentType(
+                                                  genericParams,
                                                   /*allowUnresolved=*/true),
-                     constraint.concreteType);
+                     representativeConstraint.concreteType);
 
-      noteRepresentativeConstraint();
+      if (auto existing = equivClass->findAnyConcreteConstraintAsWritten(
+                            representativeConstraint.archetype)) {
+        Diags.diagnose(existing->source->getLoc(),
+                       diag::same_type_redundancy_here,
+                       existing->source->isDerivedRequirement(),
+                       existing->archetype->getDependentType(
+                                                   genericParams,
+                                                   /*allowUnresolved=*/true),
+                       existing->concreteType);
+      }
     }
   }
 }
@@ -2849,17 +3169,19 @@
 /// the *implicit* same-type constraints.
 ///
 /// \param pa The potential archetype to visit.
-/// \param visited The set of potential archetypes that have already been
-/// seen.
-/// \param found Used to record each potential archetype visited
-static void sameTypeDFS(PotentialArchetype *pa,
-                        SmallPtrSetImpl<PotentialArchetype *> &visited,
-                        SmallVectorImpl<PotentialArchetype *> &found) {
-  // If we've already visited this potential archetype, we're done.
-  if (!visited.insert(pa).second) return;
+/// \param paToComponent A mapping from each potential archetype to its
+/// component number.
+/// \param component The component number we're currently visiting.
+///
+/// \returns the best archetype anchor seen so far.
+static PotentialArchetype *sameTypeDFS(PotentialArchetype *pa,
+                        unsigned component,
+                        llvm::SmallDenseMap<PotentialArchetype *, unsigned>
+                          &paToComponent) {
+  PotentialArchetype *anchor = pa;
 
-  // Note that we've found this potential archetype.
-  found.push_back(pa);
+  // If we've already visited this potential archetype, we're done.
+  if (!paToComponent.insert({pa, component}).second) return anchor;
 
   // Visit its adjacent potential archetypes.
   for (const auto &sameType : pa->getSameTypeConstraints()) {
@@ -2878,19 +3200,29 @@
       break;
     }
 
-    sameTypeDFS(sameType.first, visited, found);
+    sameTypeDFS(sameType.first, component, paToComponent);
+
+    // If this type is better than the anchor, use it for the anchor.
+    if (compareDependentTypes(&sameType.first, &anchor) < 0)
+      anchor = sameType.first;
   }
+
+  return anchor;
 }
 
 namespace {
   /// Describes a component in the (implied) same-type constraint graph.
   struct SameTypeComponent {
     /// The potential archetype that acts as the anchor for this component.
-    PotentialArchetype * anchor;
+    PotentialArchetype *anchor;
 
     /// The (best) requirement source within the component that makes the
     /// potential archetypes in this component equivalent to the concrete type.
-    const RequirementSource * concreteTypeSource;
+    const RequirementSource *concreteTypeSource;
+
+    /// The (best) requirement source within the component that introduces
+    /// the superclass constraint.
+    const RequirementSource *superclassSource;
 
     friend bool operator<(const SameTypeComponent &lhs,
                           const SameTypeComponent &rhs) {
@@ -2937,44 +3269,54 @@
 /// canonical edges connects vertex i to vertex i+1 for i in 0..<size-1.
 static SmallVector<SameTypeComponent, 2> getSameTypeComponents(
                                                      PotentialArchetype *rep) {
-  SmallPtrSet<PotentialArchetype *, 8> visited;
+  llvm::SmallDenseMap<PotentialArchetype *, unsigned> paToComponent;
   SmallVector<SameTypeComponent, 2> components;
   for (auto pa : rep->getEquivalenceClassMembers()) {
     // If we've already seen this potential archetype, there's nothing else to
     // do.
-    if (visited.count(pa) != 0) continue;
+    if (paToComponent.count(pa) != 0) continue;
 
     // Find all of the potential archetypes within this connected component.
-    SmallVector<PotentialArchetype *, 2> component;
-    sameTypeDFS(pa, visited, component);
-
-    // Find the best anchor and concrete type source for this component.
-    PotentialArchetype *anchor = component[0];
-    const RequirementSource *bestConcreteTypeSource = nullptr;
-    auto considerNewSource = [&](const RequirementSource *source) {
-      if (!bestConcreteTypeSource ||
-          source->compare(bestConcreteTypeSource) < 0)
-        bestConcreteTypeSource = source;
-    };
-
-    if (!anchor->getConcreteTypeSourcesAsWritten().empty())
-      bestConcreteTypeSource = anchor->getConcreteTypeSourcesAsWritten()[0];
-
-    for (auto componentPA : ArrayRef<PotentialArchetype *>(component)) {
-      // Update the anchor.
-      if (compareDependentTypes(&componentPA, &anchor) < 0)
-        anchor = componentPA;
-
-      // If this potential archetype has a better concrete type source than
-      // the best we've seen, take it.
-      for (auto source: componentPA->getConcreteTypeSourcesAsWritten())
-        considerNewSource(source);
-    }
+    auto anchor = sameTypeDFS(pa, components.size(), paToComponent);
 
     // Record the anchor.
-    components.push_back({anchor, bestConcreteTypeSource});
+    components.push_back({anchor, nullptr, nullptr});
   }
 
+  // If there is a concrete type, figure out the best concrete type anchor
+  // per component.
+  auto equivClass = rep->getOrCreateEquivalenceClass();
+  for (const auto &concrete : equivClass->concreteTypeConstraints) {
+    // Dig out the component associated with constraint.
+    assert(paToComponent.count(concrete.archetype) > 0);
+    auto &component = components[paToComponent[concrete.archetype]];
+
+    // If it has a better source than we'd seen before for this component,
+    // keep it.
+    auto &bestConcreteTypeSource = component.concreteTypeSource;
+    if (!bestConcreteTypeSource ||
+        concrete.source->compare(bestConcreteTypeSource) < 0)
+      bestConcreteTypeSource = concrete.source;
+  }
+
+  // If there is a superclass and no concrete type, figure out the best
+  // superclass source per component.
+  if (equivClass->superclass && !equivClass->concreteType) {
+    for (const auto &superclass : equivClass->superclassConstraints) {
+    // Dig out the component associated with constraint.
+    assert(paToComponent.count(superclass.archetype) > 0);
+    auto &component = components[paToComponent[superclass.archetype]];
+
+    // If it has a better source than we'd seen before for this component,
+    // keep it.
+    auto &bestSuperclassSource = component.superclassSource;
+    if (!bestSuperclassSource ||
+        superclass.source->compare(bestSuperclassSource) < 0)
+      bestSuperclassSource = superclass.source;
+    }
+  }
+
+  // Sort the components.
   llvm::array_pod_sort(components.begin(), components.end());
 
   return components;
@@ -3047,12 +3389,20 @@
         auto source =
           knownAnchor->concreteTypeSource
             ? knownAnchor->concreteTypeSource
-            : RequirementSource::forAbstract(*this);
+            : RequirementSource::forAbstract(archetype);
 
         f(RequirementKind::SameType, archetype, concreteType, source);
         continue;
       }
 
+      // If we have a superclass, produce a superclass requirement
+      if (Type superclass = rep->getSuperclass()) {
+        f(RequirementKind::Superclass, archetype, superclass,
+          knownAnchor->superclassSource
+            ? knownAnchor->superclassSource
+            : RequirementSource::forAbstract(archetype));
+      }
+
       // If we're at the last anchor in the component, do nothing;
       auto nextAnchor = knownAnchor;
       ++nextAnchor;
@@ -3063,7 +3413,7 @@
         auto otherPA = nextAnchor->anchor;
         deferredSameTypeRequirement = [&f, archetype, otherPA, this] {
           f(RequirementKind::SameType, archetype, otherPA,
-            RequirementSource::forAbstract(*this));
+            RequirementSource::forAbstract(archetype));
         };
       }
     }
@@ -3075,12 +3425,6 @@
     if (archetype != archetype->getArchetypeAnchor(*this))
       continue;
 
-    // If we have a superclass, produce a superclass requirement
-    if (Type superclass = rep->getSuperclass()) {
-      f(RequirementKind::Superclass, archetype, superclass,
-        rep->getSuperclassSource());
-    }
-
     // If we have a layout constraint, produce a layout requirement.
     if (LayoutConstraint Layout = archetype->getLayout()) {
       f(RequirementKind::Layout, archetype, Layout,
@@ -3166,9 +3510,8 @@
   for (auto param : sig->getGenericParams())
     addGenericParameter(param);
 
-  auto source = RequirementSource::forAbstract(*this);
   for (auto &reqt : sig->getRequirements()) {
-    addRequirement(reqt, source);
+    addRequirement(reqt, FloatingRequirementSource::forAbstract());
   }
 }
 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 521fcb2..659ad44 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -20,6 +20,7 @@
 #include "swift/AST/TypeWalker.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/AST.h"
+#include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/LazyResolver.h"
 #include "swift/AST/Module.h"
 #include "swift/AST/SubstitutionMap.h"
@@ -52,7 +53,7 @@
 
 bool TypeLoc::isError() const {
   assert(wasValidated() && "Type not yet validated");
-  return getType()->hasError() || getType()->getCanonicalType()->hasError();
+  return getType()->hasError();
 }
 
 SourceRange TypeLoc::getSourceRange() const {
@@ -282,111 +283,17 @@
 }
 
 bool TypeBase::isSpecialized() {
-  CanType CT = getCanonicalType();
-  if (CT.getPointer() != this)
-    return CT->isSpecialized();
+  Type t = getCanonicalType();
 
-  return CT.findIf([](Type type) -> bool {
-    return isa<BoundGenericType>(type.getPointer());
-  });
-}
-
-bool TypeBase::isUnspecializedGeneric() {
-  CanType CT = getCanonicalType();
-  if (CT.getPointer() != this)
-    return CT->isUnspecializedGeneric();
-
-  switch (getKind()) {
-#define SUGARED_TYPE(id, parent) case TypeKind::id:
-#define TYPE(id, parent)
-#include "swift/AST/TypeNodes.def"
-    llvm_unreachable("we're only working with CanType's here");
-
-  case TypeKind::Error:
-  case TypeKind::Unresolved:
-  case TypeKind::TypeVariable:
-    llvm_unreachable("querying invalid type");
-
-  case TypeKind::UnboundGeneric:
-    return true;
-
-  case TypeKind::BoundGenericClass:
-  case TypeKind::BoundGenericEnum:
-  case TypeKind::BoundGenericStruct:
-    return true;
-
-  case TypeKind::Function: {
-    auto funcTy = cast<AnyFunctionType>(this);
-    return funcTy->getInput()->isUnspecializedGeneric() ||
-           funcTy->getResult()->isUnspecializedGeneric();
+  for (;;) {
+    if (!t || !t->getAnyNominal())
+      return false;
+    if (t->is<BoundGenericType>())
+      return true;
+    t = t->getNominalParent();
   }
 
-  case TypeKind::GenericFunction:
-    return true;
-
-  case TypeKind::Class:
-  case TypeKind::Struct:
-  case TypeKind::Enum:
-    if (auto parentTy = cast<NominalType>(this)->getParent())
-      return parentTy->isUnspecializedGeneric();
-    return false;
-
-  case TypeKind::ExistentialMetatype:
-  case TypeKind::Metatype:
-    return cast<AnyMetatypeType>(this)->getInstanceType()
-             ->isUnspecializedGeneric();
-
-  case TypeKind::UnownedStorage:
-  case TypeKind::UnmanagedStorage:
-  case TypeKind::WeakStorage:
-    return cast<ReferenceStorageType>(this)->getReferentType()
-             ->isUnspecializedGeneric();
-
-  case TypeKind::LValue:
-    return cast<LValueType>(this)->getObjectType()->isUnspecializedGeneric();
-  case TypeKind::InOut:
-    return cast<InOutType>(this)->getObjectType()->isUnspecializedGeneric();
-
-  case TypeKind::Tuple: {
-    auto tupleTy = cast<TupleType>(this);
-    for (auto &Elt : tupleTy->getElements())
-      if (Elt.getType()->isUnspecializedGeneric())
-        return true;
-
-    return false;
-  }
-
-  case TypeKind::Archetype:
-  case TypeKind::BuiltinFloat:
-  case TypeKind::BuiltinInteger:
-  case TypeKind::BuiltinUnknownObject:
-  case TypeKind::BuiltinNativeObject:
-  case TypeKind::BuiltinBridgeObject:
-  case TypeKind::BuiltinRawPointer:
-  case TypeKind::BuiltinUnsafeValueBuffer:
-  case TypeKind::BuiltinVector:
-  case TypeKind::Module:
-  case TypeKind::DynamicSelf:
-  case TypeKind::Protocol:
-  case TypeKind::ProtocolComposition:
-  case TypeKind::SILFunction:
-    return false;
-
-  case TypeKind::GenericTypeParam:
-  case TypeKind::DependentMember:
-    return false;
-      
-  case TypeKind::SILBlockStorage:
-    return cast<SILBlockStorageType>(this)->getCaptureType()
-        ->isUnspecializedGeneric();
-  case TypeKind::SILBox:
-    for (auto &arg : cast<SILBoxType>(this)->getGenericArgs()) {
-      if (arg.getReplacement()->isUnspecializedGeneric())
-        return true;
-    }
-    return false;
-  }
-  llvm_unreachable("bad TypeKind");
+  return false;
 }
 
 bool TypeBase::hasOpenedExistential(ArchetypeType *opened) {
@@ -543,44 +450,16 @@
   return false;
 }
 
-namespace {
-class GetRValueTypeVisitor : public TypeVisitor<GetRValueTypeVisitor, Type> {
-public:
-  Type visitLValueType(LValueType *lvt) {
-    // Look through lvalue types.
-    assert(!lvt->getObjectType()->isLValueType()
-           && "unexpected nested lvalue");
-    return lvt->getObjectType();
-  }
-  
-  Type visitTupleType(TupleType *tt) {
-    // Look through lvalues in tuples.
-    SmallVector<TupleTypeElt, 4> elts;
-    for (auto &elt : tt->getElements()) {
-      elts.push_back(elt.getWithType(visit(elt.getType())));
-    }
-    return TupleType::get(elts, tt->getASTContext());
-  }
-  
-  Type visitParenType(ParenType *pt) {
-    return ParenType::get(pt->getASTContext(), visit(pt->getUnderlyingType()));
-  }
-
-  Type visitType(TypeBase *t) {
-    // Other types should not structurally contain lvalues.
-    assert(!t->isLValueType()
-           && "unexpected structural lvalue");
-    return t;
-  }
-};
-} // end anonymous namespace
-
 Type TypeBase::getRValueType() {
   // If the type is not an lvalue, this is a no-op.
   if (!isLValueType())
     return this;
-  
-  return GetRValueTypeVisitor().visit(this);
+
+  return Type(this).transform([](Type t) -> Type {
+      if (auto *lvalueTy = dyn_cast<LValueType>(t.getPointer()))
+        return lvalueTy->getObjectType();
+      return t;
+    });
 }
 
 Type TypeBase::getOptionalObjectType() {
@@ -661,24 +540,6 @@
   return type;
 }
 
-ClassDecl *CanType::getClassBoundImpl(CanType type) {
-  if (auto classTy = dyn_cast<ClassType>(type))
-    return classTy->getDecl();
-
-  if (auto boundTy = dyn_cast<BoundGenericClassType>(type))
-    return boundTy->getDecl();
-
-  if (auto archetypeTy = dyn_cast<ArchetypeType>(type)) {
-    assert(archetypeTy->requiresClass());
-    if (Type supertype = archetypeTy->getSuperclass()) {
-      return supertype->getClassOrBoundGenericClass();
-    }
-    return nullptr;
-  }
-
-  llvm_unreachable("class has no class bound!");
-}
-
 LayoutConstraint CanType::getLayoutConstraint() const {
   if (auto archetypeTy = dyn_cast<ArchetypeType>(*this)) {
     return archetypeTy->getLayoutConstraint();
@@ -3240,7 +3101,7 @@
 }
 
 SubstitutionMap TypeBase::getContextSubstitutionMap(
-  ModuleDecl *module, const DeclContext *dc) {
+    ModuleDecl *module, const DeclContext *dc) {
   auto *genericSig = dc->getGenericSignatureOfContext();
   if (genericSig == nullptr)
     return SubstitutionMap();
@@ -3249,7 +3110,9 @@
       LookUpConformanceInModule(module));
 }
 
-TypeSubstitutionMap TypeBase::getMemberSubstitutions(const ValueDecl *member) {
+TypeSubstitutionMap TypeBase::getMemberSubstitutions(
+    const ValueDecl *member,
+    GenericEnvironment *genericEnv) {
   auto *memberDC = member->getDeclContext();
 
   TypeSubstitutionMap substitutions;
@@ -3262,14 +3125,18 @@
   // We need this since code completion and diagnostics want to be able
   // to call getTypeOfMember() with functions and nested types.
   if (isa<AbstractFunctionDecl>(member) ||
-      isa<GenericTypeDecl>(member)) {
+      isa<GenericTypeDecl>(member) ||
+      isa<SubscriptDecl>(member)) {
     auto *innerDC = member->getInnermostDeclContext();
     if (innerDC->isInnermostContextGeneric()) {
       auto *sig = innerDC->getGenericSignatureOfContext();
       for (auto param : sig->getInnermostGenericParams()) {
         auto *genericParam = param->getCanonicalType()
             ->castTo<GenericTypeParamType>();
-        substitutions[genericParam] = param;
+        substitutions[genericParam] =
+          (genericEnv
+           ? genericEnv->mapTypeIntoContext(param)
+           : param);
       }
     }
   }
@@ -3278,13 +3145,15 @@
 }
 
 SubstitutionMap TypeBase::getMemberSubstitutionMap(
-  ModuleDecl *module, const ValueDecl *member) {
+    ModuleDecl *module, const ValueDecl *member,
+    GenericEnvironment *genericEnv) {
   auto *genericSig = member->getInnermostDeclContext()
       ->getGenericSignatureOfContext();
   if (genericSig == nullptr)
     return SubstitutionMap();
+  auto subs = getMemberSubstitutions(member, genericEnv);
   return genericSig->getSubstitutionMap(
-      QueryTypeSubstitutionMap{getMemberSubstitutions(member)},
+      QueryTypeSubstitutionMap{subs},
       LookUpConformanceInModule(module));
 }
 
diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp
index d568648..70cb225 100644
--- a/lib/AST/USRGeneration.cpp
+++ b/lib/AST/USRGeneration.cpp
@@ -57,6 +57,10 @@
     clang::index::generateUSRForObjCProtocol(ObjCName, OS);
   } else if (isa<VarDecl>(D)) {
     clang::index::generateUSRForObjCProperty(ObjCName, D->isStatic(), OS);
+  } else if (isa<ConstructorDecl>(D)) {
+    // init() is a class member in Swift, but an instance method in ObjC.
+    clang::index::generateUSRForObjCMethod(ObjCName, /*isInstanceMember=*/true,
+                                           OS);
   } else if (isa<AbstractFunctionDecl>(D)) {
     clang::index::generateUSRForObjCMethod(ObjCName, D->isInstanceMember(), OS);
   } else if (isa<EnumDecl>(D)) {
diff --git a/lib/Basic/Demangle.cpp b/lib/Basic/Demangle.cpp
index a4c71a9..281883f 100644
--- a/lib/Basic/Demangle.cpp
+++ b/lib/Basic/Demangle.cpp
@@ -628,11 +628,13 @@
 
 /// TODO: This is an atrocity. Come up with a shorter name.
 #define FUNCSIGSPEC_CREATE_PARAM_KIND(kind)                                    \
-  Factory.createNode(Node::Kind::FunctionSignatureSpecializationParamKind,    \
-                      unsigned(FunctionSigSpecializationParamKind::kind))
+  Factory.createNode(                                                          \
+      Node::Kind::FunctionSignatureSpecializationParamKind,                    \
+      Node::IndexType(FunctionSigSpecializationParamKind::kind))
+
 #define FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(payload)                              \
-  Factory.createNode(Node::Kind::FunctionSignatureSpecializationParamPayload, \
-                      payload)
+  Factory.createNode(Node::Kind::FunctionSignatureSpecializationParamPayload,  \
+                     payload)
 
   bool demangleFuncSigSpecializationConstantProp(NodePointer parent) {
     // Then figure out what was actually constant propagated. First check if
@@ -3413,7 +3415,8 @@
   case Node::Kind::ReabstractionThunk:
   case Node::Kind::ReabstractionThunkHelper: {
     if (Options.ShortenThunk) {
-      Printer << "thunk";
+      Printer << "thunk for ";
+      print(pointer->getChild(pointer->getNumChildren() - 2));
       return;
     }
     Printer << "reabstraction thunk ";
diff --git a/lib/Basic/Demangler.cpp b/lib/Basic/Demangler.cpp
index 734af69..70ded11 100644
--- a/lib/Basic/Demangler.cpp
+++ b/lib/Basic/Demangler.cpp
@@ -1412,19 +1412,24 @@
       // The parameters will be added later.
       return addChild(Param, createNode(
         Node::Kind::FunctionSignatureSpecializationParamKind,
-        unsigned(FunctionSigSpecializationParamKind::ClosureProp)));
+        uint64_t(FunctionSigSpecializationParamKind::ClosureProp)));
     case 'p': {
       switch (nextChar()) {
         case 'f':
           // Consumes an identifier parameter, which will be added later.
-          return addChild(Param, createNode(
-            Node::Kind::FunctionSignatureSpecializationParamKind,
-            unsigned(FunctionSigSpecializationParamKind::ConstantPropFunction)));
+          return addChild(
+              Param,
+              createNode(Node::Kind::FunctionSignatureSpecializationParamKind,
+                         Node::IndexType(FunctionSigSpecializationParamKind::
+                                             ConstantPropFunction)));
         case 'g':
           // Consumes an identifier parameter, which will be added later.
-          return addChild(Param, createNode(
-            Node::Kind::FunctionSignatureSpecializationParamKind,
-            unsigned(FunctionSigSpecializationParamKind::ConstantPropGlobal)));
+          return addChild(
+              Param,
+              createNode(
+                  Node::Kind::FunctionSignatureSpecializationParamKind,
+                  Node::IndexType(
+                      FunctionSigSpecializationParamKind::ConstantPropGlobal)));
         case 'i':
           return addFuncSpecParamNumber(Param,
                     FunctionSigSpecializationParamKind::ConstantPropInteger);
@@ -1441,10 +1446,12 @@
             case 'c': Encoding = "objc"; break;
             default: return nullptr;
           }
-          addChild(Param, createNode(
-                  Node::Kind::FunctionSignatureSpecializationParamKind,
-                  unsigned(swift::Demangle::FunctionSigSpecializationParamKind::
-                           ConstantPropString)));
+          addChild(Param,
+                   createNode(
+                       Node::Kind::FunctionSignatureSpecializationParamKind,
+                       Node::IndexType(
+                           swift::Demangle::FunctionSigSpecializationParamKind::
+                               ConstantPropString)));
           return addChild(Param, createNode(
                   Node::Kind::FunctionSignatureSpecializationParamPayload,
                   Encoding));
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index 19efc63..93ec8a9 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -52,6 +52,11 @@
   "big"
 };
 
+static const StringRef SupportedConditionalCompilationRuntimes[] = {
+  "_ObjC",
+  "_Native",
+};
+
 template <size_t N>
 bool contains(const StringRef (&Array)[N], const StringRef &V,
               std::vector<StringRef> &suggestions) {
@@ -75,36 +80,31 @@
   return false;
 }
 
-bool LangOptions::checkPlatformConditionOS(
-  StringRef &OSName, std::vector<StringRef> &suggestions) {
-  if (OSName == "macOS")
-    OSName = "OSX";
-  return contains(SupportedConditionalCompilationOSs,
-                  OSName,
-                  suggestions);
-}
-
-bool
-LangOptions::isPlatformConditionArchSupported(
-  StringRef ArchName, std::vector<StringRef> &suggestions) {
-  return contains(SupportedConditionalCompilationArches,
-                  ArchName,
-                  suggestions);
-}
-
-bool
-LangOptions::isPlatformConditionEndiannessSupported(
-  StringRef Endianness, std::vector<StringRef> &suggestions) {
-  return contains(SupportedConditionalCompilationEndianness,
-                  Endianness,
-                  suggestions);
+bool LangOptions::
+checkPlatformConditionSupported(PlatformConditionKind Kind, StringRef Value,
+                                std::vector<StringRef> &suggestions) {
+  switch (Kind) {
+  case PlatformConditionKind::OS:
+    return contains(SupportedConditionalCompilationOSs, Value,
+                    suggestions);
+  case PlatformConditionKind::Arch:
+    return contains(SupportedConditionalCompilationArches, Value,
+                    suggestions);
+  case PlatformConditionKind::Endianness:
+    return contains(SupportedConditionalCompilationEndianness, Value,
+                    suggestions);
+  case PlatformConditionKind::Runtime:
+    return contains(SupportedConditionalCompilationRuntimes, Value,
+                    suggestions);
+  }
+  llvm_unreachable("Unhandled enum value");
 }
 
 StringRef
-LangOptions::getPlatformConditionValue(StringRef Name) const {
+LangOptions::getPlatformConditionValue(PlatformConditionKind Kind) const {
   // Last one wins.
   for (auto &Opt : reversed(PlatformConditionValues)) {
-    if (Opt.first == Name)
+    if (Opt.first == Kind)
       return Opt.second;
   }
   return StringRef();
@@ -141,23 +141,23 @@
 
   // Set the "os" platform condition.
   if (Target.isMacOSX())
-    addPlatformConditionValue("os", "OSX");
+    addPlatformConditionValue(PlatformConditionKind::OS, "OSX");
   else if (triple.isTvOS())
-    addPlatformConditionValue("os", "tvOS");
+    addPlatformConditionValue(PlatformConditionKind::OS, "tvOS");
   else if (triple.isWatchOS())
-    addPlatformConditionValue("os", "watchOS");
+    addPlatformConditionValue(PlatformConditionKind::OS, "watchOS");
   else if (triple.isiOS())
-    addPlatformConditionValue("os", "iOS");
+    addPlatformConditionValue(PlatformConditionKind::OS, "iOS");
   else if (triple.isAndroid())
-    addPlatformConditionValue("os", "Android");
+    addPlatformConditionValue(PlatformConditionKind::OS, "Android");
   else if (triple.isOSLinux())
-    addPlatformConditionValue("os", "Linux");
+    addPlatformConditionValue(PlatformConditionKind::OS, "Linux");
   else if (triple.isOSFreeBSD())
-    addPlatformConditionValue("os", "FreeBSD");
+    addPlatformConditionValue(PlatformConditionKind::OS, "FreeBSD");
   else if (triple.isOSWindows())
-    addPlatformConditionValue("os", "Windows");
+    addPlatformConditionValue(PlatformConditionKind::OS, "Windows");
   else if (triple.isPS4())
-    addPlatformConditionValue("os", "PS4");
+    addPlatformConditionValue(PlatformConditionKind::OS, "PS4");
   else
     UnsupportedOS = true;
 
@@ -167,25 +167,25 @@
   switch (Target.getArch()) {
   case llvm::Triple::ArchType::arm:
   case llvm::Triple::ArchType::thumb:
-    addPlatformConditionValue("arch", "arm");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "arm");
     break;
   case llvm::Triple::ArchType::aarch64:
-    addPlatformConditionValue("arch", "arm64");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "arm64");
     break;
   case llvm::Triple::ArchType::ppc64:
-    addPlatformConditionValue("arch", "powerpc64");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "powerpc64");
     break;
   case llvm::Triple::ArchType::ppc64le:
-    addPlatformConditionValue("arch", "powerpc64le");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "powerpc64le");
     break;
   case llvm::Triple::ArchType::x86:
-    addPlatformConditionValue("arch", "i386");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "i386");
     break;
   case llvm::Triple::ArchType::x86_64:
-    addPlatformConditionValue("arch", "x86_64");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "x86_64");
     break;
   case llvm::Triple::ArchType::systemz:
-    addPlatformConditionValue("arch", "s390x");
+    addPlatformConditionValue(PlatformConditionKind::Arch, "s390x");
     break;
   default:
     UnsupportedArch = true;
@@ -198,25 +198,25 @@
   switch (Target.getArch()) {
   case llvm::Triple::ArchType::arm:
   case llvm::Triple::ArchType::thumb:
-    addPlatformConditionValue("_endian", "little");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "little");
     break;
   case llvm::Triple::ArchType::aarch64:
-    addPlatformConditionValue("_endian", "little");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "little");
     break;
   case llvm::Triple::ArchType::ppc64:
-    addPlatformConditionValue("_endian", "big");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "big");
     break;
   case llvm::Triple::ArchType::ppc64le:
-    addPlatformConditionValue("_endian", "little");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "little");
     break;
   case llvm::Triple::ArchType::x86:
-    addPlatformConditionValue("_endian", "little");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "little");
     break;
   case llvm::Triple::ArchType::x86_64:
-    addPlatformConditionValue("_endian", "little");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "little");
     break;
   case llvm::Triple::ArchType::systemz:
-    addPlatformConditionValue("_endian", "big");
+    addPlatformConditionValue(PlatformConditionKind::Endianness, "big");
     break;
   default:
     llvm_unreachable("undefined architecture endianness");
@@ -224,9 +224,9 @@
 
   // Set the "runtime" platform condition.
   if (EnableObjCInterop)
-    addPlatformConditionValue("_runtime", "_ObjC");
+    addPlatformConditionValue(PlatformConditionKind::Runtime, "_ObjC");
   else
-    addPlatformConditionValue("_runtime", "_Native");
+    addPlatformConditionValue(PlatformConditionKind::Runtime, "_Native");
 
   // If you add anything to this list, change the default size of
   // PlatformConditionValues to not require an extra allocation
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index 09b43dc..29b7d10 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -83,9 +83,7 @@
     void handleImport(const clang::Module *imported) {
       if (!imported)
         return;
-      ModuleDecl *nativeImported = Impl.finishLoadingClangModule(Importer, imported,
-        /*preferAdapter=*/true);
-      Impl.ImportedHeaderExports.push_back({ /*filter=*/{}, nativeImported });
+      Impl.DeferredHeaderImports.push_back(imported);
     }
 
     void InclusionDirective(clang::SourceLocation HashLoc,
@@ -835,7 +833,7 @@
   // Set up the imported header module.
   auto *importedHeaderModule = ModuleDecl::create(ctx.getIdentifier("__ObjC"), ctx);
   importer->Impl.ImportedHeaderUnit =
-    new (ctx) ClangModuleUnit(*importedHeaderModule, *importer, nullptr);
+    new (ctx) ClangModuleUnit(*importedHeaderModule, importer->Impl, nullptr);
   importedHeaderModule->addFile(*importer->Impl.ImportedHeaderUnit);
 
   importer->Impl.IsReadingBridgingPCH = false;
@@ -963,6 +961,9 @@
   // Add any defined macros to the bridging header lookup table.
   addMacrosToLookupTable(*BridgingHeaderLookupTable, getNameImporter());
 
+  // Finish loading any extra modules that were (transitively) imported.
+  handleDeferredImports();
+
   // Wrap all Clang imports under a Swift import decl.
   for (auto &Import : BridgeHeaderTopLevelImports) {
     if (auto *ClangImport = Import.dyn_cast<clang::ImportDecl*>()) {
@@ -1008,16 +1009,11 @@
                                          bool trackParsedSymbols,
                                          bool implicitImport) {
   if (llvm::sys::path::extension(header).endswith(PCH_EXTENSION)) {
-    // We already imported this with -include-pch above, so we should have
-    // collected a bunch of PCH-encoded module imports that we need to
-    // replay to the HeaderImportCallbacks for processing.
     Impl.ImportedHeaderOwners.push_back(adapter);
-    clang::ASTReader &R = *Impl.Instance->getModuleManager();
-    HeaderImportCallbacks CB(*this, Impl);
-    for (auto ID : Impl.PCHImportedSubmodules) {
-      CB.handleImport(R.getSubmodule(ID));
-    }
-    Impl.PCHImportedSubmodules.clear();
+    // We already imported this with -include-pch above, so we should have
+    // collected a bunch of PCH-encoded module imports that we just need to
+    // replay in handleDeferredImports.
+    Impl.handleDeferredImports();
     return false;
   }
   clang::FileManager &fileManager = Impl.Instance->getFileManager();
@@ -1037,7 +1033,6 @@
     llvm::MemoryBuffer::getMemBufferCopy(
       importLine, Implementation::bridgingHeaderBufferName)
   };
-
   return Impl.importHeader(adapter, header, diagLoc, trackParsedSymbols,
                            std::move(sourceBuffer), implicitImport);
 }
@@ -1234,12 +1229,11 @@
   if (!clangModule)
     return nullptr;
 
-  return Impl.finishLoadingClangModule(*this, clangModule,
+  return Impl.finishLoadingClangModule(clangModule,
                                        /*preferAdapter=*/false);
 }
 
 ModuleDecl *ClangImporter::Implementation::finishLoadingClangModule(
-    ClangImporter &owner,
     const clang::Module *clangModule,
     bool findAdapter) {
   assert(clangModule);
@@ -1269,7 +1263,7 @@
     result->setTestingEnabled();
 
     wrapperUnit =
-      new (SwiftContext) ClangModuleUnit(*result, owner, clangModule);
+      new (SwiftContext) ClangModuleUnit(*result, *this, clangModule);
     result->addFile(*wrapperUnit);
     cacheEntry.setPointerAndInt(wrapperUnit, true);
 
@@ -1280,7 +1274,7 @@
   }
 
   if (clangModule->isSubModule()) {
-    finishLoadingClangModule(owner, clangModule->getTopLevelModule(), true);
+    finishLoadingClangModule(clangModule->getTopLevelModule(), true);
   } else {
     ModuleDecl *&loaded = SwiftContext.LoadedModules[result->getName()];
     if (!loaded)
@@ -1294,6 +1288,25 @@
   return result;
 }
 
+// Run through the set of deferred imports -- either those referenced by
+// submodule ID from a bridging PCH, or those already loaded as clang::Modules
+// in response to an import directive in a bridging header -- and call
+// finishLoadingClangModule on each.
+void ClangImporter::Implementation::handleDeferredImports()
+{
+  clang::ASTReader &R = *Instance->getModuleManager();
+  for (clang::serialization::SubmoduleID ID : PCHImportedSubmodules) {
+    DeferredHeaderImports.push_back(R.getSubmodule(ID));
+  }
+  PCHImportedSubmodules.clear();
+  for (const clang::Module *M : DeferredHeaderImports) {
+    ModuleDecl *nativeImported =
+      finishLoadingClangModule(M, /*preferAdapter=*/true);
+    ImportedHeaderExports.push_back({ /*filter=*/{}, nativeImported });
+  }
+  DeferredHeaderImports.clear();
+}
+
 ModuleDecl *ClangImporter::getImportedHeaderModule() const {
   return Impl.ImportedHeaderUnit->getParentModule();
 }
@@ -1381,7 +1394,6 @@
 }
 
 ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule(
-    ClangImporter &importer,
     const clang::Module *underlying) {
   auto &cacheEntry = ModuleWrappers[underlying];
   if (ClangModuleUnit *cached = cacheEntry.getPointer())
@@ -1393,7 +1405,7 @@
   // Silence error messages about testably importing a Clang module.
   wrapper->setTestingEnabled();
 
-  auto file = new (SwiftContext) ClangModuleUnit(*wrapper, importer,
+  auto file = new (SwiftContext) ClangModuleUnit(*wrapper, *this,
                                                  underlying);
   wrapper->addFile(*file);
   cacheEntry.setPointer(file);
@@ -1414,9 +1426,7 @@
   // ClangModuleUnit.
   auto *M = maybeModule.getValue()->getTopLevelModule();
 
-  auto &importer =
-    static_cast<ClangImporter &>(*SwiftContext.getClangModuleLoader());
-  return getWrapperForModule(importer, M);
+  return getWrapperForModule(M);
 }
 
 #pragma mark Source locations
@@ -1988,9 +1998,9 @@
   }
 
   // Find the corresponding lookup table.
-  if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) {
+  if (auto lookupTable = owner.findLookupTable(clangModule)) {
     // Search it.
-    owner.Impl.lookupVisibleDecls(*lookupTable, *actualConsumer);
+    owner.lookupVisibleDecls(*lookupTable, *actualConsumer);
   }
 }
 
@@ -2021,14 +2031,14 @@
     actualConsumer = &blacklistConsumer;
 
   // Find the corresponding lookup table.
-  if (auto lookupTable = owner.Impl.findLookupTable(topLevelModule)) {
+  if (auto lookupTable = owner.findLookupTable(topLevelModule)) {
     // Search it.
-    owner.Impl.lookupVisibleDecls(*lookupTable, *actualConsumer);
+    owner.lookupVisibleDecls(*lookupTable, *actualConsumer);
 
     // Add the extensions produced by importing categories.
     for (auto category : lookupTable->categories()) {
       if (auto extension = cast_or_null<ExtensionDecl>(
-              owner.Impl.importDecl(category, owner.Impl.CurrentVersion)))
+              owner.importDecl(category, owner.CurrentVersion)))
         results.push_back(extension);
     }
 
@@ -2040,7 +2050,7 @@
     for (auto entry : lookupTable->allGlobalsAsMembers()) {
       auto decl = entry.get<clang::NamedDecl *>();
       auto importedDecl =
-          owner.Impl.importDecl(decl, owner.Impl.CurrentVersion);
+          owner.importDecl(decl, owner.CurrentVersion);
       if (!importedDecl) continue;
 
       auto ext = dyn_cast<ExtensionDecl>(importedDecl->getDeclContext());
@@ -2125,9 +2135,9 @@
   }
 
   // Find the corresponding lookup table.
-  if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) {
+  if (auto lookupTable = owner.findLookupTable(clangModule)) {
     // Search it.
-    owner.Impl.lookupValue(*lookupTable, name, *consumer);
+    owner.lookupValue(*lookupTable, name, *consumer);
   }
 }
 
@@ -2265,9 +2275,9 @@
   VectorDeclConsumer consumer(results);
 
   // Find the corresponding lookup table.
-  if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) {
+  if (auto lookupTable = owner.findLookupTable(clangModule)) {
     // Search it.
-    owner.Impl.lookupObjCMembers(*lookupTable, name, consumer);
+    owner.lookupObjCMembers(*lookupTable, name, consumer);
   }
 }
 
@@ -2278,9 +2288,9 @@
     return;
 
   // Find the corresponding lookup table.
-  if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) {
+  if (auto lookupTable = owner.findLookupTable(clangModule)) {
     // Search it.
-    owner.Impl.lookupAllObjCMembers(*lookupTable, consumer);
+    owner.lookupAllObjCMembers(*lookupTable, consumer);
   }
 }
 
@@ -2292,12 +2302,12 @@
     return;
 
   // Map the selector into a Clang selector.
-  auto clangSelector = owner.Impl.exportSelector(selector);
+  auto clangSelector = owner.exportSelector(selector);
   if (clangSelector.isNull()) return;
 
   // Collect all of the Objective-C methods with this selector.
   SmallVector<clang::ObjCMethodDecl *, 8> objcMethods;
-  auto &clangSema = owner.Impl.getClangSema();
+  auto &clangSema = owner.getClangSema();
   clangSema.CollectMultipleMethodsInGlobalPool(clangSelector,
                                                objcMethods,
                                                /*InstanceFirst=*/true,
@@ -2319,23 +2329,23 @@
 
     // If we found a property accessor, import the property.
     if (objcMethod->isPropertyAccessor())
-      (void)owner.Impl.importDecl(objcMethod->findPropertyDecl(true),
-                                  owner.Impl.CurrentVersion);
+      (void)owner.importDecl(objcMethod->findPropertyDecl(true),
+                             owner.CurrentVersion);
 
     // Import it.
     // FIXME: Retrying a failed import works around recursion bugs in the Clang
     // importer.
     auto imported =
-        owner.Impl.importDecl(objcMethod, owner.Impl.CurrentVersion);
+        owner.importDecl(objcMethod, owner.CurrentVersion);
     if (!imported)
-      imported = owner.Impl.importDecl(objcMethod, owner.Impl.CurrentVersion);
+      imported = owner.importDecl(objcMethod, owner.CurrentVersion);
     if (!imported) continue;
 
     if (auto func = dyn_cast<AbstractFunctionDecl>(imported))
       results.push_back(func);
 
     // If there is an alternate declaration, also look at it.
-    for (auto alternate : owner.Impl.getAlternateDecls(imported)) {
+    for (auto alternate : owner.getAlternateDecls(imported)) {
       if (auto func = dyn_cast<AbstractFunctionDecl>(alternate))
         results.push_back(func);
     }
@@ -2435,7 +2445,8 @@
 // ClangModule Implementation
 //===----------------------------------------------------------------------===//
 
-ClangModuleUnit::ClangModuleUnit(ModuleDecl &M, ClangImporter &owner,
+ClangModuleUnit::ClangModuleUnit(ModuleDecl &M,
+                                 ClangImporter::Implementation &owner,
                                  const clang::Module *clangModule)
   : LoadedFile(FileUnitKind::ClangModule, M), owner(owner),
     clangModule(clangModule) {
@@ -2468,7 +2479,7 @@
   if (!isTopLevel()) {
     // FIXME: Is this correct for submodules?
     auto topLevel = clangModule->getTopLevelModule();
-    auto wrapper = owner.Impl.getWrapperForModule(owner, topLevel);
+    auto wrapper = owner.getWrapperForModule(topLevel);
     return wrapper->getAdapterModule();
   }
 
@@ -2504,8 +2515,8 @@
   if (!clangModule) {
     // This is the special "imported headers" module.
     if (filter != ModuleDecl::ImportFilter::Private) {
-      imports.append(owner.Impl.ImportedHeaderExports.begin(),
-                     owner.Impl.ImportedHeaderExports.end());
+      imports.append(owner.ImportedHeaderExports.begin(),
+                     owner.ImportedHeaderExports.end());
     }
     return;
   }
@@ -2541,7 +2552,7 @@
   }
 
   for (auto importMod : imported) {
-    auto wrapper = owner.Impl.getWrapperForModule(owner, importMod);
+    auto wrapper = owner.getWrapperForModule(importMod);
 
     auto actualMod = wrapper->getAdapterModule();
     if (!actualMod) {
@@ -2550,8 +2561,7 @@
       auto importTopLevel = importMod->getTopLevelModule();
       if (importTopLevel != importMod &&
           importTopLevel != clangModule->getTopLevelModule()) {
-        auto topLevelWrapper = owner.Impl.getWrapperForModule(owner,
-                                                              importTopLevel);
+        auto topLevelWrapper = owner.getWrapperForModule(importTopLevel);
         imports.push_back({ ModuleDecl::AccessPathTy(),
                             topLevelWrapper->getParentModule() });
       }
@@ -2570,8 +2580,8 @@
 
   if (!clangModule) {
     // This is the special "imported headers" module.
-    imports.append(owner.Impl.ImportedHeaderExports.begin(),
-                   owner.Impl.ImportedHeaderExports.end());
+    imports.append(owner.ImportedHeaderExports.begin(),
+                   owner.ImportedHeaderExports.end());
     return;
   }
 
@@ -2608,7 +2618,7 @@
 
       // Don't continue looking through submodules of modules that have
       // overlays. The overlay might shadow things.
-      auto wrapper = owner.Impl.getWrapperForModule(owner, nextTopLevel);
+      auto wrapper = owner.getWrapperForModule(nextTopLevel);
       if (wrapper->getAdapterModule())
         continue;
     }
@@ -2626,7 +2636,7 @@
   }
 
   for (auto importMod : topLevelImported) {
-    auto wrapper = owner.Impl.getWrapperForModule(owner, importMod);
+    auto wrapper = owner.getWrapperForModule(importMod);
 
     auto actualMod = wrapper->getAdapterModule();
     if (!actualMod || actualMod == topLevelAdapter)
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index bcacb55..6fcdebc 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -2041,10 +2041,11 @@
       decl->setImplicit();
     }
 
-    /// Create a typealias for the Swift 2 name of a Clang type declaration.
-    Decl *importSwift2TypeAlias(const clang::NamedDecl *decl,
-                                ImportedName swift2Name,
-                                ImportedName correctSwiftName);
+    /// Create a typealias for the name of a Clang type declaration in an
+    /// alternate version of Swift.
+    Decl *importCompatibilityTypeAlias(const clang::NamedDecl *decl,
+                                       ImportedName compatibilityName,
+                                       ImportedName correctSwiftName);
 
     /// Create a swift_newtype struct corresponding to a typedef. Returns
     /// nullptr if unable.
@@ -2062,7 +2063,8 @@
       // If we've been asked to produce a Swift 2 stub, handle it via a
       // typealias.
       if (correctSwiftName)
-        return importSwift2TypeAlias(Decl, importedName, *correctSwiftName);
+        return importCompatibilityTypeAlias(Decl, importedName,
+                                            *correctSwiftName);
 
       Type SwiftType;
       if (Decl->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
@@ -2277,7 +2279,8 @@
       // If we've been asked to produce a Swift 2 stub, handle it via a
       // typealias.
       if (correctSwiftName)
-        return importSwift2TypeAlias(decl, importedName, *correctSwiftName);
+        return importCompatibilityTypeAlias(decl, importedName,
+                                            *correctSwiftName);
 
       auto dc =
           Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
@@ -2693,7 +2696,8 @@
       // If we've been asked to produce a Swift 2 stub, handle it via a
       // typealias.
       if (correctSwiftName)
-        return importSwift2TypeAlias(decl, importedName, *correctSwiftName);
+        return importCompatibilityTypeAlias(decl, importedName,
+                                            *correctSwiftName);
 
       auto dc =
           Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
@@ -3873,7 +3877,7 @@
       SmallVector<TypeLoc, 4> inheritedTypes;
       importObjCProtocols(result, decl->getReferencedProtocols(),
                           inheritedTypes);
-      result->setValidated();
+      result->setValidationStarted();
       result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
       result->setCheckedInheritanceClause();
       result->setMemberLoader(&Impl, 0);
@@ -3957,7 +3961,8 @@
       // If we've been asked to produce a Swift 2 stub, handle it via a
       // typealias.
       if (correctSwiftName)
-        return importSwift2TypeAlias(decl, importedName, *correctSwiftName);
+        return importCompatibilityTypeAlias(decl, importedName,
+                                            *correctSwiftName);
 
       Identifier name = importedName.getDeclName().getBaseName();
 
@@ -4092,7 +4097,8 @@
       // If we've been asked to produce a Swift 2 stub, handle it via a
       // typealias.
       if (correctSwiftName)
-        return importSwift2TypeAlias(decl, importedName, *correctSwiftName);
+        return importCompatibilityTypeAlias(decl, importedName,
+                                            *correctSwiftName);
 
       auto name = importedName.getDeclName().getBaseName();
 
@@ -4630,9 +4636,10 @@
   return theClass;
 }
 
-Decl *SwiftDeclConverter::importSwift2TypeAlias(const clang::NamedDecl *decl,
-                                                ImportedName swift2Name,
-                                                ImportedName correctSwiftName) {
+Decl *SwiftDeclConverter::importCompatibilityTypeAlias(
+    const clang::NamedDecl *decl,
+    ImportedName compatibilityName,
+    ImportedName correctSwiftName) {
   // Import the referenced declaration. If it doesn't come in as a type,
   // we don't care.
   auto importedDecl = Impl.importDecl(decl, getActiveSwiftVersion());
@@ -4665,19 +4672,14 @@
 
   // Create the type alias.
   auto alias = Impl.createDeclWithClangNode<TypeAliasDecl>(
-      decl,
-      Accessibility::Public, Impl.importSourceLoc(decl->getLocStart()),
-      SourceLoc(), swift2Name.getDeclName().getBaseName(),
-      Impl.importSourceLoc(decl->getLocation()),
-      genericParams, dc);
+      decl, Accessibility::Public, Impl.importSourceLoc(decl->getLocStart()),
+      SourceLoc(), compatibilityName.getDeclName().getBaseName(),
+      Impl.importSourceLoc(decl->getLocation()), genericParams, dc);
   alias->setUnderlyingType(underlyingType);
   alias->setGenericEnvironment(genericEnv);
 
-  // Record that this is the Swift 2 version of this declaration.
-  Impl.ImportedDecls[{decl->getCanonicalDecl(), ImportNameVersion::Swift2}] =
-      alias;
-
-  // Mark it as the Swift 2 variant.
+  // Record that this is the official version of this declaration.
+  Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = alias;
   markAsVariant(alias, correctSwiftName);
   return alias;
 }
@@ -6516,7 +6518,7 @@
   if (!clangDecl)
     return "";
 
-  auto importedName = importFullName(clangDecl, ImportNameVersion::Swift3);
+  auto importedName = importFullName(clangDecl, CurrentVersion);
   if (!importedName)
     return "";
 
@@ -6758,7 +6760,7 @@
     Result = converter.Visit(ClangDecl);
     HadForwardDeclaration = converter.hadForwardDeclaration();
   }
-  if (!Result && version > ImportNameVersion::Swift2) {
+  if (!Result && version == CurrentVersion) {
     // If we couldn't import this Objective-C entity, determine
     // whether it was a required member of a protocol.
     bool hasMissingRequiredMember = false;
@@ -7202,7 +7204,7 @@
   auto swiftTyLoc = TypeLoc::withoutLoc(nominal->getDeclaredType());
   auto ext = ExtensionDecl::create(SwiftContext, SourceLoc(), swiftTyLoc, {},
                                    getClangModuleForDecl(decl), nullptr);
-  ext->setValidated();
+  ext->setValidationStarted();
   ext->setCheckedInheritanceClause();
   ext->setMemberLoader(this, reinterpret_cast<uintptr_t>(declSubmodule));
 
@@ -7568,7 +7570,7 @@
 
 Identifier
 ClangImporter::getEnumConstantName(const clang::EnumConstantDecl *enumConstant){
-  return Impl.importFullName(enumConstant, ImportNameVersion::Swift3)
+  return Impl.importFullName(enumConstant, Impl.CurrentVersion)
       .getDeclName()
       .getBaseName();
 }
diff --git a/lib/ClangImporter/ImportMacro.cpp b/lib/ClangImporter/ImportMacro.cpp
index 60812f1..25966a1 100644
--- a/lib/ClangImporter/ImportMacro.cpp
+++ b/lib/ClangImporter/ImportMacro.cpp
@@ -51,9 +51,7 @@
   // ClangModule.
   auto *M = maybeModule.getValue()->getTopLevelModule();
 
-  auto &importer =
-    static_cast<ClangImporter &>(*SwiftContext.getClangModuleLoader());
-  return getWrapperForModule(importer, M);
+  return getWrapperForModule(M);
 }
 
 template <typename T = clang::Expr>
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index 841c171..36e4dfa 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -1626,7 +1626,7 @@
     }
 
     // Figure out the name for this parameter.
-    Identifier bodyName = importFullName(param, ImportNameVersion::Swift3)
+    Identifier bodyName = importFullName(param, CurrentVersion)
                               .getDeclName()
                               .getBaseName();
 
@@ -2037,7 +2037,7 @@
     }
 
     // Figure out the name for this parameter.
-    Identifier bodyName = importFullName(param, ImportNameVersion::Swift3)
+    Identifier bodyName = importFullName(param, CurrentVersion)
                               .getDeclName()
                               .getBaseName();
 
@@ -2194,7 +2194,7 @@
 
   } else {
     const clang::ParmVarDecl *param = clangDecl->parameters().front();
-    ImportedName fullBodyName = importFullName(param,ImportNameVersion::Swift3);
+    ImportedName fullBodyName = importFullName(param, CurrentVersion);
     Identifier bodyName = fullBodyName.getDeclName().getBaseName();
     SourceLoc nameLoc = importSourceLoc(param->getLocation());
     Identifier argLabel = functionName.getDeclName().getArgumentNames().front();
diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h
index 5447bd4..72b3fc6 100644
--- a/lib/ClangImporter/ImporterImpl.h
+++ b/lib/ClangImporter/ImporterImpl.h
@@ -275,6 +275,7 @@
 
   bool IsReadingBridgingPCH;
   llvm::SmallVector<clang::serialization::SubmoduleID, 2> PCHImportedSubmodules;
+  llvm::SmallVector<const clang::Module*, 2> DeferredHeaderImports;
 
   const Version CurrentVersion;
 
@@ -815,13 +816,15 @@
 
   /// \brief Retrieves the Swift wrapper for the given Clang module, creating
   /// it if necessary.
-  ClangModuleUnit *getWrapperForModule(ClangImporter &importer,
-                                       const clang::Module *underlying);
+  ClangModuleUnit *getWrapperForModule(const clang::Module *underlying);
 
   /// \brief Constructs a Swift module for the given Clang module.
-  ModuleDecl *finishLoadingClangModule(ClangImporter &importer,
-                                   const clang::Module *clangModule,
-                                   bool preferAdapter);
+  ModuleDecl *finishLoadingClangModule(const clang::Module *clangModule,
+                                       bool preferAdapter);
+
+  /// \brief Call finishLoadingClangModule on each deferred import collected
+  /// while scanning a bridging header or PCH.
+  void handleDeferredImports();
 
   /// \brief Retrieve the named Swift type, e.g., Int32.
   ///
@@ -1105,6 +1108,8 @@
     D->setAccessibility(access);
     if (auto ASD = dyn_cast<AbstractStorageDecl>(D))
       ASD->setSetterAccessibility(access);
+    // All imported decls are constructed fully validated.
+    D->setValidationStarted();
     return D;
   }
 
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 98af405..6fbb2a2 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -864,6 +864,7 @@
   
   Opts.EnableASTScopeLookup |= Args.hasArg(OPT_enable_astscope_lookup);
   Opts.DebugConstraintSolver |= Args.hasArg(OPT_debug_constraints);
+  Opts.EnableConstraintPropagation |= Args.hasArg(OPT_propagate_constraints);
   Opts.IterativeTypeChecker |= Args.hasArg(OPT_iterative_type_checker);
   Opts.DebugGenericSignatures |= Args.hasArg(OPT_debug_generic_signatures);
 
diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp
index e19700c..05936b5 100644
--- a/lib/IDE/SyntaxModel.cpp
+++ b/lib/IDE/SyntaxModel.cpp
@@ -916,7 +916,7 @@
       if (Clause.Cond && !annotateIfConfigConditionIdentifiers(Clause.Cond))
         return false;
 
-      for (auto *D : Clause.Members)
+      for (auto *D : Clause.Elements)
         if (D->walk(*this))
           return false;
     }
diff --git a/lib/IRGen/DebugTypeInfo.cpp b/lib/IRGen/DebugTypeInfo.cpp
index 47d4de1..551ea82 100644
--- a/lib/IRGen/DebugTypeInfo.cpp
+++ b/lib/IRGen/DebugTypeInfo.cpp
@@ -90,7 +90,7 @@
                                        Alignment align) {
   // Prefer the original, potentially sugared version of the type if
   // the type hasn't been mucked with by an optimization pass.
-  auto LowTy = GV->getLoweredType().getSwiftType();
+  auto LowTy = GV->getLoweredType().getSwiftRValueType();
   auto *Type = LowTy.getPointer();
   if (auto *Decl = GV->getDecl()) {
     auto DeclType =
diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp
index b48f544..472f258 100644
--- a/lib/IRGen/GenCast.cpp
+++ b/lib/IRGen/GenCast.cpp
@@ -145,8 +145,14 @@
   llvm::Constant *castFn;
 
   // Get the best known type information about the destination type.
-  auto destClass = toType.getSwiftRValueType().getClassBound();
-  assert(destClass || toType.is<ArchetypeType>());
+  ClassDecl *destClass = nullptr;
+  if (auto archetypeTy = toType.getAs<ArchetypeType>()) {
+    if (auto superclassTy = archetypeTy->getSuperclass())
+      destClass = superclassTy->getClassOrBoundGenericClass();
+  } else {
+    destClass = toType.getClassOrBoundGenericClass();
+    assert(destClass != nullptr);
+  }
 
   // If the destination type is known to have a Swift-compatible
   // implementation, use the most specific entrypoint.
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index 2d5d794..64cacf3 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -795,7 +795,7 @@
 
   // Retain 'self' if necessary.
   if (fnType->getParameters()[0].isConsumed()) {
-    IGF.emitNativeStrongRetain(selfValue);
+    IGF.emitNativeStrongRetain(selfValue, IGF.getDefaultAtomicity());
   }
 
   // Adjust down to the defining subclass type if necessary.
diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp
index 14732d8..f925bcc 100644
--- a/lib/IRGen/GenEnum.cpp
+++ b/lib/IRGen/GenEnum.cpp
@@ -1281,7 +1281,7 @@
       assert(TIK >= Loadable);
       Explosion tmp;
       loadAsTake(IGF, addr, tmp);
-      copy(IGF, tmp, e, Atomicity::Atomic);
+      copy(IGF, tmp, e, IGF.getDefaultAtomicity());
     }
 
     void assign(IRGenFunction &IGF, Explosion &e, Address addr) const override {
@@ -1291,7 +1291,7 @@
         loadAsTake(IGF, addr, old);
       initialize(IGF, e, addr);
       if (!isPOD(ResilienceExpansion::Maximal))
-        consume(IGF, old, Atomicity::Atomic);
+        consume(IGF, old, IGF.getDefaultAtomicity());
     }
 
     void initialize(IRGenFunction &IGF, Explosion &e, Address addr)
@@ -1503,7 +1503,7 @@
         Explosion payloadCopy;
         auto &loadableTI = getLoadablePayloadTypeInfo();
         loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0);
-        loadableTI.copy(IGF, payloadValue, payloadCopy, Atomicity::Atomic);
+        loadableTI.copy(IGF, payloadValue, payloadCopy, IGF.getDefaultAtomicity());
         (void)payloadCopy.claimAll(); // FIXME: repack if not bit-identical
       }
 
@@ -1536,7 +1536,7 @@
         Explosion payloadValue;
         auto &loadableTI = getLoadablePayloadTypeInfo();
         loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0);
-        loadableTI.consume(IGF, payloadValue, Atomicity::Atomic);
+        loadableTI.consume(IGF, payloadValue, IGF.getDefaultAtomicity());
       }
 
       IGF.Builder.CreateBr(endBB);
@@ -2208,7 +2208,7 @@
                                  llvm::Value *ptr) const {
       switch (CopyDestroyKind) {
       case NullableRefcounted:
-        IGF.emitStrongRetain(ptr, Refcounting, Atomicity::Atomic);
+        IGF.emitStrongRetain(ptr, Refcounting, IGF.getDefaultAtomicity());
         return;
       case POD:
       case Normal:
@@ -2232,7 +2232,7 @@
                                   llvm::Value *ptr) const {
       switch (CopyDestroyKind) {
       case NullableRefcounted:
-        IGF.emitStrongRelease(ptr, Refcounting, Atomicity::Atomic);
+        IGF.emitStrongRelease(ptr, Refcounting, IGF.getDefaultAtomicity());
         return;
       case POD:
       case Normal:
@@ -2917,7 +2917,7 @@
         projectPayloadValue(IGF, parts.payload, tagIndex, lti, value);
 
         Explosion tmp;
-        lti.copy(IGF, value, tmp, Atomicity::Atomic);
+        lti.copy(IGF, value, tmp, IGF.getDefaultAtomicity());
         (void)tmp.claimAll(); // FIXME: repack if not bit-identical
       });
 
@@ -2942,7 +2942,7 @@
         Explosion value;
         projectPayloadValue(IGF, parts.payload, tagIndex, lti, value);
 
-        lti.consume(IGF, value, Atomicity::Atomic);
+        lti.consume(IGF, value, IGF.getDefaultAtomicity());
       });
 
       IGF.Builder.CreateRetVoid();
@@ -3119,7 +3119,7 @@
                                  llvm::Value *ptr) const {
       switch (CopyDestroyKind) {
       case TaggedRefcounted:
-        IGF.emitStrongRetain(ptr, Refcounting, Atomicity::Atomic);
+        IGF.emitStrongRetain(ptr, Refcounting, IGF.getDefaultAtomicity());
         return;
       case POD:
       case BitwiseTakable:
@@ -3145,7 +3145,7 @@
                                   llvm::Value *ptr) const {
       switch (CopyDestroyKind) {
       case TaggedRefcounted:
-        IGF.emitStrongRelease(ptr, Refcounting, Atomicity::Atomic);
+        IGF.emitStrongRelease(ptr, Refcounting, IGF.getDefaultAtomicity());
         return;
       case POD:
       case BitwiseTakable:
@@ -4060,7 +4060,7 @@
 
           loadAsTake(IGF, dest, tmpOld);
           initialize(IGF, tmpSrc, dest);
-          consume(IGF, tmpOld, Atomicity::Atomic);
+          consume(IGF, tmpOld, IGF.getDefaultAtomicity());
           return;
         }
 
@@ -4254,7 +4254,7 @@
         if (TI->isLoadable()) {
           Explosion tmp;
           loadAsTake(IGF, addr, tmp);
-          consume(IGF, tmp, Atomicity::Atomic);
+          consume(IGF, tmp, IGF.getDefaultAtomicity());
           return;
         }
 
diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp
index cc16f51..b51b45e 100644
--- a/lib/IRGen/GenExistential.cpp
+++ b/lib/IRGen/GenExistential.cpp
@@ -750,7 +750,7 @@
                   Explosion &out) const override {
     // Load the instance pointer, which is unknown-refcounted.
     llvm::Value *instance = asDerived().loadValue(IGF, address);
-    asDerived().emitValueRetain(IGF, instance, Atomicity::Atomic);
+    asDerived().emitValueRetain(IGF, instance, IGF.getDefaultAtomicity());
     out.add(instance);
 
     // Load the witness table pointers.
@@ -772,7 +772,7 @@
     Address instanceAddr = asDerived().projectValue(IGF, address);
     llvm::Value *old = IGF.Builder.CreateLoad(instanceAddr);
     IGF.Builder.CreateStore(e.claimNext(), instanceAddr);
-    asDerived().emitValueRelease(IGF, old, Atomicity::Atomic);
+    asDerived().emitValueRelease(IGF, old, IGF.getDefaultAtomicity());
 
     // Store the witness table pointers.
     asDerived().emitStoreOfTables(IGF, e, address);
@@ -821,7 +821,7 @@
 
   void destroy(IRGenFunction &IGF, Address addr, SILType T) const override {
     llvm::Value *value = asDerived().loadValue(IGF, addr);
-    asDerived().emitValueRelease(IGF, value, Atomicity::Atomic);
+    asDerived().emitValueRelease(IGF, value, IGF.getDefaultAtomicity());
   }
 
   void packIntoEnumPayload(IRGenFunction &IGF,
@@ -937,12 +937,12 @@
 
   void emitValueRetain(IRGenFunction &IGF, llvm::Value *value,
                        Atomicity atomicity) const {
-    IGF.emitUnownedRetain(value, Refcounting);
+    IGF.emitUnownedRetain(value, Refcounting, atomicity);
   }
 
   void emitValueRelease(IRGenFunction &IGF, llvm::Value *value,
                         Atomicity atomicity) const {
-    IGF.emitUnownedRelease(value, Refcounting);
+    IGF.emitUnownedRelease(value, Refcounting, atomicity);
   }
 
   void emitValueFixLifetime(IRGenFunction &IGF, llvm::Value *value) const {
@@ -1077,24 +1077,29 @@
     (void)e.claim(getNumStoredProtocols());
   }
 
-  void strongRetainUnowned(IRGenFunction &IGF, Explosion &e) const override {
-    IGF.emitStrongRetainUnowned(e.claimNext(), Refcounting);
+  void strongRetainUnowned(IRGenFunction &IGF, Explosion &e,
+                           Atomicity atomicity) const override {
+    IGF.emitStrongRetainUnowned(e.claimNext(), Refcounting, atomicity);
     (void)e.claim(getNumStoredProtocols());
   }
 
   void strongRetainUnownedRelease(IRGenFunction &IGF,
-                                  Explosion &e) const override {
-    IGF.emitStrongRetainAndUnownedRelease(e.claimNext(), Refcounting);
+                                  Explosion &e,
+                                  Atomicity atomicity) const override {
+    IGF.emitStrongRetainAndUnownedRelease(e.claimNext(), Refcounting,
+                                          atomicity);
     (void)e.claim(getNumStoredProtocols());
   }
 
-  void unownedRetain(IRGenFunction &IGF, Explosion &e) const override {
-    IGF.emitUnownedRetain(e.claimNext(), Refcounting);
+  void unownedRetain(IRGenFunction &IGF, Explosion &e,
+                     Atomicity atomicity) const override {
+    IGF.emitUnownedRetain(e.claimNext(), Refcounting, atomicity);
     (void)e.claim(getNumStoredProtocols());
   }
 
-  void unownedRelease(IRGenFunction &IGF, Explosion &e) const override {
-    IGF.emitUnownedRelease(e.claimNext(), Refcounting);
+  void unownedRelease(IRGenFunction &IGF, Explosion &e,
+                      Atomicity atomicity) const override {
+    IGF.emitUnownedRelease(e.claimNext(), Refcounting, atomicity);
     (void)e.claim(getNumStoredProtocols());
   }
 
diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp
index ae977bc..e3b66ff 100644
--- a/lib/IRGen/GenFunc.cpp
+++ b/lib/IRGen/GenFunc.cpp
@@ -252,7 +252,7 @@
       Address dataAddr = projectData(IGF, address);
       auto data = IGF.Builder.CreateLoad(dataAddr);
       if (!isPOD(ResilienceExpansion::Maximal))
-        IGF.emitNativeStrongRetain(data);
+        IGF.emitNativeStrongRetain(data, IGF.getDefaultAtomicity());
       e.add(data);
     }
 
@@ -333,20 +333,24 @@
         IGF.emitNativeStrongRelease(context, atomicity);
     }
 
-    void strongRetainUnowned(IRGenFunction &IGF, Explosion &e) const override {
+    void strongRetainUnowned(IRGenFunction &IGF, Explosion &e,
+                             Atomicity atomicity) const override {
       llvm_unreachable("unowned references to functions are not supported");
     }
 
     void strongRetainUnownedRelease(IRGenFunction &IGF,
-                                    Explosion &e) const override {
-      llvm_unreachable("unowned references to functions are not supported");
-    }
-    
-    void unownedRetain(IRGenFunction &IGF, Explosion &e) const override {
+                                    Explosion &e,
+                                    Atomicity atomicity) const override {
       llvm_unreachable("unowned references to functions are not supported");
     }
 
-    void unownedRelease(IRGenFunction &IGF, Explosion &e) const override {
+    void unownedRetain(IRGenFunction &IGF, Explosion &e,
+                       Atomicity atomicity) const override {
+      llvm_unreachable("unowned references to functions are not supported");
+    }
+
+    void unownedRelease(IRGenFunction &IGF, Explosion &e,
+                        Atomicity atomicity) const override {
       llvm_unreachable("unowned references to functions are not supported");
     }
 
@@ -373,7 +377,7 @@
     void destroy(IRGenFunction &IGF, Address addr, SILType T) const override {
       auto data = IGF.Builder.CreateLoad(projectData(IGF, addr));
       if (!isPOD(ResilienceExpansion::Maximal))
-        IGF.emitNativeStrongRelease(data);
+        IGF.emitNativeStrongRelease(data, IGF.getDefaultAtomicity());
     }
 
     void packIntoEnumPayload(IRGenFunction &IGF,
@@ -555,6 +559,7 @@
       
   case SILFunctionType::Representation::Thin:
   case SILFunctionType::Representation::Method:
+  case SILFunctionType::Representation::WitnessMethod:
   case SILFunctionType::Representation::ObjCMethod:
   case SILFunctionType::Representation::CFunctionPointer:
   case SILFunctionType::Representation::Closure:
@@ -576,19 +581,6 @@
                                 std::move(spareBits),
                                 IsNotPOD);
   }
-  // Witness method values carry a reference to their originating witness table
-  // as context.
-  case SILFunctionType::Representation::WitnessMethod: {
-    SpareBitVector spareBits;
-    spareBits.append(IGM.getFunctionPointerSpareBits());
-    spareBits.append(IGM.getWitnessTablePtrSpareBits());
-    return FuncTypeInfo::create(CanSILFunctionType(T),
-                                IGM.WitnessFunctionPairTy,
-                                IGM.getPointerSize() * 2,
-                                IGM.getPointerAlignment(),
-                                std::move(spareBits),
-                                IsPOD);
-  }
   }
   llvm_unreachable("bad function type representation");
 }
@@ -911,7 +903,7 @@
     switch (argConvention) {
     case ParameterConvention::Indirect_In:
     case ParameterConvention::Direct_Owned:
-      if (!consumesContext) subIGF.emitNativeStrongRetain(rawData);
+      if (!consumesContext) subIGF.emitNativeStrongRetain(rawData, subIGF.getDefaultAtomicity());
       break;
 
     case ParameterConvention::Indirect_In_Guaranteed:
@@ -919,7 +911,7 @@
       dependsOnContextLifetime = true;
       if (outType->getCalleeConvention() ==
             ParameterConvention::Direct_Unowned) {
-        subIGF.emitNativeStrongRetain(rawData);
+        subIGF.emitNativeStrongRetain(rawData, subIGF.getDefaultAtomicity());
         consumesContext = true;
       }
       break;
@@ -1060,7 +1052,7 @@
     // so we can tail call. The safety of this assumes that neither this release
     // nor any of the loads can throw.
     if (consumesContext && !dependsOnContextLifetime && rawData)
-      subIGF.emitNativeStrongRelease(rawData);
+      subIGF.emitNativeStrongRelease(rawData, subIGF.getDefaultAtomicity());
   }
 
   // Derive the callee function pointer.  If we found a function
@@ -1157,7 +1149,7 @@
   
   // If the parameters depended on the context, consume the context now.
   if (rawData && consumesContext && dependsOnContextLifetime)
-    subIGF.emitNativeStrongRelease(rawData);
+    subIGF.emitNativeStrongRelease(rawData, subIGF.getDefaultAtomicity());
   
   // FIXME: Reabstract the result value as substituted.
 
@@ -1224,24 +1216,20 @@
     argValTypes.push_back(argType);
     argConventions.push_back(param.getConvention());
     
-    CanType argLoweringTy;
+    auto argLoweringTy = argType.getSwiftRValueType();
     switch (param.getConvention()) {
     // Capture value parameters by value, consuming them.
     case ParameterConvention::Direct_Owned:
     case ParameterConvention::Direct_Unowned:
     case ParameterConvention::Direct_Guaranteed:
-      argLoweringTy = argType.getSwiftRValueType();
-      break;
-      
     case ParameterConvention::Indirect_In:
     case ParameterConvention::Indirect_In_Guaranteed:
-      argLoweringTy = argType.getSwiftRValueType();
       break;
       
     // Capture inout parameters by pointer.
     case ParameterConvention::Indirect_Inout:
     case ParameterConvention::Indirect_InoutAliasable:
-      argLoweringTy = argType.getSwiftType();
+      argLoweringTy = CanInOutType::get(argLoweringTy);
       break;
     }
     
diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp
index 0e6f309..7f36897 100644
--- a/lib/IRGen/GenHeap.cpp
+++ b/lib/IRGen/GenHeap.cpp
@@ -426,12 +426,12 @@
 
     void emitScalarRetain(IRGenFunction &IGF, llvm::Value *value,
                           Atomicity atomicity) const {
-      IGF.emitNativeUnownedRetain(value);
+      IGF.emitNativeUnownedRetain(value, atomicity);
     }
 
     void emitScalarRelease(IRGenFunction &IGF, llvm::Value *value,
                            Atomicity atomicity) const {
-      IGF.emitNativeUnownedRelease(value);
+      IGF.emitNativeUnownedRelease(value, atomicity);
     }
 
     void emitScalarFixLifetime(IRGenFunction &IGF, llvm::Value *value) const {
@@ -975,7 +975,7 @@
   Builder.CreateStore(newValue, address);
 
   // Release the old value.
-  emitNativeStrongRelease(oldValue);
+  emitNativeStrongRelease(oldValue, getDefaultAtomicity());
 }
 
 /// Emit an initialize of a live value to the given retaining variable.
@@ -1106,31 +1106,35 @@
 #undef DEFINE_BINARY_OPERATION
 
 void IRGenFunction::emitUnownedRetain(llvm::Value *value,
-                                      ReferenceCounting style) {
+                                      ReferenceCounting style,
+                                      Atomicity atomicity) {
   assert(style == ReferenceCounting::Native &&
          "only native references support scalar unowned reference-counting");
-  emitNativeUnownedRetain(value);
+  emitNativeUnownedRetain(value, atomicity);
 }
 
 void IRGenFunction::emitUnownedRelease(llvm::Value *value,
-                                       ReferenceCounting style) {
+                                       ReferenceCounting style,
+                                       Atomicity atomicity) {
   assert(style == ReferenceCounting::Native &&
          "only native references support scalar unowned reference-counting");
-  emitNativeUnownedRelease(value);
+  emitNativeUnownedRelease(value, atomicity);
 }
 
 void IRGenFunction::emitStrongRetainUnowned(llvm::Value *value,
-                                            ReferenceCounting style) {
+                                            ReferenceCounting style,
+                                            Atomicity atomicity) {
   assert(style == ReferenceCounting::Native &&
          "only native references support scalar unowned reference-counting");
-  emitNativeStrongRetainUnowned(value);
+  emitNativeStrongRetainUnowned(value, atomicity);
 }
 
 void IRGenFunction::emitStrongRetainAndUnownedRelease(llvm::Value *value,
-                                                      ReferenceCounting style) {
+                                                      ReferenceCounting style,
+                                                      Atomicity atomicity) {
   assert(style == ReferenceCounting::Native &&
          "only native references support scalar unowned reference-counting");
-  emitNativeStrongRetainAndUnownedRelease(value);
+  emitNativeStrongRetainAndUnownedRelease(value, atomicity);
 }
 
 /// Emit a release of a live value.
@@ -1154,7 +1158,7 @@
   value = Builder.CreateBitCast(value, IGM.RefCountedPtrTy);
   dest = Builder.CreateStructGEP(dest, 0, Size(0));
   Builder.CreateStore(value, dest);
-  emitNativeUnownedRetain(value);
+  emitNativeUnownedRetain(value, getDefaultAtomicity());
 }
 
 void IRGenFunction::emitNativeUnownedAssign(llvm::Value *value,
@@ -1163,8 +1167,8 @@
   dest = Builder.CreateStructGEP(dest, 0, Size(0));
   auto oldValue = Builder.CreateLoad(dest);
   Builder.CreateStore(value, dest);
-  emitNativeUnownedRetain(value);
-  emitNativeUnownedRelease(oldValue);
+  emitNativeUnownedRetain(value, getDefaultAtomicity());
+  emitNativeUnownedRelease(oldValue, getDefaultAtomicity());
 }
 
 llvm::Value *IRGenFunction::emitNativeUnownedLoadStrong(Address src,
@@ -1172,7 +1176,7 @@
   src = Builder.CreateStructGEP(src, 0, Size(0));
   llvm::Value *value = Builder.CreateLoad(src);
   value = Builder.CreateBitCast(value, type);
-  emitNativeStrongRetainUnowned(value);
+  emitNativeStrongRetainUnowned(value, getDefaultAtomicity());
   return value;
 }
 
@@ -1181,14 +1185,14 @@
   src = Builder.CreateStructGEP(src, 0, Size(0));
   llvm::Value *value = Builder.CreateLoad(src);
   value = Builder.CreateBitCast(value, type);
-  emitNativeStrongRetainAndUnownedRelease(value);
+  emitNativeStrongRetainAndUnownedRelease(value, getDefaultAtomicity());
   return value;
 }
 
 void IRGenFunction::emitNativeUnownedDestroy(Address ref) {
   ref = Builder.CreateStructGEP(ref, 0, Size(0));
   llvm::Value *value = Builder.CreateLoad(ref);
-  emitNativeUnownedRelease(value);
+  emitNativeUnownedRelease(value, getDefaultAtomicity());
 }
 
 void IRGenFunction::emitNativeUnownedCopyInit(Address dest, Address src) {
@@ -1196,7 +1200,7 @@
   dest = Builder.CreateStructGEP(dest, 0, Size(0));
   llvm::Value *newValue = Builder.CreateLoad(src);
   Builder.CreateStore(newValue, dest);
-  emitNativeUnownedRetain(newValue);
+  emitNativeUnownedRetain(newValue, getDefaultAtomicity());
 }
 
 void IRGenFunction::emitNativeUnownedTakeInit(Address dest, Address src) {
@@ -1212,8 +1216,8 @@
   llvm::Value *newValue = Builder.CreateLoad(src);
   llvm::Value *oldValue = Builder.CreateLoad(dest);
   Builder.CreateStore(newValue, dest);
-  emitNativeUnownedRetain(newValue);
-  emitNativeUnownedRelease(oldValue);
+  emitNativeUnownedRetain(newValue, getDefaultAtomicity());
+  emitNativeUnownedRelease(oldValue, getDefaultAtomicity());
 }
 
 void IRGenFunction::emitNativeUnownedTakeAssign(Address dest, Address src) {
@@ -1222,7 +1226,7 @@
   llvm::Value *newValue = Builder.CreateLoad(src);
   llvm::Value *oldValue = Builder.CreateLoad(dest);
   Builder.CreateStore(newValue, dest);
-  emitNativeUnownedRelease(oldValue);
+  emitNativeUnownedRelease(oldValue, getDefaultAtomicity());
 }
 
 llvm::Constant *IRGenModule::getFixLifetimeFn() {
@@ -1646,9 +1650,11 @@
 }
 
 #define DEFINE_VALUE_OP(ID)                                           \
-void IRGenFunction::emit##ID(llvm::Value *value) {                    \
+void IRGenFunction::emit##ID(llvm::Value *value, Atomicity atomicity) { \
   if (doesNotRequireRefCounting(value)) return;                       \
-  emitUnaryRefCountCall(*this, IGM.get##ID##Fn(), value);             \
+  emitUnaryRefCountCall(*this, (atomicity == Atomicity::Atomic)       \
+                        ? IGM.get##ID##Fn() : IGM.getNonAtomic##ID##Fn(), \
+                        value);                                       \
 }
 #define DEFINE_ADDR_OP(ID)                                            \
 void IRGenFunction::emit##ID(Address addr) {                          \
diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp
index e16bbad..bb659fc 100644
--- a/lib/IRGen/GenObjC.cpp
+++ b/lib/IRGen/GenObjC.cpp
@@ -909,7 +909,7 @@
       subIGF.emitObjCAutoreleaseCall(self);
     }
     // Release the context.
-    subIGF.emitNativeStrongRelease(context);
+    subIGF.emitNativeStrongRelease(context, subIGF.getDefaultAtomicity());
   };
   
    // Emit the call and produce the return value.
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index b559b52..1102627 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -2259,10 +2259,23 @@
   if (concreteConformance->getProtocol() != proto) {
     concreteConformance = concreteConformance->getInheritedConformance(proto);
   }
+
+  // Check immediately for an existing cache entry.
+  auto wtable = IGF.tryGetLocalTypeData(
+    srcType,
+    LocalTypeDataKind::forConcreteProtocolWitnessTable(concreteConformance));
+  if (wtable) return wtable;
+
   auto &protoI = IGF.IGM.getProtocolInfo(proto);
   auto &conformanceI =
     protoI.getConformance(IGF.IGM, proto, concreteConformance);
-  return conformanceI.getTable(IGF, srcType, srcMetadataCache);
+  wtable = conformanceI.getTable(IGF, srcType, srcMetadataCache);
+
+  IGF.setScopedLocalTypeData(
+    srcType,
+    LocalTypeDataKind::forConcreteProtocolWitnessTable(concreteConformance),
+    wtable);
+  return wtable;
 }
 
 /// Emit the witness table references required for the given type
@@ -2747,7 +2760,6 @@
   
   // Build the value.
   out.add(witness);
-  out.add(wtable);
 }
 
 llvm::FunctionType *IRGenModule::getAssociatedTypeMetadataAccessFunctionTy() {
diff --git a/lib/IRGen/GenRecord.h b/lib/IRGen/GenRecord.h
index ba1efd6..2b7a803 100644
--- a/lib/IRGen/GenRecord.h
+++ b/lib/IRGen/GenRecord.h
@@ -489,14 +489,14 @@
             Explosion &dest, Atomicity atomicity) const override {
     for (auto &field : getFields())
       cast<LoadableTypeInfo>(field.getTypeInfo())
-          .copy(IGF, src, dest, Atomicity::Atomic);
+          .copy(IGF, src, dest, atomicity);
   }
 
   void consume(IRGenFunction &IGF, Explosion &src,
                Atomicity atomicity) const override {
     for (auto &field : getFields())
       cast<LoadableTypeInfo>(field.getTypeInfo())
-          .consume(IGF, src, Atomicity::Atomic);
+          .consume(IGF, src, atomicity);
   }
 
   void fixLifetime(IRGenFunction &IGF, Explosion &src) const override {
diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp
index d66e20a..33cafb2 100644
--- a/lib/IRGen/GenValueWitness.cpp
+++ b/lib/IRGen/GenValueWitness.cpp
@@ -899,10 +899,10 @@
     Address src(&*(it++), IGM.getPointerAlignment());
 
     llvm::Value *newValue = IGF.Builder.CreateLoad(src, "new");
-    IGF.emitNativeStrongRetain(newValue);
+    IGF.emitNativeStrongRetain(newValue, IGF.getDefaultAtomicity());
     llvm::Value *oldValue = IGF.Builder.CreateLoad(dest, "old");
     IGF.Builder.CreateStore(newValue, dest);
-    IGF.emitNativeStrongRelease(oldValue);
+    IGF.emitNativeStrongRelease(oldValue, IGF.getDefaultAtomicity());
 
     IGF.Builder.CreateRet(dest.getAddress());
   });
@@ -925,7 +925,7 @@
     llvm::Value *newValue = IGF.Builder.CreateLoad(src, "new");
     llvm::Value *oldValue = IGF.Builder.CreateLoad(dest, "old");
     IGF.Builder.CreateStore(newValue, dest);
-    IGF.emitNativeStrongRelease(oldValue);
+    IGF.emitNativeStrongRelease(oldValue, IGF.getDefaultAtomicity());
 
     IGF.Builder.CreateRet(dest.getAddress());
   });
@@ -945,7 +945,7 @@
     Address src(&*(it++), IGM.getPointerAlignment());
 
     llvm::Value *newValue = IGF.Builder.CreateLoad(src, "new");
-    IGF.emitNativeStrongRetain(newValue);
+    IGF.emitNativeStrongRetain(newValue, IGF.getDefaultAtomicity());
     IGF.Builder.CreateStore(newValue, dest);
 
     IGF.Builder.CreateRet(dest.getAddress());
@@ -960,7 +960,7 @@
                                        IGM.VoidTy, argTys,
                                        [&](IRGenFunction &IGF) {
     Address arg(&*IGF.CurFn->arg_begin(), IGM.getPointerAlignment());
-    IGF.emitNativeStrongRelease(IGF.Builder.CreateLoad(arg));
+    IGF.emitNativeStrongRelease(IGF.Builder.CreateLoad(arg), IGF.getDefaultAtomicity());
     IGF.Builder.CreateRetVoid();
   });
 }
diff --git a/lib/IRGen/HeapTypeInfo.h b/lib/IRGen/HeapTypeInfo.h
index a21dc1e..15021eb 100644
--- a/lib/IRGen/HeapTypeInfo.h
+++ b/lib/IRGen/HeapTypeInfo.h
@@ -116,26 +116,32 @@
     asDerived().emitScalarRelease(IGF, value, atomicity);
   }
 
-  void strongRetainUnowned(IRGenFunction &IGF, Explosion &e) const override {
+  void strongRetainUnowned(IRGenFunction &IGF, Explosion &e,
+                           Atomicity atomicity) const override {
     llvm::Value *value = e.claimNext();
-    IGF.emitStrongRetainUnowned(value, asDerived().getReferenceCounting());
+    IGF.emitStrongRetainUnowned(value, asDerived().getReferenceCounting(),
+                                atomicity);
   }
 
   void strongRetainUnownedRelease(IRGenFunction &IGF,
-                                  Explosion &e) const override {
+                                  Explosion &e,
+                                  Atomicity atomicity) const override {
     llvm::Value *value = e.claimNext();
     IGF.emitStrongRetainAndUnownedRelease(value,
-                                          asDerived().getReferenceCounting());
+                                          asDerived().getReferenceCounting(),
+                                          atomicity);
   }
 
-  void unownedRetain(IRGenFunction &IGF, Explosion &e) const override {
+  void unownedRetain(IRGenFunction &IGF, Explosion &e,
+                     Atomicity atomicity) const override {
     llvm::Value *value = e.claimNext();
-    IGF.emitUnownedRetain(value, asDerived().getReferenceCounting());
+    IGF.emitUnownedRetain(value, asDerived().getReferenceCounting(), atomicity);
   }
 
-  void unownedRelease(IRGenFunction &IGF, Explosion &e) const override {
+  void unownedRelease(IRGenFunction &IGF, Explosion &e,
+                      Atomicity atomicity) const override {
     llvm::Value *value = e.claimNext();
-    IGF.emitUnownedRelease(value, asDerived().getReferenceCounting());
+    IGF.emitUnownedRelease(value, asDerived().getReferenceCounting(), atomicity);
   }
 
   void unownedLoadStrong(IRGenFunction &IGF, Address src,
diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp
index 47b118a..0018616 100644
--- a/lib/IRGen/IRGenDebugInfo.cpp
+++ b/lib/IRGen/IRGenDebugInfo.cpp
@@ -569,8 +569,10 @@
 void IRGenDebugInfo::createParameterType(
     llvm::SmallVectorImpl<llvm::Metadata *> &Parameters, SILType type,
     DeclContext *DeclCtx) {
-  // FIXME: This use of getSwiftType() is extremely suspect.
-  auto DbgTy = DebugTypeInfo::getFromTypeInfo(DeclCtx, type.getSwiftType(),
+  auto RealType = type.getSwiftRValueType();
+  if (type.isAddress())
+    RealType = CanInOutType::get(RealType);
+  auto DbgTy = DebugTypeInfo::getFromTypeInfo(DeclCtx, RealType,
                                               IGM.getTypeInfo(type));
   Parameters.push_back(getOrCreateType(DbgTy));
 }
@@ -1590,7 +1592,7 @@
       auto DT = getOrCreateDesugaredType(ObjectTy, DbgTy);
       return createPointerSizedStruct(
           Scope, MangledName, DT, File, 0, Flags,
-          BaseTy->isUnspecializedGeneric() ? StringRef() : MangledName);
+          MangledName);
     } else
       return createOpaqueStruct(Scope, MangledName, File, 0, SizeInBits,
                                 AlignInBits, Flags, MangledName);
diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp
index 686d442..e25c89e 100644
--- a/lib/IRGen/IRGenFunction.cpp
+++ b/lib/IRGen/IRGenFunction.cpp
@@ -72,6 +72,11 @@
   return IGM.getSILTypes();
 }
 
+// Returns the default atomicity of the module.
+Atomicity IRGenFunction::getDefaultAtomicity() {
+  return getSILModule().isDefaultAtomic() ? Atomicity::Atomic : Atomicity::NonAtomic;
+}
+
 /// Call the llvm.memcpy intrinsic.  The arguments need not already
 /// be of i8* type.
 void IRGenFunction::emitMemCpy(llvm::Value *dest, llvm::Value *src,
diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h
index b23d42d..4782647 100644
--- a/lib/IRGen/IRGenFunction.h
+++ b/lib/IRGen/IRGenFunction.h
@@ -231,6 +231,9 @@
 
 //--- Reference-counting methods -----------------------------------------------
 public:
+  // Returns the default atomicity of the module.
+  Atomicity getDefaultAtomicity();
+
   llvm::Value *emitUnmanagedAlloc(const HeapLayout &layout,
                                   const llvm::Twine &name,
                                   llvm::Constant *captureDescriptor,
@@ -248,11 +251,15 @@
   llvm::Value *emitLoadRefcountedPtr(Address addr, ReferenceCounting style);
 
   //   - unowned references
-  void emitUnownedRetain(llvm::Value *value, ReferenceCounting style);
-  void emitUnownedRelease(llvm::Value *value, ReferenceCounting style);
-  void emitStrongRetainUnowned(llvm::Value *value, ReferenceCounting style);
+  void emitUnownedRetain(llvm::Value *value, ReferenceCounting style,
+                         Atomicity atomicity);
+  void emitUnownedRelease(llvm::Value *value, ReferenceCounting style,
+                          Atomicity atomicity);
+  void emitStrongRetainUnowned(llvm::Value *value, ReferenceCounting style,
+                               Atomicity atomicity);
   void emitStrongRetainAndUnownedRelease(llvm::Value *value,
-                                         ReferenceCounting style);
+                                         ReferenceCounting style,
+                                         Atomicity atomicity);
   void emitUnownedInit(llvm::Value *val, Address dest, ReferenceCounting style);
   void emitUnownedAssign(llvm::Value *value, Address dest,
                          ReferenceCounting style);
@@ -295,16 +302,15 @@
   //   - strong references
   void emitNativeStrongAssign(llvm::Value *value, Address addr);
   void emitNativeStrongInit(llvm::Value *value, Address addr);
-  void emitNativeStrongRetain(llvm::Value *value,
-                              Atomicity atomicity = Atomicity::Atomic);
-  void emitNativeStrongRelease(llvm::Value *value,
-                               Atomicity atomicity = Atomicity::Atomic);
+  void emitNativeStrongRetain(llvm::Value *value, Atomicity atomicity);
+  void emitNativeStrongRelease(llvm::Value *value, Atomicity atomicity);
   void emitNativeSetDeallocating(llvm::Value *value);
   //   - unowned references
-  void emitNativeUnownedRetain(llvm::Value *value);
-  void emitNativeUnownedRelease(llvm::Value *value);
-  void emitNativeStrongRetainUnowned(llvm::Value *value);
-  void emitNativeStrongRetainAndUnownedRelease(llvm::Value *value);
+  void emitNativeUnownedRetain(llvm::Value *value, Atomicity atomicity);
+  void emitNativeUnownedRelease(llvm::Value *value, Atomicity atomicity);
+  void emitNativeStrongRetainUnowned(llvm::Value *value, Atomicity atomicity);
+  void emitNativeStrongRetainAndUnownedRelease(llvm::Value *value,
+                                               Atomicity atomicity);
   void emitNativeUnownedInit(llvm::Value *val, Address dest);
   void emitNativeUnownedAssign(llvm::Value *value, Address dest);
   void emitNativeUnownedCopyInit(Address destAddr, Address srcAddr);
@@ -341,10 +347,8 @@
   // Routines for an unknown reference-counting style (meaning,
   // dynamically something compatible with either the ObjC or Swift styles).
   //   - strong references
-  void emitUnknownStrongRetain(llvm::Value *value,
-                               Atomicity atomicity = Atomicity::Atomic);
-  void emitUnknownStrongRelease(llvm::Value *valuei,
-                                Atomicity atomicity = Atomicity::Atomic);
+  void emitUnknownStrongRetain(llvm::Value *value, Atomicity atomicity);
+  void emitUnknownStrongRelease(llvm::Value *value, Atomicity atomicity);
   //   - unowned references
   void emitUnknownUnownedInit(llvm::Value *val, Address dest);
   void emitUnknownUnownedAssign(llvm::Value *value, Address dest);
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index d3359ba..e70a62c 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -273,10 +273,6 @@
     FunctionPtrTy,
     RefCountedPtrTy,
   });
-  WitnessFunctionPairTy = createStructType(*this, "swift.function", {
-    FunctionPtrTy,
-    WitnessTablePtrTy,
-  });
   
   OpaquePtrTy = llvm::StructType::create(LLVMContext, "swift.opaque")
                   ->getPointerTo(DefaultAS);
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 2468b79..e5282b1 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -430,7 +430,6 @@
   llvm::PointerType *UnownedReferencePtrTy;/// %swift.unowned_reference*
   llvm::Constant *RefCountedNull;      /// %swift.refcounted* null
   llvm::StructType *FunctionPairTy;    /// { i8*, %swift.refcounted* }
-  llvm::StructType *WitnessFunctionPairTy;    /// { i8*, %witness.table* }
   llvm::FunctionType *DeallocatingDtorTy; /// void (%swift.refcounted*)
   llvm::StructType *TypeMetadataStructTy; /// %swift.type = type { ... }
   llvm::PointerType *TypeMetadataPtrTy;/// %swift.type*
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index dfff469..97e61fb 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -887,7 +887,8 @@
   void visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *i);
   void visitInitExistentialRefInst(InitExistentialRefInst *i);
   void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *i);
-  
+  void visitDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *i);
+
   void visitAllocExistentialBoxInst(AllocExistentialBoxInst *i);
   void visitOpenExistentialBoxInst(OpenExistentialBoxInst *i);
   void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i);
@@ -1887,14 +1888,11 @@
     //
     // We recover the witness table from the substitution that was used to
     // produce the substituted callee type.
-    //
-    // There can be multiple substitutions, but the first one is the Self type.
-    assert(subs.size() >= 1);
-    assert(subs[0].getConformances().size() == 1);
-
-    auto conformance = subs[0].getConformances()[0];
-    assert(conformance.getRequirement() == proto); (void) proto;
-    auto substSelfType = subs[0].getReplacement()->getCanonicalType();
+    auto subMap = origCalleeType->getGenericSignature()
+      ->getSubstitutionMap(subs);
+    auto origSelfType = proto->getSelfInterfaceType()->getCanonicalType();
+    auto substSelfType = origSelfType.subst(subMap)->getCanonicalType();
+    auto conformance = *subMap.lookupConformance(origSelfType, proto);
 
     llvm::Value *argMetadata = IGF.emitTypeMetadataRef(substSelfType);
     wtable = emitWitnessTableRef(IGF, substSelfType, &argMetadata,
@@ -1992,12 +1990,8 @@
 
       if (origCalleeType->getRepresentation()
             == SILFunctionType::Representation::WitnessMethod) {
-        // @convention(witness_method) callees are exploded as a
-        // triple consisting of the function, Self metadata, and
-        // the Self witness table.
-        witnessMetadata->SelfWitnessTable = calleeValues.claimNext();
-        assert(witnessMetadata->SelfWitnessTable->getType() ==
-               IGF.IGM.WitnessTablePtrTy);
+        witnessMetadata->SelfWitnessTable = emitWitnessTableForLoweredCallee(
+          IGF, origCalleeType, substitutions);
       }
 
       if (origCalleeType->getRepresentation()
@@ -2221,12 +2215,9 @@
     case SILFunctionType::Representation::Closure:
     case SILFunctionType::Representation::ObjCMethod:
       break;
-    case SILFunctionType::Representation::WitnessMethod: {
-      llvm::Value *wtable = ex.claimNext();
-      assert(wtable->getType() == IGF.IGM.WitnessTablePtrTy);
-      context = wtable;
+    case SILFunctionType::Representation::WitnessMethod:
+      context = emitWitnessTableForLoweredCallee(IGF, fnType, subs);
       break;
-    }
     case SILFunctionType::Representation::CFunctionPointer:
       break;
     case SILFunctionType::Representation::Thick:
@@ -2434,7 +2425,7 @@
     defaultDest = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
   }
 
-  if (ty.getAs<BuiltinIntegerType>()) {
+  if (ty.is<BuiltinIntegerType>()) {
     auto *discriminator = value.claimNext();
     auto *i = IGF.Builder.CreateSwitch(discriminator, defaultDest,
                                      dests.size());
@@ -2444,7 +2435,7 @@
     // Get the value we're testing, which is a function.
     llvm::Value *val;
     llvm::BasicBlock *nextTest = nullptr;
-    if (ty.getSwiftType()->is<SILFunctionType>()) {
+    if (ty.is<SILFunctionType>()) {
       val = value.claimNext();   // Function pointer.
       //values.claimNext();         // Ignore the data pointer.
     } else {
@@ -2455,7 +2446,7 @@
       auto casePair = dests[i];
       llvm::Value *caseval;
       auto casevalue = IGF.getLoweredExplosion(casePair.first);
-      if (casePair.first->getType().getSwiftType()->is<SILFunctionType>()) {
+      if (casePair.first->getType().is<SILFunctionType>()) {
         caseval = casevalue.claimNext();   // Function pointer.
         //values.claimNext();         // Ignore the data pointer.
       } else {
@@ -3013,7 +3004,7 @@
   Explosion in = getLoweredExplosion(i->getOperand());
   Explosion out;
   cast<LoadableTypeInfo>(getTypeInfo(i->getOperand()->getType()))
-      .copy(*this, in, out, irgen::Atomicity::Atomic);
+      .copy(*this, in, out, getDefaultAtomicity());
   setLoweredExplosion(i, out);
 }
 
@@ -3071,7 +3062,7 @@
 void IRGenSILFunction::visitDestroyValueInst(swift::DestroyValueInst *i) {
   Explosion in = getLoweredExplosion(i->getOperand());
   cast<LoadableTypeInfo>(getTypeInfo(i->getOperand()->getType()))
-      .consume(*this, in, irgen::Atomicity::Atomic);
+      .consume(*this, in, getDefaultAtomicity());
 }
 
 void IRGenSILFunction::visitStructInst(swift::StructInst *i) {
@@ -3276,21 +3267,16 @@
   StringRef Name = getVarName(i);
   DebugTypeInfo DbgTy;
   SILType SILTy = SILVal->getType();
-  // An inout/lvalue type that is described by a debug value has been
-  // promoted by an optimization pass. Unwrap the type.
-  bool Unwrap = true;
-  auto RealTy = SILVal->getType().getSwiftType();
+  auto RealTy = SILVal->getType().getSwiftRValueType();
   if (VarDecl *Decl = i->getDecl()) {
     DbgTy = DebugTypeInfo::getLocalVariable(
         CurSILFn->getDeclContext(), Decl, RealTy,
-        getTypeInfo(SILVal->getType()), Unwrap);
+        getTypeInfo(SILVal->getType()), /*Unwrap=*/false);
   } else if (i->getFunction()->isBare() &&
-             !SILTy.getSwiftType()->hasArchetype() && !Name.empty()) {
+             !SILTy.hasArchetype() && !Name.empty()) {
     // Preliminary support for .sil debug information.
     DbgTy = DebugTypeInfo::getFromTypeInfo(CurSILFn->getDeclContext(), RealTy,
                                            getTypeInfo(SILTy));
-    if (Unwrap)
-      DbgTy.unwrapLValueOrInOutType();
   } else
     return;
 
@@ -3317,7 +3303,9 @@
   StringRef Name = getVarName(i);
   auto Addr = getLoweredAddress(SILVal).getAddress();
   SILType SILTy = SILVal->getType();
-  auto RealType = SILTy.getSwiftType();
+  auto RealType = SILTy.getSwiftRValueType();
+  if (SILTy.isAddress())
+    RealType = CanInOutType::get(RealType);
   // Unwrap implicitly indirect types and types that are passed by
   // reference only at the SIL level and below.
   //
@@ -3326,7 +3314,7 @@
   // 'Unwrap' set to false.
   bool Unwrap =
       i->getVarInfo().Constant ||
-      RealType->getLValueOrInOutObjectType()->is<ArchetypeType>();
+      SILTy.is<ArchetypeType>();
   auto DbgTy = DebugTypeInfo::getLocalVariable(
       CurSILFn->getDeclContext(), Decl, RealType,
       getTypeInfo(SILVal->getType()), Unwrap);
@@ -3445,19 +3433,22 @@
 visitStrongRetainUnownedInst(swift::StrongRetainUnownedInst *i) {
   Explosion lowered = getLoweredExplosion(i->getOperand());
   auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType());
-  ti.strongRetainUnowned(*this, lowered);
+  ti.strongRetainUnowned(*this, lowered, i->isAtomic() ? irgen::Atomicity::Atomic
+                                                       : irgen::Atomicity::NonAtomic);
 }
 
 void IRGenSILFunction::visitUnownedRetainInst(swift::UnownedRetainInst *i) {
   Explosion lowered = getLoweredExplosion(i->getOperand());
   auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType());
-  ti.unownedRetain(*this, lowered);
+  ti.unownedRetain(*this, lowered, i->isAtomic() ? irgen::Atomicity::Atomic
+                                                 : irgen::Atomicity::NonAtomic);
 }
 
 void IRGenSILFunction::visitUnownedReleaseInst(swift::UnownedReleaseInst *i) {
   Explosion lowered = getLoweredExplosion(i->getOperand());
   auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType());
-  ti.unownedRelease(*this, lowered);
+  ti.unownedRelease(*this, lowered, i->isAtomic() ? irgen::Atomicity::Atomic
+                                                  : irgen::Atomicity::NonAtomic);
 }
 
 void IRGenSILFunction::visitLoadUnownedInst(swift::LoadUnownedInst *i) {
@@ -3597,14 +3588,10 @@
           Pattern->getKind() != PatternKind::OptionalSome)
         return;
 
-    // Discard any inout or lvalue qualifiers. Since the object itself
-    // is stored in the alloca, emitting it as a reference type would
-    // be wrong.
-    bool Unwrap = true;
     SILType SILTy = i->getType();
-    auto RealType = SILTy.getSwiftType().getLValueOrInOutObjectType();
+    auto RealType = SILTy.getSwiftRValueType();
     auto DbgTy = DebugTypeInfo::getLocalVariable(CurSILFn->getDeclContext(),
-                                                 Decl, RealType, type, Unwrap);
+                                                 Decl, RealType, type, false);
     StringRef Name = getVarName(i);
     if (auto DS = i->getDebugScope())
       emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name,
@@ -3785,10 +3772,13 @@
 
     assert(i->getBoxType()->getLayout()->getFields().size() == 1
            && "box for a local variable should only have one field");
+    auto SILTy = i->getBoxType()->getFieldType(IGM.getSILModule(), 0);
+    auto RealType = SILTy.getSwiftRValueType();
+    if (SILTy.isAddress())
+      RealType = CanInOutType::get(RealType);
     auto DbgTy = DebugTypeInfo::getLocalVariable(
         CurSILFn->getDeclContext(), Decl,
-        i->getBoxType()->getFieldType(IGM.getSILModule(), 0).getSwiftType(),
-          type, /*Unwrap=*/false);
+        RealType, type, /*Unwrap=*/false);
 
     if (isInlinedGeneric(Decl, i->getDebugScope()))
       return;
@@ -4343,7 +4333,7 @@
   llvm::Value *val;
   const LoweredValue &lv = getLoweredValue(i->getOperand());
   
-  if (i->getOperand()->getType().getSwiftType()->is<SILFunctionType>()) {
+  if (i->getOperand()->getType().is<SILFunctionType>()) {
     Explosion values = lv.getExplosion(*this);
     val = values.claimNext();   // Function pointer.
     values.claimNext();         // Ignore the data pointer.
@@ -4511,6 +4501,11 @@
                                        i->getOperand()->getType());
 }
 
+void IRGenSILFunction::visitDeinitExistentialOpaqueInst(
+    swift::DeinitExistentialOpaqueInst *i) {
+  llvm_unreachable("unsupported instruction during IRGen");
+}
+
 void IRGenSILFunction::visitOpenExistentialAddrInst(OpenExistentialAddrInst *i) {
   SILType baseTy = i->getOperand()->getType();
   Address base = getLoweredAddress(i->getOperand());
diff --git a/lib/IRGen/ReferenceTypeInfo.h b/lib/IRGen/ReferenceTypeInfo.h
index 56e3c33..816a240 100644
--- a/lib/IRGen/ReferenceTypeInfo.h
+++ b/lib/IRGen/ReferenceTypeInfo.h
@@ -49,20 +49,24 @@
 
   /// Strongly retains a value that has come from a safe [unowned] reference.
   /// This operation is not supported for all reference types.
-  virtual void strongRetainUnowned(IRGenFunction &IGF, Explosion &in) const = 0;
+  virtual void strongRetainUnowned(IRGenFunction &IGF, Explosion &in,
+                                   Atomicity atomicity) const = 0;
 
   /// Strongly retains a value that has come from a safe [unowned] reference.
   /// This operation is not supported for all reference types.
   virtual void strongRetainUnownedRelease(IRGenFunction &IGF,
-                                          Explosion &in) const = 0;
+                                          Explosion &in,
+                                          Atomicity atomicity) const = 0;
 
   /// Weakly retains a value in the manner of a safe [unowned] reference.
   /// This operation is not supported for all reference types.
-  virtual void unownedRetain(IRGenFunction &IGF, Explosion &in) const = 0;
+  virtual void unownedRetain(IRGenFunction &IGF, Explosion &in,
+                             Atomicity atomicity) const = 0;
 
   /// Weakly releases a value in the manner of a safe [unowned] reference.
   /// This operation is not supported for all reference types.
-  virtual void unownedRelease(IRGenFunction &IGF, Explosion &in) const = 0;
+  virtual void unownedRelease(IRGenFunction &IGF, Explosion &in,
+                              Atomicity atomicity) const = 0;
 
   /// Load a reference from a safe [unowned] reference in memory and
   /// destroy the [unowned] location.
diff --git a/lib/IRGen/ScalarTypeInfo.h b/lib/IRGen/ScalarTypeInfo.h
index d2471e6..dd7dbc9 100644
--- a/lib/IRGen/ScalarTypeInfo.h
+++ b/lib/IRGen/ScalarTypeInfo.h
@@ -127,7 +127,7 @@
                   Explosion &out) const override {
     addr = asDerived().projectScalar(IGF, addr);
     llvm::Value *value = IGF.Builder.CreateLoad(addr);
-    asDerived().emitScalarRetain(IGF, value, Atomicity::Atomic);
+    asDerived().emitScalarRetain(IGF, value, IGF.getDefaultAtomicity());
     out.add(value);
   }
 
@@ -153,7 +153,7 @@
 
     // Release the old value if we need to.
     if (!Derived::IsScalarPOD) {
-      asDerived().emitScalarRelease(IGF, oldValue, Atomicity::Atomic);
+      asDerived().emitScalarRelease(IGF, oldValue, IGF.getDefaultAtomicity());
     }
   }
 
@@ -179,7 +179,7 @@
     if (!Derived::IsScalarPOD) {
       addr = asDerived().projectScalar(IGF, addr);
       llvm::Value *value = IGF.Builder.CreateLoad(addr, "toDestroy");
-      asDerived().emitScalarRelease(IGF, value, Atomicity::Atomic);
+      asDerived().emitScalarRelease(IGF, value, IGF.getDefaultAtomicity());
     }
   }
   
diff --git a/lib/IRGen/SwiftTargetInfo.cpp b/lib/IRGen/SwiftTargetInfo.cpp
index ea5464e..1c68338 100644
--- a/lib/IRGen/SwiftTargetInfo.cpp
+++ b/lib/IRGen/SwiftTargetInfo.cpp
@@ -158,6 +158,7 @@
     break;
 
   case llvm::Triple::arm:
+  case llvm::Triple::thumb:
     configureARM(IGM, triple, target);
     break;
 
diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp
index 0464ab1..52bf53c 100644
--- a/lib/Index/Index.cpp
+++ b/lib/Index/Index.cpp
@@ -191,6 +191,14 @@
 
   bool addRelation(IndexSymbol &Info, SymbolRoleSet RelationRoles, Decl *D) {
     assert(D);
+    auto Match = std::find_if(Info.Relations.begin(), Info.Relations.end(),
+                              [D](IndexRelation R) { return R.decl == D; });
+    if (Match != Info.Relations.end()) {
+      Match->roles |= RelationRoles;
+      Info.roles |= RelationRoles;
+      return false;
+    }
+
     StringRef Name, USR;
     SymbolInfo SymInfo = getSymbolInfoForDecl(D);
 
@@ -400,7 +408,8 @@
   }
 
   bool isLocal(ValueDecl *D) const {
-    return D->getDeclContext()->getLocalContext();
+    return D->getDeclContext()->getLocalContext() &&
+      (!isa<ParamDecl>(D) || cast<ParamDecl>(D)->getArgumentNameLoc().isValid());
   }
 
   void getModuleHash(SourceFileOrModule SFOrMod, llvm::raw_ostream &OS);
@@ -605,7 +614,7 @@
         return false;
 
     } else if (auto ParentED = dyn_cast<ExtensionDecl>(Parent)) {
-      if (NominalTypeDecl *NTD = ParentED->getExtendedType()->getAnyNominal()) {
+      if (ParentED->getExtendedType()->getAnyNominal()) {
         if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationChildOf, ParentED))
           return false;
       }
@@ -866,10 +875,14 @@
 
   // Cannot be extension, which is not a ValueDecl.
 
-  if (IsRef)
+  if (IsRef) {
     Info.roles |= (unsigned)SymbolRole::Reference;
-  else
+    auto Parent = getParentDecl();
+    if (Parent && isa<AbstractFunctionDecl>(Parent))
+      addRelation(Info, (unsigned)SymbolRole::RelationContainedBy, Parent);
+  } else {
     Info.roles |= (unsigned)SymbolRole::Definition;
+  }
 
   if (getNameAndUSR(D, /*ExtD=*/nullptr, Info.name, Info.USR))
     return true;
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index 1537c91..d59d1ba 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -112,10 +112,10 @@
       info.SubKind = SymbolSubKind::SwiftSubscript;
       break;
     case DeclKind::Constructor:      info.Kind = SymbolKind::Constructor; break;
-    case DeclKind::Destructor:       info.Kind = SymbolKind::Destructor; break;;
+    case DeclKind::Destructor:       info.Kind = SymbolKind::Destructor; break;
     case DeclKind::Param:
-      llvm_unreachable("unexpected parameter seen while indexing");
-
+      info.Kind = SymbolKind::Parameter;
+      break;
     case DeclKind::Func:
       setFuncSymbolInfo(cast<FuncDecl>(D), info);
       break;
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 870e1be..c0b384d 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -3,6 +3,7 @@
   ParseDecl.cpp
   ParseExpr.cpp
   ParseGeneric.cpp
+  ParseIfConfig.cpp
   ParsePattern.cpp
   Parser.cpp
   ParseSIL.cpp
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0b449e6..c61e690 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2727,32 +2727,31 @@
 }
 
 /// Parse a Decl item in decl list.
-static ParserStatus parseDeclItem(Parser &P,
-                                  bool &PreviousHadSemi,
-                                  Parser::ParseDeclOptions Options,
-                                  llvm::function_ref<void(Decl*)> handler) {
-  if (P.Tok.is(tok::semi)) {
+ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
+                                   Parser::ParseDeclOptions Options,
+                                   llvm::function_ref<void(Decl*)> handler) {
+  if (Tok.is(tok::semi)) {
     // Consume ';' without preceding decl.
-    P.diagnose(P.Tok, diag::unexpected_separator, ";")
-      .fixItRemove(P.Tok.getLoc());
-    P.consumeToken();
+    diagnose(Tok, diag::unexpected_separator, ";")
+      .fixItRemove(Tok.getLoc());
+    consumeToken();
     // Return success because we already recovered.
     return makeParserSuccess();
   }
 
   // If the previous declaration didn't have a semicolon and this new
   // declaration doesn't start a line, complain.
-  if (!PreviousHadSemi && !P.Tok.isAtStartOfLine() && !P.Tok.is(tok::unknown)) {
-    auto endOfPrevious = P.getEndOfPreviousLoc();
-    P.diagnose(endOfPrevious, diag::declaration_same_line_without_semi)
+  if (!PreviousHadSemi && !Tok.isAtStartOfLine() && !Tok.is(tok::unknown)) {
+    auto endOfPrevious = getEndOfPreviousLoc();
+    diagnose(endOfPrevious, diag::declaration_same_line_without_semi)
       .fixItInsert(endOfPrevious, ";");
   }
 
-  auto Result = P.parseDecl(Options, handler);
+  auto Result = parseDecl(Options, handler);
   if (Result.isParseError())
-    P.skipUntilDeclRBrace(tok::semi, tok::pound_endif);
+    skipUntilDeclRBrace(tok::semi, tok::pound_endif);
   SourceLoc SemiLoc;
-  PreviousHadSemi = P.consumeIf(tok::semi, SemiLoc);
+  PreviousHadSemi = consumeIf(tok::semi, SemiLoc);
   if (PreviousHadSemi && Result.isNonNull())
     Result.get()->TrailingSemiLoc = SemiLoc;
   return Result;
@@ -2769,7 +2768,7 @@
   ParserStatus Status;
   bool PreviousHadSemi = true;
   while (Tok.isNot(tok::r_brace)) {
-    Status |= parseDeclItem(*this, PreviousHadSemi, Options, handler);
+    Status |= parseDeclItem(PreviousHadSemi, Options, handler);
     if (Tok.isAny(tok::eof, tok::pound_endif, tok::pound_else,
                   tok::pound_elseif)) {
       IsInputIncomplete = true;
@@ -2999,94 +2998,6 @@
   return makeParserSuccess();
 }
 
-ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
-  StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(),
-                                  StructureMarkerKind::IfConfig);
-
-  SmallVector<IfConfigDeclClause, 4> Clauses;
-
-  bool foundActive = false;
-  ConditionalCompilationExprState ConfigState;
-  while (1) {
-    bool isElse = Tok.is(tok::pound_else);
-    SourceLoc ClauseLoc = consumeToken();
-    Expr *Condition = nullptr;
-
-    if (isElse) {
-      ConfigState.setConditionActive(!foundActive);
-    } else {
-      // Evaluate the condition.
-      llvm::SaveAndRestore<bool> S(InPoundIfEnvironment, true);
-      ParserResult<Expr> Result = parseExprSequence(diag::expected_expr,
-                                                    /*isBasic*/true,
-                                                    /*isForDirective*/true);
-      if (Result.isNull())
-        return makeParserError();
-
-      Condition = Result.get();
-
-      // Evaluate the condition, to validate it.
-      ConfigState = classifyConditionalCompilationExpr(Condition, Context,
-                                                       Diags);
-      if (foundActive)
-        ConfigState.setConditionActive(false);
-    }
-
-    foundActive |= ConfigState.isConditionActive();
-
-    if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
-      diagnose(Tok.getLoc(),
-               diag::extra_tokens_conditional_compilation_directive);
-    }
-
-    Optional<Scope> scope;
-    if (!ConfigState.isConditionActive())
-      scope.emplace(this, getScopeInfo().getCurrentScope()->getKind(),
-                    /*inactiveConfigBlock=*/true);
-
-    SmallVector<Decl*, 8> Decls;
-    if (ConfigState.shouldParse()) {
-      ParserStatus Status;
-      bool PreviousHadSemi = true;
-      while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif,
-                       tok::eof)) {
-        if (Tok.is(tok::r_brace)) {
-          diagnose(Tok.getLoc(),
-                   diag::unexpected_rbrace_in_conditional_compilation_block);
-          // If we see '}', following declarations don't look like belong to
-          // the current decl context; skip them.
-          skipUntilConditionalBlockClose();
-          break;
-        }
-        Status |= parseDeclItem(*this, PreviousHadSemi, Flags,
-                                [&](Decl *D) {Decls.push_back(D);});
-      }
-    } else {
-      DiagnosticTransaction DT(Diags);
-      skipUntilConditionalBlockClose();
-      DT.abort();
-    }
-
-    Clauses.push_back(IfConfigDeclClause(ClauseLoc, Condition,
-                                         Context.AllocateCopy(Decls),
-                                         ConfigState.isConditionActive()));
-
-    if (Tok.isNot(tok::pound_elseif) && Tok.isNot(tok::pound_else))
-      break;
-
-    if (isElse)
-      diagnose(Tok, diag::expected_close_after_else_directive);
-  }
-
-  SourceLoc EndLoc;
-  bool HadMissingEnd = parseEndIfDirective(EndLoc);
-
-  IfConfigDecl *ICD = new (Context) IfConfigDecl(CurDeclContext,
-                                                 Context.AllocateCopy(Clauses),
-                                                 EndLoc, HadMissingEnd);
-  return makeParserResult(ICD);
-}
-
 /// \brief Parse a typealias decl.
 ///
 /// \verbatim
@@ -3185,7 +3096,7 @@
 ///
 /// \verbatim
 ///   decl-associatedtype:
-///     'associatedtype' identifier inheritance? ('=' type)?
+///     'associatedtype' identifier inheritance? ('=' type)? where-clause?
 /// \endverbatim
 
 ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags,
@@ -3239,15 +3150,32 @@
     if (UnderlyingTy.isNull())
       return Status;
   }
-  
-  // Parse a 'where' clause if present. These are not supported, but we will
-  // get better QoI this way.
+
+  TrailingWhereClause *TrailingWhere = nullptr;
+  // Parse a 'where' clause if present.
   if (Tok.is(tok::kw_where)) {
-    GenericParamList *unused = nullptr;
-    auto whereStatus = parseFreestandingGenericWhereClause(
-        unused, WhereClauseKind::AssociatedType);
-    if (whereStatus.shouldStopParsing())
-      return whereStatus;
+    SourceLoc whereLoc;
+    SmallVector<RequirementRepr, 4> requirements;
+    bool firstTypeInComplete;
+    auto whereStatus =
+        parseGenericWhereClause(whereLoc, requirements, firstTypeInComplete);
+    if (whereStatus.isSuccess()) {
+      TrailingWhere =
+          TrailingWhereClause::create(Context, whereLoc, requirements);
+    } else if (whereStatus.hasCodeCompletion()) {
+      // FIXME: this is completely (hah) cargo culted.
+      if (CodeCompletion && firstTypeInComplete) {
+        CodeCompletion->completeGenericParams(nullptr);
+      } else {
+        return makeParserCodeCompletionResult<AssociatedTypeDecl>();
+      }
+    }
+
+    if (Context.isSwiftVersion3()) {
+      diagnose(whereLoc, diag::associatedtype_where_swift_3);
+      // There's nothing to see here, move along.
+      TrailingWhere = nullptr;
+    }
   }
 
   if (!Flags.contains(PD_InProtocol)) {
@@ -3256,10 +3184,10 @@
     Status.setIsParseError();
     return Status;
   }
-  
-  auto assocType = new (Context) AssociatedTypeDecl(CurDeclContext,
-                                                    AssociatedTypeLoc, Id, IdLoc,
-                                                    UnderlyingTy.getPtrOrNull());
+
+  auto assocType = new (Context)
+      AssociatedTypeDecl(CurDeclContext, AssociatedTypeLoc, Id, IdLoc,
+                         UnderlyingTy.getPtrOrNull(), TrailingWhere);
   assocType->getAttrs() = Attributes;
   if (!Inherited.empty())
     assocType->setInherited(Context.AllocateCopy(Inherited));
diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp
new file mode 100644
index 0000000..f6c064d
--- /dev/null
+++ b/lib/Parse/ParseIfConfig.cpp
@@ -0,0 +1,427 @@
+//===--- ParseDecl.cpp - Swift Language Parser for #if directives -- ------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// Conditional Compilation Block Parsing and AST Building
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Parse/Parser.h"
+#include "swift/Basic/Defer.h"
+#include "swift/Basic/LangOptions.h"
+#include "swift/Basic/Version.h"
+#include "swift/Parse/Lexer.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/SaveAndRestore.h"
+
+using namespace swift;
+
+/// Parse and populate a list of #if/#elseif/#else/#endif clauses.
+/// Delegate callback function to parse elements in the blocks.
+template <typename ElemTy, unsigned N>
+static ParserStatus parseIfConfig(
+    Parser &P, SmallVectorImpl<IfConfigClause<ElemTy>> &Clauses,
+    SourceLoc &EndLoc, bool HadMissingEnd,
+    llvm::function_ref<void(SmallVectorImpl<ElemTy> &, bool)> parseElements) {
+  Parser::StructureMarkerRAII ParsingDecl(
+      P, P.Tok.getLoc(), Parser::StructureMarkerKind::IfConfig);
+
+  bool foundActive = false;
+  ConditionalCompilationExprState ConfigState;
+  while (1) {
+    bool isElse = P.Tok.is(tok::pound_else);
+    SourceLoc ClauseLoc = P.consumeToken();
+    Expr *Condition = nullptr;
+
+    // Parse and evaluate the directive.
+    if (isElse) {
+      ConfigState.setConditionActive(!foundActive);
+    } else {
+      llvm::SaveAndRestore<bool> S(P.InPoundIfEnvironment, true);
+      ParserResult<Expr> Result = P.parseExprSequence(diag::expected_expr,
+                                                      /*isBasic*/true,
+                                                      /*isForDirective*/true);
+      if (Result.isNull())
+        return makeParserError();
+
+      Condition = Result.get();
+
+      // Evaluate the condition, to validate it.
+      ConfigState = P.classifyConditionalCompilationExpr(Condition, P.Context,
+                                                         P.Diags);
+      if (foundActive)
+        ConfigState.setConditionActive(false);
+    }
+
+    foundActive |= ConfigState.isConditionActive();
+
+    if (!P.Tok.isAtStartOfLine() && P.Tok.isNot(tok::eof)) {
+      P.diagnose(P.Tok.getLoc(),
+                 diag::extra_tokens_conditional_compilation_directive);
+    }
+
+    // Parse elements
+    SmallVector<ElemTy, N> Elements;
+    if (ConfigState.shouldParse()) {
+      parseElements(Elements, ConfigState.isConditionActive());
+    } else {
+      DiagnosticTransaction DT(P.Diags);
+      P.skipUntilConditionalBlockClose();
+      DT.abort();
+    }
+
+    Clauses.push_back(IfConfigClause<ElemTy>(ClauseLoc, Condition,
+                                             P.Context.AllocateCopy(Elements),
+                                             ConfigState.isConditionActive()));
+
+    if (P.Tok.isNot(tok::pound_elseif, tok::pound_else))
+      break;
+
+    if (isElse)
+      P.diagnose(P.Tok, diag::expected_close_after_else_directive);
+  }
+
+  HadMissingEnd = P.parseEndIfDirective(EndLoc);
+  return makeParserSuccess();
+}
+
+ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
+  SmallVector<IfConfigClause<Decl *>, 4> Clauses;
+  SourceLoc EndLoc;
+  bool HadMissingEnd = false;
+  auto Status = parseIfConfig<Decl *, 8>(
+      *this, Clauses, EndLoc, HadMissingEnd,
+      [&](SmallVectorImpl<Decl *> &Decls, bool IsActive) {
+    Optional<Scope> scope;
+    if (!IsActive)
+      scope.emplace(this, getScopeInfo().getCurrentScope()->getKind(),
+                    /*inactiveConfigBlock=*/true);
+
+    ParserStatus Status;
+    bool PreviousHadSemi = true;
+    while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif,
+                      tok::eof)) {
+      if (Tok.is(tok::r_brace)) {
+        diagnose(Tok.getLoc(),
+                  diag::unexpected_rbrace_in_conditional_compilation_block);
+        // If we see '}', following declarations don't look like belong to
+        // the current decl context; skip them.
+        skipUntilConditionalBlockClose();
+        break;
+      }
+      Status |= parseDeclItem(PreviousHadSemi, Flags,
+                              [&](Decl *D) {Decls.push_back(D);});
+    }
+  });
+  if (Status.isError())
+    return makeParserErrorResult<IfConfigDecl>();
+
+  IfConfigDecl *ICD = new (Context) IfConfigDecl(CurDeclContext,
+                                                 Context.AllocateCopy(Clauses),
+                                                 EndLoc, HadMissingEnd);
+  return makeParserResult(ICD);
+}
+
+ParserResult<Stmt> Parser::parseStmtIfConfig(BraceItemListKind Kind) {
+  SmallVector<IfConfigClause<ASTNode>, 4> Clauses;
+  SourceLoc EndLoc;
+  bool HadMissingEnd = false;
+  auto Status = parseIfConfig<ASTNode, 16>(
+      *this, Clauses, EndLoc, HadMissingEnd,
+      [&](SmallVectorImpl<ASTNode> &Elements, bool IsActive) {
+    parseBraceItems(Elements, Kind, IsActive
+                      ? BraceItemListKind::ActiveConditionalBlock
+                      : BraceItemListKind::InactiveConditionalBlock);
+  });
+  if (Status.isError())
+    return makeParserErrorResult<Stmt>();
+
+  auto *ICS = new (Context) IfConfigStmt(Context.AllocateCopy(Clauses),
+                                         EndLoc, HadMissingEnd);
+  return makeParserResult(ICS);
+}
+
+// Evaluate a subset of expression types suitable for build configuration
+// conditional expressions.  The accepted expression types are:
+//  - The magic constants "true" and "false".
+//  - Named decl ref expressions ("FOO")
+//  - Parenthesized expressions ("(FOO)")
+//  - Binary "&&" or "||" operations applied to other build configuration
+//    conditional expressions
+//  - Unary "!" expressions applied to other build configuration conditional
+//    expressions
+//  - Single-argument call expressions, where the function being invoked is a
+//    supported target configuration (currently "os", "arch", and
+//    "_compiler_version"), and whose argument is a named decl ref expression
+ConditionalCompilationExprState
+Parser::classifyConditionalCompilationExpr(Expr *condition,
+                                           ASTContext &Context,
+                                           DiagnosticEngine &D) {
+  assert(condition && "Cannot classify a NULL condition expression!");
+
+  // Evaluate a ParenExpr.
+  if (auto *PE = dyn_cast<ParenExpr>(condition))
+    return classifyConditionalCompilationExpr(PE->getSubExpr(), Context, D);
+
+  // Evaluate a "&&" or "||" expression.
+  if (auto *SE = dyn_cast<SequenceExpr>(condition)) {
+    // Check for '&&' or '||' as the expression type.
+    if (SE->getNumElements() < 3) {
+      D.diagnose(SE->getLoc(),
+                 diag::unsupported_conditional_compilation_binary_expression);
+      return ConditionalCompilationExprState::error();
+    }
+    // Before type checking, chains of binary expressions will not be fully
+    // parsed, so associativity has not yet been encoded in the subtree.
+    auto elements = SE->getElements();
+    auto numElements = SE->getNumElements();
+    size_t iOperator = 1;
+    size_t iOperand = 2;
+
+    auto result = classifyConditionalCompilationExpr(elements[0], Context, D);
+
+    while (iOperand < numElements) {
+
+      if (auto *UDREOp = dyn_cast<UnresolvedDeclRefExpr>(elements[iOperator])) {
+        auto name = UDREOp->getName().getBaseName().str();
+
+        if (name.equals("||") || name.equals("&&")) {
+          auto rhs = classifyConditionalCompilationExpr(elements[iOperand],
+                                                        Context, D);
+
+          if (name.equals("||")) {
+            result = result || rhs;
+            if (result.isConditionActive())
+              break;
+          }
+
+          if (name.equals("&&")) {
+            result = result && rhs;
+            if (!result.isConditionActive())
+              break;
+          }
+        } else {
+          D.diagnose(
+              SE->getLoc(),
+              diag::unsupported_conditional_compilation_binary_expression);
+          return ConditionalCompilationExprState::error();
+        }
+      } else {
+        // Swift3 didn't have this branch. the operator and the RHS are
+        // silently ignored.
+        if (!Context.isSwiftVersion3()) {
+          D.diagnose(
+              elements[iOperator]->getLoc(),
+              diag::unsupported_conditional_compilation_expression_type);
+          return ConditionalCompilationExprState::error();
+        } else {
+          SourceRange ignoredRange(elements[iOperator]->getLoc(),
+                                   elements[iOperand]->getEndLoc());
+          D.diagnose(
+              elements[iOperator]->getLoc(),
+              diag::swift3_unsupported_conditional_compilation_expression_type)
+            .highlight(ignoredRange);
+        }
+      }
+
+      iOperator += 2;
+      iOperand += 2;
+    }
+
+    return result;
+  }
+
+  // Evaluate a named reference expression.
+  if (auto *UDRE = dyn_cast<UnresolvedDeclRefExpr>(condition)) {
+    auto name = UDRE->getName().getBaseName().str();
+    return {Context.LangOpts.isCustomConditionalCompilationFlagSet(name),
+      ConditionalCompilationExprKind::DeclRef};
+  }
+
+  // Evaluate a Boolean literal.
+  if (auto *boolLit = dyn_cast<BooleanLiteralExpr>(condition)) {
+    return {boolLit->getValue(), ConditionalCompilationExprKind::Boolean};
+  }
+
+  // Evaluate a negation (unary "!") expression.
+  if (auto *PUE = dyn_cast<PrefixUnaryExpr>(condition)) {
+    // If the PUE is not a negation expression, return false
+    auto name =
+    cast<UnresolvedDeclRefExpr>(PUE->getFn())->getName().getBaseName().str();
+    if (name != "!") {
+      D.diagnose(PUE->getLoc(),
+                 diag::unsupported_conditional_compilation_unary_expression);
+      return ConditionalCompilationExprState::error();
+    }
+
+    return !classifyConditionalCompilationExpr(PUE->getArg(), Context, D);
+  }
+
+  // Evaluate a target config call expression.
+  if (auto *CE = dyn_cast<CallExpr>(condition)) {
+    // look up target config, and compare value
+    auto fnNameExpr = dyn_cast<UnresolvedDeclRefExpr>(CE->getFn());
+
+    // Get the arg, which should be in a paren expression.
+    if (!fnNameExpr) {
+      D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_expression);
+      return ConditionalCompilationExprState::error();
+    }
+
+    auto fnName = fnNameExpr->getName().getBaseName().str();
+
+    auto *PE = dyn_cast<ParenExpr>(CE->getArg());
+    if (!PE) {
+      auto diag = D.diagnose(CE->getLoc(),
+                             diag::platform_condition_expected_one_argument);
+      return ConditionalCompilationExprState::error();
+    }
+
+    if (!fnName.equals("arch") && !fnName.equals("os") &&
+        !fnName.equals("_endian") &&
+        !fnName.equals("_runtime") &&
+        !fnName.equals("swift") &&
+        !fnName.equals("_compiler_version")) {
+      D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_expression);
+      return ConditionalCompilationExprState::error();
+    }
+
+    if (fnName.equals("_compiler_version")) {
+      if (auto SLE = dyn_cast<StringLiteralExpr>(PE->getSubExpr())) {
+        if (SLE->getValue().empty()) {
+          D.diagnose(CE->getLoc(), diag::empty_version_string);
+          return ConditionalCompilationExprState::error();
+        }
+        auto versionRequirement =
+        version::Version::parseCompilerVersionString(SLE->getValue(),
+                                                     SLE->getLoc(),
+                                                     &D);
+        auto thisVersion = version::Version::getCurrentCompilerVersion();
+        auto VersionNewEnough = thisVersion >= versionRequirement;
+        return {VersionNewEnough,
+          ConditionalCompilationExprKind::CompilerVersion};
+      } else {
+        D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_argument,
+                 "string literal");
+        return ConditionalCompilationExprState::error();
+      }
+    } else if (fnName.equals("swift")) {
+      auto PUE = dyn_cast<PrefixUnaryExpr>(PE->getSubExpr());
+      if (!PUE) {
+        D.diagnose(PE->getSubExpr()->getLoc(),
+                   diag::unsupported_platform_condition_argument,
+                   "a unary comparison, such as '>=2.2'");
+        return ConditionalCompilationExprState::error();
+      }
+
+      auto prefix = dyn_cast<UnresolvedDeclRefExpr>(PUE->getFn());
+      auto versionArg = PUE->getArg();
+      auto versionStartLoc = versionArg->getStartLoc();
+      auto endLoc = Lexer::getLocForEndOfToken(Context.SourceMgr,
+                                               versionArg->getSourceRange().End);
+      CharSourceRange versionCharRange(Context.SourceMgr, versionStartLoc,
+                                       endLoc);
+      auto versionString = Context.SourceMgr.extractText(versionCharRange);
+
+      auto versionRequirement =
+        version::Version::parseVersionString(versionString,
+                                             versionStartLoc,
+                                             &D);
+
+      if (!versionRequirement.hasValue())
+        return ConditionalCompilationExprState::error();
+
+      auto thisVersion = Context.LangOpts.EffectiveLanguageVersion;
+
+      if (!prefix->getName().getBaseName().str().equals(">=")) {
+        D.diagnose(PUE->getFn()->getLoc(),
+                   diag::unexpected_version_comparison_operator)
+          .fixItReplace(PUE->getFn()->getLoc(), ">=");
+        return ConditionalCompilationExprState::error();
+      }
+
+      auto VersionNewEnough = thisVersion >= versionRequirement.getValue();
+      return {VersionNewEnough,
+        ConditionalCompilationExprKind::LanguageVersion};
+    } else {
+      if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(PE->getSubExpr())) {
+        // The sub expression should be an UnresolvedDeclRefExpr (we won't
+        // tolerate extra parens).
+        auto argumentIdent = UDRE->getName().getBaseName();
+        auto argument = argumentIdent.str();
+        PlatformConditionKind Kind =
+          llvm::StringSwitch<PlatformConditionKind>(fnName)
+          .Case("os", PlatformConditionKind::OS)
+          .Case("arch", PlatformConditionKind::Arch)
+          .Case("_endian", PlatformConditionKind::Endianness)
+          .Case("_runtime", PlatformConditionKind::Runtime);
+
+        // FIXME: Perform the replacement macOS -> OSX elsewhere.
+        if (Kind == PlatformConditionKind::OS && argument == "macOS")
+          argument = "OSX";
+
+        std::vector<StringRef> suggestions;
+        if (!LangOptions::checkPlatformConditionSupported(Kind, argument,
+                                                          suggestions)) {
+          if (Kind == PlatformConditionKind::Runtime) {
+            // Error for _runtime()
+            D.diagnose(UDRE->getLoc(),
+                       diag::unsupported_platform_runtime_condition_argument);
+            return ConditionalCompilationExprState::error();
+          }
+          StringRef DiagName;
+          switch (Kind) {
+          case PlatformConditionKind::OS:
+            DiagName = "operating system"; break;
+          case PlatformConditionKind::Arch:
+            DiagName = "architecture"; break;
+          case PlatformConditionKind::Endianness:
+            DiagName = "endianness"; break;
+          case PlatformConditionKind::Runtime:
+            llvm_unreachable("handled above");
+          }
+          D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
+                     DiagName, fnName);
+          for (const StringRef &suggestion : suggestions) {
+            D.diagnose(UDRE->getLoc(), diag::note_typo_candidate, suggestion)
+              .fixItReplace(UDRE->getSourceRange(), suggestion);
+          }
+        }
+
+        auto target = Context.LangOpts.getPlatformConditionValue(Kind);
+        return {target == argument, ConditionalCompilationExprKind::DeclRef};
+      } else {
+        D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_argument,
+                   "identifier");
+        return ConditionalCompilationExprState::error();
+      }
+    }
+  }
+
+  // "#if 0" isn't valid, but it is common, so recognize it and handle it
+  // with a fixit elegantly.
+  if (auto *IL = dyn_cast<IntegerLiteralExpr>(condition))
+    if (IL->getDigitsText() == "0" || IL->getDigitsText() == "1") {
+      StringRef replacement = IL->getDigitsText() == "0" ? "false" :"true";
+      D.diagnose(IL->getLoc(), diag::unsupported_conditional_compilation_integer,
+                 IL->getDigitsText(), replacement)
+       .fixItReplace(IL->getLoc(), replacement);
+      return {IL->getDigitsText() == "1",
+        ConditionalCompilationExprKind::Integer};
+    }
+
+
+  // If we've gotten here, it's an unsupported expression type.
+  D.diagnose(condition->getLoc(),
+             diag::unsupported_conditional_compilation_expression_type);
+  return ConditionalCompilationExprState::error();
+}
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index 771cdda..dedf8c8 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -2133,9 +2133,9 @@
     UNARY_INSTRUCTION(DestroyValue)
     UNARY_INSTRUCTION(CondFail)
     UNARY_INSTRUCTION(EndBorrowArgument)
-    UNARY_INSTRUCTION(UnmanagedReleaseValue)
-    UNARY_INSTRUCTION(UnmanagedRetainValue)
-    UNARY_INSTRUCTION(UnmanagedAutoreleaseValue)
+    REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
+    REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
+    REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
     REFCOUNTING_INSTRUCTION(StrongPin)
     REFCOUNTING_INSTRUCTION(StrongRetain)
     REFCOUNTING_INSTRUCTION(StrongRelease)
@@ -3724,6 +3724,12 @@
     ResultVal = B.createDeinitExistentialAddr(InstLoc, Val);
     break;
   }
+  case ValueKind::DeinitExistentialOpaqueInst: {
+    if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
+      return true;
+    ResultVal = B.createDeinitExistentialOpaque(InstLoc, Val);
+    break;
+  }
   case ValueKind::InitExistentialAddrInst: {
     CanType Ty;
     SourceLoc TyLoc;
@@ -3758,7 +3764,7 @@
     SourceLoc TyLoc;
 
     if (parseTypedValueRef(Val, B) ||
-        P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
+        P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
         P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
         parseASTType(FormalConcreteTy, TyLoc) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index ed621fd..f670b8b 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1486,358 +1486,6 @@
               new (Context) GuardStmt(GuardLoc, Condition, Body.get()));
 }
 
-
-// Evaluate a subset of expression types suitable for build configuration
-// conditional expressions.  The accepted expression types are:
-//  - The magic constants "true" and "false".
-//  - Named decl ref expressions ("FOO")
-//  - Parenthesized expressions ("(FOO)")
-//  - Binary "&&" or "||" operations applied to other build configuration
-//    conditional expressions
-//  - Unary "!" expressions applied to other build configuration conditional
-//    expressions
-//  - Single-argument call expressions, where the function being invoked is a
-//    supported target configuration (currently "os", "arch", and
-//    "_compiler_version"), and whose argument is a named decl ref expression
-ConditionalCompilationExprState
-Parser::classifyConditionalCompilationExpr(Expr *condition,
-                                           ASTContext &Context,
-                                           DiagnosticEngine &D) {
-  assert(condition && "Cannot classify a NULL condition expression!");
-
-  // Evaluate a ParenExpr.
-  if (auto *PE = dyn_cast<ParenExpr>(condition))
-    return classifyConditionalCompilationExpr(PE->getSubExpr(), Context, D);
-
-  // Evaluate a "&&" or "||" expression.
-  if (auto *SE = dyn_cast<SequenceExpr>(condition)) {
-    // Check for '&&' or '||' as the expression type.
-    if (SE->getNumElements() < 3) {
-      D.diagnose(SE->getLoc(),
-                 diag::unsupported_conditional_compilation_binary_expression);
-      return ConditionalCompilationExprState::error();
-    }
-    // Before type checking, chains of binary expressions will not be fully
-    // parsed, so associativity has not yet been encoded in the subtree.
-    auto elements = SE->getElements();
-    auto numElements = SE->getNumElements();
-    size_t iOperator = 1;
-    size_t iOperand = 2;
-
-    auto result = classifyConditionalCompilationExpr(elements[0], Context, D);
-
-    while (iOperand < numElements) {
-
-      if (auto *UDREOp = dyn_cast<UnresolvedDeclRefExpr>(elements[iOperator])) {
-        auto name = UDREOp->getName().getBaseName().str();
-
-        if (name.equals("||") || name.equals("&&")) {
-          auto rhs = classifyConditionalCompilationExpr(elements[iOperand],
-                                                        Context, D);
-
-          if (name.equals("||")) {
-            result = result || rhs;
-            if (result.isConditionActive())
-              break;
-          }
-
-          if (name.equals("&&")) {
-            result = result && rhs;
-            if (!result.isConditionActive())
-              break;
-          }
-        } else {
-          D.diagnose(
-              SE->getLoc(),
-              diag::unsupported_conditional_compilation_binary_expression);
-          return ConditionalCompilationExprState::error();
-        }
-      } else {
-        // Swift3 didn't have this branch. the operator and the RHS are
-        // silently ignored.
-        if (!Context.isSwiftVersion3()) {
-          D.diagnose(
-              elements[iOperator]->getLoc(),
-              diag::unsupported_conditional_compilation_expression_type);
-          return ConditionalCompilationExprState::error();
-        } else {
-          SourceRange ignoredRange(elements[iOperator]->getLoc(),
-                                   elements[iOperand]->getEndLoc());
-          D.diagnose(
-              elements[iOperator]->getLoc(),
-              diag::swift3_unsupported_conditional_compilation_expression_type)
-            .highlight(ignoredRange);
-        }
-      }
-
-      iOperator += 2;
-      iOperand += 2;
-    }
-
-    return result;
-  }
-
-  // Evaluate a named reference expression.
-  if (auto *UDRE = dyn_cast<UnresolvedDeclRefExpr>(condition)) {
-    auto name = UDRE->getName().getBaseName().str();
-    return {Context.LangOpts.isCustomConditionalCompilationFlagSet(name),
-      ConditionalCompilationExprKind::DeclRef};
-  }
-
-  // Evaluate a Boolean literal.
-  if (auto *boolLit = dyn_cast<BooleanLiteralExpr>(condition)) {
-    return {boolLit->getValue(), ConditionalCompilationExprKind::Boolean};
-  }
-
-  // Evaluate a negation (unary "!") expression.
-  if (auto *PUE = dyn_cast<PrefixUnaryExpr>(condition)) {
-    // If the PUE is not a negation expression, return false
-    auto name =
-    cast<UnresolvedDeclRefExpr>(PUE->getFn())->getName().getBaseName().str();
-    if (name != "!") {
-      D.diagnose(PUE->getLoc(),
-                 diag::unsupported_conditional_compilation_unary_expression);
-      return ConditionalCompilationExprState::error();
-    }
-
-    return !classifyConditionalCompilationExpr(PUE->getArg(), Context, D);
-  }
-
-  // Evaluate a target config call expression.
-  if (auto *CE = dyn_cast<CallExpr>(condition)) {
-    // look up target config, and compare value
-    auto fnNameExpr = dyn_cast<UnresolvedDeclRefExpr>(CE->getFn());
-
-    // Get the arg, which should be in a paren expression.
-    if (!fnNameExpr) {
-      D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_expression);
-      return ConditionalCompilationExprState::error();
-    }
-
-    auto fnName = fnNameExpr->getName().getBaseName().str();
-
-    auto *PE = dyn_cast<ParenExpr>(CE->getArg());
-    if (!PE) {
-      auto diag = D.diagnose(CE->getLoc(),
-                             diag::platform_condition_expected_one_argument);
-      return ConditionalCompilationExprState::error();
-    }
-
-    if (!fnName.equals("arch") && !fnName.equals("os") &&
-        !fnName.equals("_endian") &&
-        !fnName.equals("_runtime") &&
-        !fnName.equals("swift") &&
-        !fnName.equals("_compiler_version")) {
-      D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_expression);
-      return ConditionalCompilationExprState::error();
-    }
-
-    if (fnName.equals("_compiler_version")) {
-      if (auto SLE = dyn_cast<StringLiteralExpr>(PE->getSubExpr())) {
-        if (SLE->getValue().empty()) {
-          D.diagnose(CE->getLoc(), diag::empty_version_string);
-          return ConditionalCompilationExprState::error();
-        }
-        auto versionRequirement =
-        version::Version::parseCompilerVersionString(SLE->getValue(),
-                                                     SLE->getLoc(),
-                                                     &D);
-        auto thisVersion = version::Version::getCurrentCompilerVersion();
-        auto VersionNewEnough = thisVersion >= versionRequirement;
-        return {VersionNewEnough,
-          ConditionalCompilationExprKind::CompilerVersion};
-      } else {
-        D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_argument,
-                 "string literal");
-        return ConditionalCompilationExprState::error();
-      }
-    } else if (fnName.equals("swift")) {
-      auto PUE = dyn_cast<PrefixUnaryExpr>(PE->getSubExpr());
-      if (!PUE) {
-        D.diagnose(PE->getSubExpr()->getLoc(),
-                   diag::unsupported_platform_condition_argument,
-                   "a unary comparison, such as '>=2.2'");
-        return ConditionalCompilationExprState::error();
-      }
-
-      auto prefix = dyn_cast<UnresolvedDeclRefExpr>(PUE->getFn());
-      auto versionArg = PUE->getArg();
-      auto versionStartLoc = versionArg->getStartLoc();
-      auto endLoc = Lexer::getLocForEndOfToken(Context.SourceMgr,
-                                               versionArg->getSourceRange().End);
-      CharSourceRange versionCharRange(Context.SourceMgr, versionStartLoc,
-                                       endLoc);
-      auto versionString = Context.SourceMgr.extractText(versionCharRange);
-
-      auto versionRequirement =
-        version::Version::parseVersionString(versionString,
-                                             versionStartLoc,
-                                             &D);
-
-      if (!versionRequirement.hasValue())
-        return ConditionalCompilationExprState::error();
-
-      auto thisVersion = Context.LangOpts.EffectiveLanguageVersion;
-
-      if (!prefix->getName().getBaseName().str().equals(">=")) {
-        D.diagnose(PUE->getFn()->getLoc(),
-                   diag::unexpected_version_comparison_operator)
-          .fixItReplace(PUE->getFn()->getLoc(), ">=");
-        return ConditionalCompilationExprState::error();
-      }
-
-      auto VersionNewEnough = thisVersion >= versionRequirement.getValue();
-      return {VersionNewEnough,
-        ConditionalCompilationExprKind::LanguageVersion};
-    } else {
-      if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(PE->getSubExpr())) {
-        // The sub expression should be an UnresolvedDeclRefExpr (we won't
-        // tolerate extra parens).
-        auto argumentIdent = UDRE->getName().getBaseName();
-        auto argument = argumentIdent.str();
-
-        // Error for values that don't make sense if there's a clear definition
-        // of the possible values (as there is for _runtime).
-        if (fnName.equals("_runtime") &&
-            !argument.equals("_ObjC") && !argument.equals("_Native")) {
-          D.diagnose(CE->getLoc(),
-                     diag::unsupported_platform_runtime_condition_argument);
-          return ConditionalCompilationExprState::error();
-        }
-
-        std::vector<StringRef> suggestions;
-        SWIFT_DEFER {
-          for (const StringRef& suggestion : suggestions) {
-            D.diagnose(UDRE->getLoc(), diag::note_typo_candidate,
-                       suggestion)
-            .fixItReplace(UDRE->getSourceRange(), suggestion);
-          }
-        };
-        if (fnName == "os") {
-          if (!LangOptions::checkPlatformConditionOS(argument,
-                                                     suggestions)) {
-            D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
-                       "operating system", fnName);
-            return ConditionalCompilationExprState::error();
-          }
-        } else if (fnName == "arch") {
-          if (!LangOptions::isPlatformConditionArchSupported(argument,
-                                                             suggestions)) {
-            D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
-                       "architecture", fnName);
-            return ConditionalCompilationExprState::error();
-          }
-        } else if (fnName == "_endian") {
-          if (!LangOptions::isPlatformConditionEndiannessSupported(argument,
-                                                                   suggestions)) {
-            D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
-                       "endianness", fnName);
-          }
-        }
-
-        // FIXME: Perform the replacement macOS -> OSX elsewhere.
-        if (fnName == "os" && argument == "macOS")
-          argument = "OSX";
-
-        auto target = Context.LangOpts.getPlatformConditionValue(fnName);
-        return {target == argument, ConditionalCompilationExprKind::DeclRef};
-      } else {
-        D.diagnose(CE->getLoc(), diag::unsupported_platform_condition_argument,
-                   "identifier");
-        return ConditionalCompilationExprState::error();
-      }
-    }
-  }
-
-  // "#if 0" isn't valid, but it is common, so recognize it and handle it
-  // with a fixit elegantly.
-  if (auto *IL = dyn_cast<IntegerLiteralExpr>(condition))
-    if (IL->getDigitsText() == "0" || IL->getDigitsText() == "1") {
-      StringRef replacement = IL->getDigitsText() == "0" ? "false" :"true";
-      D.diagnose(IL->getLoc(), diag::unsupported_conditional_compilation_integer,
-                 IL->getDigitsText(), replacement)
-       .fixItReplace(IL->getLoc(), replacement);
-      return {IL->getDigitsText() == "1",
-        ConditionalCompilationExprKind::Integer};
-    }
-
-
-  // If we've gotten here, it's an unsupported expression type.
-  D.diagnose(condition->getLoc(),
-             diag::unsupported_conditional_compilation_expression_type);
-  return ConditionalCompilationExprState::error();
-}
-
-ParserResult<Stmt> Parser::parseStmtIfConfig(BraceItemListKind Kind) {
-  StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(),
-                                  StructureMarkerKind::IfConfig);
-  SmallVector<IfConfigStmtClause, 4> Clauses;
-
-  bool foundActive = false;
-  ConditionalCompilationExprState ConfigState;
-  while (1) {
-    bool isElse = Tok.is(tok::pound_else);
-    SourceLoc ClauseLoc = consumeToken();
-    Expr *Condition = nullptr;
-
-    if (isElse) {
-      ConfigState.setConditionActive(!foundActive);
-    } else {
-      // Evaluate the condition.
-      llvm::SaveAndRestore<bool> S(InPoundIfEnvironment, true);
-      ParserResult<Expr> Result = parseExprSequence(diag::expected_expr,
-                                                    /*basic*/true,
-                                                    /*isForDirective*/true);
-      if (Result.isNull())
-        return makeParserError();
-
-      Condition = Result.get();
-
-      // Evaluate the condition, to validate it.
-      ConfigState = classifyConditionalCompilationExpr(Condition, Context,
-                                                       Diags);
-      if (foundActive)
-        ConfigState.setConditionActive(false);
-    }
-
-    foundActive |= ConfigState.isConditionActive();
-
-    if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
-      diagnose(Tok.getLoc(),
-               diag::extra_tokens_conditional_compilation_directive);
-    }
-
-    SmallVector<ASTNode, 16> Elements;
-    if (ConfigState.shouldParse()) {
-      parseBraceItems(Elements, Kind,
-                      ConfigState.isConditionActive()
-                        ? BraceItemListKind::ActiveConditionalBlock
-                        : BraceItemListKind::InactiveConditionalBlock);
-    } else {
-      DiagnosticTransaction DT(Diags);
-      skipUntilConditionalBlockClose();
-      DT.abort();
-    }
-
-    Clauses.push_back(IfConfigStmtClause(ClauseLoc, Condition,
-                                         Context.AllocateCopy(Elements),
-                                         ConfigState.isConditionActive()));
-
-    if (Tok.isNot(tok::pound_elseif) && Tok.isNot(tok::pound_else))
-      break;
-
-    if (isElse)
-      diagnose(Tok, diag::expected_close_after_else_directive);
-  }
-
-  SourceLoc EndLoc;
-  bool HadMissingEnd = parseEndIfDirective(EndLoc);
-
-  auto *ICS = new (Context) IfConfigStmt(Context.AllocateCopy(Clauses),
-                                         EndLoc, HadMissingEnd);
-  return makeParserResult(ICS);
-}
-
 /// 
 ///   stmt-while:
 ///     (identifier ':')? 'while' expr-basic stmt-brace
diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp
index 66e142d..32521d1 100644
--- a/lib/PrintAsObjC/PrintAsObjC.cpp
+++ b/lib/PrintAsObjC/PrintAsObjC.cpp
@@ -15,6 +15,7 @@
 #include "swift/AST/AST.h"
 #include "swift/AST/ASTVisitor.h"
 #include "swift/AST/ForeignErrorConvention.h"
+#include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/NameLookup.h"
 #include "swift/AST/PrettyStackTrace.h"
 #include "swift/AST/ProtocolConformance.h"
@@ -172,6 +173,23 @@
     ASTVisitor::visit(const_cast<Decl *>(D));
   }
 
+  void maybePrintObjCGenericParameters(const ClassDecl *importedClass) {
+    auto *clangDecl = importedClass->getClangDecl();
+    auto *objcClass = dyn_cast_or_null<clang::ObjCInterfaceDecl>(clangDecl);
+    if (!objcClass)
+      return;
+    if (!objcClass->getTypeParamList())
+      return;
+    assert(objcClass->getTypeParamList()->size() != 0);
+    os << "<";
+    interleave(*objcClass->getTypeParamList(),
+               [this](const clang::ObjCTypeParamDecl *param) {
+                 os << param->getName();
+               },
+               [this] { os << ", "; });
+    os << ">";
+  }
+
   void printAdHocCategory(iterator_range<const ValueDecl * const *> members) {
     assert(members.begin() != members.end());
 
@@ -182,8 +200,10 @@
       baseClass = extendedTy->getClassOrBoundGenericClass();
     }
 
-    os << "@interface " << getNameForObjC(baseClass)
-    << " (SWIFT_EXTENSION(" << origDC->getParentModule()->getName() << "))\n";
+    os << "@interface " << getNameForObjC(baseClass);
+    maybePrintObjCGenericParameters(baseClass);
+    os << " (SWIFT_EXTENSION(" << origDC->getParentModule()->getName()
+       << "))\n";
     printMembers</*allowDelayed*/true>(members);
     os << "@end\n\n";
   }
@@ -312,8 +332,9 @@
   void visitExtensionDecl(ExtensionDecl *ED) {
     auto baseClass = ED->getExtendedType()->getClassOrBoundGenericClass();
 
-    os << "@interface " << getNameForObjC(baseClass)
-       << " (SWIFT_EXTENSION(" << ED->getModuleContext()->getName() << "))";
+    os << "@interface " << getNameForObjC(baseClass);
+    maybePrintObjCGenericParameters(baseClass);
+    os << " (SWIFT_EXTENSION(" << ED->getModuleContext()->getName() << "))";
     printProtocols(ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit));
     os << "\n";
     printMembers(ED->getMembers());
@@ -1574,6 +1595,30 @@
       visitType(MT, optionalKind);
     }
   }
+
+  void visitGenericTypeParamType(GenericTypeParamType *type,
+                                 Optional<OptionalTypeKind> optionalKind) {
+    const GenericTypeParamDecl *decl = type->getDecl();
+    assert(decl && "can't print canonicalized GenericTypeParamType");
+
+    if (auto *extension = dyn_cast<ExtensionDecl>(decl->getDeclContext())) {
+      const ClassDecl *extendedClass =
+          extension->getAsClassOrClassExtensionContext();
+      assert(extendedClass->isGeneric());
+      assert(extension->getGenericParams()->size() ==
+             extendedClass->getGenericParams()->size() &&
+             "extensions with custom generic parameters?");
+      assert(extension->getGenericSignature()->getCanonicalSignature() ==
+             extendedClass->getGenericSignature()->getCanonicalSignature() &&
+             "constrained extensions or custom generic parameters?");
+      type = extendedClass->getGenericEnvironment()->getSugaredType(type);
+      decl = type->getDecl();
+    }
+
+    assert(decl->getClangDecl() && "can only handle imported ObjC generics");
+    os << cast<clang::ObjCTypeParamDecl>(decl->getClangDecl())->getName();
+    printNullability(optionalKind);
+  }
                       
   void printFunctionType(FunctionType *FT, char pointerSigil,
                          Optional<OptionalTypeKind> optionalKind) {
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index e528d87..eedca48 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -1139,23 +1139,30 @@
   // non-NSError superclass constraint. Casts to archetypes thus must always be
   // indirect.
   if (auto archetype = targetType->getAs<ArchetypeType>()) {
-    auto super = archetype->getSuperclass();
-    if (super.isNull())
-      return false;
-
     // Only ever permit this if the source type is a reference type.
     if (!objectType.isAnyClassReferenceType())
       return false;
+    
+    if (M.getASTContext().LangOpts.EnableObjCInterop) {
+      auto super = archetype->getSuperclass();
+      if (super.isNull())
+        return false;
 
-    // A base class constraint that isn't NSError rules out the archetype being
-    // bound to NSError.
-    if (auto nserror = M.Types.getNSErrorType())
-      return !super->isEqual(nserror);
-    // If NSError wasn't loaded, any base class constraint must not be NSError.
-    return true;
+      // A base class constraint that isn't NSError rules out the archetype being
+      // bound to NSError.
+        if (auto nserror = M.Types.getNSErrorType())
+          return !super->isEqual(nserror);
+      // If NSError wasn't loaded, any base class constraint must not be NSError.
+      return true;
+    } else {
+      // If ObjC bridging isn't enabled, we can do a scalar cast from any
+      // reference type to any class-constrained archetype.
+      return archetype->requiresClass();
+    }
   }
   
-  if (targetType == M.Types.getNSErrorType()) {
+  if (M.getASTContext().LangOpts.EnableObjCInterop
+      && targetType == M.Types.getNSErrorType()) {
     // If we statically know the source is an NSError subclass, then the cast
     // can go through the scalar path (and it's trivially true so can be
     // killed).
diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp
index 8961f2d..e0dee29 100644
--- a/lib/SIL/SILBuilder.cpp
+++ b/lib/SIL/SILBuilder.cpp
@@ -245,7 +245,7 @@
   }
 
   // If we didn't find a retain to fold this into, emit the release.
-  return createStrongRelease(Loc, Operand, Atomicity::Atomic);
+  return createStrongRelease(Loc, Operand, getDefaultAtomicity());
 }
 
 /// Emit a release_value instruction at the current location, attempting to
@@ -272,7 +272,7 @@
   }
 
   // If we didn't find a retain to fold this into, emit the release.
-  return createReleaseValue(Loc, Operand, Atomicity::Atomic);
+  return createReleaseValue(Loc, Operand, getDefaultAtomicity());
 }
 
 PointerUnion<CopyValueInst *, DestroyValueInst *>
diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp
index d1b799d..e6573ea 100644
--- a/lib/SIL/SILFunction.cpp
+++ b/lib/SIL/SILFunction.cpp
@@ -163,109 +163,24 @@
       getGenericEnvironment(), type);
 }
 
-namespace {
-template<typename SubstFn>
-struct SubstDependentSILType
-  : CanTypeVisitor<SubstDependentSILType<SubstFn>, CanType>
-{
-  SILModule &M;
-  SubstFn Subst;
-  
-  SubstDependentSILType(SILModule &M, SubstFn Subst)
-    : M(M), Subst(std::move(Subst))
-  {}
-  
-  using super = CanTypeVisitor<SubstDependentSILType<SubstFn>, CanType>;
-  using super::visit;
-  
-  CanType visitDependentMemberType(CanDependentMemberType t) {
-    // If a dependent member type appears in lowered position, we need to lower
-    // its context substitution against the associated type's abstraction
-    // pattern.
-    CanType astTy = Subst(t);
-    auto origTy = AbstractionPattern::getOpaque();
-    
-    return M.Types.getLoweredType(origTy, astTy)
-      .getSwiftRValueType();
-  }
-  
-  CanType visitTupleType(CanTupleType t) {
-    // Dependent members can appear in lowered position inside tuples.
-    
-    SmallVector<TupleTypeElt, 4> elements;
-    
-    for (auto &elt : t->getElements())
-      elements.push_back(elt.getWithType(visit(CanType(elt.getType()))));
-    
-    return TupleType::get(elements, t->getASTContext())
-      ->getCanonicalType();
-  }
-  
-  CanType visitSILFunctionType(CanSILFunctionType t) {
-    // Dependent members can appear in lowered position inside SIL functions.
-    
-    SmallVector<SILParameterInfo, 4> params;
-    for (auto &param : t->getParameters())
-      params.push_back(param.map([&](CanType pt) -> CanType {
-        return visit(pt);
-      }));
-
-    SmallVector<SILResultInfo, 4> results;
-    for (auto &result : t->getResults())
-      results.push_back(result.map([&](CanType pt) -> CanType {
-        return visit(pt);
-      }));
-    
-    Optional<SILResultInfo> errorResult;
-    if (t->hasErrorResult()) {
-      errorResult = t->getErrorResult().map([&](CanType elt) -> CanType {
-          return visit(elt);
-      });
-    }
-    
-    return SILFunctionType::get(t->getGenericSignature(),
-                                t->getExtInfo(),
-                                t->getCalleeConvention(),
-                                params, results, errorResult,
-                                t->getASTContext());
-  }
-  
-  CanType visitType(CanType t) {
-    // Other types get substituted into context normally.
-    return Subst(t);
-  }
-};
-
-template<typename SubstFn>
-SILType doSubstDependentSILType(SILModule &M,
-                                SubstFn Subst,
-                                SILType t) {
-  CanType result = SubstDependentSILType<SubstFn>(M, std::move(Subst))
-    .visit(t.getSwiftRValueType());
-  return SILType::getPrimitiveType(result, t.getCategory());
-}
-  
-} // end anonymous namespace
-
 SILType SILFunction::mapTypeIntoContext(SILType type) const {
-  return doSubstDependentSILType(getModule(),
-    [&](CanType t) { return mapTypeIntoContext(t)->getCanonicalType(); },
-    type);
+  if (auto *genericEnv = getGenericEnvironment())
+    return genericEnv->mapTypeIntoContext(getModule(), type);
+  return type;
 }
 
 SILType GenericEnvironment::mapTypeIntoContext(SILModule &M,
                                                SILType type) const {
-  return doSubstDependentSILType(M,
-    [&](CanType t) {
-      return mapTypeIntoContext(t)->getCanonicalType();
-    },
-    type);
+  auto genericSig = getGenericSignature()->getCanonicalSignature();
+  return type.subst(M,
+                    QueryInterfaceTypeSubstitutions(this),
+                    LookUpConformanceInSignature(*genericSig),
+                    genericSig);
 }
 
 Type SILFunction::mapTypeOutOfContext(Type type) const {
   return GenericEnvironment::mapTypeOutOfContext(
-      getGenericEnvironment(),
-      type);
+      getGenericEnvironment(), type);
 }
 
 bool SILFunction::isNoReturnFunction() const {
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index 09cd8f2..3246a39 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -1760,268 +1760,6 @@
   return result;
 }
 
-namespace {
-  class SILFunctionTypeSubstituter {
-    TypeConverter &TC;
-    CanSILFunctionType OrigFnType;
-    ArrayRef<SILParameterInfo> OrigParams;
-    ArrayRef<SILResultInfo> OrigResults;
-    unsigned NextOrigParamIndex = 0;
-    unsigned NextOrigResultIndex = 0;
-    SmallVector<SILParameterInfo, 8> SubstParams;
-    SmallVector<SILResultInfo, 8> SubstResults;
-    const Optional<ForeignErrorConvention> &ForeignError;
-
-  public:
-    SILFunctionTypeSubstituter(
-        TypeConverter &TC, CanSILFunctionType origFnType,
-        const Optional<ForeignErrorConvention> &foreignError)
-        : TC(TC), OrigFnType(origFnType),
-          OrigParams(origFnType->getParameters()),
-          OrigResults(origFnType->getResults()), ForeignError(foreignError) {}
-
-    ArrayRef<SILResultInfo> getSubstResults() const {
-      assert(NextOrigResultIndex == OrigResults.size() &&
-             "didn't claim all results?!");
-      return SubstResults;
-    }
-
-    void substResults(AbstractionPattern origType, CanType substType);
-
-    ArrayRef<SILParameterInfo> getSubstParams() const {
-      assert(NextOrigParamIndex == OrigParams.size() &&
-             "didn't claim all parameters?!");
-      return SubstParams;
-    }
-
-    void substInputs(AbstractionPattern origType, CanType substType) {
-      maybeSkipForeignErrorParameter();
-
-      // Decompose tuples.
-      if (origType.isTuple()) {
-        auto substTuple = cast<TupleType>(substType);
-        assert(origType.getNumTupleElements() == substTuple->getNumElements());
-        for (auto i : indices(substTuple.getElementTypes())) {
-          substInputs(origType.getTupleElementType(i),
-                      substTuple.getElementType(i));
-        }
-        return;
-      }
-
-      // Every other type corresponds to a single parameter in the
-      // original signature, since we're dealing with like-uncurried
-      // types and thus don't have to worry about expanding archetypes
-      // to unmaterializable parameter clauses in result function types.
-      auto origParam = claimNextOrigParam();
-
-      // If the type hasn't changed and doesn't rely on context, just use the
-      // original parameter.
-      if (origType.isExactType(substType) &&
-          !origParam.getType()->hasTypeParameter()) {
-        SubstParams.push_back(origParam);
-        return;
-      }
-
-      // Otherwise, lower the substituted type using the abstraction
-      // patterns of the original.
-      auto &substTL = TC.getTypeLowering(origType, substType);
-      auto substConvention = getSubstConvention(origParam.getConvention(),
-                                                substTL.isTrivial());
-      assert(isIndirectFormalParameter(substConvention)
-             || !substTL.isAddressOnly());
-      addSubstParam(substTL.getLoweredType().getSwiftRValueType(),
-                    substConvention);
-    }
-
-  private:
-    void decomposeResult(AbstractionPattern origType, CanType substType);
-
-    SILParameterInfo claimNextOrigParam() {
-      maybeSkipForeignErrorParameter();
-      return OrigParams[NextOrigParamIndex++];
-    }
-
-    SILResultInfo claimNextOrigResult() {
-      return OrigResults[NextOrigResultIndex++];
-    }
-
-    void maybeSkipForeignErrorParameter() {
-      if (!ForeignError ||
-          NextOrigParamIndex != ForeignError->getErrorParameterIndex())
-        return;
-      SubstParams.push_back(OrigParams[NextOrigParamIndex++]);
-    }
-
-    void addSubstParam(CanType type, ParameterConvention conv) {
-      SubstParams.push_back(SILParameterInfo(type, conv));
-    }
-
-    ParameterConvention getSubstConvention(ParameterConvention orig,
-                                           bool isTrivial) {
-      // We use the original convention, except that we have an
-      // invariant that direct trivial parameters are always unowned.
-      switch (orig) {
-      case ParameterConvention::Direct_Owned:
-      case ParameterConvention::Direct_Guaranteed:
-        if (isTrivial) return ParameterConvention::Direct_Unowned;
-        LLVM_FALLTHROUGH;
-      case ParameterConvention::Direct_Unowned:
-      case ParameterConvention::Indirect_Inout:
-      case ParameterConvention::Indirect_InoutAliasable:
-      case ParameterConvention::Indirect_In:
-      case ParameterConvention::Indirect_In_Guaranteed:
-        return orig;
-      }
-      llvm_unreachable("bad parameter convention");
-    }
-
-    ResultConvention getSubstConvention(ResultConvention orig,
-                                        bool isTrivial) {
-      // We use the original convention, except that we have an
-      // invariant that direct trivial results are always unowned.
-      switch (orig) {
-      case ResultConvention::Owned:
-      case ResultConvention::Autoreleased:
-        if (isTrivial) return ResultConvention::Unowned;
-        LLVM_FALLTHROUGH;
-      case ResultConvention::Indirect:
-      case ResultConvention::Unowned:
-      case ResultConvention::UnownedInnerPointer:
-        return orig;
-      }
-      llvm_unreachable("bad parameter convention");
-    }
-  };
-} // end anonymous namespace
-
-void SILFunctionTypeSubstituter::substResults(AbstractionPattern origResultType,
-                                              CanType substResultType) {
-  // Fast path: if the results of the original type are not type-dependent,
-  // we can just copy them over.
-  auto allResults = OrigFnType->getResults();
-  if (std::find_if(allResults.begin(), allResults.end(),
-                   [&](SILResultInfo result) { 
-                     return result.getType()->hasTypeParameter();
-                   }) == allResults.end()) {
-    SubstResults.append(allResults.begin(), allResults.end());
-    return;
-  }
-
-  // Okay, we need to walk the types and re-lower.
-
-  // If we have a foreign-error convention that strips result
-  // optionality, we need to wrap both the original and
-  // substituted types in a level of optionality.
-  if (ForeignError && ForeignError->stripsResultOptionality()) {
-    origResultType =
-      AbstractionPattern::getOptional(origResultType, OTK_Optional);
-    substResultType =
-      OptionalType::get(substResultType)->getCanonicalType();
-  }
-
-  decomposeResult(origResultType, substResultType);
-}
-
-void
-SILFunctionTypeSubstituter::decomposeResult(AbstractionPattern origResultType,
-                                            CanType substResultType) {
-  // If the result is a tuple, we need to expand it.
-  if (origResultType.isTuple()) {
-    auto substResultTupleType = cast<TupleType>(substResultType);
-    for (auto eltIndex : indices(substResultTupleType.getElementTypes())) {
-      auto origEltType = origResultType.getTupleElementType(eltIndex);
-      auto substEltType = substResultTupleType.getElementType(eltIndex);
-      decomposeResult(origEltType, substEltType);
-    }
-    return;
-  }
-
-  // Okay, the result is a single value, which will either be an
-  // indirect result or not.
-
-  // Grab the next result.
-  SILResultInfo origResult = claimNextOrigResult();
-
-  // If substitution is trivial, fast path.
-  if (!origResult.getType()->hasTypeParameter()) {
-    SubstResults.push_back(origResult);
-    return;
-  }
-
-  // Lower the substituted result using the abstraction patterns
-  // of the original result.
-  auto &substResultTL = TC.getTypeLowering(origResultType, substResultType);
-  auto loweredResultTy = substResultTL.getLoweredType().getSwiftRValueType();
-
-  // Return the new type with the old convention.
-  SILResultInfo substResult(loweredResultTy,
-                            getSubstConvention(origResult.getConvention(),
-                                               substResultTL.isTrivial()));
-  SubstResults.push_back(substResult);
-}
-
-/// Apply a substitution to the given SILFunctionType so that it has
-/// the form of the normal SILFunctionType for the substituted type,
-/// except using the original conventions.
-///
-/// This is equivalent to
-///    getLoweredType(origLoweredType,
-///                   substLoweredType).castTo<SILFunctionType>()
-/// except that origFnType's conventions may not correspond to the
-/// standard conventions of the lowered type.
-CanSILFunctionType
-TypeConverter::substFunctionType(CanSILFunctionType origFnType,
-                                 CanAnyFunctionType origLoweredType,
-                                 CanAnyFunctionType substLoweredInterfaceType,
-                         const Optional<ForeignErrorConvention> &foreignError) {
-  // FIXME: is this inefficient now?
-  if (origLoweredType == substLoweredInterfaceType)
-    return origFnType;
-
-  // Use the generic parameters from the substituted type.
-  CanGenericSignature genericSig;
-  if (auto genSubstFn = dyn_cast<GenericFunctionType>(substLoweredInterfaceType))
-    genericSig = genSubstFn.getGenericSignature();
-
-  GenericContextScope scope(*this, genericSig);
-  SILFunctionTypeSubstituter substituter(*this, origFnType, foreignError);
-
-  AbstractionPattern origLoweredPattern(origLoweredType);
-
-  // Map the results.
-  substituter.substResults(origLoweredPattern.getFunctionResultType(),
-                           substLoweredInterfaceType.getResult());
-
-  // Map the error result.  Currently this is never dependent.
-  Optional<SILResultInfo> substErrorResult
-    = origFnType->getOptionalErrorResult();
-  assert(!substErrorResult ||
-         (!substErrorResult->getType()->hasTypeParameter() &&
-          !substErrorResult->getType()->hasArchetype()));
-
-  // Map the inputs.
-  substituter.substInputs(origLoweredPattern.getFunctionInputType(),
-                          substLoweredInterfaceType.getInput());
-
-  // Allow the substituted type to add thick-ness, but not remove it.
-  assert(!origFnType->getExtInfo().hasContext()
-           || substLoweredInterfaceType->getExtInfo().hasContext());
-  assert(substLoweredInterfaceType->getExtInfo().getSILRepresentation()
-           == substLoweredInterfaceType->getExtInfo().getSILRepresentation());
-
-  auto rep = substLoweredInterfaceType->getExtInfo().getSILRepresentation();
-  auto extInfo = origFnType->getExtInfo().withRepresentation(rep);
-
-  // FIXME: Map into archetype context.
-  return SILFunctionType::get(genericSig,
-                              extInfo,
-                              origFnType->getCalleeConvention(),
-                              substituter.getSubstParams(),
-                              substituter.getSubstResults(),
-                              substErrorResult,
-                              Context);
-}
-
 /// Returns the SILParameterInfo for the given declaration's `self` parameter.
 /// `constant` must refer to a method.
 SILParameterInfo TypeConverter::getConstantSelfParameter(SILDeclRef constant) {
@@ -2129,27 +1867,38 @@
     SILModule &TheSILModule;
     TypeSubstitutionFn Subst;
     LookupConformanceFn Conformances;
+    // The signature for the original type.
+    //
+    // Replacement types are lowered with respect to the current
+    // context signature.
+    CanGenericSignature Sig;
 
     ASTContext &getASTContext() { return TheSILModule.getASTContext(); }
 
   public:
     SILTypeSubstituter(SILModule &silModule,
                        TypeSubstitutionFn Subst,
-                       LookupConformanceFn Conformances)
+                       LookupConformanceFn Conformances,
+                       CanGenericSignature Sig)
       : TheSILModule(silModule),
         Subst(Subst),
-        Conformances(Conformances)
+        Conformances(Conformances),
+        Sig(Sig)
     {}
 
     // SIL type lowering only does special things to tuples and functions.
 
-    /// Functions need to preserve their abstraction structure.
-    CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType,
-                                            bool dropGenerics = false)
-    {
-      GenericContextScope scope(TheSILModule.Types,
-                                origType->getGenericSignature());
+    // When a function appears inside of another type, we only perform
+    // substitutions if it does not have a generic signature.
+    CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType) {
+      if (origType->getGenericSignature())
+        return origType;
 
+      return substSILFunctionType(origType);
+    }
+
+    // Entry point for use by SILType::substGenericArgs().
+    CanSILFunctionType substSILFunctionType(CanSILFunctionType origType) {
       SmallVector<SILResultInfo, 8> substResults;
       substResults.reserve(origType->getNumResults());
       for (auto origResult : origType->getResults()) {
@@ -2167,10 +1916,7 @@
         substParams.push_back(subst(origParam));
       }
 
-      auto genericSig
-        = (dropGenerics ? nullptr : origType->getGenericSignature());
-
-      return SILFunctionType::get(genericSig,
+      return SILFunctionType::get(nullptr,
                                   origType->getExtInfo(),
                                   origType->getCalleeConvention(),
                                   substParams, substResults,
@@ -2230,16 +1976,7 @@
     CanType visitType(CanType origType) {
       assert(!isa<AnyFunctionType>(origType));
       assert(!isa<LValueType>(origType) && !isa<InOutType>(origType));
-
-      CanGenericSignature genericSig =
-          TheSILModule.Types.getCurGenericContext();
-      AbstractionPattern abstraction(genericSig, origType);
-
-      assert(TheSILModule.Types.getLoweredType(abstraction, origType)
-               .getSwiftRValueType() == origType);
-
-      CanType substType =
-        origType.subst(Subst, Conformances, None)->getCanonicalType();
+      auto substType = origType.subst(Subst, Conformances)->getCanonicalType();
 
       // If the substitution didn't change anything, we know that the
       // original type was a lowered type, so we're good.
@@ -2247,6 +1984,7 @@
         return origType;
       }
 
+      AbstractionPattern abstraction(Sig, origType);
       return TheSILModule.Types.getLoweredType(abstraction, substType)
                .getSwiftRValueType();
     }
@@ -2255,8 +1993,15 @@
 
 SILType SILType::subst(SILModule &silModule,
                        TypeSubstitutionFn subs,
-                       LookupConformanceFn conformances) const {
-  SILTypeSubstituter STST(silModule, subs, conformances);
+                       LookupConformanceFn conformances,
+                       CanGenericSignature genericSig) const {
+  if (!hasArchetype() && !hasTypeParameter())
+    return *this;
+
+  if (!genericSig)
+    genericSig = silModule.Types.getCurGenericContext();
+  SILTypeSubstituter STST(silModule, subs, conformances,
+                          genericSig);
   return STST.subst(*this);
 }
 
@@ -2266,16 +2011,6 @@
                LookUpConformanceInSubstitutionMap(subs));
 }
 
-CanSILFunctionType SILType::substFuncType(SILModule &silModule,
-                                          const SubstitutionMap &subs,
-                                          CanSILFunctionType SrcTy,
-                                          bool dropGenerics) {
-  auto subFn = QuerySubstitutionMap{subs};
-  auto lookupFn = LookUpConformanceInSubstitutionMap(subs);
-  SILTypeSubstituter STST(silModule, subFn, lookupFn);
-  return STST.visitSILFunctionType(SrcTy, dropGenerics);
-}
-
 /// Apply a substitution to this polymorphic SILFunctionType so that
 /// it has the form of the normal SILFunctionType for the substituted
 /// type, except using the original conventions.
@@ -2313,9 +2048,9 @@
                                   TypeSubstitutionFn subs,
                                   LookupConformanceFn conformances) {
   if (!isPolymorphic()) return CanSILFunctionType(this);
-  SILTypeSubstituter substituter(silModule, subs, conformances);
-  return substituter.visitSILFunctionType(CanSILFunctionType(this),
-                                          /*dropGenerics*/ true);
+  SILTypeSubstituter substituter(silModule, subs, conformances,
+                                 getGenericSignature());
+  return substituter.substSILFunctionType(CanSILFunctionType(this));
 }
 
 /// Fast path for bridging types in a function type without uncurrying.
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index b8c1344..70da549 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -457,6 +457,7 @@
 CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, CheckedCastBranch)
 CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, SwitchEnum)
 CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, InitExistentialOpaque)
+CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, DeinitExistentialOpaque)
 #undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
 
 #define ACCEPTS_ANY_OWNERSHIP_INST(INST)                                       \
@@ -1785,6 +1786,12 @@
   // If SILOwnership is not enabled, do not perform verification.
   if (!getModule().getOptions().EnableSILOwnership)
     return;
+
+  // If the given function has unqualified ownership, there is nothing to
+  // verify.
+  if (getFunction()->hasUnqualifiedOwnership())
+    return;
+
   // If we are testing the verifier, bail so we only print errors once when
   // performing a full verification, instead of additionally in the SILBuilder.
   if (IsSILOwnershipVerifierTestingEnabled)
@@ -1808,6 +1815,21 @@
 void SILValue::verifyOwnership(SILModule &Mod,
                                TransitivelyUnreachableBlocksInfo *TUB) const {
 #ifndef NDEBUG
+  // If we are SILUndef, just bail. SILUndef can pair with anything. Any uses of
+  // the SILUndef will make sure that the matching checks out.
+  if (isa<SILUndef>(*this))
+    return;
+
+  // Since we do not have SILUndef, we now know that getFunction() should return
+  // a real function. Assert in case this assumption is no longer true.
+  SILFunction *F = (*this)->getFunction();
+  assert(F && "Instructions and arguments should have a function");
+
+  // If the given function has unqualified ownership, there is nothing further
+  // to verify.
+  if (F->hasUnqualifiedOwnership())
+    return;
+
   if (TUB) {
     SILValueOwnershipChecker(Mod, *TUB, *this).check();
   } else {
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index a9f2d52..654a13a 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1522,6 +1522,9 @@
   void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *DEI) {
     *this << getIDAndType(DEI->getOperand());
   }
+  void visitDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *DEI) {
+    *this << getIDAndType(DEI->getOperand());
+  }
   void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEI) {
     *this << getIDAndType(DEI->getOperand()) << ", $" << DEI->getConcreteType();
   }
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index 95f249b..1a154c7 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -460,6 +460,10 @@
 /// Error existentials.
 static bool isBridgedErrorClass(SILModule &M,
                                 Type t) {
+  // There's no bridging if ObjC interop is disabled.
+  if (!M.getASTContext().LangOpts.EnableObjCInterop)
+    return false;
+
   if (!t)
     return false;
 
@@ -565,21 +569,13 @@
   
   // Apply generic arguments if the layout is generic.
   if (!getGenericArgs().empty()) {
-    // FIXME: Map the field type into the layout's generic context because
-    // SIL TypeLowering currently expects to lower abstract generic parameters
-    // with a generic context pushed, but nested generic contexts are not
-    // supported by TypeLowering. If TypeLowering were properly
-    // de-contextualized and plumbed through the generic signature, this could
-    // be avoided.
-    auto *env = getLayout()->getGenericSignature()
-      .getGenericEnvironment(*M.getSwiftModule());
-    auto substMap =
-      env->getSubstitutionMap(getGenericArgs());
-    fieldTy = env->mapTypeIntoContext(fieldTy)
-      ->getCanonicalType();
-    
-    fieldTy = SILType::getPrimitiveObjectType(fieldTy)
-      .subst(M, substMap)
+    auto sig = getLayout()->getGenericSignature();
+    auto subs = sig->getSubstitutionMap(getGenericArgs());
+    return SILType::getPrimitiveObjectType(fieldTy)
+      .subst(M,
+             QuerySubstitutionMap{subs},
+             LookUpConformanceInSubstitutionMap(subs),
+             sig)
       .getSwiftRValueType();
   }
   return fieldTy;
diff --git a/lib/SIL/SILValue.cpp b/lib/SIL/SILValue.cpp
index 7de3009..f9bf589 100644
--- a/lib/SIL/SILValue.cpp
+++ b/lib/SIL/SILValue.cpp
@@ -331,6 +331,7 @@
 NO_RESULT_OWNERSHIP_INST(AllocGlobal)
 NO_RESULT_OWNERSHIP_INST(InjectEnumAddr)
 NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
+NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque)
 NO_RESULT_OWNERSHIP_INST(CondFail)
 
 // Terminators. These do not produce SILValue, so they do not have a
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index dfd06f9..541709a 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -1288,7 +1288,7 @@
             PointerRVType->is<UnownedStorageType>(),
             "load_unowned operand must be an unowned address");
     require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() ==
-            LUI->getType().getSwiftType(),
+            LUI->getType().getSwiftRValueType(),
             "Load operand type and result type mismatch");
   }
 
@@ -1301,13 +1301,13 @@
             PointerRVType->is<UnownedStorageType>(),
             "store_unowned address operand must be an unowned address");
     require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() ==
-            SUI->getSrc()->getType().getSwiftType(),
+            SUI->getSrc()->getType().getSwiftRValueType(),
             "Store operand type and dest type mismatch");
   }
 
   void checkLoadWeakInst(LoadWeakInst *LWI) {
     require(LWI->getType().isObject(), "Result of load must be an object");
-    require(LWI->getType().getSwiftType()->getAnyOptionalObjectType(),
+    require(LWI->getType().getAnyOptionalObjectType(),
             "Result of weak load must be an optional");
     auto PointerType = LWI->getOperand()->getType();
     auto PointerRVType = PointerType.getSwiftRValueType();
@@ -1315,14 +1315,14 @@
             PointerRVType->is<WeakStorageType>(),
             "load_weak operand must be a weak address");
     require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() ==
-            LWI->getType().getSwiftType(),
+            LWI->getType().getSwiftRValueType(),
             "Load operand type and result type mismatch");
   }
 
   void checkStoreWeakInst(StoreWeakInst *SWI) {
     require(SWI->getSrc()->getType().isObject(),
             "Can't store from an address source");
-    require(SWI->getSrc()->getType().getSwiftType()->getAnyOptionalObjectType(),
+    require(SWI->getSrc()->getType().getAnyOptionalObjectType(),
             "store_weak must be of an optional value");
     auto PointerType = SWI->getDest()->getType();
     auto PointerRVType = PointerType.getSwiftRValueType();
@@ -1330,7 +1330,7 @@
             PointerRVType->is<WeakStorageType>(),
             "store_weak address operand must be a weak address");
     require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() ==
-            SWI->getSrc()->getType().getSwiftType(),
+            SWI->getSrc()->getType().getSwiftRValueType(),
             "Store operand type and dest type mismatch");
   }
 
@@ -1642,8 +1642,8 @@
             "Tuple field count mismatch!");
 
     for (size_t i = 0, size = TI->getElements().size(); i < size; ++i) {
-      require(TI->getElement(i)->getType().getSwiftType()
-               ->isEqual(ResTy.getElementType(i)),
+      require(TI->getElement(i)->getType().getSwiftRValueType()
+              == ResTy.getElementType(i),
               "Tuple element arguments do not match tuple type!");
     }
   }
@@ -2080,9 +2080,9 @@
 
     require(EMI->getMember().getDecl()->isObjC(), "method must be @objc");
     if (!EMI->getMember().getDecl()->isInstanceMember()) {
-      require(operandType.getSwiftType()->is<MetatypeType>(),
+      require(operandType.is<MetatypeType>(),
               "operand must have metatype type");
-      require(operandType.getSwiftType()->castTo<MetatypeType>()
+      require(operandType.castTo<MetatypeType>()
                 ->getInstanceType()->mayHaveSuperclass(),
               "operand must have metatype of class or class-bounded type");
     }
@@ -2153,7 +2153,7 @@
 
     require(methodClass->getClassOrBoundGenericClass(),
             "super_method must look up a class method");
-    require(!methodClass->isEqual(operandType.getSwiftType()),
+    require(!methodClass->isEqual(operandType.getSwiftRValueType()),
             "super_method operand should be a subtype of the "
             "lookup class type");
   }
@@ -2210,7 +2210,7 @@
 
     CanType resultInstanceTy = OEI->getType().getSwiftRValueType();
 
-    require(OEI->getType().isAddress(),
+    require(OEI->getType().isAddress() || !fnConv.useLoweredAddresses(),
             "open_existential_box result must be an address");
 
     auto archetype = getOpenedArchetypeOf(resultInstanceTy);
@@ -2358,7 +2358,7 @@
 
   void checkInitExistentialRefInst(InitExistentialRefInst *IEI) {
     SILType concreteType = IEI->getOperand()->getType();
-    require(concreteType.getSwiftType()->isBridgeableObjectType(),
+    require(concreteType.getSwiftRValueType()->isBridgeableObjectType(),
             "init_existential_ref operand must be a class instance");
     require(IEI->getType().canUseExistentialRepresentation(F.getModule(),
                                      ExistentialRepresentation::Class,
@@ -2390,10 +2390,19 @@
     SILType exType = DEI->getOperand()->getType();
     require(exType.isAddress(),
             "deinit_existential_addr must be applied to an address");
-    require(exType.canUseExistentialRepresentation(F.getModule(),
-                                       ExistentialRepresentation::Opaque),
-            "deinit_existential_addr must be applied to an opaque "
-            "existential");
+    require(exType.canUseExistentialRepresentation(
+                F.getModule(), ExistentialRepresentation::Opaque),
+            "deinit_existential_addr must be applied to an opaque existential");
+  }
+
+  void checkDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *DEI) {
+    SILType exType = DEI->getOperand()->getType();
+    require(!exType.isAddress(),
+            "deinit_existential_opaque must not be applied to an address");
+    require(
+        exType.canUseExistentialRepresentation(
+            F.getModule(), ExistentialRepresentation::Opaque),
+        "deinit_existential_opaque must be applied to an opaque existential");
   }
   
   void checkDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEBI) {
@@ -2555,8 +2564,20 @@
                 CBI->getCastType(),
             "success dest block argument of checked_cast_br must match type of "
             "cast");
-    require(CBI->getFailureBB()->args_empty(),
-            "failure dest of checked_cast_br must take no arguments");
+    require(F.hasQualifiedOwnership() || CBI->getFailureBB()->args_empty(),
+            "failure dest of checked_cast_br in unqualified ownership sil must "
+            "take no arguments");
+#if 0
+    require(F.hasUnqualifiedOwnership() ||
+                CBI->getFailureBB()->args_size() == 1,
+            "failure dest of checked_cast_br must take one argument in "
+            "ownership qualified sil");
+    require(F.hasUnqualifiedOwnership() ||
+                CBI->getFailureBB()->args_begin()[0]->getType() ==
+                    CBI->getOperand()->getType(),
+            "failure dest block argument must match type of original type in "
+            "ownership qualified sil");
+#endif
   }
 
   void checkCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI) {
@@ -2738,7 +2759,7 @@
 
   void checkIsNonnullInst(IsNonnullInst *II) {
     // The operand must be a function type or a class type.
-    auto OpTy = II->getOperand()->getType().getSwiftType();
+    auto OpTy = II->getOperand()->getType().getSwiftRValueType();
     require(OpTy->mayHaveSuperclass() || OpTy->is<SILFunctionType>(),
             "is_nonnull operand must be a class or function type");
   }
@@ -2746,7 +2767,7 @@
   void checkAddressToPointerInst(AddressToPointerInst *AI) {
     require(AI->getOperand()->getType().isAddress(),
             "address-to-pointer operand must be an address");
-    require(AI->getType().getSwiftType()->isEqual(
+    require(AI->getType().getSwiftRValueType()->isEqual(
                               AI->getType().getASTContext().TheRawPointerType),
             "address-to-pointer result type must be RawPointer");
   }
@@ -2803,11 +2824,11 @@
   }
 
   void checkRefToRawPointerInst(RefToRawPointerInst *AI) {
-    require(AI->getOperand()->getType().getSwiftType()
+    require(AI->getOperand()->getType().getSwiftRValueType()
               ->isAnyClassReferenceType(),
             "ref-to-raw-pointer operand must be a class reference or"
             " NativeObject");
-    require(AI->getType().getSwiftType()->isEqual(
+    require(AI->getType().getSwiftRValueType()->isEqual(
                             AI->getType().getASTContext().TheRawPointerType),
             "ref-to-raw-pointer result must be RawPointer");
   }
@@ -2815,13 +2836,13 @@
   void checkRawPointerToRefInst(RawPointerToRefInst *AI) {
     verifyOpenedArchetype(AI, AI->getType().getSwiftRValueType());
     require(AI->getType()
-              .getSwiftType()->isBridgeableObjectType()
-            || AI->getType().getSwiftType()->isEqual(
+              .getSwiftRValueType()->isBridgeableObjectType()
+            || AI->getType().getSwiftRValueType()->isEqual(
                              AI->getType().getASTContext().TheNativeObjectType)
-            || AI->getType().getSwiftType()->isEqual(
+            || AI->getType().getSwiftRValueType()->isEqual(
                             AI->getType().getASTContext().TheUnknownObjectType),
         "raw-pointer-to-ref result must be a class reference or NativeObject");
-    require(AI->getOperand()->getType().getSwiftType()->isEqual(
+    require(AI->getOperand()->getType().getSwiftRValueType()->isEqual(
                             AI->getType().getASTContext().TheRawPointerType),
             "raw-pointer-to-ref operand must be NativeObject");
   }
@@ -2876,8 +2897,12 @@
     requireObjectType(BuiltinRawPointerType, CI,
                       "thin_function_to_pointer result");
 
-    require(opTI->getRepresentation() == SILFunctionType::Representation::Thin,
-            "thin_function_to_pointer only works on thin functions");
+    auto rep = opTI->getRepresentation();
+    require(rep == SILFunctionTypeRepresentation::Thin ||
+            rep == SILFunctionTypeRepresentation::Method ||
+            rep == SILFunctionTypeRepresentation::WitnessMethod,
+            "thin_function_to_pointer only works on thin, method or "
+            "witness_method functions");
   }
 
   void checkPointerToThinFunctionInst(PointerToThinFunctionInst *CI) {
@@ -2886,8 +2911,12 @@
     requireObjectType(BuiltinRawPointerType, CI->getOperand(),
                       "pointer_to_thin_function operand");
 
-    require(resultTI->getRepresentation() == SILFunctionType::Representation::Thin,
-            "pointer_to_thin_function only works on thin functions");
+    auto rep = resultTI->getRepresentation();
+    require(rep == SILFunctionTypeRepresentation::Thin ||
+            rep == SILFunctionTypeRepresentation::Method ||
+            rep == SILFunctionTypeRepresentation::WitnessMethod,
+            "pointer_to_thin_function only works on thin, method or "
+            "witness_method functions");
   }
 
   void checkCondFailInst(CondFailInst *CFI) {
@@ -3225,9 +3254,9 @@
 
     require(DMBI->getMember().getDecl()->isObjC(), "method must be @objc");
     if (!DMBI->getMember().getDecl()->isInstanceMember()) {
-      require(operandType.getSwiftType()->is<MetatypeType>(),
+      require(operandType.getSwiftRValueType()->is<MetatypeType>(),
               "operand must have metatype type");
-      require(operandType.getSwiftType()->castTo<MetatypeType>()
+      require(operandType.getSwiftRValueType()->castTo<MetatypeType>()
                 ->getInstanceType()->mayHaveSuperclass(),
               "operand must have metatype of class or class-bound type");
     }
diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp
index 01dd21b..ea66f37 100644
--- a/lib/SIL/TypeLowering.cpp
+++ b/lib/SIL/TypeLowering.cpp
@@ -758,7 +758,7 @@
                            SILValue value) const override {
       if (B.getFunction().hasQualifiedOwnership())
         return B.createCopyValue(loc, value);
-      B.createRetainValue(loc, value, Atomicity::Atomic);
+      B.createRetainValue(loc, value, B.getDefaultAtomicity());
       return value;
     }
 
@@ -891,7 +891,7 @@
                            SILValue value) const override {
       if (B.getFunction().hasQualifiedOwnership())
         return B.createCopyValue(loc, value);
-      B.createRetainValue(loc, value, Atomicity::Atomic);
+      B.createRetainValue(loc, value, B.getDefaultAtomicity());
       return value;
     }
 
@@ -900,7 +900,7 @@
                                   LoweringStyle style) const override {
       if (B.getFunction().hasQualifiedOwnership())
         return B.createCopyValue(loc, value);
-      B.createRetainValue(loc, value, Atomicity::Atomic);
+      B.createRetainValue(loc, value, B.getDefaultAtomicity());
       return value;
     }
 
@@ -960,7 +960,7 @@
       if (B.getFunction().hasQualifiedOwnership())
         return B.createCopyValue(loc, value);
 
-      B.createStrongRetain(loc, value, Atomicity::Atomic);
+      B.createStrongRetain(loc, value, B.getDefaultAtomicity());
       return value;
     }
 
@@ -985,7 +985,7 @@
       if (B.getFunction().hasQualifiedOwnership())
         return B.createCopyValue(loc, value);
 
-      B.createUnownedRetain(loc, value, Atomicity::Atomic);
+      B.createUnownedRetain(loc, value, B.getDefaultAtomicity());
       return value;
     }
 
@@ -995,7 +995,7 @@
         B.createDestroyValue(loc, value);
         return;
       }
-      B.createUnownedRelease(loc, value, Atomicity::Atomic);
+      B.createUnownedRelease(loc, value, B.getDefaultAtomicity());
     }
   };
 
@@ -1105,25 +1105,12 @@
       llvm_unreachable("destroy address");
     }
 
-    void emitDestroyRValue(SILBuilder &B, SILLocation loc,
-                           SILValue value) const override {
-      llvm_unreachable("destroy value");
-    }
-
     void emitCopyInto(SILBuilder &B, SILLocation loc,
                       SILValue src, SILValue dest, IsTake_t isTake,
                       IsInitialization_t isInit) const override {
       llvm_unreachable("copy into");
     }
 
-    // --- Same as NonTrivialLoadableTypeLowering
-
-    void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
-                         SILValue newValue, SILValue addr,
-                         IsInitialization_t isInit) const override {
-      llvm_unreachable("store copy");
-    }
-
     // --- Same as LeafLoadableTypeLowering.
 
     SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
@@ -2130,7 +2117,8 @@
 CanSILFunctionType TypeConverter::
 getMaterializeForSetCallbackType(AbstractStorageDecl *storage,
                                  CanGenericSignature genericSig,
-                                 Type selfType) {
+                                 Type selfType,
+                                 SILFunctionTypeRepresentation rep) {
   auto &ctx = M.getASTContext();
 
   // Get lowered formal types for callback parameters.
@@ -2168,9 +2156,8 @@
     { canSelfMetatypeType, ParameterConvention::Direct_Unowned },
   };
   ArrayRef<SILResultInfo> results = {};
-  auto extInfo = 
-    SILFunctionType::ExtInfo()
-      .withRepresentation(SILFunctionTypeRepresentation::Thin);
+
+  auto extInfo = SILFunctionType::ExtInfo().withRepresentation(rep);
 
   if (genericSig && genericSig->areAllParamsConcrete())
     genericSig = nullptr;
diff --git a/lib/SILGen/ManagedValue.cpp b/lib/SILGen/ManagedValue.cpp
index 14dd691..3268c90 100644
--- a/lib/SILGen/ManagedValue.cpp
+++ b/lib/SILGen/ManagedValue.cpp
@@ -60,7 +60,7 @@
 void ManagedValue::copyInto(SILGenFunction &gen, SILValue dest,
                             SILLocation loc) {
   auto &lowering = gen.getTypeLowering(getType());
-  if (lowering.isAddressOnly()) {
+  if (lowering.isAddressOnly() && gen.silConv.useLoweredAddresses()) {
     gen.B.createCopyAddr(loc, getValue(), dest, IsNotTake, IsInitialization);
     return;
   }
diff --git a/lib/SILGen/ManagedValue.h b/lib/SILGen/ManagedValue.h
index b3330b6..8c02138 100644
--- a/lib/SILGen/ManagedValue.h
+++ b/lib/SILGen/ManagedValue.h
@@ -230,12 +230,6 @@
     return M;
   }
 
-  CanType getSwiftType() const {
-    return isLValue()
-      ? getType().getSwiftType()
-      : getType().getSwiftRValueType();
-  }
-  
   /// Emit a copy of this value with independent ownership.
   ManagedValue copy(SILGenFunction &gen, SILLocation loc);
 
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index f2b4b55..dbc9b5d 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -42,7 +42,7 @@
   if (member->isInstanceMember()) {
     selfTy = ctx.TheUnknownObjectType;
   } else {
-    selfTy = proto->getType().getSwiftType();
+    selfTy = proto->getType().getSwiftRValueType();
   }
   auto extInfo = FunctionType::ExtInfo()
                    .withRepresentation(FunctionType::Representation::Thin);
@@ -99,7 +99,7 @@
     selfTy = proto->getType().getSwiftRValueType();
     assert(selfTy->is<ArchetypeType>() && "Dynamic lookup needs an archetype");
   } else {
-    selfTy = proto->getType().getSwiftType();
+    selfTy = proto->getType().getSwiftRValueType();
   }
 
   // Replace the 'self' parameter type in the method type with it.
@@ -1367,8 +1367,7 @@
 
         // If the 'self' value is a metatype, update the target type
         // accordingly.
-        if (auto selfMetaTy
-                    = selfValue.getSwiftType()->getAs<AnyMetatypeType>()) {
+        if (auto selfMetaTy = selfValue.getType().getAs<AnyMetatypeType>()) {
           resultTy = CanMetatypeType::get(resultTy,
                                           selfMetaTy->getRepresentation());
         }
@@ -1809,9 +1808,9 @@
   };
 
   TupleTypeElt TypeEltsArray[] = {
-    EltsArray[0].getSwiftType(),
-    EltsArray[1].getSwiftType(),
-    EltsArray[2].getSwiftType()
+    EltsArray[0].getType().getSwiftRValueType(),
+    EltsArray[1].getType().getSwiftRValueType(),
+    EltsArray[2].getType().getSwiftRValueType()
   };
 
   ArrayRef<ManagedValue> Elts;
@@ -2486,7 +2485,7 @@
       assert(lifetimeExtendedSelf
              && "did not save lifetime-extended self param");
       if (!hasAlreadyLifetimeExtendedSelf) {
-        B.createAutoreleaseValue(loc, lifetimeExtendedSelf, Atomicity::Atomic);
+        B.createAutoreleaseValue(loc, lifetimeExtendedSelf, B.getDefaultAtomicity());
         hasAlreadyLifetimeExtendedSelf = true;
       }
       LLVM_FALLTHROUGH;
@@ -3453,7 +3452,7 @@
           emittedArg = ManagedValue(erased, emittedArg.getCleanup());
         }
         
-        assert(isAnyObjectType(emittedArg.getSwiftType()));
+        assert(isAnyObjectType(emittedArg.getType().getSwiftRValueType()));
         return emittedArg;
       };
       
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index 3ced3d4..e89eab2 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -35,7 +35,7 @@
                              ManagedValue swiftValue,
                              ProtocolConformance *conformance) {
   // Dig out the nominal type we're bridging from.
-  Type swiftValueType = swiftValue.getSwiftType()->getRValueType();
+  Type swiftValueType = swiftValue.getType().getSwiftRValueType();
 
   // Find the _bridgeToObjectiveC requirement.
   auto requirement = gen.SGM.getBridgeToObjectiveCRequirement(loc);
@@ -988,7 +988,7 @@
       gen.emitBridgedToNativeValue(loc,
                                    bridgedArgs[i],
                                    SILFunctionTypeRepresentation::ObjCMethod,
-                                   argTy.getSwiftType());
+                                   argTy.getSwiftRValueType());
     SILValue argValue;
 
     if (nativeInputs[i].isConsumed()) {
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index baad164..b791ed3 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -209,7 +209,7 @@
   SILValue result = SILBuilder::createUnmanagedToRef(
       loc, originalValue.getValue(),
       SILType::getPrimitiveObjectType(unmanagedType.getReferentType()));
-  SILBuilder::createUnmanagedRetainValue(loc, result);
+  SILBuilder::createUnmanagedRetainValue(loc, result, getDefaultAtomicity());
   return gen.emitManagedRValueWithCleanup(result);
 }
 
@@ -489,3 +489,25 @@
   return gen.emitManagedRValueWithCleanup(result);
 }
 
+ManagedValue SILGenBuilder::createUnconditionalCheckedCastOpaque(
+    SILLocation loc, ManagedValue operand, SILType type) {
+  SILValue result = SILBuilder::createUnconditionalCheckedCastOpaque(
+      loc, operand.forward(gen), type);
+  return gen.emitManagedRValueWithCleanup(result);
+}
+
+ManagedValue SILGenBuilder::createUnconditionalCheckedCast(SILLocation loc,
+                                                           ManagedValue operand,
+                                                           SILType type) {
+  SILValue result = SILBuilder::createUnconditionalCheckedCast(
+      loc, operand.forward(gen), type);
+  return gen.emitManagedRValueWithCleanup(result);
+}
+
+void SILGenBuilder::createCheckedCastBranch(SILLocation loc, bool isExact,
+                                            ManagedValue operand, SILType type,
+                                            SILBasicBlock *trueBlock,
+                                            SILBasicBlock *falseBlock) {
+  SILBuilder::createCheckedCastBranch(loc, isExact, operand.forward(gen), type,
+                                      trueBlock, falseBlock);
+}
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index f5bd0ab..3e4701c 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -211,6 +211,21 @@
   ManagedValue formalAccessBufferForExpr(
       SILLocation loc, SILType ty, const TypeLowering &lowering,
       SGFContext context, std::function<void(SILValue)> rvalueEmitter);
+
+  using SILBuilder::createUnconditionalCheckedCastOpaque;
+  ManagedValue createUnconditionalCheckedCastOpaque(SILLocation loc,
+                                                    ManagedValue operand,
+                                                    SILType type);
+  using SILBuilder::createUnconditionalCheckedCast;
+  ManagedValue createUnconditionalCheckedCast(SILLocation loc,
+                                              ManagedValue operand,
+                                              SILType type);
+
+  using SILBuilder::createCheckedCastBranch;
+  void createCheckedCastBranch(SILLocation loc, bool isExact,
+                               ManagedValue operand, SILType type,
+                               SILBasicBlock *trueBlock,
+                               SILBasicBlock *falseBlock);
 };
 
 } // namespace Lowering
diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp
index 93e449a..10fa3b4 100644
--- a/lib/SILGen/SILGenBuiltin.cpp
+++ b/lib/SILGen/SILGenBuiltin.cpp
@@ -72,7 +72,8 @@
   // The value was produced at +1; we can produce an unbalanced retain simply by
   // disabling the cleanup. But this would violate ownership semantics. Instead,
   // we must allow for the cleanup and emit a new unmanaged retain value.
-  gen.B.createUnmanagedRetainValue(loc, args[0].getValue());
+  gen.B.createUnmanagedRetainValue(loc, args[0].getValue(),
+                                   gen.B.getDefaultAtomicity());
   return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));    
 }
 
@@ -85,7 +86,8 @@
   // The value was produced at +1, so to produce an unbalanced
   // release we need to leave the cleanup intact and then do a *second*
   // release.
-  gen.B.createUnmanagedReleaseValue(loc, args[0].getValue());
+  gen.B.createUnmanagedReleaseValue(loc, args[0].getValue(),
+                                    gen.B.getDefaultAtomicity());
   return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));    
 }
 
@@ -95,7 +97,8 @@
                                            ArrayRef<ManagedValue> args,
                                            CanFunctionType formalApplyType,
                                            SGFContext C) {
-  gen.B.createUnmanagedAutoreleaseValue(loc, args[0].getValue());
+  gen.B.createUnmanagedAutoreleaseValue(loc, args[0].getValue(),
+                                        gen.B.getDefaultAtomicity());
   return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));    
 }
 
@@ -127,7 +130,7 @@
   // retain, so we have to leave the cleanup in place.  TODO: try to
   // emit the argument at +0.
   SILValue result =
-      gen.B.createStrongPin(loc, args[0].getValue(), Atomicity::Atomic);
+      gen.B.createStrongPin(loc, args[0].getValue(), gen.B.getDefaultAtomicity());
 
   // The handle, if non-null, is effectively +1.
   return gen.emitManagedRValueWithCleanup(result);
@@ -143,7 +146,7 @@
 
   if (requireIsOptionalNativeObject(gen, loc, subs[0].getReplacement())) {
     // Unpinning takes responsibility for the +1 handle.
-    gen.B.createStrongUnpin(loc, args[0].forward(gen), Atomicity::Atomic);
+    gen.B.createStrongUnpin(loc, args[0].forward(gen), gen.B.getDefaultAtomicity());
   }
 
   return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 9438e8d..c160037 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -781,26 +781,25 @@
   SILType existentialType = existentialValue.getType();
   switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) {
   case ExistentialRepresentation::Opaque: {
+    SILValue archetypeValue;
     if (existentialType.isAddress()) {
       OpenedExistentialAccess allowedAccess =
           getOpenedExistentialAccessFor(accessKind);
-      SILValue archetypeValue = B.createOpenExistentialAddr(
-          loc, existentialValue.forward(*this), loweredOpenedType,
-          allowedAccess);
-      if (existentialValue.hasCleanup()) {
-        canConsume = true;
-        // Leave a cleanup to deinit the existential container.
-        enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
-                                      ExistentialRepresentation::Opaque);
-        archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
-      } else {
-        canConsume = false;
-        archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
-      }
+      archetypeValue =
+          B.createOpenExistentialAddr(loc, existentialValue.forward(*this),
+                                      loweredOpenedType, allowedAccess);
     } else {
-      SILValue archetypeValue = B.createOpenExistentialOpaque(
+      archetypeValue = B.createOpenExistentialOpaque(
           loc, existentialValue.forward(*this), loweredOpenedType);
-      assert(!existentialValue.hasCleanup());
+    }
+
+    if (existentialValue.hasCleanup()) {
+      canConsume = true;
+      // Leave a cleanup to deinit the existential container.
+      enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
+                                    ExistentialRepresentation::Opaque);
+      archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
+    } else {
       canConsume = false;
       archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
     }
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index e4a5168..cbe0448 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -83,7 +83,7 @@
   // A scalar value is being copied into the tuple, break it into elements
   // and assign/init each element in turn.
   SILValue value = valueMV.forward(SGF);
-  auto sourceType = cast<TupleType>(valueMV.getSwiftType());
+  auto sourceType = valueMV.getType().castTo<TupleType>();
   auto sourceSILType = value->getType();
   for (unsigned i = 0, e = sourceType->getNumElements(); i != e; ++i) {
     SILType fieldTy = sourceSILType.getTupleElementType(i);
@@ -813,9 +813,10 @@
   
   // Reabstract to the substituted type, if needed.
   CanType substEltTy =
-    value.getSwiftType()->getTypeOfMember(SGF.SGM.M.getSwiftModule(),
-                                      ElementDecl,
-                                      ElementDecl->getArgumentInterfaceType())
+    value.getType().getSwiftRValueType()
+      ->getTypeOfMember(SGF.SGM.M.getSwiftModule(),
+                        ElementDecl,
+                        ElementDecl->getArgumentInterfaceType())
       ->getCanonicalType();
 
   AbstractionPattern origEltTy =
@@ -1233,7 +1234,11 @@
       case ExistentialRepresentation::Metatype:
         llvm_unreachable("cannot cleanup existential");
       case ExistentialRepresentation::Opaque:
-        gen.B.createDeinitExistentialAddr(l, existentialAddr);
+        if (gen.silConv.useLoweredAddresses()) {
+          gen.B.createDeinitExistentialAddr(l, existentialAddr);
+        } else {
+          gen.B.createDeinitExistentialOpaque(l, existentialAddr);
+        }
         break;
       case ExistentialRepresentation::Boxed:
         gen.B.createDeallocExistentialBox(l, concreteFormalType,
diff --git a/lib/SILGen/SILGenDynamicCast.cpp b/lib/SILGen/SILGenDynamicCast.cpp
index 1b717f2..da67262 100644
--- a/lib/SILGen/SILGenDynamicCast.cpp
+++ b/lib/SILGen/SILGenDynamicCast.cpp
@@ -100,6 +100,285 @@
                                              abstraction, origTargetTL, ctx));
       }
 
+      ManagedValue result;
+      if (Strategy == CastStrategy::Address) {
+        result = SGF.B.createUnconditionalCheckedCastOpaque(
+            Loc, operand, origTargetTL.getLoweredType());
+      } else {
+        result = SGF.B.createUnconditionalCheckedCast(
+            Loc, operand, origTargetTL.getLoweredType());
+      }
+
+      return RValue(SGF, Loc, TargetType,
+                    finishFromResultScalar(hasAbstraction, result,
+                                           CastConsumptionKind::TakeAlways,
+                                           abstraction, origTargetTL, ctx));
+    }
+
+    /// Emit a conditional cast.
+    void emitConditional(
+        ManagedValue operand, CastConsumptionKind consumption, SGFContext ctx,
+        const std::function<void(ManagedValue)> &handleTrue,
+        const std::function<void(Optional<ManagedValue>)> &handleFalse) {
+      // The cast instructions don't know how to work with anything
+      // but the most general possible abstraction level.
+      AbstractionPattern abstraction =
+          SGF.SGM.Types.getMostGeneralAbstraction();
+      auto &origTargetTL = SGF.getTypeLowering(abstraction, TargetType);
+      auto &substTargetTL = SGF.getTypeLowering(TargetType);
+      bool hasAbstraction =
+          (origTargetTL.getLoweredType() != substTargetTL.getLoweredType());
+
+      SILBasicBlock *falseBB = SGF.B.splitBlockForFallthrough();
+      SILBasicBlock *trueBB = SGF.B.splitBlockForFallthrough();
+
+      // Emit the branch.
+      ManagedValue scalarOperandValue;
+      SILValue resultBuffer;
+      if (Strategy == CastStrategy::Address) {
+        assert(operand.getType().isAddress());
+        resultBuffer =
+            createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx);
+        SGF.B.createCheckedCastAddrBranch(
+            Loc, consumption, operand.forward(SGF), SourceType, resultBuffer,
+            TargetType, trueBB, falseBB);
+      } else {
+        // Tolerate being passed an address here.  It comes up during switch
+        // emission.
+        scalarOperandValue = std::move(operand);
+        if (scalarOperandValue.getType().isAddress()) {
+          scalarOperandValue = SGF.B.createLoadTake(Loc, scalarOperandValue);
+        }
+        SGF.B.createCheckedCastBranch(Loc, /*exact*/ false, scalarOperandValue,
+                                      origTargetTL.getLoweredType(), trueBB,
+                                      falseBB);
+      }
+
+      // Emit the success block.
+      SGF.B.setInsertionPoint(trueBB);
+      {
+        FullExpr scope(SGF.Cleanups, CleanupLocation::get(Loc));
+
+        ManagedValue result;
+        if (Strategy == CastStrategy::Address) {
+          result = finishFromResultBuffer(hasAbstraction, resultBuffer,
+                                          abstraction, origTargetTL, ctx);
+        } else {
+          ManagedValue argument =
+              SGF.B.createOwnedPHIArgument(origTargetTL.getLoweredType());
+          result = finishFromResultScalar(hasAbstraction, argument, consumption,
+                                          abstraction, origTargetTL, ctx);
+        }
+
+        handleTrue(result);
+        assert(!SGF.B.hasValidInsertionPoint() && "handler did not end block");
+      }
+
+      // Emit the failure block.
+      SGF.B.setInsertionPoint(falseBB);
+      {
+        FullExpr scope(SGF.Cleanups, CleanupLocation::get(Loc));
+
+        // If we have an address only type, do not handle the consumption
+        // rules. These are handled for us by the user.
+        if (Strategy == CastStrategy::Address) {
+          handleFalse(None);
+          assert(!SGF.B.hasValidInsertionPoint() &&
+                 "handler did not end block");
+          return;
+        }
+
+        // Otherwise, we use the following strategy:
+        //
+        // 1. If we have a take_always, we create a phi node argument for the
+        // failure case and a scope for that so that it is immediately
+        // destroyed.
+        //
+        // 2. If we have a take_on_success or copy_on_success, then on failure,
+        // we propagate through the default argument, but do not clean it up. On
+        // the false case, our user must treat the taken value as a new value.
+        if (shouldDestroyOnFailure(consumption)) {
+          {
+            FullExpr argScope(SGF.Cleanups, CleanupLocation::get(Loc));
+            SGF.B.createOwnedPHIArgument(scalarOperandValue.getType());
+          }
+          handleFalse(None);
+          assert(!SGF.B.hasValidInsertionPoint() &&
+                 "handler did not end block");
+          return;
+        }
+
+        handleFalse(SGF.B.createOwnedPHIArgument(scalarOperandValue.getType()));
+        assert(!SGF.B.hasValidInsertionPoint() && "handler did not end block");
+      }
+    }
+
+    SILValue createAbstractResultBuffer(bool hasAbstraction,
+                                        const TypeLowering &origTargetTL,
+                                        SGFContext ctx) {
+      if (!hasAbstraction) {
+        if (auto emitInto = ctx.getEmitInto()) {
+          if (SILValue addr = emitInto->getAddressOrNull()) {
+            return addr;
+          }
+        }
+      }
+
+      return SGF.emitTemporaryAllocation(Loc, origTargetTL.getLoweredType());
+    }
+
+    ManagedValue finishFromResultBuffer(bool hasAbstraction, SILValue buffer,
+                                        AbstractionPattern abstraction,
+                                        const TypeLowering &origTargetTL,
+                                        SGFContext ctx) {
+      if (!hasAbstraction) {
+        if (auto emitInto = ctx.getEmitInto()) {
+          if (emitInto->getAddressOrNull()) {
+            emitInto->finishInitialization(SGF);
+            return ManagedValue::forInContext();
+          }
+        }
+      }
+
+      ManagedValue result;
+      if (!origTargetTL.isAddressOnly()) {
+        result = SGF.emitLoad(Loc, buffer, origTargetTL, ctx, IsTake);
+      } else {
+        result = SGF.emitManagedBufferWithCleanup(buffer, origTargetTL);
+      }
+
+      if (hasAbstraction) {
+        result =
+            SGF.emitOrigToSubstValue(Loc, result, abstraction, TargetType, ctx);
+      }
+      return result;
+    }
+
+    /// Our cast succeeded and gave us this abstracted value.
+    ManagedValue finishFromResultScalar(bool hasAbstraction, ManagedValue value,
+                                        CastConsumptionKind consumption,
+                                        AbstractionPattern abstraction,
+                                        const TypeLowering &origTargetTL,
+                                        SGFContext ctx) {
+      ManagedValue result = value;
+      // Copy the result if this is copy-on-success.
+      if (!shouldTakeOnSuccess(consumption))
+        result = result.copy(SGF, Loc);
+
+      // Re-abstract if necessary.
+      if (hasAbstraction) {
+        result =
+            SGF.emitOrigToSubstValue(Loc, result, abstraction, TargetType, ctx);
+      }
+
+      return result;
+    }
+
+  private:
+    CastStrategy computeStrategy() const {
+      if (canUseScalarCheckedCastInstructions(SGF.SGM.M, SourceType,
+                                              TargetType))
+        return CastStrategy::Scalar;
+      return CastStrategy::Address;
+    }
+  };
+} // end anonymous namespace
+
+void SILGenFunction::emitCheckedCastBranch(
+    SILLocation loc, Expr *source, Type targetType, SGFContext ctx,
+    std::function<void(ManagedValue)> handleTrue,
+    std::function<void(Optional<ManagedValue>)> handleFalse) {
+  CheckedCastEmitter emitter(*this, loc, source->getType(), targetType);
+  ManagedValue operand = emitter.emitOperand(source);
+  emitter.emitConditional(operand, CastConsumptionKind::TakeAlways, ctx,
+                          handleTrue, handleFalse);
+}
+
+void SILGenFunction::emitCheckedCastBranch(
+    SILLocation loc, ConsumableManagedValue src, Type sourceType,
+    CanType targetType, SGFContext ctx,
+    std::function<void(ManagedValue)> handleTrue,
+    std::function<void(Optional<ManagedValue>)> handleFalse) {
+  CheckedCastEmitter emitter(*this, loc, sourceType, targetType);
+  emitter.emitConditional(src.getFinalManagedValue(),
+                          src.getFinalConsumption(), ctx, handleTrue,
+                          handleFalse);
+}
+
+namespace {
+  class CheckedCastEmitterOld {
+    SILGenFunction &SGF;
+    SILLocation Loc;
+    CanType SourceType;
+    CanType TargetType;
+
+    enum class CastStrategy : uint8_t {
+      Address,
+      Scalar,
+    };
+    CastStrategy Strategy;
+
+  public:
+    CheckedCastEmitterOld(SILGenFunction &SGF, SILLocation loc, Type sourceType,
+                          Type targetType)
+        : SGF(SGF), Loc(loc), SourceType(sourceType->getCanonicalType()),
+          TargetType(targetType->getCanonicalType()),
+          Strategy(computeStrategy()) {}
+
+    bool isOperandIndirect() const { return Strategy == CastStrategy::Address; }
+
+    ManagedValue emitOperand(Expr *operand) {
+      AbstractionPattern mostGeneral =
+          SGF.SGM.Types.getMostGeneralAbstraction();
+      auto &origSourceTL = SGF.getTypeLowering(mostGeneral, SourceType);
+
+      SGFContext ctx;
+
+      std::unique_ptr<TemporaryInitialization> temporary;
+      if (isOperandIndirect() && SGF.silConv.useLoweredAddresses()) {
+        temporary = SGF.emitTemporary(Loc, origSourceTL);
+        ctx = SGFContext(temporary.get());
+      }
+
+      auto result =
+          SGF.emitRValueAsOrig(operand, mostGeneral, origSourceTL, ctx);
+
+      if (isOperandIndirect() && SGF.silConv.useLoweredAddresses()) {
+        // Force the result into the temporary if it's not already there.
+        if (!result.isInContext()) {
+          result.forwardInto(SGF, Loc, temporary->getAddress());
+          temporary->finishInitialization(SGF);
+        }
+        return temporary->getManagedAddress();
+      }
+
+      return result;
+    }
+
+    RValue emitUnconditionalCast(ManagedValue operand, SGFContext ctx) {
+      // The cast functions don't know how to work with anything but
+      // the most general possible abstraction level.
+      AbstractionPattern abstraction =
+          SGF.SGM.Types.getMostGeneralAbstraction();
+      auto &origTargetTL = SGF.getTypeLowering(abstraction, TargetType);
+      auto &substTargetTL = SGF.getTypeLowering(TargetType);
+      bool hasAbstraction =
+          (origTargetTL.getLoweredType() != substTargetTL.getLoweredType());
+
+      // If we're using checked_cast_addr, take the operand (which
+      // should be an address) and build into the destination buffer.
+      if (Strategy == CastStrategy::Address &&
+          SGF.silConv.useLoweredAddresses()) {
+        SILValue resultBuffer =
+            createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx);
+        SGF.B.createUnconditionalCheckedCastAddr(
+            Loc, CastConsumptionKind::TakeAlways, operand.forward(SGF),
+            SourceType, resultBuffer, TargetType);
+        return RValue(SGF, Loc, TargetType,
+                      finishFromResultBuffer(hasAbstraction, resultBuffer,
+                                             abstraction, origTargetTL, ctx));
+      }
+
       SILValue resultScalar;
       if (Strategy == CastStrategy::Address) {
         resultScalar = SGF.B.createUnconditionalCheckedCastOpaque(
@@ -265,25 +544,22 @@
   };
 } // end anonymous namespace
 
-void SILGenFunction::emitCheckedCastBranch(SILLocation loc, Expr *source,
-                                           Type targetType,
-                                           SGFContext ctx,
-                                std::function<void(ManagedValue)> handleTrue,
-                                           std::function<void()> handleFalse) {
-  CheckedCastEmitter emitter(*this, loc, source->getType(), targetType);
+void SILGenFunction::emitCheckedCastBranchOld(
+    SILLocation loc, Expr *source, Type targetType, SGFContext ctx,
+    std::function<void(ManagedValue)> handleTrue,
+    std::function<void()> handleFalse) {
+  CheckedCastEmitterOld emitter(*this, loc, source->getType(), targetType);
   ManagedValue operand = emitter.emitOperand(source);
   emitter.emitConditional(operand, CastConsumptionKind::TakeAlways, ctx,
                           handleTrue, handleFalse);
 }
 
-void SILGenFunction::emitCheckedCastBranch(SILLocation loc,
-                                           ConsumableManagedValue src,
-                                           Type sourceType,
-                                           CanType targetType,
-                                           SGFContext ctx,
-                                std::function<void(ManagedValue)> handleTrue,
-                                           std::function<void()> handleFalse) {
-  CheckedCastEmitter emitter(*this, loc, sourceType, targetType);
+void SILGenFunction::emitCheckedCastBranchOld(
+    SILLocation loc, ConsumableManagedValue src, Type sourceType,
+    CanType targetType, SGFContext ctx,
+    std::function<void(ManagedValue)> handleTrue,
+    std::function<void()> handleFalse) {
+  CheckedCastEmitterOld emitter(*this, loc, sourceType, targetType);
   emitter.emitConditional(src.getFinalManagedValue(), src.getFinalConsumption(),
                           ctx, handleTrue, handleFalse);
 }
@@ -459,53 +735,59 @@
   ExitableFullExpr scope(SGF, CleanupLocation::get(loc));
 
   auto operandCMV = ConsumableManagedValue::forOwned(operand);
-  SGF.emitCheckedCastBranch(loc, operandCMV, operandType,
-                            resultObjectType, resultObjectCtx,
-    // The success path.
-    [&](ManagedValue objectValue) {
-      // If we're not emitting into a temporary, just wrap up the result
-      // in Some and go to the continuation block.
-      if (!resultObjectTemp) {
-        auto some = SGF.B.createEnum(loc, objectValue.forward(SGF),
-                                     someDecl, resultTL.getLoweredType());
-        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { some });
-        return;
-      }
+  assert(operandCMV.getFinalConsumption() == CastConsumptionKind::TakeAlways);
 
-      // Otherwise, make sure the value is in the context.
-      if (!objectValue.isInContext()) {
-        objectValue.forwardInto(SGF, loc, resultObjectBuffer);
-      }
-      SGF.B.createInjectEnumAddr(loc, resultBuffer, someDecl);
-      SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
-    },
-    // The failure path.
-    [&] {
-      auto noneDecl = SGF.getASTContext().getOptionalNoneDecl();
+  SGF.emitCheckedCastBranch(
+      loc, operandCMV, operandType, resultObjectType, resultObjectCtx,
+      // The success path.
+      [&](ManagedValue objectValue) {
+        // If we're not emitting into a temporary, just wrap up the result
+        // in Some and go to the continuation block.
+        if (!resultObjectTemp) {
+          auto some = SGF.B.createEnum(loc, objectValue.forward(SGF), someDecl,
+                                       resultTL.getLoweredType());
+          SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, {some});
+          return;
+        }
 
-      // If we're not emitting into a temporary, just wrap up the result
-      // in None and go to the continuation block.
-      if (!resultObjectTemp) {
-        auto none =
-          SGF.B.createEnum(loc, nullptr, noneDecl, resultTL.getLoweredType());
-        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { none });
-
-      // Just construct the enum directly in the context.
-      } else {
-        SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl);
+        // Otherwise, make sure the value is in the context.
+        if (!objectValue.isInContext()) {
+          objectValue.forwardInto(SGF, loc, resultObjectBuffer);
+        }
+        SGF.B.createInjectEnumAddr(loc, resultBuffer, someDecl);
         SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
-      }
-    });
+      },
+      // The failure path.
+      [&](Optional<ManagedValue> Value) {
+        // We always are performing a take here, so Value should be None since
+        // the
+        // object should have been destroyed immediately in the fail block.
+        assert(!Value.hasValue() && "Expected a take_always consumption kind");
+        auto noneDecl = SGF.getASTContext().getOptionalNoneDecl();
+
+        // If we're not emitting into a temporary, just wrap up the result
+        // in None and go to the continuation block.
+        if (!resultObjectTemp) {
+          auto none = SGF.B.createEnum(loc, nullptr, noneDecl,
+                                       resultTL.getLoweredType());
+          SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, {none});
+
+          // Just construct the enum directly in the context.
+        } else {
+          SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl);
+          SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
+        }
+      });
 
   // Enter the continuation block.
-  auto contBB = scope.exit();
+  SILBasicBlock *contBlock = scope.exit();
 
   ManagedValue result;
   if (resultObjectTemp) {
     result = SGF.manageBufferForExprResult(resultBuffer, resultTL, C);
   } else {
-    auto argument = contBB->createPHIArgument(resultTL.getLoweredType(),
-                                              ValueOwnershipKind::Owned);
+    auto argument = contBlock->createPHIArgument(resultTL.getLoweredType(),
+                                                 ValueOwnershipKind::Owned);
     result = SGF.emitManagedRValueWithCleanup(argument, resultTL);
   }
 
@@ -543,15 +825,18 @@
 
   auto i1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext());
 
-  SGF.emitCheckedCastBranch(loc, operand, targetType, SGFContext(),
-    [&](ManagedValue value) {
-      SILValue yes = SGF.B.createIntegerLiteral(loc, i1Ty, 1);
-      SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, yes);
-    },
-    [&] {
-      SILValue no = SGF.B.createIntegerLiteral(loc, i1Ty, 0);
-      SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, no);
-    });
+  // When we pass in an expr, we perform a take_always cast.
+  SGF.emitCheckedCastBranch(
+      loc, operand, targetType, SGFContext(),
+      [&](ManagedValue value) {
+        SILValue yes = SGF.B.createIntegerLiteral(loc, i1Ty, 1);
+        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, yes);
+      },
+      [&](Optional<ManagedValue> Value) {
+        assert(!Value.hasValue() && "Expected take_always semantics");
+        SILValue no = SGF.B.createIntegerLiteral(loc, i1Ty, 0);
+        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, no);
+      });
 
   auto contBB = scope.exit();
   auto isa = contBB->createPHIArgument(i1Ty, ValueOwnershipKind::Trivial);
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 4580307..7407c7a 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -290,7 +290,8 @@
 
 ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v,
                                                const TypeLowering &lowering) {
-  assert(lowering.getLoweredType().getAddressType() == v->getType());
+  assert(lowering.getLoweredType().getAddressType() == v->getType() ||
+         !silConv.useLoweredAddresses());
   if (lowering.isTrivial())
     return ManagedValue::forUnmanaged(v);
 
@@ -856,7 +857,7 @@
   case AddressorKind::NativePinning:
     // Emit the unpin immediately.
     SGF.B.createStrongUnpin(loc, addressorResult.second.forward(SGF),
-                            Atomicity::Atomic);
+                            SGF.B.getDefaultAtomicity());
     break;
   }
   
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 563f171..a11b63e 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -1408,11 +1408,22 @@
   ///                     terminated.
   /// \param handleFalse  A callback to invoke in the failure path.  The
   ///                     current BB should be terminated.
-  void emitCheckedCastBranch(SILLocation loc, ConsumableManagedValue src,
-                             Type sourceType, CanType targetType,
-                             SGFContext C,
-                             std::function<void(ManagedValue)> handleTrue,
-                             std::function<void()> handleFalse);
+  void emitCheckedCastBranch(
+      SILLocation loc, ConsumableManagedValue src, Type sourceType,
+      CanType targetType, SGFContext C,
+      std::function<void(ManagedValue)> handleTrue,
+      std::function<void(Optional<ManagedValue>)> handleFalse);
+
+  /// A form of checked cast branch that uses the old non-ownership preserving
+  /// semantics.
+  ///
+  /// The main difference is that this code does not pass the old argument as a
+  /// block argument in the failure case. This causes values to be double
+  /// consumed.
+  void emitCheckedCastBranchOld(SILLocation loc, Expr *source, Type targetType,
+                                SGFContext ctx,
+                                std::function<void(ManagedValue)> handleTrue,
+                                std::function<void()> handleFalse);
 
   /// \brief Emit a conditional checked cast branch, starting from an
   /// expression.  Terminates the current BB.
@@ -1426,10 +1437,22 @@
   ///                     terminated.
   /// \param handleFalse  A callback to invoke in the failure path.  The
   ///                     current BB should be terminated.
-  void emitCheckedCastBranch(SILLocation loc, Expr *src,
-                             Type targetType, SGFContext C,
-                             std::function<void(ManagedValue)> handleTrue,
-                             std::function<void()> handleFalse);
+  void emitCheckedCastBranch(
+      SILLocation loc, Expr *src, Type targetType, SGFContext C,
+      std::function<void(ManagedValue)> handleTrue,
+      std::function<void(Optional<ManagedValue>)> handleFalse);
+
+  /// A form of checked cast branch that uses the old non-ownership preserving
+  /// semantics.
+  ///
+  /// The main difference is that this code does not pass the old argument as a
+  /// block argument in the failure case. This causes values to be double
+  /// consumed.
+  void emitCheckedCastBranchOld(SILLocation loc, ConsumableManagedValue src,
+                                Type sourceType, CanType targetType,
+                                SGFContext ctx,
+                                std::function<void(ManagedValue)> handleTrue,
+                                std::function<void()> handleFalse);
 
   /// Emit the control flow for an optional 'bind' operation, branching to the
   /// active failure destination if the optional value addressed by optionalAddr
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 8c3e03f..ccdaf53 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -227,7 +227,8 @@
 
   assert(temporary.getType().isAddress());
   auto &tempTL = gen.getTypeLowering(temporary.getType());
-  if (!tempTL.isAddressOnly() || !isFinal) {
+  if (!tempTL.isAddressOnly() || !isFinal ||
+      !gen.silConv.useLoweredAddresses()) {
     if (isFinal) temporary.forward(gen);
     temporary = gen.emitLoad(loc, temporary.getValue(), tempTL,
                              SGFContext(), IsTake_t(isFinal));
@@ -879,8 +880,14 @@
             rawPointerTy, ValueOwnershipKind::Trivial);
 
         // Cast the callback to the correct polymorphic function type.
+        SILFunctionTypeRepresentation rep;
+        if (isa<ProtocolDecl>(decl->getDeclContext()))
+          rep = SILFunctionTypeRepresentation::WitnessMethod;
+        else
+          rep = SILFunctionTypeRepresentation::Method;
+
         auto origCallbackFnType = gen.SGM.Types.getMaterializeForSetCallbackType(
-            decl, materialized.genericSig, materialized.origSelfType);
+          decl, materialized.genericSig, materialized.origSelfType, rep);
         auto origCallbackType = SILType::getPrimitiveObjectType(origCallbackFnType);
         callback = gen.B.createPointerToThinFunction(loc, callback, origCallbackType);
 
@@ -1094,7 +1101,7 @@
       if (!isFinal)
         baseValue = gen.B.createCopyValue(loc, baseValue);
 
-      gen.B.createStrongUnpin(loc, baseValue, Atomicity::Atomic);
+      gen.B.createStrongUnpin(loc, baseValue, gen.B.getDefaultAtomicity());
     }
 
     void print(raw_ostream &OS) const override {
@@ -2138,7 +2145,7 @@
     assert(unownedType->isLoadable(ResilienceExpansion::Maximal));
     (void) unownedType;
 
-    B.createStrongRetainUnowned(loc, src, Atomicity::Atomic);
+    B.createStrongRetainUnowned(loc, src, B.getDefaultAtomicity());
     return B.createUnownedToRef(loc, src,
                 SILType::getPrimitiveObjectType(unownedType.getReferentType()));
   }
@@ -2199,9 +2206,9 @@
 
     auto unownedValue =
         gen.B.emitLoadValueOperation(loc, src, LoadOwnershipQualifier::Take);
-    gen.B.createStrongRetainUnowned(loc, unownedValue, Atomicity::Atomic);
+    gen.B.createStrongRetainUnowned(loc, unownedValue, gen.B.getDefaultAtomicity());
     if (isTake)
-      gen.B.createUnownedRelease(loc, unownedValue, Atomicity::Atomic);
+      gen.B.createUnownedRelease(loc, unownedValue, gen.B.getDefaultAtomicity());
     return gen.B.createUnownedToRef(
         loc, unownedValue,
         SILType::getPrimitiveObjectType(unownedType.getReferentType()));
@@ -2264,7 +2271,7 @@
 
     auto unownedValue =
       gen.B.createRefToUnowned(loc, value, storageType.getObjectType());
-    gen.B.createUnownedRetain(loc, unownedValue, Atomicity::Atomic);
+    gen.B.createUnownedRetain(loc, unownedValue, gen.B.getDefaultAtomicity());
     emitUnloweredStoreOfCopy(gen.B, loc, unownedValue, dest, isInit);
     gen.B.emitDestroyValueOperation(loc, value);
     return;
@@ -2366,7 +2373,7 @@
     (void) unownedType;
 
     SILValue unowned = B.createRefToUnowned(loc, semanticValue, storageType);
-    B.createUnownedRetain(loc, unowned, Atomicity::Atomic);
+    B.createUnownedRetain(loc, unowned, B.getDefaultAtomicity());
     B.emitDestroyValueOperation(loc, semanticValue);
     return unowned;
   }
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index 52aaa46..53326de 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -12,6 +12,147 @@
 //
 // Emission of materializeForSet.
 //
+// There are two cases where materializeForSet is used for inout access:
+//
+// === Storage is virtually dispatched on a base class ===
+//
+// For example, suppose we have this setup, where a computed property in a
+// base class is overridden with a computed property in the derived class:
+//
+//   class Base<T> { var x: T }
+//   class Derived : Base<Int> { override var x: Int { ... } }
+//   func operate(b: Base<Int>) {
+//     b.x += 1
+//   }
+//
+// As far as caller is concerned, the callback is invoked with the following
+// SIL type:
+//
+// @convention(method)
+// <T> (RawPointer, @inout UnsafeValueBuffer, @inout Base<T>, @thick Base<T>.Type) -> ()
+//
+// The caller will pass the first four formal parameters, followed by the
+// type metadata for 'T'.
+//
+// However if the dynamic type of the parameter 'b' is actually 'Derived',
+// then the actual callback has this SIL type:
+//
+// @convention(method)
+// (RawPointer, @inout UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
+//
+// This is a fully concrete function type, with no additional generic metadata.
+//
+// These two callbacks are be ABI-compatible though, because IRGen makes three
+// guarantees:
+//
+// 1) Passing extra arguments (in this case, the type metadata for 'T') is a
+//    no-op.
+//
+// 2) IRGen knows to recover the type metadata for 'T' from the
+//    '@thick Base<T>.Type' parameter, instead of passing it separately.
+//
+// 3) The metatype for 'Derived' must be layout-compatible with 'Base<T>';
+//    since the generic parameter 'T' is made concrete, we expect to find the
+//    type metadata for 'Int' at the same offset within 'Derived.Type' as the
+//    generic parameter 'T' in 'Base<T>.Type'.
+//
+// === Storage is virtually dispatched on a protocol ===
+//
+// For example,
+//
+//   protocol BoxLike { associatedtype Element; var x: Element { get set } }
+//   func operate<B : BoxLike>(b: B) where B.Element == Int {
+//     b.x += 1
+//   }
+//
+// As far as the caller is concerned, the callback is invoked with following
+// SIL type:
+//
+// <Self : BoxLike> (RawPointer, @inout UnsafeValueBuffer, @inout Self, @thick Self.Type) -> ()
+//
+// At the IRGen level, a call of a SIL function with the above type will pass
+// the four formal parameters, followed by the type metadata for 'Self', and
+// then followed by the protocol witness table for 'Self : BoxLike'.
+//
+// As in the class case, the callback won't have the same identical SIL type,
+// because it might have a different representation of 'Self'.
+//
+// So we must consider two separate cases:
+//
+// 1) The witness is a method of the concrete conforming type, eg,
+//
+//      struct Box<T> : BoxLike { var x: T }
+//
+//    Here, the actual callback will have the following type:
+//
+//    @convention(method)
+//    <T> (RawPointer, @inout UnsafeValueBuffer, @inout Box<T>, @thick Box<T>.Type) -> ()
+//
+//    As with the class case, IRGen can already do the right thing -- the type
+//    metadata for 'T' is recovered from the '@thick Box<T>.Type' parameter,
+//    and the type metadata for 'Self' as well as the conformance
+//    'Self : BoxLike' are ignored.
+//
+// 2) The witness is a protocol extension method, possibly of some other protocol, eg,
+//
+//      protocol SomeOtherProtocol { }
+//      extension SomeOtherProtocol { var x: Element { ... } }
+//      struct FunnyBox<T> : BoxLike, SomeOtherProtocol { typealias Element = T }
+//
+//    Here, the actual callback will have the following type:
+//
+//    @convention(method)
+//    <Self : SomeOtherProtocol> (RawPointer, @inout UnsafeValueBuffer, @inout Self, @thick Self.Type) -> ()
+//
+//    Here, the actual callback expects to receive the four formal parameters,
+//    followed by the type metadata for 'Self', followed by the witness table
+//    for the conformance 'Self : SomeOtherProtocol'. Note that the
+//    conformance cannot be recovered from the thick metatype.
+//
+//    This is *not* ABI-compatible with the type used at the call site,
+//    because the caller is passing in the conformance of 'Self : BoxLike'
+//    (the requirement's signature) but the callee is expecting
+//    'Self : SomeOtherProtocol' (the witness signature).
+//
+//    For this reason the materializeForSet method in the protocol extension
+//    of 'SomeOtherProtocol' cannot witness the materializeForSet requirement
+//    of 'BoxLike'. So instead, the protocol witness thunk for
+//    materializeForSet cannot delegate to the materializeForSet witness at
+//    all; it's entirely open-coded, with its own callback that has the right
+//    calling convention.
+//
+// === Storage has its own generic parameters ===
+//
+// One final special case is where the storage has its own generic parameters;
+// that is, a generic subscript.
+//
+// Suppose we have the following protocol:
+//
+//   protocol GenericSubscript { subscript<T, U>(t: T) -> U { get set } }
+//
+// At the call site, the callback is invoked with the following signature:
+//
+// @convention(witness_method)
+// <Self : GenericSubscript, T, U> (RawPointer, @inout UnsafeValueBuffer, @inout Self, @thick Self.Type) -> ()
+//
+// If the witness is a member of a concrete type 'AnyDictionary', the actual
+// callback will have the following signature:
+//
+// @convention(method)
+// <T, U> (RawPointer, @inout UnsafeValueBuffer, @inout AnyDictionary, @thick SelfAnyDictionary.Type) -> ()
+//
+// These are ABI-compatible; the key is that witness_method passes the Self
+// metadata and conformance at the end, after the type metadata for innermost
+// generic parameters, and so everything lines up.
+//
+// === Summary ===
+//
+// To recap, we assume the following types are ABI-compatible:
+//
+// @convention(method) <T, U, V> (..., Foo<T, U>.Type)
+// @convention(witness_method) <T, U, V> (..., Foo<T, U>.Type)
+// @convention(witness_method) <Self : P, V> (..., Self.Type)
+//
 //===----------------------------------------------------------------------===//
 
 #include "SILGen.h"
@@ -21,10 +162,9 @@
 #include "Scope.h"
 #include "Initialization.h"
 #include "swift/AST/AST.h"
-#include "swift/AST/DiagnosticsSIL.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/Types.h"
-#include "swift/AST/DiagnosticsCommon.h"
+#include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/Mangle.h"
 #include "swift/AST/ASTMangler.h"
 #include "swift/AST/ProtocolConformance.h"
@@ -125,11 +265,15 @@
 
   SILType WitnessStorageType;
 
+  SILFunctionTypeRepresentation CallbackRepresentation;
+
 private:
 
   MaterializeForSetEmitter(SILGenModule &SGM, SILLinkage linkage,
                            FuncDecl *witness, SubstitutionList subs,
-                           Type selfInterfaceType, Type selfType)
+                           GenericEnvironment *genericEnv,
+                           Type selfInterfaceType, Type selfType,
+                           SILFunctionTypeRepresentation callbackRepresentation)
     : SGM(SGM),
       Linkage(linkage),
       RequirementStorage(nullptr),
@@ -138,11 +282,12 @@
       WitnessStorage(witness->getAccessorStorageDecl()),
       WitnessStoragePattern(AbstractionPattern::getInvalid()),
       WitnessSubs(subs),
-      GenericEnv(nullptr),
+      GenericEnv(genericEnv),
       SelfInterfaceType(selfInterfaceType->getCanonicalType()),
       SubstSelfType(selfType->getCanonicalType()),
       TheAccessSemantics(AccessSemantics::Ordinary),
-      IsSuper(false) {
+      IsSuper(false),
+      CallbackRepresentation(callbackRepresentation) {
 
     // Determine the formal type of the 'self' parameter.
     if (WitnessStorage->isStatic()) {
@@ -164,6 +309,9 @@
     WitnessStorageType =
       SGM.Types.getLoweredType(WitnessStoragePattern, SubstStorageType)
                .getObjectType();
+
+    if (genericEnv)
+      GenericSig = genericEnv->getGenericSignature()->getCanonicalSignature();
   }
 
 public:
@@ -176,18 +324,8 @@
                   FuncDecl *requirement, FuncDecl *witness,
                   SubstitutionList witnessSubs) {
     MaterializeForSetEmitter emitter(SGM, linkage, witness, witnessSubs,
-                                     selfInterfaceType, selfType);
-
-    if (conformance) {
-      if (auto signature = conformance->getGenericSignature())
-        emitter.GenericSig = signature->getCanonicalSignature();
-      emitter.GenericEnv = genericEnv;
-    } else {
-      auto signature = requirement->getGenericSignatureOfContext();
-      emitter.GenericSig = signature->getCanonicalSignature();
-      emitter.GenericEnv = genericEnv;
-    }
-
+                                     genericEnv, selfInterfaceType, selfType,
+                                     SILFunctionTypeRepresentation::WitnessMethod);
     emitter.RequirementStorage = requirement->getAccessorStorageDecl();
 
     // Determine the desired abstraction pattern of the storage type
@@ -214,15 +352,11 @@
     Type selfType = witness->mapTypeIntoContext(selfInterfaceType);
 
     SILDeclRef constant(witness);
-    auto constantInfo = SGM.Types.getConstantInfo(constant);
-
     MaterializeForSetEmitter emitter(SGM, constant.getLinkage(ForDefinition),
                                      witness, witnessSubs,
-                                     selfInterfaceType, selfType);
-
-    if (auto signature = witness->getGenericSignatureOfContext())
-      emitter.GenericSig = signature->getCanonicalSignature();
-    emitter.GenericEnv = constantInfo.GenericEnv;
+                                     witness->getGenericEnvironment(),
+                                     selfInterfaceType, selfType,
+                                     SILFunctionTypeRepresentation::Method);
 
     emitter.RequirementStorage = emitter.WitnessStorage;
     emitter.RequirementStoragePattern = emitter.WitnessStoragePattern;
@@ -317,11 +451,8 @@
     CanType witnessSelfType =
       Witness->computeInterfaceSelfType()->getCanonicalType();
     witnessSelfType = getSubstWitnessInterfaceType(witnessSelfType);
-    if (auto selfTuple = dyn_cast<TupleType>(witnessSelfType)) {
-      assert(selfTuple->getNumElements() == 1);
-      witnessSelfType = selfTuple.getElementType(0);
-    }
-    witnessSelfType = witnessSelfType.getLValueOrInOutObjectType();
+    witnessSelfType = witnessSelfType->getInOutObjectType()
+      ->getCanonicalType();
 
     // Eagerly loading here could cause an unnecessary
     // load+materialize in some cases, but it's not really important.
@@ -387,9 +518,12 @@
   /// Given part of the witness's interface type, produce its
   /// substitution according to the witness substitutions.
   CanType getSubstWitnessInterfaceType(CanType type) {
-    auto subs = SubstSelfType->getRValueInstanceType()
-        ->getMemberSubstitutionMap(SGM.SwiftModule, WitnessStorage);
-    return type.subst(subs)->getCanonicalType();
+    if (auto *witnessSig = Witness->getGenericSignature()) {
+      auto subMap = witnessSig->getSubstitutionMap(WitnessSubs);
+      return type.subst(subMap, SubstFlags::UseErrorType)->getCanonicalType();
+    }
+
+    return type;
   }
 
 };
@@ -550,14 +684,23 @@
   auto callbackType =
       SGM.Types.getMaterializeForSetCallbackType(WitnessStorage,
                                                  GenericSig,
-                                                 SelfInterfaceType);
-  auto callback =
-      SGM.M.getOrCreateFunction(Witness, CallbackName, Linkage,
-                                callbackType, IsBare,
-                                F.isTransparent(),
-                                F.isFragile());
+                                                 SelfInterfaceType,
+                                                 CallbackRepresentation);
 
-  callback->setGenericEnvironment(GenericEnv);
+  auto *genericEnv = GenericEnv;
+  if (GenericEnv && GenericEnv->getGenericSignature()->areAllParamsConcrete())
+    genericEnv = nullptr;
+
+  auto callback =
+    SGM.M.createFunction(Linkage, CallbackName, callbackType,
+                         genericEnv, SILLocation(Witness),
+                         IsBare, F.isTransparent(), F.isFragile(),
+                         IsNotThunk,
+                         /*ClassVisibility=*/SILFunction::NotRelevant,
+                         /*InlineStrategy=*/InlineDefault,
+                         /*EffectsKind=*/EffectsKind::Unspecified,
+                         /*InsertBefore=*/&F);
+
   callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, callback));
 
   PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback);
@@ -680,7 +823,7 @@
       break;
 
     case AddressorKind::NativePinning:
-      gen.B.createStrongUnpin(loc, owner, Atomicity::Atomic);
+      gen.B.createStrongUnpin(loc, owner, gen.B.getDefaultAtomicity());
       break;
     }
 
@@ -784,7 +927,7 @@
       // ownership of it.
       SILValue indicesV =
         gen.B.createProjectValueBuffer(loc, indicesTy, callbackBuffer);
-      if (indicesTL->isLoadable())
+      if (indicesTL->isLoadable() || !gen.silConv.useLoweredAddresses())
         indicesV = indicesTL->emitLoad(gen.B, loc, indicesV,
                                        LoadOwnershipQualifier::Take);
       ManagedValue mIndices =
@@ -805,7 +948,7 @@
     auto &valueTL = gen.getTypeLowering(lvalue.getTypeOfRValue());
     value = gen.B.createPointerToAddress(
       loc, value, valueTL.getLoweredType().getAddressType(), /*isStrict*/ true);
-    if (valueTL.isLoadable())
+    if (valueTL.isLoadable() || !gen.silConv.useLoweredAddresses())
       value = valueTL.emitLoad(gen.B, loc, value, LoadOwnershipQualifier::Take);
     ManagedValue mValue = gen.emitManagedRValueWithCleanup(value, valueTL);
     RValue rvalue(gen, loc, lvalue.getSubstFormalType(), mValue);
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index a2b74b6..c53f642 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -1527,16 +1527,16 @@
     innerFailure = &specializedFailure;
   
   // Perform a conditional cast branch.
-  SGF.emitCheckedCastBranch(loc, castOperand,
-                            sourceType, targetType, SGFContext(),
-    // Success block: recurse.
-    [&](ManagedValue castValue) {
-      handleCase(ConsumableManagedValue::forOwned(castValue),
-                 specializedRows, *innerFailure);
-      assert(!SGF.B.hasValidInsertionPoint() && "did not end block");
-    },
-    // Failure block: branch out to the continuation block.
-    [&] { (*innerFailure)(loc); });
+  SGF.emitCheckedCastBranchOld(
+      loc, castOperand, sourceType, targetType, SGFContext(),
+      // Success block: recurse.
+      [&](ManagedValue castValue) {
+        handleCase(ConsumableManagedValue::forOwned(castValue), specializedRows,
+                   *innerFailure);
+        assert(!SGF.B.hasValidInsertionPoint() && "did not end block");
+      },
+      // Failure block: branch out to the continuation block.
+      [&] { (*innerFailure)(loc); });
 }
 
 /// Perform specialized dispatch for a sequence of EnumElementPattern or an
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index fb6d960..8092c04 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -1097,7 +1097,7 @@
         SGF.B.createInitExistentialAddr(Loc, existentialBuf,
                                         inputTupleType,
                                         concreteTL.getLoweredType(),
-                                        /*Conformances=*/{});
+                                        /*conformances=*/{});
 
       auto tupleTemp = SGF.useBufferAsTemporary(tupleBuf, concreteTL);
       translateAndImplodeInto(inputOrigType, inputTupleType,
@@ -1911,7 +1911,7 @@
     SILValue outerConcreteResultAddr
       = Gen.B.createInitExistentialAddr(Loc, outerResultAddr, innerSubstType,
                                         Gen.getLoweredType(opaque, innerSubstType),
-                                        /*Conformances=*/{});
+                                        /*conformances=*/{});
 
     // Emit into that address.
     planTupleIntoIndirectResult(innerOrigType, innerSubstType,
@@ -2517,7 +2517,8 @@
   builder.addGenericParameter(newGenericParam);
   Requirement newRequirement(RequirementKind::Conformance, newGenericParam,
                              openedExistential->getOpenedExistentialType());
-  auto source = RequirementSource::forAbstract(builder);
+  auto source =
+    GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
   builder.addRequirement(newRequirement, source);
 
   builder.finalize(SourceLoc(), {newGenericParam},
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index fb7a624..971662d 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -494,8 +494,6 @@
       SGM.emitPropertyBehavior(vd);
     if (vd->hasStorage()) {
       assert(vd->isStatic() && "stored property in extension?!");
-      ExtensionDecl *ext = cast<ExtensionDecl>(vd->getDeclContext());
-      NominalTypeDecl *theType = ext->getExtendedType()->getAnyNominal();
       return emitTypeMemberGlobalVariable(SGM, vd);
     }
     visitAbstractStorageDecl(vd);
diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp
index 064b980..aa2d3f1 100644
--- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp
+++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp
@@ -374,17 +374,19 @@
   bool IsOwnedSelf = SelfConvention == ParameterConvention::Direct_Owned;
 
   // Emit matching release for owned self if we are moving the original call.
-  if (!LeaveOriginal && IsOwnedSelf)
-    SILBuilderWithScope(SemanticsCall)
-        .createReleaseValue(SemanticsCall->getLoc(), Self, Atomicity::Atomic);
+  if (!LeaveOriginal && IsOwnedSelf) {
+    SILBuilderWithScope Builder(SemanticsCall);
+    Builder.createReleaseValue(SemanticsCall->getLoc(), Self, Builder.getDefaultAtomicity());
+  }
 
   auto NewArrayStructValue = copyArrayLoad(Self, InsertBefore, DT);
 
   // Retain the array.
-  if (IsOwnedSelf)
-    SILBuilderWithScope(InsertBefore, SemanticsCall)
-        .createRetainValue(SemanticsCall->getLoc(), NewArrayStructValue,
-                           Atomicity::Atomic);
+  if (IsOwnedSelf) {
+    SILBuilderWithScope Builder(InsertBefore, SemanticsCall);
+    Builder.createRetainValue(SemanticsCall->getLoc(), NewArrayStructValue,
+                              Builder.getDefaultAtomicity());
+  }
 
   return NewArrayStructValue;
 }
@@ -477,10 +479,11 @@
 
 void swift::ArraySemanticsCall::removeCall() {
   if (getSelfParameterConvention(SemanticsCall) ==
-      ParameterConvention::Direct_Owned)
-    SILBuilderWithScope(SemanticsCall)
-        .createReleaseValue(SemanticsCall->getLoc(), getSelf(),
-                            Atomicity::Atomic);
+      ParameterConvention::Direct_Owned) {
+    SILBuilderWithScope Builder(SemanticsCall);
+    Builder.createReleaseValue(SemanticsCall->getLoc(), getSelf(),
+                               Builder.getDefaultAtomicity());
+  }
 
   switch (getKind()) {
   default: break;
diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
index 8c0637f..44a04c6 100644
--- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
@@ -1004,7 +1004,7 @@
   if (Ty.hasReferenceSemantics())
     return true;
 
-  if (Ty.getSwiftType() == Mod->getASTContext().TheRawPointerType)
+  if (Ty.getSwiftRValueType() == Mod->getASTContext().TheRawPointerType)
     return true;
 
   if (auto *Str = Ty.getStructOrBoundGenericStruct()) {
diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp
index b53c482..9a6ed88 100644
--- a/lib/SILOptimizer/IPO/CapturePromotion.cpp
+++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp
@@ -192,36 +192,22 @@
 namespace {
 /// \brief A SILCloner subclass which clones a closure function while converting
 /// one or more captures from 'inout' (by-reference) to by-value.
-class ClosureCloner : public TypeSubstCloner<ClosureCloner> {
+class ClosureCloner : public SILClonerWithScopes<ClosureCloner> {
 public:
   friend class SILVisitor<ClosureCloner>;
   friend class SILCloner<ClosureCloner>;
 
   ClosureCloner(SILFunction *Orig, IsFragile_t Fragile,
                 StringRef ClonedName,
-                SubstitutionMap &InterfaceSubs,
-                SubstitutionList ApplySubs,
                 IndicesSet &PromotableIndices);
 
   void populateCloned();
 
   SILFunction *getCloned() { return &getBuilder().getFunction(); }
 
-protected:
-  // FIXME: We intentionally call SILClonerWithScopes here to ensure
-  //        the debug scopes are set correctly for cloned
-  //        functions. TypeSubstCloner, SILClonerWithScopes, and
-  //        SILCloner desperately need refactoring and/or combining so
-  //        that the obviously right things are happening for cloning
-  //        vs. inlining.
-  void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
-    SILClonerWithScopes<ClosureCloner>::postProcess(Orig, Cloned);
-  }
-
 private:
   static SILFunction *initCloned(SILFunction *Orig, IsFragile_t Fragile,
                                  StringRef ClonedName,
-                                 SubstitutionMap &InterfaceSubs,
                                  IndicesSet &PromotableIndices);
 
   void visitDebugValueAddrInst(DebugValueAddrInst *Inst);
@@ -316,13 +302,9 @@
 
 ClosureCloner::ClosureCloner(SILFunction *Orig, IsFragile_t Fragile,
                              StringRef ClonedName,
-                             SubstitutionMap &InterfaceSubs,
-                             SubstitutionList ApplySubs,
                              IndicesSet &PromotableIndices)
-  : TypeSubstCloner<ClosureCloner>(
-                           *initCloned(Orig, Fragile, ClonedName, InterfaceSubs,
-                                       PromotableIndices),
-                           *Orig, ApplySubs),
+  : SILClonerWithScopes<ClosureCloner>(
+                           *initCloned(Orig, Fragile, ClonedName, PromotableIndices)),
     Orig(Orig), PromotableIndices(PromotableIndices) {
   assert(Orig->getDebugScope()->Parent != getCloned()->getDebugScope()->Parent);
 }
@@ -419,7 +401,6 @@
 SILFunction*
 ClosureCloner::initCloned(SILFunction *Orig, IsFragile_t Fragile,
                           StringRef ClonedName,
-                          SubstitutionMap &InterfaceSubs,
                           IndicesSet &PromotableIndices) {
   SILModule &M = Orig->getModule();
 
@@ -436,9 +417,6 @@
       OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(),
       M.getASTContext());
 
-  auto SubstTy = SILType::substFuncType(M, InterfaceSubs, ClonedTy,
-                                        /* dropGenerics = */ false);
-  
   assert((Orig->isTransparent() || Orig->isBare() || Orig->getLocation())
          && "SILFunction missing location");
   assert((Orig->isTransparent() || Orig->isBare() || Orig->getDebugScope())
@@ -446,7 +424,7 @@
   assert(!Orig->isGlobalInit() && "Global initializer cannot be cloned");
 
   auto *Fn = M.createFunction(
-      Orig->getLinkage(), ClonedName, SubstTy, Orig->getGenericEnvironment(),
+      Orig->getLinkage(), ClonedName, ClonedTy, Orig->getGenericEnvironment(),
       Orig->getLocation(), Orig->isBare(), IsNotTransparent, Fragile,
       Orig->isThunk(), Orig->getClassVisibility(), Orig->getInlineStrategy(),
       Orig->getEffectsKind(), Orig, Orig->getDebugScope());
@@ -726,18 +704,6 @@
   return false;
 }
 
-static bool signatureHasDependentTypes(SILFunction *Callee) {
-  SILFunctionConventions conventions = Callee->getConventions();
-  if (conventions.getSILResultType().hasTypeParameter())
-    return true;
-
-  for (auto Param : conventions.funcTy->getParameters())
-    if (conventions.getSILType(Param).hasTypeParameter())
-      return true;
-
-  return false;
-}
-
 /// \brief Examine an alloc_box instruction, returning true if at least one
 /// capture of the boxed variable is promotable.  If so, then the pair of the
 /// partial_apply instruction and the index of the box argument in the closure's
@@ -759,11 +725,6 @@
       if (IM.count(PAI))
         return false;
 
-      // Bail if the signature has any dependent types as we do not
-      // currently support these.
-      if (signatureHasDependentTypes(PAI->getCalleeFunction()))
-        return false;
-
       SILModule &M = PAI->getModule();
       auto closureType = PAI->getType().castTo<SILFunctionType>();
       SILFunctionConventions closureConv(closureType, M);
@@ -864,13 +825,6 @@
                         IndicesSet &PromotableIndices) {
   SILFunction *F = PAI->getFunction();
 
-  // Create the substitution maps.
-  auto ApplySubs = PAI->getSubstitutions();
-
-  SubstitutionMap InterfaceSubs;
-  if (auto genericSig = PAI->getOrigCalleeType()->getGenericSignature())
-    InterfaceSubs = genericSig->getSubstitutionMap(ApplySubs);
-
   // Create the Cloned Name for the function.
   SILFunction *Orig = FRI->getReferencedFunction();
 
@@ -887,8 +841,7 @@
   }
 
   // Otherwise, create a new clone.
-  ClosureCloner cloner(Orig, Fragile, ClonedName, InterfaceSubs,
-                       ApplySubs, PromotableIndices);
+  ClosureCloner cloner(Orig, Fragile, ClonedName, PromotableIndices);
   cloner.populateCloned();
   return cloner.getCloned();
 }
diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
index 24c9fe0..860c4fc 100644
--- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
@@ -343,9 +343,9 @@
       // Emit the retain that matches the captured argument by the partial_apply
       // in the callee that is consumed by the partial_apply.
       Builder.setInsertionPoint(AI.getInstruction());
-      Builder.createRetainValue(Closure->getLoc(), Arg, Atomicity::Atomic);
+      Builder.createRetainValue(Closure->getLoc(), Arg, Builder.getDefaultAtomicity());
     } else {
-      Builder.createRetainValue(Closure->getLoc(), Arg, Atomicity::Atomic);
+      Builder.createRetainValue(Closure->getLoc(), Arg, Builder.getDefaultAtomicity());
     }
   }
 
@@ -364,9 +364,9 @@
     // argument to AI.
     if (CSDesc.isClosureConsumed() && CSDesc.closureHasRefSemanticContext()) {
       Builder.setInsertionPoint(TAI->getNormalBB()->begin());
-      Builder.createReleaseValue(Closure->getLoc(), Closure, Atomicity::Atomic);
+      Builder.createReleaseValue(Closure->getLoc(), Closure, Builder.getDefaultAtomicity());
       Builder.setInsertionPoint(TAI->getErrorBB()->begin());
-      Builder.createReleaseValue(Closure->getLoc(), Closure, Atomicity::Atomic);
+      Builder.createReleaseValue(Closure->getLoc(), Closure, Builder.getDefaultAtomicity());
       Builder.setInsertionPoint(AI.getInstruction());
     }
   } else {
@@ -377,7 +377,7 @@
     // right after NewAI. This is to balance the +1 from being an @owned
     // argument to AI.
     if (CSDesc.isClosureConsumed() && CSDesc.closureHasRefSemanticContext())
-      Builder.createReleaseValue(Closure->getLoc(), Closure, Atomicity::Atomic);
+      Builder.createReleaseValue(Closure->getLoc(), Closure, Builder.getDefaultAtomicity());
   }
 
   // Replace all uses of the old apply with the new apply.
@@ -425,10 +425,10 @@
 
   // Extend the lifetime of a captured argument to cover the callee.
   SILBuilderWithScope Builder(getClosure());
-  Builder.createRetainValue(getClosure()->getLoc(), Arg, Atomicity::Atomic);
+  Builder.createRetainValue(getClosure()->getLoc(), Arg, Builder.getDefaultAtomicity());
   for (auto *I : CInfo->LifetimeFrontier) {
     Builder.setInsertionPoint(I);
-    Builder.createReleaseValue(getClosure()->getLoc(), Arg, Atomicity::Atomic);
+    Builder.createReleaseValue(getClosure()->getLoc(), Arg, Builder.getDefaultAtomicity());
   }
 }
 
@@ -647,7 +647,7 @@
       if (isa<ReturnInst>(TI)) {
         Builder.setInsertionPoint(TI);
         Builder.createReleaseValue(Loc, SILValue(NewClosure),
-                                   Atomicity::Atomic);
+                                   Builder.getDefaultAtomicity());
         continue;
       }
 
@@ -663,7 +663,7 @@
       // value, we will retain the partial apply before we release it and
       // potentially eliminate it.
       Builder.setInsertionPoint(NoReturnApply.getInstruction());
-      Builder.createReleaseValue(Loc, SILValue(NewClosure), Atomicity::Atomic);
+      Builder.createReleaseValue(Loc, SILValue(NewClosure), Builder.getDefaultAtomicity());
     }
   }
 }
diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
index 6bf6614..4731fe0 100644
--- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp
+++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
@@ -77,6 +77,12 @@
     return valueHashMap.find(value) != valueHashMap.end();
   }
 
+  ValueStorage &getStorage(SILValue value) {
+    auto hashIter = valueHashMap.find(value);
+    assert(hashIter != valueHashMap.end() && "Missing SILValue");
+    return valueVector[hashIter->second].second;
+  }
+
   ValueStorage &insertValue(SILValue value) {
     auto hashResult =
         valueHashMap.insert(std::make_pair(value, valueVector.size()));
@@ -87,10 +93,18 @@
     return valueVector.back().second;
   }
 
-  ValueStorage &getStorage(SILValue value) {
-    auto hashIter = valueHashMap.find(value);
+  // Replace entry for `oldValue` with an entry for `newValue` preserving the
+  // the mapped ValueStorage.
+  void replaceValue(SILValue oldValue, SILValue newValue) {
+    auto hashIter = valueHashMap.find(oldValue);
     assert(hashIter != valueHashMap.end() && "Missing SILValue");
-    return valueVector[hashIter->second].second;
+    unsigned idx = hashIter->second;
+    valueHashMap.erase(hashIter);
+
+    valueVector[idx].first = newValue;
+    
+    auto hashResult = valueHashMap.insert(std::make_pair(newValue, idx));
+    assert(hashResult.second && "SILValue already mapped");
   }
 };
 } // end anonymous namespace
@@ -117,7 +131,10 @@
   AddressLoweringState(SILFunction *F) : F(F) {}
 
   void markDeadInst(SILInstruction *inst) {
-    assert(onlyHaveDebugUses(inst));
+#ifndef NDEBUG
+    for (Operand *use : inst->getUses())
+      assert(instsToDelete.count(use->getUser()));
+#endif
     instsToDelete.insert(inst);
   }
 };
@@ -128,7 +145,7 @@
 //===----------------------------------------------------------------------===//
 
 namespace {
-/// Collect all Opaque/Resilient values, inserting them in a ValueStorageMap in
+/// Collect all opaque/resilient values, inserting them in `valueStorageMap` in
 /// RPO order.
 ///
 /// Collect all call arguments with formally indirect SIL argument convention in
@@ -152,7 +169,10 @@
 };
 } // end anonymous namespace
 
-/// Populate valueStorageMap. Find all Opaque/Resilient SILValues and add them
+/// Top-level entry: Populate `valueStorageMap`, `indirectResults`, and
+/// `indirectOperands`.
+///
+/// Find all Opaque/Resilient SILValues and add them
 /// to valueStorageMap in RPO.
 void OpaqueValueVisitor::mapValueStorage() {
   for (auto *BB : postorderInfo.getReversePostOrder()) {
@@ -176,8 +196,12 @@
   }
 }
 
-/// Populate indirectOperands. Add an operand for each call argument with a
-/// formally indirect convention.
+/// Populate `indirectResults` and `indirectOperands`.
+///
+/// If this call has indirect formal results, add it to `indirectResults`.
+/// 
+/// Add each call operand with a formally indirect convention to
+/// `indirectOperands`.
 void OpaqueValueVisitor::visitApply(ApplySite applySite) {
   if (applySite.getSubstCalleeType()->hasIndirectFormalResults())
     pass.indirectResults.push_back(applySite.getInstruction());
@@ -195,11 +219,14 @@
   }
 }
 
+/// If `value` is address-only add it to the `valueStorageMap`.
+/// 
 /// TODO: Set ValueStorage.projectionFrom whenever there is a single
 /// isComposingOperand() use and the aggregate's storage can be hoisted to a
 /// dominating point.
 void OpaqueValueVisitor::visitValue(SILValue value) {
-  if (value->getType().isAddressOnly(pass.F->getModule())) {
+  if (value->getType().isObject()
+      && value->getType().isAddressOnly(pass.F->getModule())) {
     if (pass.valueStorageMap.contains(value)) {
       assert(isa<SILFunctionArgument>(
           pass.valueStorageMap.getStorage(value).storageAddress));
@@ -241,6 +268,11 @@
   unsigned insertIndirectResultParameters(unsigned argIdx, SILType resultType);
   void allocateForValue(SILValue value, ValueStorage &storage);
   void allocateForOperand(Operand *operand);
+  void canonicalizeResults(
+    ApplyInst *applyInst,
+    SmallVectorImpl<SILInstruction*> &directResultValues,
+    ArrayRef<Operand*> nonCanonicalUses);
+  void canonicalizeResults(ApplyInst *applyInst);
   void allocateForResults(SILInstruction *origInst);
 };
 } // end anonymous namespace
@@ -280,14 +312,17 @@
   // Create an AllocStack for every formally indirect argument.
   for (Operand *operand : pass.indirectOperands)
     allocateForOperand(operand);
+  pass.indirectOperands.clear();
 
   // Create an AllocStack for every formally indirect result.
+  // This rewrites and potentially erases the original call.
   for (SILInstruction *callInst : pass.indirectResults)
     allocateForResults(callInst);
+  pass.indirectResults.clear();
 }
 
-/// Replace each value-typed argument with an address-typed argument by
-/// inserting a temprorary load instruction.
+/// Replace each value-typed argument to the current function with an
+/// address-typed argument by inserting a temporary load instruction.
 void OpaqueStorageAllocation::replaceFunctionArgs() {
   // Insert temporary argument loads at the top of the function.
   SILBuilder argBuilder(pass.F->getEntryBlock()->begin());
@@ -297,7 +332,7 @@
   for (SILParameterInfo param :
        pass.F->getLoweredFunctionType()->getParameters()) {
 
-    if (param.isFormalIndirect()) {
+    if (param.isFormalIndirect() && !fnConv.isSILIndirect(param)) {
       SILArgument *arg = pass.F->getArgument(argIdx);
       SILType addrType = arg->getType().getAddressType();
 
@@ -326,7 +361,8 @@
 /// Recursively insert function arguments for any @out result type at the
 /// specified index. Return the index after the last inserted result argument.
 ///
-/// This is effectively moved from the old SILGen emitIndirectResultParameters.
+/// Note: This is effectively moved from the old SILGen
+/// emitIndirectResultParameters.
 ///
 /// TODO: It might be faster to generate args directly from
 /// SILFunctionConventions without drilling through the result SILType. But one
@@ -362,6 +398,7 @@
 }
 
 /// Utility to derive SILLocation.
+/// 
 /// TODO: This should be a common utility.
 static SILLocation getLocForValue(SILValue value) {
   if (auto *instr = dyn_cast<SILInstruction>(value)) {
@@ -384,6 +421,11 @@
   if (isa<TupleInst>(value))
     return;
 
+  // Don't bother allocating storage for result tuples. Each element has its own
+  // storage.
+  if (isa<FullApplySite>(value))
+    return;
+
   // Argument loads already have a storage address.
   if (storage.storageAddress) {
     assert(isa<SILFunctionArgument>(storage.storageAddress));
@@ -404,11 +446,16 @@
 }
 
 /// Deallocate temporary call-site stack storage.
+///
+/// `argLoad` is non-null for @out args that are loaded.
 static void insertStackDeallocationAtCall(AllocStackInst *allocInst,
-                                          SILInstruction *applyInst) {
+                                          SILInstruction *applyInst,
+                                          SILInstruction *argLoad) {
+  SILInstruction *lastUse = argLoad ? argLoad : applyInst;
+
   switch (applyInst->getKind()) {
   case ValueKind::ApplyInst: {
-    SILBuilder deallocBuilder(&*std::next(applyInst->getIterator()));
+    SILBuilder deallocBuilder(&*std::next(lastUse->getIterator()));
     deallocBuilder.createDeallocStack(allocInst->getLoc(), allocInst);
     break;
   }
@@ -425,6 +472,9 @@
 /// Allocate storage for formally indirect arguments.
 /// Update the operand to this address.
 /// After this, the SIL argument types no longer match SIL function conventions.
+///
+/// Note: The temporary argument storage does not own its value. If the argument
+/// is owner, the stored value should already have been copied.
 void OpaqueStorageAllocation::allocateForOperand(Operand *operand) {
   SILInstruction *apply = operand->getUser();
   SILValue argValue = operand->get();
@@ -433,77 +483,174 @@
   AllocStackInst *allocInstr =
       callBuilder.createAllocStack(apply->getLoc(), argValue->getType());
 
-  // This is a store [init], but qualifications aren't allowed.
   callBuilder.createStore(apply->getLoc(), argValue, allocInstr,
                           StoreOwnershipQualifier::Unqualified);
 
   operand->set(allocInstr);
 
-  insertStackDeallocationAtCall(allocInstr, apply);
+  insertStackDeallocationAtCall(allocInstr, apply, /*argLoad=*/nullptr);
+}
+
+// Canonicalize call result uses. Treat each result of a multi-result call as
+// independent values. Currently, SILGen may generate tuple_extract for each
+// result but generate a single destroy_value for the entire tuple of
+// results. This makes it impossible to reason about each call result as an
+// independent value according to the callee's function type.
+//
+// directResultValues has an entry for each tuple extract corresponding to
+// that result if one exists. This function will add an entry to
+// directResultValues whenever it needs to materialize a TupleExtractInst.
+void OpaqueStorageAllocation::canonicalizeResults(
+  ApplyInst *applyInst,
+  SmallVectorImpl<SILInstruction*> &directResultValues,
+  ArrayRef<Operand*> nonCanonicalUses) {
+
+  for (Operand *operand : nonCanonicalUses) {
+    auto *destroyInst = dyn_cast<DestroyValueInst>(operand->getUser());
+    if (!destroyInst)
+      llvm::report_fatal_error("Simultaneous use of multiple call results.");
+
+    for (unsigned resultIdx = 0, endIdx = directResultValues.size();
+         resultIdx < endIdx; ++resultIdx) {
+      SILInstruction *result = directResultValues[resultIdx];
+      if (!result) {
+        SILBuilder resultBuilder(std::next(SILBasicBlock::iterator(applyInst)));
+        result = resultBuilder.createTupleExtract(applyInst->getLoc(),
+                                                  applyInst, resultIdx);
+        directResultValues[resultIdx] = result;
+      }
+      SILBuilder B(destroyInst);
+      auto &TL = pass.F->getModule().getTypeLowering(result->getType());
+      TL.emitDestroyValue(B, destroyInst->getLoc(), result);
+    }
+    destroyInst->eraseFromParent();
+  }
 }
 
 /// Allocate storage for formally indirect results at the given call site.
 /// Create a new call instruction with indirect SIL arguments.
-void OpaqueStorageAllocation::allocateForResults(SILInstruction *origInst) {
-  ApplySite apply(origInst);
+void OpaqueStorageAllocation::allocateForResults(SILInstruction *origCallInst) {
+  ApplySite apply(origCallInst);
+
+  SILFunctionConventions origFnConv = apply.getSubstCalleeConv();
+
+  // Gather the original direct return values.
+  // Canonicalize results so no user uses more than one result.
+  SmallVector<SILInstruction *, 8> origDirectResultValues(
+    origFnConv.getNumDirectSILResults());
+  SmallVector<Operand *, 4> nonCanonicalUses;
+  if (origCallInst->getType().is<TupleType>()) {
+    for (Operand *operand : origCallInst->getUses()) {
+      if (auto *extract = dyn_cast<TupleExtractInst>(operand->getUser()))
+        origDirectResultValues[extract->getFieldNo()] = extract;
+      else
+        nonCanonicalUses.push_back(operand);
+    }
+    if (!nonCanonicalUses.empty()) {
+      auto *applyInst = cast<ApplyInst>(origCallInst);
+      canonicalizeResults(applyInst, origDirectResultValues, nonCanonicalUses);
+    }
+  } else {
+    // A call with no indirect results should not have been added to
+    // pass.indirectResults.
+    assert(origDirectResultValues.size() == 1);
+    if (!origCallInst->use_empty()) {
+      origDirectResultValues[0] = origCallInst;
+      // Tuple extract values were already mapped. The call itself was not.
+      pass.valueStorageMap.insertValue(origCallInst);
+    }
+  }
+
+  // Prepare to emit a new call instruction.
+  SILLocation loc = origCallInst->getLoc();
+  SILBuilder callBuilder(origCallInst);
+
+  // Lambda to allocate and map storage for an indirect result.
+  // Note: origDirectResultValues contains null for unused results.
+  auto mapIndirectArg = [&](SILInstruction *origDirectResultVal,
+                            SILType argTy) {
+    if (origDirectResultVal
+        && pass.valueStorageMap.contains(origDirectResultVal)) {
+      // Pass the local storage address as the indirect result address.
+      return
+        pass.valueStorageMap.getStorage(origDirectResultVal).storageAddress;
+    }
+    // Allocate temporary call-site storage for an unused or loadable result.
+    auto *allocInst =
+    callBuilder.createAllocStack(loc, argTy);
+    LoadInst *loadInst = nullptr;
+    if (origDirectResultVal) {
+      // TODO: Find the try_apply's result block.
+      // Build results outside-in to next stack allocations.
+      SILBuilder resultBuilder(
+        std::next(SILBasicBlock::iterator(origCallInst)));
+      // This is a formally indirect argument, but is loadable.
+      loadInst = resultBuilder.createLoad(loc, allocInst,
+                                          LoadOwnershipQualifier::Unqualified);
+      origDirectResultVal->replaceAllUsesWith(loadInst);
+      pass.markDeadInst(origDirectResultVal);
+    }
+    insertStackDeallocationAtCall(allocInst, origCallInst, loadInst);
+    return SILValue(allocInst);
+  };
+
+  // The new call instruction's SIL calling convention.
   SILFunctionConventions loweredFnConv(
       apply.getSubstCalleeType(),
       SILModuleConventions::getLoweredAddressConventions());
 
-  SILLocation loc = origInst->getLoc();
-  SILBuilder callBuilder(origInst);
+  // The new call instruction's SIL argument list.
+  SmallVector<SILValue, 8> newCallArgs(loweredFnConv.getNumSILArguments());
 
-  SmallVector<SILValue, 8> args(loweredFnConv.getNumSILArguments());
-  unsigned firstResultIdx = loweredFnConv.getSILArgIndexOfFirstIndirectResult();
+  // Map the original result indices to new result indices.
+  SmallVector<unsigned, 8> newDirectResultIndices(
+    origFnConv.getNumDirectSILResults());
+  // Indices used to populate newDirectResultIndices.
+  unsigned oldDirectResultIdx = 0, newDirectResultIdx = 0;
 
-  // Find the storage location of each indirect result and populate the SIL
-  // argument vector.
-  SmallVector<TupleExtractInst *, 4> concreteResults;
-  if (origInst->getType().is<TupleType>()) {
-    for (Operand *operand : origInst->getUses()) {
-      if (auto *extract = dyn_cast<TupleExtractInst>(operand->getUser())) {
-        unsigned argIdx = firstResultIdx + extract->getFieldNo();
-        assert(argIdx < loweredFnConv.getSILArgIndexOfFirstParam());
-        if (!extract->getType().isAddressOnly(pass.F->getModule())) {
-          concreteResults.push_back(extract);
-          continue;
-        }
-        auto addr = pass.valueStorageMap.getStorage(extract).storageAddress;
-        assert(addr);
-        args[argIdx] = addr;
+  // The index of the next indirect result argument.
+  unsigned newResultArgIdx =
+    loweredFnConv.getSILArgIndexOfFirstIndirectResult();
+
+  // Visit each result. Redirect results that are now indirect.
+  // Result that remain direct will be redirected later.
+  // Populate newCallArgs and newDirectResultIndices.
+  for_each(
+    apply.getSubstCalleeType()->getResults(),
+    origDirectResultValues, 
+    [&](SILResultInfo resultInfo, SILInstruction *origDirectResultVal) {
+      // Assume that all original results are direct in SIL.
+      assert(!origFnConv.isSILIndirect(resultInfo));
+
+      if (loweredFnConv.isSILIndirect(resultInfo)) {
+        newCallArgs[newResultArgIdx++] =
+          mapIndirectArg(origDirectResultVal,
+                         loweredFnConv.getSILType(resultInfo));;
+        newDirectResultIndices[oldDirectResultIdx++] = newDirectResultIdx;
+      } else {
+        newDirectResultIndices[oldDirectResultIdx++] = newDirectResultIdx++;
       }
-    }
-  } else {
-    auto addr = pass.valueStorageMap.getStorage(origInst).storageAddress;
-    assert(addr);
-    args[firstResultIdx] = addr;
-  }
-  // Allocate storage for any unused or concrete results. One for each missing
-  // entry in the SIL arguments list.
-  unsigned argIdx = firstResultIdx;
-  for (SILType resultTy : loweredFnConv.getIndirectSILResultTypes()) {
-    if (!args[argIdx]) {
-      AllocStackInst *allocInstr = callBuilder.createAllocStack(loc, resultTy);
-      args[argIdx] = allocInstr;
-      insertStackDeallocationAtCall(allocInstr, origInst);
-    }
-    ++argIdx;
-  }
+      // replaceAllUses will be called later to handle direct results that
+      // remain direct results of the new call instruction.
+    });
+
   // Append the existing call arguments to the SIL argument list. They were
   // already lowered to addresses by allocateForOperand.
-  assert(argIdx == loweredFnConv.getSILArgIndexOfFirstParam());
+  assert(newResultArgIdx == loweredFnConv.getSILArgIndexOfFirstParam());
   unsigned origArgIdx = apply.getSubstCalleeConv().getSILArgIndexOfFirstParam();
-  for (unsigned endIdx = args.size(); argIdx < endIdx; ++argIdx, ++origArgIdx) {
-    args[argIdx] = apply.getArgument(origArgIdx);
+  for (unsigned endIdx = newCallArgs.size(); newResultArgIdx < endIdx;
+       ++newResultArgIdx, ++origArgIdx) {
+    newCallArgs[newResultArgIdx] = apply.getArgument(origArgIdx);
   }
+
   // Create a new apply with indirect result operands.
-  SILInstruction *callInst;
-  switch (origInst->getKind()) {
+  SILInstruction *newCallInst;
+  switch (origCallInst->getKind()) {
   case ValueKind::ApplyInst:
-    callInst = callBuilder.createApply(
+    newCallInst = callBuilder.createApply(
         loc, apply.getCallee(), apply.getSubstCalleeSILType(),
-        loweredFnConv.getSILResultType(), apply.getSubstitutions(), args,
-        cast<ApplyInst>(origInst)->isNonThrowing());
+        loweredFnConv.getSILResultType(), apply.getSubstitutions(), newCallArgs,
+        cast<ApplyInst>(origCallInst)->isNonThrowing());
     break;
   case ValueKind::TryApplyInst:
     // TODO: insert dealloc in the catch block.
@@ -513,23 +660,48 @@
   default:
     llvm_unreachable("not implemented for this instruction!");
   }
-  if (pass.valueStorageMap.contains(origInst)) {
-    pass.valueStorageMap.insertValue(callInst);
-    pass.valueStorageMap.getStorage(callInst).storageAddress =
-        pass.valueStorageMap.getStorage(origInst).storageAddress;
-    // origInst remains in the map but has no users.
+
+  // Replace all unmapped uses of the original call with uses of the new call.
+  // 
+  // TODO: handle bbargs from try_apply.
+  SILBuilder resultBuilder(
+    std::next(SILBasicBlock::iterator(origCallInst)));
+  SmallVector<Operand*, 8> origUses(origCallInst->getUses());
+  for (Operand *operand : origUses) {
+    auto *extractInst = dyn_cast<TupleExtractInst>(operand->getUser());
+    if (!extractInst) {
+      assert(origFnConv.getNumDirectSILResults() == 1);
+      assert(pass.valueStorageMap.contains(origCallInst));
+      continue;
+    }
+    unsigned origResultIdx = extractInst->getFieldNo();
+    auto resultInfo = origFnConv.getResults()[origResultIdx];
+
+    if (extractInst->getType().isAddressOnly(pass.F->getModule())) {
+      assert(loweredFnConv.isSILIndirect(resultInfo));
+      assert(pass.valueStorageMap.contains(extractInst));
+      continue;
+    }
+    if (loweredFnConv.isSILIndirect(resultInfo)) {
+      // This loadable indirect use should already be
+      // redirected to a load from the argument storage and marked dead.
+      assert(extractInst->use_empty());
+      continue;
+    }
+    // Either the new call instruction has only a single direct result, or we
+    // map the original tuple field to the new tuple field.
+    SILInstruction *newValue = newCallInst;
+    if (loweredFnConv.getNumDirectSILResults() > 1) {
+      assert(newCallInst->getType().is<TupleType>());
+      newValue = resultBuilder.createTupleExtract(
+        extractInst->getLoc(), newCallInst,
+        newDirectResultIndices[origResultIdx]);
+    }
+    extractInst->replaceAllUsesWith(newValue);
+    extractInst->eraseFromParent();
   }
-  origInst->replaceAllUsesWith(callInst);
-  pass.markDeadInst(origInst);
-  // Load concrete args, and mark the extract for deletion.
-  for (TupleExtractInst *extract : concreteResults) {
-    unsigned argIdx = firstResultIdx + extract->getFieldNo();
-    SILValue arg = args[argIdx];
-    LoadInst *loadArg = callBuilder.createLoad(
-        extract->getLoc(), arg, LoadOwnershipQualifier::Unqualified);
-    extract->replaceAllUsesWith(loadArg);
-    pass.markDeadInst(extract);
-  }
+  if (!pass.valueStorageMap.contains(origCallInst))
+    pass.markDeadInst(origCallInst);
 }
 
 //===----------------------------------------------------------------------===//
@@ -553,15 +725,21 @@
 
   void rewriteFunction() {
     for (auto &valueStorageI : pass.valueStorageMap) {
+      SILValue valueDef = valueStorageI.first;
       valueStorage = valueStorageI.second;
-      DEBUG(llvm::dbgs() << "VALUE   "; valueStorageI.first->dump());
+      DEBUG(llvm::dbgs() << "VALUE   "; valueDef->dump());
       DEBUG(if (valueStorage.storageAddress) {
-        llvm::dbgs() << "STORAGE ";
+        llvm::dbgs() << "  STORAGE ";
         valueStorage.storageAddress->dump();
       });
-      for (Operand *currOper : valueStorageI.first->getUses()) {
+      SmallVector<Operand*, 8> uses(valueDef->getUses());
+      for (Operand *oper : uses) {
+        currOper = oper;
         visit(currOper->getUser());
       }
+      currOper = nullptr;
+      if (auto *defInst = dyn_cast<SILInstruction>(valueDef))
+        visit(defInst);
     }
   }
 
@@ -572,19 +750,24 @@
   }
 
   void beforeVisit(ValueBase *V) {
-    DEBUG(llvm::dbgs() << "REWRITE "; V->dump());
+    DEBUG(llvm::dbgs() << "  REWRITE "; V->dump());
     auto *I = cast<SILInstruction>(V);
     B.setInsertionPoint(I);
     B.setCurrentDebugScope(I->getDebugScope());
   }
 
   void visitApplyInst(ApplyInst *applyInst) {
-    DEBUG(llvm::dbgs() << "CALL "; applyInst->dump();
-          llvm::dbgs() << "OPERAND "; currOper->get()->dump());
-    llvm_unreachable("Unhandled call result.");
+    if (currOper) {
+      DEBUG(llvm::dbgs() << "  CALL "; applyInst->dump();
+            llvm::dbgs() << "  OPERAND "; currOper->get()->dump());
+      llvm_unreachable("Unhandled call result.");
+    }
   }
 
   void visitCopyValueInst(CopyValueInst *copyInst) {
+    if (!currOper)
+      return;
+    
     SILValue srcAddr =
         pass.valueStorageMap.getStorage(copyInst->getOperand()).storageAddress;
     SILValue destAddr =
@@ -593,40 +776,126 @@
                      IsInitialization);
   }
   
+  void visitDebugValueInst(DebugValueInst *debugInst) {
+    SILValue addr =
+      pass.valueStorageMap.getStorage((debugInst->getOperand())).storageAddress;
+    B.createDebugValueAddr(debugInst->getLoc(), addr);
+    pass.markDeadInst(debugInst);
+  }
+  
   void visitDestroyValueInst(DestroyValueInst *destroyInst) {
-    SILValue src = destroyInst->getOperand();
+    assert(currOper->get() == destroyInst->getOperand());
+    SILValue src = currOper->get();
     SILValue addr = pass.valueStorageMap.getStorage(src).storageAddress;
     B.createDestroyAddr(destroyInst->getLoc(), addr);
     pass.markDeadInst(destroyInst);
   }
 
+  void visitLoadInst(LoadInst *loadInst) {
+    assert(!currOper);
+    // Bitwise copy the value. Two locations now share ownership. This is
+    // modeled as a take-init.
+    SILValue addr = pass.valueStorageMap.getStorage(loadInst).storageAddress;
+    if (addr != loadInst->getOperand()) {
+      B.createCopyAddr(loadInst->getLoc(), loadInst->getOperand(), addr,
+                       IsTake, IsInitialization);
+    }
+  }
+
   void visitReturnInst(ReturnInst *returnInst) {
+    assert(currOper->get() == returnInst->getOperand());
+
+    auto insertPt = SILBasicBlock::iterator(returnInst);
+    auto bbStart = returnInst->getParent()->begin();
+    while (insertPt != bbStart) {
+      --insertPt;
+      if (!isa<DeallocStackInst>(*insertPt))
+        break;
+    }
+    B.setInsertionPoint(insertPt);
+
+    // Gather direct function results.
+    unsigned numOrigDirectResults =
+      pass.F->getConventions().getNumDirectSILResults();
+    SmallVector<SILValue, 8> origDirectResultValues;
+    if (numOrigDirectResults == 1)
+      origDirectResultValues.push_back(currOper->get());
+    else {
+      auto *tupleInst = cast<TupleInst>(currOper->get());
+      origDirectResultValues.append(tupleInst->getElements().begin(),
+                                    tupleInst->getElements().end());
+      assert(origDirectResultValues.size() == numOrigDirectResults);
+    }
+
+    SILFunctionConventions origFnConv(pass.F->getConventions());
     SILFunctionConventions loweredFnConv(
         pass.F->getLoweredFunctionType(),
         SILModuleConventions::getLoweredAddressConventions());
 
-    unsigned resultArgIdx = loweredFnConv.getSILArgIndexOfFirstIndirectResult();
-    auto copyResult = [&](SILValue result) {
-      SILArgument *resultArg = B.getFunction().getArgument(resultArgIdx);
-      SILValue resultAddr =
-          pass.valueStorageMap.getStorage(result).storageAddress;
-      B.createCopyAddr(returnInst->getLoc(), resultAddr, resultArg, IsTake,
-                       IsInitialization);
-    };
-    unsigned numIndirectResults = loweredFnConv.getNumIndirectSILResults();
-    if (numIndirectResults == 1) {
-      copyResult(returnInst->getOperand());
-    } else {
-      for (unsigned endIdx = resultArgIdx + numIndirectResults;
-           resultArgIdx < endIdx; ++resultArgIdx) {
-        auto *tupleInst = cast<TupleInst>(returnInst->getOperand());
-        copyResult(tupleInst->getElement(resultArgIdx));
-      }
-    }
-    SILType emptyTy = B.getModule().Types.getLoweredType(
+    // Convert each result.
+    SmallVector<SILValue, 8> newDirectResults;
+    unsigned newResultArgIdx =
+      loweredFnConv.getSILArgIndexOfFirstIndirectResult();
+
+    for_each(
+      pass.F->getLoweredFunctionType()->getResults(),
+      origDirectResultValues, 
+      [&](SILResultInfo resultInfo, SILValue origDirectResultVal) 
+      {
+        // Assume that all original results are direct in SIL.
+        assert(!origFnConv.isSILIndirect(resultInfo));
+        if (loweredFnConv.isSILIndirect(resultInfo)) {
+          assert(newResultArgIdx < loweredFnConv.getSILArgIndexOfFirstParam());
+          SILArgument *resultArg = B.getFunction().getArgument(newResultArgIdx);
+          if (pass.valueStorageMap.contains(origDirectResultVal)) {
+            // Copy the result from local storage into the result argument.
+            SILValue resultAddr =
+              pass.valueStorageMap.getStorage(origDirectResultVal)
+              .storageAddress;
+
+            B.createCopyAddr(returnInst->getLoc(), resultAddr, resultArg,
+                             IsTake, IsInitialization);
+            ++newResultArgIdx;
+          }
+          else {
+            // Sore the result into the result argument.
+            B.createStore(returnInst->getLoc(), origDirectResultVal,
+                          resultArg, StoreOwnershipQualifier::Init);
+            llvm_unreachable("untested."); //!!!
+          }
+        } else {
+          // Record the direct result for populating the result tuple.
+          newDirectResults.push_back(origDirectResultVal);
+        }
+      });
+    assert(newDirectResults.size() == loweredFnConv.getNumDirectSILResults());
+    SILValue newReturnVal;
+    if (newDirectResults.empty()) {
+      SILType emptyTy = B.getModule().Types.getLoweredType(
         TupleType::getEmpty(B.getModule().getASTContext()));
-    auto *tupleInst = B.createTuple(returnInst->getLoc(), emptyTy, {});
-    returnInst->setOperand(tupleInst);
+      newReturnVal = B.createTuple(returnInst->getLoc(), emptyTy, {});
+    } else if (newDirectResults.size() == 1) {
+      newReturnVal = newDirectResults[0];
+    } else {
+      newReturnVal = B.createTuple(returnInst->getLoc(),
+                                   loweredFnConv.getSILResultType(),
+                                   newDirectResults);
+    }
+    returnInst->setOperand(newReturnVal);
+  }
+
+  void visitStoreInst(StoreInst *storeInst) {
+    assert(currOper->get() == storeInst->getSrc());
+    SILValue srcAddr =
+      pass.valueStorageMap.getStorage(currOper->get()).storageAddress;
+    assert(storeInst->getOwnershipQualifier() ==
+           StoreOwnershipQualifier::Unqualified);
+
+    // Bitwise copy the value. Two locations now share ownership. This is
+    // modeled as a take-init.
+    B.createCopyAddr(storeInst->getLoc(), srcAddr, storeInst->getDest(),
+                     IsTake, IsInitialization);
+    pass.markDeadInst(storeInst);
   }
 
   void visitTupleInst(TupleInst *tupleInst) {
@@ -635,15 +904,16 @@
   }
 
   void visitTupleExtractInst(TupleExtractInst *extractInst) {
-    // Tuple element instructions don't require rewrite. They are dead.
-    llvm_unreachable("Untested.");
-    return;
+    // TupleExtract merely names a storage location. It doesn't need to be
+    // rewritten.
+    assert(extractInst->use_empty()
+           || pass.valueStorageMap.getStorage(extractInst).storageAddress);
   }
 };
 } // end anonymous namespace
 
 //===----------------------------------------------------------------------===//
-// AddressLowering: Top Level Function Transform.
+// AddressLowering: Top-Level Function Transform.
 //===----------------------------------------------------------------------===//
 
 namespace {
@@ -658,14 +928,14 @@
 } // end anonymous namespace
 
 void AddressLowering::runOnFunction(SILFunction *F) {
-  DEBUG(llvm::dbgs() << "LOWER "; F->dump());
-
   AddressLoweringState pass(F);
 
   // Rewrite function args and insert alloc_stack/dealloc_stack.
   OpaqueStorageAllocation allocator(pass);
   allocator.allocateOpaqueStorage();
 
+  DEBUG(llvm::dbgs() << "\nREWRITING: " << F->getName(); F->dump());
+
   // Rewrite instructions with address-only operands or results.
   AddressOnlyRewriter(pass).rewriteFunction();
 
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
index 794592e..3d8f05c 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
@@ -145,7 +145,7 @@
   // by apply instructions.
   bool needsReleases = false;
   CanSILFunctionType PAITy =
-      dyn_cast<SILFunctionType>(PAI->getCallee()->getType().getSwiftType());
+    PAI->getCallee()->getType().getAs<SILFunctionType>();
 
   // Emit a destroy value for each captured closure argument.
   ArrayRef<SILParameterInfo> Params = PAITy->getParameters();
@@ -228,7 +228,7 @@
       if (!TmpType.isAddressOnly(PAI->getModule())) {
         auto *Load = Builder.createLoad(PAI->getLoc(), Op,
                                         LoadOwnershipQualifier::Unqualified);
-        Builder.createReleaseValue(PAI->getLoc(), Load, Atomicity::Atomic);
+        Builder.createReleaseValue(PAI->getLoc(), Load, Builder.getDefaultAtomicity());
       } else {
         Builder.createDestroyAddr(PAI->getLoc(), Op);
       }
@@ -320,20 +320,20 @@
     for (auto Arg : ToBeReleasedArgs) {
       Builder.emitDestroyValueOperation(PAI->getLoc(), Arg);
     }
-    Builder.createStrongRelease(AI.getLoc(), PAI, Atomicity::Atomic);
+    Builder.createStrongRelease(AI.getLoc(), PAI, Builder.getDefaultAtomicity());
     Builder.setInsertionPoint(TAI->getErrorBB()->begin());
     // Release the non-consumed parameters.
     for (auto Arg : ToBeReleasedArgs) {
       Builder.emitDestroyValueOperation(PAI->getLoc(), Arg);
     }
-    Builder.createStrongRelease(AI.getLoc(), PAI, Atomicity::Atomic);
+    Builder.createStrongRelease(AI.getLoc(), PAI, Builder.getDefaultAtomicity());
     Builder.setInsertionPoint(AI.getInstruction());
   } else {
     // Release the non-consumed parameters.
     for (auto Arg : ToBeReleasedArgs) {
       Builder.emitDestroyValueOperation(PAI->getLoc(), Arg);
     }
-    Builder.createStrongRelease(AI.getLoc(), PAI, Atomicity::Atomic);
+    Builder.createStrongRelease(AI.getLoc(), PAI, Builder.getDefaultAtomicity());
   }
 
   SilCombiner->replaceInstUsesWith(*AI.getInstruction(), NAI.getInstruction());
@@ -519,7 +519,7 @@
           Builder.createDestroyAddr(FAS.getLoc(), Arg);
           break;
         case ParameterConvention::Direct_Owned:
-          Builder.createReleaseValue(FAS.getLoc(), Arg, Atomicity::Atomic);
+          Builder.createReleaseValue(FAS.getLoc(), Arg, Builder.getDefaultAtomicity());
           break;
         case ParameterConvention::Indirect_In_Guaranteed:
         case ParameterConvention::Indirect_Inout:
@@ -961,7 +961,7 @@
   // In we find arguments that are not the 'self' argument and if
   // they are of the Self type then we abort the optimization.
   for (auto Arg : AI.getArgumentsWithoutSelf()) {
-    if (Arg->getType().getSwiftType().getLValueOrInOutObjectType() ==
+    if (Arg->getType().getSwiftRValueType() ==
         AI.getArguments().back()->getType().getSwiftRValueType())
       return nullptr;
   }
@@ -1044,7 +1044,7 @@
 
   // Emit a retain for the @owned return.
   SILBuilderWithScope Builder(Call);
-  Builder.createRetainValue(Call->getLoc(), OnX, Atomicity::Atomic);
+  Builder.createRetainValue(Call->getLoc(), OnX, Builder.getDefaultAtomicity());
 
   // Emit a release for the @owned parameter, or none for a @guaranteed
   // parameter.
@@ -1056,7 +1056,7 @@
          ParamInfo == ParameterConvention::Direct_Guaranteed);
 
   if (ParamInfo == ParameterConvention::Direct_Owned)
-    Builder.createReleaseValue(Call->getLoc(), OnX, Atomicity::Atomic);
+    Builder.createReleaseValue(Call->getLoc(), OnX, Builder.getDefaultAtomicity());
 }
 
 /// Replace an application of a cast composition f_inverse(f(x)) by x.
@@ -1097,14 +1097,16 @@
     // X might not be strong_retain/release'able. Replace it by a
     // retain/release_value on X instead.
     if (isa<StrongRetainInst>(User)) {
-      SILBuilderWithScope(User).createRetainValue(User->getLoc(), X,
-                                                  Atomicity::Atomic);
+      SILBuilderWithScope Builder(User);
+      Builder.createRetainValue(User->getLoc(), X,
+                                cast<StrongRetainInst>(User)->getAtomicity());
       eraseInstFromFunction(*User);
       continue;
     }
     if (isa<StrongReleaseInst>(User)) {
-      SILBuilderWithScope(User).createReleaseValue(User->getLoc(), X,
-                                                   Atomicity::Atomic);
+      SILBuilderWithScope Builder(User);
+      Builder.createReleaseValue(User->getLoc(), X,
+                                 cast<StrongReleaseInst>(User)->getAtomicity());
       eraseInstFromFunction(*User);
       continue;
     }
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
index c72cbb7..5949dfd 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
@@ -35,7 +35,7 @@
   if (auto *URCI = dyn_cast<UncheckedRefCastInst>(RRPI->getOperand())) {
     // (ref_to_raw_pointer (unchecked_ref_cast x))
     //    -> (ref_to_raw_pointer x)
-    if (URCI->getOperand()->getType().getSwiftType()
+    if (URCI->getOperand()->getType().getSwiftRValueType()
         ->isAnyClassReferenceType()) {
       RRPI->setOperand(URCI->getOperand());
       return URCI->use_empty() ? eraseInstFromFunction(*URCI) : nullptr;
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
index bb59509..b8b7dfe 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
@@ -86,7 +86,7 @@
     // is going away so we need to release the stored value now.
     Builder.setInsertionPoint(SingleStore);
     Builder.createReleaseValue(AEBI->getLoc(), SingleStore->getSrc(),
-                               Atomicity::Atomic);
+                               SingleRelease->getAtomicity());
 
     // Erase the instruction that stores into the box and the release that
     // releases the box, and finally, release the box.
@@ -494,19 +494,19 @@
     // reduced to a retain_value on the payload.
     if (EI->hasOperand()) {
       return Builder.createReleaseValue(RVI->getLoc(), EI->getOperand(),
-                                        Atomicity::Atomic);
+                                        RVI->getAtomicity());
     }
   }
 
   // ReleaseValueInst of an unowned type is an unowned_release.
   if (OperandTy.is<UnownedStorageType>())
     return Builder.createUnownedRelease(RVI->getLoc(), Operand,
-                                        Atomicity::Atomic);
+                                        RVI->getAtomicity());
 
   // ReleaseValueInst of a reference type is a strong_release.
   if (OperandTy.isReferenceCounted(RVI->getModule()))
     return Builder.createStrongRelease(RVI->getLoc(), Operand,
-                                       Atomicity::Atomic);
+                                       RVI->getAtomicity());
 
   // ReleaseValueInst of a trivial type is a no-op.
   if (OperandTy.isTrivial(RVI->getModule()))
@@ -532,19 +532,19 @@
     // reduced to a retain_value on the payload.
     if (EI->hasOperand()) {
       return Builder.createRetainValue(RVI->getLoc(), EI->getOperand(),
-                                       Atomicity::Atomic);
+                                       RVI->getAtomicity());
     }
   }
 
   // RetainValueInst of an unowned type is an unowned_retain.
   if (OperandTy.is<UnownedStorageType>())
     return Builder.createUnownedRetain(RVI->getLoc(), Operand,
-                                       Atomicity::Atomic);
+                                       RVI->getAtomicity());
 
   // RetainValueInst of a reference type is a strong_release.
   if (OperandTy.isReferenceCounted(RVI->getModule())) {
     return Builder.createStrongRetain(RVI->getLoc(), Operand,
-                                      Atomicity::Atomic);
+                                      RVI->getAtomicity());
   }
 
   // RetainValueInst of a trivial type is a no-op + use propagation.
diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
index 572b588..92c338d 100644
--- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
@@ -558,9 +558,9 @@
     // can simply ask SSAUpdater for the reaching store.
     SILValue RelVal = SSAUp.GetValueAtEndOfBlock(RelPoint->getParent());
     if (StVal->getType().isReferenceCounted(RelPoint->getModule()))
-      B.createStrongRelease(Loc, RelVal, Atomicity::Atomic);
+      B.createStrongRelease(Loc, RelVal, B.getDefaultAtomicity());
     else
-      B.createReleaseValue(Loc, RelVal, Atomicity::Atomic);
+      B.createReleaseValue(Loc, RelVal, B.getDefaultAtomicity());
   }
 }
 
diff --git a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
index 05586c1..ce6a1d1 100644
--- a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
+++ b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
@@ -760,19 +760,19 @@
     Builder.setInsertionPoint(&*std::next(SILBasicBlock::iterator(Call)));
     Builder.createReleaseValue(RegularLocation(SourceLoc()),
                                F->getArguments()[AD.Index],
-                               Atomicity::Atomic);
+                               Builder.getDefaultAtomicity());
   } else {
     SILBasicBlock *NormalBB = dyn_cast<TryApplyInst>(Call)->getNormalBB();
     Builder.setInsertionPoint(&*NormalBB->begin());
     Builder.createReleaseValue(RegularLocation(SourceLoc()),
                                F->getArguments()[AD.Index],
-                               Atomicity::Atomic);
+                               Builder.getDefaultAtomicity());
 
     SILBasicBlock *ErrorBB = dyn_cast<TryApplyInst>(Call)->getErrorBB();
     Builder.setInsertionPoint(&*ErrorBB->begin());
     Builder.createReleaseValue(RegularLocation(SourceLoc()),
                                F->getArguments()[AD.Index],
-                               Atomicity::Atomic);
+                               Builder.getDefaultAtomicity());
   }
 }
 
@@ -790,12 +790,12 @@
   if (isa<ApplyInst>(Call)) {
     Builder.setInsertionPoint(&*std::next(SILBasicBlock::iterator(Call)));
     Builder.createRetainValue(RegularLocation(SourceLoc()), Call,
-                              Atomicity::Atomic);
+                              Builder.getDefaultAtomicity());
   } else {
     SILBasicBlock *NormalBB = dyn_cast<TryApplyInst>(Call)->getNormalBB();
     Builder.setInsertionPoint(&*NormalBB->begin());
     Builder.createRetainValue(RegularLocation(SourceLoc()),
-                              NormalBB->getArgument(0), Atomicity::Atomic);
+                              NormalBB->getArgument(0), Builder.getDefaultAtomicity());
   }
 }
 
diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
index dbd8b80..0ec3d33 100644
--- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
+++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
@@ -67,6 +67,7 @@
   bool visitUnmanagedRetainValueInst(UnmanagedRetainValueInst *URVI);
   bool visitUnmanagedReleaseValueInst(UnmanagedReleaseValueInst *URVI);
   bool visitUnmanagedAutoreleaseValueInst(UnmanagedAutoreleaseValueInst *UAVI);
+  bool visitCheckedCastBranchInst(CheckedCastBranchInst *CBI);
 };
 
 } // end anonymous namespace
@@ -144,7 +145,7 @@
 bool OwnershipModelEliminatorVisitor::visitCopyUnownedValueInst(
     CopyUnownedValueInst *CVI) {
   B.createStrongRetainUnowned(CVI->getLoc(), CVI->getOperand(),
-                              Atomicity::Atomic);
+                              B.getDefaultAtomicity());
   // Users of copy_value_unowned expect an owned value. So we need to convert
   // our unowned value to a ref.
   auto *UTRI =
@@ -178,7 +179,7 @@
   // Now that we have set the unqualified ownership flag, destroy value
   // operation will delegate to the appropriate strong_release, etc.
   B.createAutoreleaseValue(UAVI->getLoc(), UAVI->getOperand(),
-                           Atomicity::Atomic);
+                           UAVI->getAtomicity());
   UAVI->eraseFromParent();
   return true;
 }
@@ -195,6 +196,24 @@
   return true;
 }
 
+bool OwnershipModelEliminatorVisitor::visitCheckedCastBranchInst(
+    CheckedCastBranchInst *CBI) {
+  // In ownership qualified SIL, checked_cast_br must pass its argument to the
+  // fail case so we can clean it up. In non-ownership qualified SIL, we expect
+  // no argument from the checked_cast_br in the default case. The way that we
+  // handle this transformation is that:
+  //
+  // 1. We replace all uses of the argument to the false block with a use of the
+  // checked cast branch's operand.
+  // 2. We delete the argument from the false block.
+  SILBasicBlock *FailureBlock = CBI->getFailureBB();
+  if (FailureBlock->getNumArguments() == 0)
+    return false;
+  FailureBlock->getArgument(0)->replaceAllUsesWith(CBI->getOperand());
+  FailureBlock->eraseArgument(0);
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 //                           Top Level Entry Point
 //===----------------------------------------------------------------------===//
@@ -224,9 +243,8 @@
     }
 
     if (MadeChange) {
-      // If we made any changes, we just changed instructions, so invalidate
-      // that analysis.
-      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
+      invalidateAnalysis(
+          SILAnalysis::InvalidationKind::BranchesAndInstructions);
     }
   }
 
diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
index ebd9d0c..fb14a28 100644
--- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
+++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
@@ -547,6 +547,10 @@
       (ModuleName == STDLIB_NAME || ModuleName == SWIFT_ONONE_SUPPORT))
     return false;
 
+  // Do not inline into thunks.
+  if (AI.getFunction()->isThunk())
+    return false;
+
   // Always inline generic functions which are marked as
   // AlwaysInline or transparent.
   if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent())
diff --git a/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp b/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp
index ece72e4..797002c 100644
--- a/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp
+++ b/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp
@@ -161,7 +161,8 @@
 
   // Do what a release would do before calling the deallocator: set the object
   // in deallocating state, which means set the RC_DEALLOCATING_FLAG flag.
-  B.createSetDeallocating(ReleaseInst->getLoc(), object, Atomicity::Atomic);
+  B.createSetDeallocating(ReleaseInst->getLoc(), object,
+                          cast<RefCountingInst>(ReleaseInst)->getAtomicity());
 
   // Create the call to the destructor with the allocated object as self
   // argument.
diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp
index d1c8b95..41f663d 100644
--- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp
+++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp
@@ -73,17 +73,19 @@
 
   ++NumRefCountOpsSimplified;
 
+  auto *RCI = cast<RefCountingInst>(I);
+
   // If we have a retain value...
   if (isa<RetainValueInst>(I)) {
     // And our payload is refcounted, insert a strong_retain onto the
     // payload.
     if (UEDITy.isReferenceCounted(Mod)) {
-      Builder.createStrongRetain(I->getLoc(), UEDI, Atomicity::Atomic);
+      Builder.createStrongRetain(I->getLoc(), UEDI, RCI->getAtomicity());
       return;
     }
 
     // Otherwise, insert a retain_value on the payload.
-    Builder.createRetainValue(I->getLoc(), UEDI, Atomicity::Atomic);
+    Builder.createRetainValue(I->getLoc(), UEDI, RCI->getAtomicity());
     return;
   }
 
@@ -94,13 +96,13 @@
 
   // If our payload has reference semantics, insert the strong release.
   if (UEDITy.isReferenceCounted(Mod)) {
-    Builder.createStrongRelease(I->getLoc(), UEDI, Atomicity::Atomic);
+    Builder.createStrongRelease(I->getLoc(), UEDI, RCI->getAtomicity());
     return;
   }
 
   // Otherwise if our payload is non-trivial but lacking reference semantics,
   // insert the release_value.
-  Builder.createReleaseValue(I->getLoc(), UEDI, Atomicity::Atomic);
+  Builder.createReleaseValue(I->getLoc(), UEDI, RCI->getAtomicity());
 }
 
 //===----------------------------------------------------------------------===//
@@ -1545,9 +1547,9 @@
     //
     // TODO: Which debug loc should we use here? Using one of the locs from the
     // delete list seems reasonable for now...
-    SILBuilder(getBB()->begin()).createRetainValue(DeleteList[0]->getLoc(),
-                                                   EnumValue,
-                                                   Atomicity::Atomic);
+    SILBuilder Builder(getBB()->begin());
+    Builder.createRetainValue(DeleteList[0]->getLoc(), EnumValue,
+                              cast<RefCountingInst>(DeleteList[0])->getAtomicity());
     for (auto *I : DeleteList)
       I->eraseFromParent();
     ++NumSunk;
diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
index 57e7554..28d247e 100644
--- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
+++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
@@ -1875,23 +1875,6 @@
   if (!TargetFnTy || !TargetFnTy->hasErrorResult())
     return false;
 
-  // Check if the converted function type has the same number of arguments.
-  // Currently this is always the case, but who knows what convert_function can
-  // do in the future?
-  unsigned numParams = OrigFnTy->getParameters().size();
-  if (TargetFnTy->getParameters().size() != numParams)
-    return false;
-
-  // Check that the argument types are matching.
-  SILModuleConventions silConv(TAI->getModule());
-  for (unsigned Idx = 0; Idx < numParams; Idx++) {
-    if (!canCastValueToABICompatibleType(
-            TAI->getModule(),
-            silConv.getSILType(OrigFnTy->getParameters()[Idx]),
-            silConv.getSILType(TargetFnTy->getParameters()[Idx])))
-      return false;
-  }
-
   // Look through the conversions and find the real callee.
   Callee = getActualCallee(CFI->getConverted());
   CalleeType = Callee->getType();
@@ -1936,12 +1919,6 @@
     auto ResultTy = calleeConv.getSILResultType();
     auto OrigResultTy = TAI->getNormalBB()->getArgument(0)->getType();
 
-    // Bail if the cast between the actual and expected return types cannot
-    // be handled.
-    if (!canCastValueToABICompatibleType(TAI->getModule(),
-                                         ResultTy, OrigResultTy))
-      return false;
-
     SILBuilderWithScope Builder(TAI);
 
     auto TargetFnTy = CalleeFnTy;
@@ -1959,28 +1936,14 @@
     }
     SILFunctionConventions origConv(OrigFnTy, TAI->getModule());
 
-    unsigned numArgs = TAI->getNumArguments();
-
-    // First check if it is possible to convert all arguments.
-    // Currently we believe that castValueToABICompatibleType can handle all
-    // cases, so this check should never fail. We just do it to be absolutely
-    // sure that we don't crash.
-    for (unsigned i = 0; i < numArgs; ++i) {
-      if (!canCastValueToABICompatibleType(TAI->getModule(),
-                                           origConv.getSILArgumentType(i),
-                                           targetConv.getSILArgumentType(i))) {
-        return false;
-      }
-    }
-
     SmallVector<SILValue, 8> Args;
+    unsigned numArgs = TAI->getNumArguments();
     for (unsigned i = 0; i < numArgs; ++i) {
       auto Arg = TAI->getArgument(i);
       // Cast argument if required.
       Arg = castValueToABICompatibleType(&Builder, TAI->getLoc(), Arg,
                                          origConv.getSILArgumentType(i),
-                                         targetConv.getSILArgumentType(i))
-                .getValue();
+                                         targetConv.getSILArgumentType(i));
       Args.push_back(Arg);
     }
 
@@ -1998,8 +1961,7 @@
     auto *NormalBB = TAI->getNormalBB();
 
     auto CastedResult = castValueToABICompatibleType(&Builder, Loc, NewAI,
-                                                     ResultTy, OrigResultTy)
-                                                    .getValue();
+                                                     ResultTy, OrigResultTy);
 
     Builder.createBranch(Loc, NormalBB, { CastedResult });
     TAI->eraseFromParent();
diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
index 604969f..cf0eea1 100644
--- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
+++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
@@ -143,9 +143,9 @@
       (next == Continue->end()) ? nullptr : dyn_cast<StrongReleaseInst>(next);
   if (Release && Release->getOperand() == CMI->getOperand()) {
     VirtBuilder.createStrongRelease(Release->getLoc(), CMI->getOperand(),
-                                    Atomicity::Atomic);
+                                    Release->getAtomicity());
     IdenBuilder.createStrongRelease(Release->getLoc(), DownCastedClassInstance,
-                                    Atomicity::Atomic);
+                                    Release->getAtomicity());
     Release->eraseFromParent();
   }
 
diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp
index 4fa1094..318d777 100644
--- a/lib/SILOptimizer/Utils/Devirtualize.cpp
+++ b/lib/SILOptimizer/Utils/Devirtualize.cpp
@@ -546,31 +546,6 @@
     return false;
   }
 
-  // Type of the actual function to be called.
-  CanSILFunctionType GenCalleeType = F->getLoweredFunctionType();
-
-  // Type of the actual function to be called with substitutions applied.
-  CanSILFunctionType SubstCalleeType = GenCalleeType;
-
-  // For polymorphic functions, bail if the number of substitutions is
-  // not the same as the number of expected generic parameters.
-  if (GenCalleeType->isPolymorphic()) {
-    // First, find proper list of substitutions for the concrete
-    // method to be called.
-    SmallVector<Substitution, 4> Subs;
-    getSubstitutionsForCallee(Mod, GenCalleeType,
-                              ClassOrMetatypeType.getSwiftRValueType(),
-                              AI, Subs);
-    SubstCalleeType = GenCalleeType->substGenericArgs(Mod, Subs);
-  }
-
-  // Check if the optimizer knows how to cast the return type.
-  SILType ReturnType =
-      SILFunctionConventions(SubstCalleeType, Mod).getSILResultType();
-
-  if (!canCastValueToABICompatibleType(Mod, ReturnType, AI.getType()))
-      return false;
-
   return true;
 }
 
@@ -612,8 +587,7 @@
   for (auto ResultTy : substConv.getIndirectSILResultTypes()) {
     NewArgs.push_back(
         castValueToABICompatibleType(&B, AI.getLoc(), *IndirectResultArgIter,
-                                     IndirectResultArgIter->getType(), ResultTy)
-            .getValue());
+                                     IndirectResultArgIter->getType(), ResultTy));
     ++IndirectResultArgIter;
   }
 
@@ -623,8 +597,7 @@
     auto paramType = substConv.getSILType(param);
     NewArgs.push_back(
         castValueToABICompatibleType(&B, AI.getLoc(), *ParamArgIter,
-                                     ParamArgIter->getType(), paramType)
-            .getValue());
+                                     ParamArgIter->getType(), paramType));
     ++ParamArgIter;
   }
 
@@ -634,7 +607,7 @@
   NewArgs.push_back(castValueToABICompatibleType(&B, AI.getLoc(),
                                                  ClassOrMetatype,
                                                  ClassOrMetatypeType,
-                                                 SelfParamTy).getValue());
+                                                 SelfParamTy));
 
   SILType ResultTy = substConv.getSILResultType();
 
@@ -707,7 +680,7 @@
 
   // Check if any casting is required for the return value.
   ResultValue = castValueToABICompatibleType(&B, NewAI.getLoc(), ResultValue,
-                                             ResultTy, AI.getType()).getValue();
+                                             ResultTy, AI.getType());
 
   DEBUG(llvm::dbgs() << "        SUCCESS: " << F->getName() << "\n");
   NumClassDevirt++;
@@ -871,75 +844,6 @@
                                 origSubs, isDefaultWitness, NewSubs);
 }
 
-/// Check if an upcast is legal.
-/// The logic in this function is heavily based on the checks in
-/// the SILVerifier.
-bool swift::isLegalUpcast(SILType FromTy, SILType ToTy) {
-  if (ToTy.is<MetatypeType>()) {
-    CanType InstTy(ToTy.castTo<MetatypeType>()->getInstanceType());
-    if (!FromTy.is<MetatypeType>())
-      return false;
-    CanType OpInstTy(FromTy.castTo<MetatypeType>()->getInstanceType());
-    auto InstClass = InstTy->getClassOrBoundGenericClass();
-    if (!InstClass)
-      return false;
-
-    bool CanBeUpcasted =
-        InstClass->usesObjCGenericsModel()
-            ? InstClass->getDeclaredTypeInContext()->isBindableToSuperclassOf(
-                  OpInstTy, nullptr)
-            : InstTy->isExactSuperclassOf(OpInstTy, nullptr);
-
-    return CanBeUpcasted;
-  }
-
-  // Upcast from Optional<B> to Optional<A> is legal as long as B is a
-  // subclass of A.
-  if (ToTy.getSwiftRValueType().getAnyOptionalObjectType() &&
-      FromTy.getSwiftRValueType().getAnyOptionalObjectType()) {
-    ToTy = SILType::getPrimitiveObjectType(
-        ToTy.getSwiftRValueType().getAnyOptionalObjectType());
-    FromTy = SILType::getPrimitiveObjectType(
-        FromTy.getSwiftRValueType().getAnyOptionalObjectType());
-  }
-
-  auto ToClass = ToTy.getClassOrBoundGenericClass();
-  if (!ToClass)
-    return false;
-  bool CanBeUpcasted =
-      ToClass->usesObjCGenericsModel()
-          ? ToClass->getDeclaredTypeInContext()->isBindableToSuperclassOf(
-                FromTy.getSwiftRValueType(), nullptr)
-          : ToTy.isExactSuperclassOf(FromTy);
-
-  return CanBeUpcasted;
-}
-
-/// Check if we can pass/convert all arguments of the original apply
-/// as required by the found devirtualized method.
-/// FIXME: This method was introduced as a workaround. We need to
-/// revisit it and check if it is still needed.
-static bool
-canPassOrConvertAllArguments(ApplySite AI,
-                             CanSILFunctionType SubstCalleeCanType) {
-  SILFunctionConventions substConv(SubstCalleeCanType, AI.getModule());
-  unsigned substArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg();
-  for (auto arg : AI.getArguments()) {
-    // Check if we can cast the provided argument into the required
-    // parameter type.
-    auto FromTy = arg->getType();
-    auto ToTy = substConv.getSILArgumentType(substArgIdx++);
-    // If types are the same, no conversion will be required.
-    if (FromTy == ToTy)
-      continue;
-    // Otherwise, it should be possible to upcast the arguments.
-    if (!isLegalUpcast(FromTy, ToTy))
-      return false;
-  }
-  assert(substArgIdx == substConv.getNumSILArguments());
-  return true;
-}
-
 /// Generate a new apply of a function_ref to replace an apply of a
 /// witness_method when we've determined the actual function we'll end
 /// up calling.
@@ -963,11 +867,6 @@
   auto CalleeCanType = F->getLoweredFunctionType();
   auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, NewSubs);
 
-  // Bail if some of the arguments cannot be converted into
-  // types required by the found devirtualized method.
-  if (!canPassOrConvertAllArguments(AI, SubstCalleeCanType))
-    return ApplySite();
-
   // Collect arguments from the apply instruction.
   auto Arguments = SmallVector<SILValue, 4>();
 
@@ -979,7 +878,8 @@
   for (auto arg : AI.getArguments()) {
     auto paramType = substConv.getSILArgumentType(substArgIdx++);
     if (arg->getType() != paramType)
-      arg = B.createUpcast(AI.getLoc(), arg, paramType);
+      arg = castValueToABICompatibleType(&B, AI.getLoc(), arg,
+                                         arg->getType(), paramType);
     Arguments.push_back(arg);
   }
   assert(substArgIdx == substConv.getNumSILArguments());
@@ -1030,26 +930,6 @@
       return false;
   }
 
-  // Collect all the required substitutions.
-  //
-  // The complete set of substitutions may be different, e.g. because the found
-  // witness thunk F may have been created by a specialization pass and have
-  // additional generic parameters.
-  SmallVector<Substitution, 4> NewSubs;
-
-  getWitnessMethodSubstitutions(AI, F, WMI->getConformance(), NewSubs);
-
-  // Figure out the exact bound type of the function to be called by
-  // applying all substitutions.
-  auto &Module = AI.getModule();
-  auto CalleeCanType = F->getLoweredFunctionType();
-  auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, NewSubs);
-
-  // Bail if some of the arguments cannot be converted into
-  // types required by the found devirtualized method.
-  if (!canPassOrConvertAllArguments(AI, SubstCalleeCanType))
-    return false;
-
   return true;
 }
 
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index 7100496..2adfd48 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -52,7 +52,8 @@
 // Initialize SpecializedType iff the specialization is allowed.
 ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *OrigF,
                                      SubstitutionList ParamSubs) {
-  if (!OrigF->shouldOptimize()) {
+  if (!OrigF->shouldOptimize() ||
+      OrigF->hasSemanticsAttr("optimize.sil.specialize.generic.never")) {
     DEBUG(llvm::dbgs() << "    Cannot specialize function " << OrigF->getName()
                        << " marked to be excluded from optimizations.\n");
     return;
@@ -97,9 +98,8 @@
   }
 
   SILModule &M = OrigF->getModule();
-  SubstitutedType = SILType::substFuncType(M, InterfaceSubs,
-                                           OrigF->getLoweredFunctionType(),
-                                           /*dropGenerics = */ true);
+  SubstitutedType = OrigF->getLoweredFunctionType()->substGenericArgs(
+    M, InterfaceSubs);
 
   NumFormalIndirectResults = SubstitutedType->getNumIndirectFormalResults();
   Conversions.resize(NumFormalIndirectResults
@@ -213,9 +213,7 @@
   auto OrigFnTy = OrigF->getLoweredFunctionType();
 
   // First substitute concrete types into the existing function type.
-  auto FnTy = OrigFnTy->substGenericArgs(
-      M, QuerySubstitutionMap{SubstMap},
-        LookUpConformanceInSubstitutionMap(SubstMap));
+  auto FnTy = OrigFnTy->substGenericArgs(M, SubstMap);
 
   if ((SpecializedGenericSig &&
        SpecializedGenericSig->areAllParamsConcrete()) ||
@@ -294,7 +292,8 @@
   // First, add the old generic signature.
   Builder.addGenericSignature(OrigGenSig);
 
-  auto Source = RequirementSource::forAbstract(Builder);
+  auto Source =
+    GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
   // For each substitution with a concrete type as a replacement,
   // add a new concrete type equality requirement.
   for (auto &Req : Requirements) {
diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp
index 8fe8ec5..750ea7f 100644
--- a/lib/SILOptimizer/Utils/Local.cpp
+++ b/lib/SILOptimizer/Utils/Local.cpp
@@ -44,10 +44,10 @@
   // If Ptr is refcounted itself, create the strong_retain and
   // return.
   if (Ptr->getType().isReferenceCounted(B.getModule()))
-    return B.createStrongRetain(Loc, Ptr, Atomicity::Atomic);
+    return B.createStrongRetain(Loc, Ptr, B.getDefaultAtomicity());
 
   // Otherwise, create the retain_value.
-  return B.createRetainValue(Loc, Ptr, Atomicity::Atomic);
+  return B.createRetainValue(Loc, Ptr, B.getDefaultAtomicity());
 }
 
 /// Creates a decrement on \p Ptr before insertion point \p InsertPt that
@@ -61,10 +61,10 @@
 
   // If Ptr has reference semantics itself, create a strong_release.
   if (Ptr->getType().isReferenceCounted(B.getModule()))
-    return B.createStrongRelease(Loc, Ptr, Atomicity::Atomic);
+    return B.createStrongRelease(Loc, Ptr, B.getDefaultAtomicity());
 
   // Otherwise create a release value.
-  return B.createReleaseValue(Loc, Ptr, Atomicity::Atomic);
+  return B.createReleaseValue(Loc, Ptr, B.getDefaultAtomicity());
 }
 
 /// \brief Perform a fast local check to see if the instruction is dead.
@@ -475,80 +475,63 @@
 ///
 /// NOTE: The implementation of this function is very closely related to the
 /// rules checked by SILVerifier::requireABICompatibleFunctionTypes.
-Optional<SILValue> swift::castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
+SILValue swift::castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
                                              SILValue Value,
-                                             SILType SrcTy, SILType DestTy,
-                                             bool CheckOnly) {
+                                             SILType SrcTy, SILType DestTy) {
 
   // No cast is required if types are the same.
   if (SrcTy == DestTy)
     return Value;
 
-  SILValue CastedValue;
+  assert(SrcTy.isAddress() == DestTy.isAddress() &&
+         "Addresses aren't compatible with values");
 
   if (SrcTy.isAddress() && DestTy.isAddress()) {
     // Cast between two addresses and that's it.
-    if (CheckOnly)
-      return Value;
-    CastedValue = B->createUncheckedAddrCast(Loc, Value, DestTy);
-    return CastedValue;
+    return B->createUncheckedAddrCast(Loc, Value, DestTy);
   }
 
-  if (SrcTy.isAddress() != DestTy.isAddress()) {
-    // Addresses aren't compatible with values.
-    if (CheckOnly)
-      return None;
-    llvm_unreachable("Addresses aren't compatible with values");
-    return SILValue();
-  }
-
-  auto &M = B->getModule();
-
-  // Check if src and dest types are optional.
-  auto OptionalSrcTy = SrcTy.getSwiftRValueType()
-                            .getAnyOptionalObjectType();
-  auto OptionalDestTy = DestTy.getSwiftRValueType()
-                              .getAnyOptionalObjectType();
-
   // If both types are classes and dest is the superclass of src,
   // simply perform an upcast.
-  if (SrcTy.getSwiftRValueType()->mayHaveSuperclass() &&
-      DestTy.getSwiftRValueType()->mayHaveSuperclass() &&
-      DestTy.isExactSuperclassOf(SrcTy)) {
-    if (CheckOnly)
-      return Value;
-    CastedValue = B->createUpcast(Loc, Value, DestTy);
-    return CastedValue;
+  if (DestTy.isExactSuperclassOf(SrcTy)) {
+    return B->createUpcast(Loc, Value, DestTy);
   }
 
-  SILType OptionalSrcLoweredTy;
-  SILType OptionalDestLoweredTy;
+  if (SrcTy.isHeapObjectReferenceType() &&
+      DestTy.isHeapObjectReferenceType()) {
+    return B->createUncheckedRefCast(Loc, Value, DestTy);
+  }
 
-  if (OptionalSrcTy)
-    OptionalSrcLoweredTy = M.Types.getLoweredType(OptionalSrcTy);
+  if (auto mt1 = dyn_cast<AnyMetatypeType>(SrcTy.getSwiftRValueType())) {
+    if (auto mt2 = dyn_cast<AnyMetatypeType>(DestTy.getSwiftRValueType())) {
+      if (mt1->getRepresentation() == mt2->getRepresentation()) {
+        // If B.Type needs to be casted to A.Type and
+        // A is a superclass of B, then it can be done by means
+        // of a simple upcast.
+        if (mt2.getInstanceType()->isExactSuperclassOf(
+              mt1.getInstanceType(), nullptr)) {
+          return B->createUpcast(Loc, Value, DestTy);
+        }
+ 
+        // Cast between two metatypes and that's it.
+        return B->createUncheckedBitCast(Loc, Value, DestTy);
+      }
+    }
+  }
 
-  if (OptionalDestTy)
-    OptionalDestLoweredTy = M.Types.getLoweredType(OptionalDestTy);
+  // Check if src and dest types are optional.
+  auto OptionalSrcTy = SrcTy.getAnyOptionalObjectType();
+  auto OptionalDestTy = DestTy.getAnyOptionalObjectType();
 
   // Both types are optional.
   if (OptionalDestTy && OptionalSrcTy) {
     // If both wrapped types are classes and dest is the superclass of src,
     // simply perform an upcast.
-    if (OptionalDestTy->mayHaveSuperclass() &&
-        OptionalSrcTy->mayHaveSuperclass() &&
-        OptionalDestLoweredTy.isExactSuperclassOf(OptionalSrcLoweredTy)) {
+    if (OptionalDestTy.isExactSuperclassOf(OptionalSrcTy)) {
       // Insert upcast.
-      if (CheckOnly)
-        return Value;
-      CastedValue = B->createUpcast(Loc, Value, DestTy);
-      return CastedValue;
+      return B->createUpcast(Loc, Value, DestTy);
     }
 
-    if (CheckOnly)
-      return castValueToABICompatibleType(B, Loc, Value,
-          OptionalSrcLoweredTy,
-          OptionalDestLoweredTy, CheckOnly);
-
     // Unwrap the original optional value.
     auto *SomeDecl = B->getASTContext().getOptionalSomeDecl();
     auto *NoneBB = B->getFunction().createBasicBlock();
@@ -570,10 +553,10 @@
     // Cast the unwrapped value.
     auto CastedUnwrappedValue =
         castValueToABICompatibleType(B, Loc, UnwrappedValue,
-                                     OptionalSrcLoweredTy,
-                                     OptionalDestLoweredTy).getValue();
+                                     OptionalSrcTy,
+                                     OptionalDestTy);
     // Wrap into optional.
-    CastedValue =  B->createOptionalSome(Loc, CastedUnwrappedValue, DestTy);
+    auto CastedValue =  B->createOptionalSome(Loc, CastedUnwrappedValue, DestTy);
     B->createBranch(Loc, ContBB, {CastedValue});
 
     // Handle the None case.
@@ -582,19 +565,15 @@
     B->createBranch(Loc, ContBB, {CastedValue});
     B->setInsertionPoint(ContBB->begin());
 
-    CastedValue = ContBB->getArgument(0);
-    return CastedValue;
+    return ContBB->getArgument(0);
   }
 
   // Src is not optional, but dest is optional.
   if (!OptionalSrcTy && OptionalDestTy) {
-    auto OptionalSrcCanTy =
-      OptionalType::get(SrcTy.getSwiftRValueType())->getCanonicalType();
-    auto LoweredOptionalSrcType = M.Types.getLoweredType(OptionalSrcCanTy);
-    if (CheckOnly)
-      return castValueToABICompatibleType(B, Loc, Value,
-                                          LoweredOptionalSrcType, DestTy,
-                                          CheckOnly);
+    auto OptionalSrcCanTy = OptionalType::get(SrcTy.getSwiftRValueType())
+      ->getCanonicalType();
+    auto LoweredOptionalSrcType = SILType::getPrimitiveObjectType(
+      OptionalSrcCanTy);
 
     // Wrap the source value into an optional first.
     SILValue WrappedValue = B->createOptionalSome(Loc, Value,
@@ -605,127 +584,33 @@
                                         DestTy);
   }
 
-  // Both types are not optional.
-  if (SrcTy.getSwiftRValueType()->mayHaveSuperclass() &&
-      DestTy.getSwiftRValueType()->mayHaveSuperclass()) {
-    if (CheckOnly)
-      return Value;
-
-    if (DestTy.isExactSuperclassOf(SrcTy)) {
-      // Insert upcast.
-      CastedValue = B->createUpcast(Loc, Value, DestTy);
-      return CastedValue;
-    }
-
-    // Cast the reference.
-    CastedValue = B->createUncheckedBitCast(Loc, Value, DestTy);
-    return CastedValue;
-  }
-
-  // If B.Type needs to be casted to A.Type and
-  // A is a superclass of B, then it can be done by means
-  // of a simple upcast.
-  if (isa<AnyMetatypeType>(SrcTy.getSwiftRValueType()) &&
-      isa<AnyMetatypeType>(DestTy.getSwiftRValueType()) &&
-      SrcTy.isClassOrClassMetatype() && DestTy.isClassOrClassMetatype() &&
-      DestTy.getMetatypeInstanceType(M).isExactSuperclassOf(
-          SrcTy.getMetatypeInstanceType(M))) {
-    if (CheckOnly)
-      return Value;
-    CastedValue = B->createUpcast(Loc, Value, DestTy);
-    return CastedValue;
-  }
-
-  if (auto mt1 = dyn_cast<AnyMetatypeType>(SrcTy.getSwiftRValueType())) {
-    if (auto mt2 = dyn_cast<AnyMetatypeType>(DestTy.getSwiftRValueType())) {
-      if (mt1->getRepresentation() == mt2->getRepresentation()) {
-        // Cast between two metatypes and that's it.
-        if (CheckOnly)
-          return Value;
-        CastedValue = B->createUncheckedBitCast(Loc, Value, DestTy);
-        return CastedValue;
-      }
-    }
-  }
-
-  if (SrcTy.isAddress() && DestTy.isAddress()) {
-    if (CheckOnly)
-      return Value;
-    CastedValue = B->createUncheckedAddrCast(Loc, Value, DestTy);
-    return CastedValue;
-  }
-
-  if (SrcTy.isHeapObjectReferenceType() && DestTy.isHeapObjectReferenceType()) {
-    if (CheckOnly)
-      return Value;
-    CastedValue = B->createUncheckedRefCast(Loc, Value, DestTy);
-    return CastedValue;
-  }
-
   // Handle tuple types.
   // Extract elements, cast each of them, create a new tuple.
-  if (auto tup = SrcTy.getAs<TupleType>()) {
-    SmallVector<CanType, 1> aElements, bElements;
-    auto atypes = tup.getElementTypes();
-    aElements.append(atypes.begin(), atypes.end());
-    auto btypes = DestTy.getAs<TupleType>().getElementTypes();
-    bElements.append(btypes.begin(), btypes.end());
-
-    if (CheckOnly && aElements.size() != bElements.size())
-      return None;
-
-    assert (aElements.size() == bElements.size() &&
-          "Tuple types should have the same number of elements");
-
+  if (auto SrcTupleTy = SrcTy.getAs<TupleType>()) {
     SmallVector<SILValue, 8> ExpectedTuple;
-    for (unsigned i : indices(aElements)) {
-      auto aa = M.Types.getLoweredType(aElements[i]),
-           bb = M.Types.getLoweredType(bElements[i]);
-
-      if (CheckOnly) {
-        if (!castValueToABICompatibleType(B, Loc, Value, aa, bb, CheckOnly).hasValue())
-          return None;
-        continue;
-      }
-
+    for (unsigned i = 0, e = SrcTupleTy->getNumElements(); i < e; i++) {
       SILValue Element = B->createTupleExtract(Loc, Value, i);
       // Cast the value if necessary.
-      Element = castValueToABICompatibleType(B, Loc, Element, aa, bb).getValue();
+      Element = castValueToABICompatibleType(B, Loc, Element,
+                                             SrcTy.getTupleElementType(i),
+                                             DestTy.getTupleElementType(i));
       ExpectedTuple.push_back(Element);
     }
 
-    if (CheckOnly)
-      return Value;
-
-    CastedValue = B->createTuple(Loc, DestTy, ExpectedTuple);
-    return CastedValue;
+    return B->createTuple(Loc, DestTy, ExpectedTuple);
   }
 
   // Function types are interchangeable if they're also ABI-compatible.
   if (SrcTy.getAs<SILFunctionType>()) {
     if (DestTy.getAs<SILFunctionType>()) {
-      if (CheckOnly)
-        return Value;
       // Insert convert_function.
-      CastedValue = B->createConvertFunction(Loc, Value, DestTy);
-      return CastedValue;
+      return B->createConvertFunction(Loc, Value, DestTy);
     }
   }
 
-  if (CheckOnly)
-    return None;
+  llvm::errs() << "Source type: " << SrcTy << "\n";
+  llvm::errs() << "Destination type: " << DestTy << "\n";
   llvm_unreachable("Unknown combination of types for casting");
-  return SILValue();
-}
-
-bool swift::canCastValueToABICompatibleType(SILModule &M,
-                                            SILType SrcTy, SILType DestTy) {
-  SILBuilder B(*M.begin());
-  SILLocation Loc = ArtificialUnreachableLocation();
-  auto Result = castValueToABICompatibleType(&B, Loc, SILValue(),
-                                             SrcTy, DestTy,
-                                             /* CheckOnly */ true);
-  return Result.hasValue();
 }
 
 ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index){
@@ -1070,7 +955,7 @@
   SILBuilderWithScope Builder(PAI);
   SILLocation Loc = PAI->getLoc();
   CanSILFunctionType PAITy =
-      dyn_cast<SILFunctionType>(PAI->getCallee()->getType().getSwiftType());
+      PAI->getCallee()->getType().getAs<SILFunctionType>();
 
   // Emit a destroy value for each captured closure argument.
   ArrayRef<SILParameterInfo> Params = PAITy->getParameters();
@@ -1502,7 +1387,7 @@
          "Parameter should be @owned");
 
   // Emit a retain.
-  Builder.createRetainValue(Loc, SrcOp, Atomicity::Atomic);
+  Builder.createRetainValue(Loc, SrcOp, Builder.getDefaultAtomicity());
 
   Args.push_back(InOutOptionalParam);
   Args.push_back(SrcOp);
@@ -1515,18 +1400,18 @@
   if (auto *UCCAI = dyn_cast<UnconditionalCheckedCastAddrInst>(Inst)) {
     assert(UCCAI->getConsumptionKind() == CastConsumptionKind::TakeAlways);
     if (UCCAI->getConsumptionKind() == CastConsumptionKind::TakeAlways) {
-      Builder.createReleaseValue(Loc, SrcOp, Atomicity::Atomic);
+      Builder.createReleaseValue(Loc, SrcOp, Builder.getDefaultAtomicity());
     }
   }
 
   if (auto *CCABI = dyn_cast<CheckedCastAddrBranchInst>(Inst)) {
     if (CCABI->getConsumptionKind() == CastConsumptionKind::TakeAlways) {
-      Builder.createReleaseValue(Loc, SrcOp, Atomicity::Atomic);
+      Builder.createReleaseValue(Loc, SrcOp, Builder.getDefaultAtomicity());
     } else if (CCABI->getConsumptionKind() ==
                CastConsumptionKind::TakeOnSuccess) {
       // Insert a release in the success BB.
       Builder.setInsertionPoint(SuccessBB->begin());
-      Builder.createReleaseValue(Loc, SrcOp, Atomicity::Atomic);
+      Builder.createReleaseValue(Loc, SrcOp, Builder.getDefaultAtomicity());
     }
   }
 
@@ -1748,17 +1633,17 @@
   }
 
   if (needRetainBeforeCall)
-    Builder.createRetainValue(Loc, Src, Atomicity::Atomic);
+    Builder.createRetainValue(Loc, Src, Builder.getDefaultAtomicity());
 
   // Generate a code to invoke the bridging function.
   auto *NewAI = Builder.createApply(Loc, FnRef, SubstFnTy, ResultTy, Subs, Src,
                                     false);
 
   if (needReleaseAfterCall) {
-    Builder.createReleaseValue(Loc, Src, Atomicity::Atomic);
+    Builder.createReleaseValue(Loc, Src, Builder.getDefaultAtomicity());
   } else if (needReleaseInSucc) {
     SILBuilder SuccBuilder(SuccessBB->begin());
-    SuccBuilder.createReleaseValue(Loc, Src, Atomicity::Atomic);
+    SuccBuilder.createReleaseValue(Loc, Src, SuccBuilder.getDefaultAtomicity());
   }
   SILInstruction *NewI = NewAI;
 
diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp
index 4cea2bd..a01756c 100644
--- a/lib/SILOptimizer/Utils/SILInliner.cpp
+++ b/lib/SILOptimizer/Utils/SILInliner.cpp
@@ -337,6 +337,7 @@
     case ValueKind::DeallocStackInst:
     case ValueKind::DeallocValueBufferInst:
     case ValueKind::DeinitExistentialAddrInst:
+    case ValueKind::DeinitExistentialOpaqueInst:
     case ValueKind::DestroyAddrInst:
     case ValueKind::ProjectValueBufferInst:
     case ValueKind::ProjectBoxInst:
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 401e1f9..7d87dfa 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -7,6 +7,7 @@
   CSApply.cpp
   CSDiag.cpp
   CSGen.cpp
+  CSPropagate.cpp
   CSRanking.cpp
   CSSimplify.cpp
   CSSolver.cpp
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index de33fab..4f27b76 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -3495,11 +3495,13 @@
     Expr *visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) {
       // If we end up here, we should have diagnosed somewhere else
       // already.
-      if (!SuppressDiagnostics) {
-        cs.TC.diagnose(expr->getLoc(), diag::pattern_in_expr,
+      Expr *simplified = simplifyExprType(expr);
+      if (!SuppressDiagnostics
+          && !simplified->getType()->is<UnresolvedType>()) {
+        cs.TC.diagnose(simplified->getLoc(), diag::pattern_in_expr,
                        expr->getSubPattern()->getKind());
       }
-      return expr;
+      return simplified;
     }
     
     Expr *visitBindOptionalExpr(BindOptionalExpr *expr) {
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 9c00226..1730ae3 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -5752,13 +5752,13 @@
     }
   };
 
+  auto dc = env->getOwningDeclContext();
   RequirementsListener genericReqListener;
-  auto result =
-    TC.checkGenericArguments(env->getOwningDeclContext(), argExpr->getLoc(),
-                             AFD->getLoc(), AFD->getInterfaceType(),
-                             env->getGenericSignature(), substitutions, nullptr,
-                             ConformanceCheckFlags::SuppressDependencyTracking,
-                             &genericReqListener);
+  auto result = TC.checkGenericArguments(
+      dc, argExpr->getLoc(), AFD->getLoc(), AFD->getInterfaceType(),
+      env->getGenericSignature(), QueryTypeSubstitutionMap{substitutions},
+      LookUpConformanceInModule{dc->getParentModule()}, nullptr,
+      ConformanceCheckFlags::SuppressDependencyTracking, &genericReqListener);
 
   return !result.second;
 }
@@ -5915,14 +5915,6 @@
   if (auto fn = fnType->getAs<AnyFunctionType>()) {
     using Closeness = CalleeCandidateInfo::ClosenessResultTy;
 
-    auto isGenericType = [](Type type) -> bool {
-      if (type->hasError() || type->hasTypeVariable() ||
-          type->hasUnresolvedType())
-        return false;
-
-      return type->isCanonical() && type->isUnspecializedGeneric();
-    };
-
     calleeInfo.filterList([&](UncurriedCandidate candidate) -> Closeness {
       auto resultType = candidate.getResultType();
       if (!resultType)
@@ -5933,8 +5925,7 @@
       // because there is no easy way to do that, and candidate set is going
       // to be pruned by matching of the argument types later on anyway, so
       // it's better to over report than to be too conservative.
-      if ((isGenericType(resultType) && isGenericType(fn->getResult())) ||
-          resultType->isEqual(fn->getResult()))
+      if (resultType->isEqual(fn->getResult()))
         return {CC_ExactMatch, {}};
 
       return {CC_GeneralMismatch, {}};
@@ -6086,9 +6077,13 @@
 
     if (callExpr->isImplicit() && overloadName == "~=") {
       // This binop was synthesized when typechecking an expression pattern.
-      auto diag = diagnose(lhsExpr->getLoc(),
-                    diag::cannot_match_expr_pattern_with_value,
-                           lhsType, rhsType);
+      auto diag = lhsType->is<UnresolvedType>()
+        ? diagnose(lhsExpr->getLoc(),
+                   diag::cannot_match_unresolved_expr_pattern_with_value,
+                   rhsType)
+        : diagnose(lhsExpr->getLoc(),
+                   diag::cannot_match_expr_pattern_with_value,
+                   lhsType, rhsType);
       diag.highlight(lhsExpr->getSourceRange());
       diag.highlight(rhsExpr->getSourceRange());
       if (auto optUnwrappedType = rhsType->getOptionalObjectType()) {
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index a90ec12..f84b7dd 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -2670,8 +2670,13 @@
     
     Type visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) {
       // If there are UnresolvedPatterns floating around after name binding,
-      // they are pattern productions in invalid positions.
-      return ErrorType::get(CS.getASTContext());
+      // they are pattern productions in invalid positions. However, we will
+      // diagnose that condition elsewhere; to avoid unnecessary noise errors,
+      // just plop an open type variable here.
+      
+      auto locator = CS.getConstraintLocator(expr);
+      auto typeVar = CS.createTypeVariable(locator, TVO_CanBindToLValue);
+      return typeVar;
     }
 
     /// Get the type T?
@@ -3056,7 +3061,11 @@
   
   if (result)
     this->optimizeConstraints(result);
-  
+
+  // If the experimental constraint propagation pass is enabled, run it.
+  if (TC.Context.LangOpts.EnableConstraintPropagation)
+    propagateConstraints();
+
   return result;
 }
 
diff --git a/lib/Sema/CSPropagate.cpp b/lib/Sema/CSPropagate.cpp
new file mode 100644
index 0000000..79d0723
--- /dev/null
+++ b/lib/Sema/CSPropagate.cpp
@@ -0,0 +1,25 @@
+//===--- CSPropagate.cpp - Constraint Propagation -------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the constraint propagation algorithm in the solver.
+//
+//===----------------------------------------------------------------------===//
+#include "ConstraintGraph.h"
+#include "ConstraintSystem.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+using namespace swift;
+using namespace constraints;
+
+void ConstraintSystem::propagateConstraints() {
+}
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index d9ce9c6..d337194 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -3351,6 +3351,10 @@
                                              Type type2,
                                              TypeMatchOptions flags,
                                              ConstraintLocatorBuilder locator) {
+  // There's no bridging without ObjC interop.
+  if (!TC.Context.LangOpts.EnableObjCInterop)
+    return SolutionKind::Error;
+  
   TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
 
   /// Form an unresolved result.
diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp
index 94d4dee..8a72947 100644
--- a/lib/Sema/CSSolver.cpp
+++ b/lib/Sema/CSSolver.cpp
@@ -889,7 +889,7 @@
       hasNonDependentMemberRelationalConstraints = true;
 
       // Handle unspecialized types directly.
-      if (!defaultType->isUnspecializedGeneric()) {
+      if (!defaultType->hasUnboundGenericType()) {
         if (!exactTypes.insert(defaultType->getCanonicalType()).second)
           continue;
 
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index 82a3e5b..ef5f386 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -2060,6 +2060,10 @@
   /// \returns a possibly-sanitized initializer, or null if an error occurred.
   Type generateConstraints(Pattern *P, ConstraintLocatorBuilder locator);
 
+  /// \brief Propagate constraints in an effort to enforce local
+  /// consistency to reduce the time to solve the system.
+  void propagateConstraints();
+
   /// \brief The result of attempting to resolve a constraint or set of
   /// constraints.
   enum class SolutionKind : char {
diff --git a/lib/Sema/GenericTypeResolver.h b/lib/Sema/GenericTypeResolver.h
index 69d0ef5..63af3fb 100644
--- a/lib/Sema/GenericTypeResolver.h
+++ b/lib/Sema/GenericTypeResolver.h
@@ -144,8 +144,37 @@
 
   virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp);
 
-  virtual Type resolveDependentMemberType(Type baseTy,
-                                          DeclContext *DC,
+  virtual Type resolveDependentMemberType(Type baseTy, DeclContext *DC,
+                                          SourceRange baseRange,
+                                          ComponentIdentTypeRepr *ref);
+
+  virtual Type resolveSelfAssociatedType(Type selfTy,
+                                         AssociatedTypeDecl *assocType);
+
+  virtual Type resolveTypeOfContext(DeclContext *dc);
+
+  virtual Type resolveTypeOfDecl(TypeDecl *decl);
+
+  virtual bool areSameType(Type type1, Type type2);
+
+  virtual void recordParamType(ParamDecl *decl, Type ty);
+};
+
+/// Generic type resolver that only handles what can appear in a protocol
+/// definition, i.e. Self, and Self.A.B.C dependent types.
+///
+/// This should only be used when resolving/validating where clauses in
+/// protocols.
+class ProtocolRequirementTypeResolver : public GenericTypeResolver {
+  ProtocolDecl *Proto;
+
+public:
+  explicit ProtocolRequirementTypeResolver(ProtocolDecl *proto)
+      : Proto(proto) {}
+
+  virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp);
+
+  virtual Type resolveDependentMemberType(Type baseTy, DeclContext *DC,
                                           SourceRange baseRange,
                                           ComponentIdentTypeRepr *ref);
 
diff --git a/lib/Sema/ITCDecl.cpp b/lib/Sema/ITCDecl.cpp
index f3bd518..430e43a 100644
--- a/lib/Sema/ITCDecl.cpp
+++ b/lib/Sema/ITCDecl.cpp
@@ -60,6 +60,10 @@
         }
       }
     }
+
+    if (!isa<EnumDecl>(typeDecl)) {
+      options |= TR_NonEnumInheritanceClauseOuterLayer;
+    }
   } else {
     auto ext = decl.get<ExtensionDecl *>();
     inheritanceClause = ext->getInherited();
@@ -100,7 +104,7 @@
   // FIXME: Declaration validation is overkill. Sink it down into type
   // resolution when it is actually needed.
   if (auto nominal = dyn_cast<NominalTypeDecl>(dc))
-    TC.validateDecl(nominal);
+    TC.validateDeclForNameLookup(nominal);
   else if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
     TC.validateExtension(ext);
   }
@@ -311,7 +315,7 @@
     } else if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
       if (ext->isBeingValidated())
         return true;
-      if (ext->validated())
+      if (ext->hasValidationStarted())
         return false;
     } else {
       break;
@@ -329,7 +333,7 @@
   if (auto typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
     if (typeAliasDecl->getDeclContext()->isModuleScopeContext() &&
         typeAliasDecl->getGenericParams() == nullptr) {
-      typeAliasDecl->setHasCompletedValidation();
+      typeAliasDecl->setValidationStarted();
 
       TypeResolutionOptions options;
       if (typeAliasDecl->getFormalAccess() <= Accessibility::FilePrivate)
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index a9195ab..d8169a2 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -1769,6 +1769,10 @@
   // Add the requirements to the builder.
   for (auto &req : resolvedRequirements)
     Builder.addRequirement(&req);
+
+  // Check the result.
+  Builder.finalize(attr->getLocation(), genericSig->getGenericParams(),
+                   /*allowConcreteGenericParams=*/true);
 }
 
 static Accessibility getAccessForDiagnostics(const ValueDecl *D) {
diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp
index 4d8b110..bb4c21b 100644
--- a/lib/Sema/TypeCheckCaptures.cpp
+++ b/lib/Sema/TypeCheckCaptures.cpp
@@ -192,7 +192,9 @@
 
     // If VD is a noescape decl, then the closure we're computing this for
     // must also be noescape.
-    if (VD->hasInterfaceType() &&
+    if (AFR.hasType() &&
+        !AFR.getType()->hasError() &&
+        VD->hasInterfaceType() &&
         VD->getInterfaceType()->is<AnyFunctionType>() &&
         VD->getInterfaceType()->castTo<AnyFunctionType>()->isNoEscape() &&
         !capture.isNoEscape() &&
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 2ec4bdc..11fa677 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -3365,16 +3365,18 @@
   // We can conditionally cast from NSError to an Error-conforming
   // type.  This is handled in the runtime, so it doesn't need a special cast
   // kind.
-  if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
-    if (conformsToProtocol(toType, errorTypeProto, dc,
-                           (ConformanceCheckFlags::InExpression|
-                            ConformanceCheckFlags::Used)))
-      if (auto NSErrorTy = getNSErrorType(dc))
-        if (isSubtypeOf(fromType, NSErrorTy, dc)
-            // Don't mask "always true" warnings if NSError is cast to
-            // Error itself.
-            && !isSubtypeOf(fromType, toType, dc))
-          return CheckedCastKind::ValueCast;
+  if (Context.LangOpts.EnableObjCInterop) {
+    if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
+      if (conformsToProtocol(toType, errorTypeProto, dc,
+                             (ConformanceCheckFlags::InExpression|
+                              ConformanceCheckFlags::Used)))
+        if (auto NSErrorTy = getNSErrorType(dc))
+          if (isSubtypeOf(fromType, NSErrorTy, dc)
+              // Don't mask "always true" warnings if NSError is cast to
+              // Error itself.
+              && !isSubtypeOf(fromType, toType, dc))
+            return CheckedCastKind::ValueCast;
+    }
   }
 
   // The runtime doesn't support casts to CF types and always lets them succeed.
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 80fc5d4..d324496 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -979,21 +979,14 @@
   return true;
 }
 
-/// Validate the given pattern binding declaration.
-static void validatePatternBindingDecl(TypeChecker &tc,
-                                       PatternBindingDecl *binding,
-                                       unsigned entryNumber) {
+/// Validate the \c entryNumber'th entry in \c binding.
+static void validatePatternBindingEntry(TypeChecker &tc,
+                                        PatternBindingDecl *binding,
+                                        unsigned entryNumber) {
   // If the pattern already has a type, we're done.
-  if (binding->getPattern(entryNumber)->hasType() ||
-      binding->isBeingValidated())
+  if (binding->getPattern(entryNumber)->hasType())
     return;
 
-  binding->setIsBeingValidated();
-
-  // On any path out of this function, make sure to mark the binding as done
-  // being type checked.
-  SWIFT_DEFER { binding->setIsBeingValidated(false); };
-
   // Resolve the pattern.
   auto *pattern = tc.resolvePattern(binding->getPattern(entryNumber),
                                     binding->getDeclContext(),
@@ -1078,6 +1071,19 @@
       tc.checkTypeModifyingDeclAttributes(var);
 }
 
+/// Validate the entries in the given pattern binding declaration.
+static void validatePatternBindingEntries(TypeChecker &tc,
+                                          PatternBindingDecl *binding) {
+  if (binding->hasValidationStarted())
+    return;
+
+  binding->setIsBeingValidated();
+  SWIFT_DEFER { binding->setIsBeingValidated(false); };
+
+  for (unsigned i = 0, e = binding->getNumPatternEntries(); i != e; ++i)
+    validatePatternBindingEntry(tc, binding, i);
+}
+
 void swift::makeFinal(ASTContext &ctx, ValueDecl *D) {
   if (D && !D->isFinal()) {
     D->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true));
@@ -1256,7 +1262,9 @@
   if (!ED->getExtendedType().isNull() &&
       !ED->getExtendedType()->hasError()) {
     if (NominalTypeDecl *nominal = ED->getExtendedType()->getAnyNominal()) {
-      validateDecl(nominal);
+      validateDeclForNameLookup(nominal);
+      if (ED->hasDefaultAccessibility())
+        return;
       maxAccess = std::max(nominal->getFormalAccess(),
                            Accessibility::FilePrivate);
     }
@@ -3430,7 +3438,7 @@
   checkDeclAttributesEarly(PGD);
   checkDeclAttributes(PGD);
 
-  if (PGD->isInvalid() || PGD->isBeingValidated())
+  if (PGD->isInvalid() || PGD->hasValidationStarted())
     return;
   PGD->setIsBeingValidated();
   SWIFT_DEFER { PGD->setIsBeingValidated(false); };
@@ -3753,8 +3761,7 @@
 
   void visitPatternBindingDecl(PatternBindingDecl *PBD) {
     // Check all the pattern/init pairs in the PBD.
-    for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i)
-      validatePatternBindingDecl(TC, PBD, i);
+    validatePatternBindingEntries(TC, PBD);
 
     if (PBD->isBeingValidated())
       return;
@@ -3982,7 +3989,7 @@
   }
   
   void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) {
-    if (!assocType->hasInterfaceType())
+    if (!assocType->hasValidationStarted())
       TC.validateDecl(assocType);
   }
 
@@ -4334,9 +4341,28 @@
     TC.checkDeclAttributesEarly(PD);
     TC.computeAccessibility(PD);
 
-    if (!IsSecondPass)
+    if (!IsSecondPass) {
       checkUnsupportedNestedType(PD);
 
+      for (auto member : PD->getMembers()) {
+        if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
+          if (auto whereClause = assocType->getTrailingWhereClause()) {
+            DeclContext *lookupDC = assocType->getDeclContext();
+
+            ProtocolRequirementTypeResolver resolver(PD);
+            TypeResolutionOptions options;
+
+            for (auto &req : whereClause->getRequirements()) {
+              if (!TC.validateRequirement(whereClause->getWhereLoc(), req,
+                                          lookupDC, options, &resolver))
+                // FIXME handle error?
+                continue;
+            }
+          }
+        }
+      }
+    }
+
     if (IsSecondPass) {
       checkAccessibility(TC, PD);
       for (auto member : PD->getMembers()) {
@@ -5011,6 +5037,10 @@
         return false;
       if (func->isGeneric() != parentFunc->isGeneric())
         return false;
+    } else if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
+      auto parentCtor = cast<ConstructorDecl>(parentDecl);
+      if (ctor->isGeneric() != parentCtor->isGeneric())
+        return false;
     } else if (auto var = dyn_cast<VarDecl>(decl)) {
       auto parentVar = cast<VarDecl>(parentDecl);
       if (var->isStatic() != parentVar->isStatic())
@@ -6908,8 +6938,12 @@
   // Handling validation failure due to re-entrancy is left
   // up to the caller, who must call hasValidSignature() to
   // check that validateDecl() returned a fully-formed decl.
-  if (D->isBeingValidated())
+  if (D->hasValidationStarted()) {
+    // If this isn't reentrant (i.e. D has already been validated), the
+    // signature better be valid.
+    assert(D->isBeingValidated() || D->hasValidSignature());
     return;
+  }
 
   PrettyStackTraceDecl StackTrace("validating", D);
 
@@ -6952,40 +6986,48 @@
     llvm_unreachable("handled above");
 
   case DeclKind::AssociatedType: {
-    if (D->hasInterfaceType())
-      return;
-
     auto assocType = cast<AssociatedTypeDecl>(D);
 
     assocType->setIsBeingValidated();
     SWIFT_DEFER { assocType->setIsBeingValidated(false); };
 
+    validateAccessibility(assocType);
+
     checkDeclAttributesEarly(assocType);
     checkInheritanceClause(assocType);
 
     // Check the default definition, if there is one.
     TypeLoc &defaultDefinition = assocType->getDefaultDefinitionLoc();
-    if (!defaultDefinition.isNull() &&
-        validateType(defaultDefinition, assocType->getDeclContext())) {
-      defaultDefinition.setInvalidType(Context);
-    }
+    if (!defaultDefinition.isNull()) {
+      if (validateType(defaultDefinition, assocType->getDeclContext())) {
+        defaultDefinition.setInvalidType(Context);
+      } else {
+        // associatedtype X = X is invalid
+        auto mentionsItself =
+            defaultDefinition.getType().findIf([&](Type type) {
+              if (auto DMT = type->getAs<ArchetypeType>()) {
+                return DMT->getAssocType() == assocType;
+              }
+              return false;
+            });
 
+        if (mentionsItself) {
+          diagnose(defaultDefinition.getLoc(), diag::recursive_type_reference,
+                   assocType->getDescriptiveKind(), assocType->getName());
+          diagnose(assocType, diag::type_declared_here);
+        }
+      }
+    }
     // Finally, set the interface type.
-    assocType->computeType();
+    if (!assocType->hasInterfaceType())
+      assocType->computeType();
 
     checkDeclAttributes(assocType);
     break;
   }
 
   case DeclKind::TypeAlias: {
-    // Type aliases may not have an underlying type yet.
     auto typeAlias = cast<TypeAliasDecl>(D);
-
-    if (typeAlias->hasCompletedValidation())
-      return;
-
-    typeAlias->setHasCompletedValidation();
-
     // Check generic parameters, if needed.
     typeAlias->setIsBeingValidated();
     SWIFT_DEFER { typeAlias->setIsBeingValidated(false); };
@@ -7017,8 +7059,6 @@
   case DeclKind::Struct:
   case DeclKind::Class: {
     auto nominal = cast<NominalTypeDecl>(D);
-    if (nominal->hasInterfaceType())
-      return;
     nominal->computeType();
 
     // Check generic parameters, if needed.
@@ -7056,9 +7096,8 @@
 
   case DeclKind::Protocol: {
     auto proto = cast<ProtocolDecl>(D);
-    if (proto->hasInterfaceType())
-      return;
-    proto->computeType();
+    if (!proto->hasInterfaceType())
+      proto->computeType();
 
     // Validate the generic type signature, which is just <Self : P>.
     proto->setIsBeingValidated();
@@ -7110,8 +7149,7 @@
           diagnose(VD, diag::pattern_used_in_type, VD->getName());
 
         } else {
-          for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i)
-            validatePatternBindingDecl(*this, PBD, i);
+          validatePatternBindingEntries(*this, PBD);
         }
 
         auto parentPattern = VD->getParentPattern();
@@ -7221,23 +7259,17 @@
   }
       
   case DeclKind::Func: {
-    if (D->hasInterfaceType())
-      return;
     typeCheckDecl(D, true);
     break;
   }
 
   case DeclKind::Subscript:
   case DeclKind::Constructor:
-    if (D->hasInterfaceType())
-      return;
     typeCheckDecl(D, true);
     break;
 
   case DeclKind::Destructor:
   case DeclKind::EnumElement: {
-    if (D->hasInterfaceType())
-      return;
     if (auto container = dyn_cast<NominalTypeDecl>(D->getDeclContext())) {
       validateDecl(container);
       typeCheckDecl(D, true);
@@ -7251,6 +7283,40 @@
   assert(D->hasValidSignature());
 }
 
+void TypeChecker::validateDeclForNameLookup(ValueDecl *D) {
+  switch (D->getKind()) {
+  case DeclKind::Protocol: {
+    auto proto = cast<ProtocolDecl>(D);
+    if (proto->hasInterfaceType())
+      return;
+    proto->computeType();
+
+    validateAccessibility(proto);
+
+    // Record inherited protocols.
+    resolveInheritedProtocols(proto);
+
+    for (auto member : proto->getMembers()) {
+      if (auto ATD = dyn_cast<AssociatedTypeDecl>(member)) {
+        validateDeclForNameLookup(ATD);
+      }
+    }
+    break;
+  }
+  case DeclKind::AssociatedType: {
+    auto assocType = cast<AssociatedTypeDecl>(D);
+    if (assocType->hasInterfaceType())
+      return;
+    assocType->computeType();
+    validateAccessibility(assocType);
+    break;
+  }
+
+  default:
+    validateDecl(D);
+    break;
+  }
+}
 
 void TypeChecker::validateAccessibility(ValueDecl *D) {
   if (D->hasAccessibility())
@@ -7394,9 +7460,7 @@
 
   // Local function used to infer requirements from the extended type.
   auto inferExtendedTypeReqs = [&](GenericSignatureBuilder &builder) {
-    builder.inferRequirements(TypeLoc::withoutLoc(extInterfaceType),
-                              /*minDepth=*/0,
-                              /*maxDepth=*/genericParams->getDepth());
+    builder.inferRequirements(TypeLoc::withoutLoc(extInterfaceType));
   };
 
   // Validate the generic type signature.
@@ -7430,12 +7494,11 @@
 } // namespace swift
 
 void TypeChecker::validateExtension(ExtensionDecl *ext) {
-  // If we already validated this extension, there's nothing more to do.
-  if (ext->validated())
+  // If we're currently validating, or have already validated this extension,
+  // there's nothing more to do now.
+  if (ext->hasValidationStarted())
     return;
 
-  ext->setValidated();
-
   ext->setIsBeingValidated();
   SWIFT_DEFER { ext->setIsBeingValidated(false); };
 
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 737fa2f..a0dc719 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -128,6 +128,43 @@
         GenericEnv, type));
 }
 
+Type ProtocolRequirementTypeResolver::resolveGenericTypeParamType(
+    GenericTypeParamType *gp) {
+  assert(gp->isEqual(Proto->getSelfInterfaceType()) &&
+         "found non-Self-shaped GTPT when resolving protocol requirement");
+  return gp;
+}
+
+Type ProtocolRequirementTypeResolver::resolveDependentMemberType(
+    Type baseTy, DeclContext *DC, SourceRange baseRange,
+    ComponentIdentTypeRepr *ref) {
+  return DependentMemberType::get(baseTy, ref->getIdentifier());
+}
+
+Type ProtocolRequirementTypeResolver::resolveSelfAssociatedType(
+    Type selfTy, AssociatedTypeDecl *assocType) {
+  assert(selfTy->isEqual(Proto->getSelfInterfaceType()));
+  return assocType->getDeclaredInterfaceType();
+}
+
+Type ProtocolRequirementTypeResolver::resolveTypeOfContext(DeclContext *dc) {
+  return dc->getSelfInterfaceType();
+}
+
+Type ProtocolRequirementTypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
+  return decl->getDeclaredInterfaceType();
+}
+
+bool ProtocolRequirementTypeResolver::areSameType(Type type1, Type type2) {
+  return type1->isEqual(type2);
+}
+
+void ProtocolRequirementTypeResolver::recordParamType(ParamDecl *decl,
+                                                      Type type) {
+  llvm_unreachable(
+      "recording a param type of a protocol requirement doesn't make sense");
+}
+
 Type CompleteGenericTypeResolver::resolveGenericTypeParamType(
                                               GenericTypeParamType *gp) {
   assert(gp->getDecl() && "Missing generic parameter declaration");
@@ -276,8 +313,6 @@
       builder->addGenericParameter(param);
   }
 
-  unsigned depth = genericParams->getDepth();
-
   // Now, check the inheritance clauses of each parameter.
   for (auto param : *genericParams) {
     checkInheritanceClause(param, resolver);
@@ -287,9 +322,7 @@
 
       // Infer requirements from the inherited types.
       for (const auto &inherited : param->getInherited()) {
-        builder->inferRequirements(inherited,
-                                   /*minDepth=*/depth,
-                                   /*maxDepth=*/depth);
+        builder->inferRequirements(inherited);
       }
     }
   }
@@ -298,73 +331,76 @@
   // Add the requirements clause to the builder, validating the types in
   // the requirements clause along the way.
   for (auto &req : genericParams->getRequirements()) {
-    if (req.isInvalid())
+    if (validateRequirement(genericParams->getWhereLoc(), req, lookupDC,
+                            options, resolver))
       continue;
 
-    switch (req.getKind()) {
-    case RequirementReprKind::TypeConstraint: {
-      // Validate the types.
-      if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
-        req.setInvalid();
-        continue;
-      }
-
-      if (validateType(req.getConstraintLoc(), lookupDC, options,
-                       resolver)) {
-        req.setInvalid();
-        continue;
-      }
-
-      // FIXME: Feels too early to perform this check.
-      if (!req.getConstraint()->isExistentialType() &&
-          !req.getConstraint()->getClassOrBoundGenericClass()) {
-        diagnose(genericParams->getWhereLoc(),
-                 diag::requires_conformance_nonprotocol,
-                 req.getSubjectLoc(), req.getConstraintLoc());
-        req.getConstraintLoc().setInvalidType(Context);
-        req.setInvalid();
-        continue;
-      }
-
-      break;
-    }
-
-    case RequirementReprKind::LayoutConstraint: {
-      // Validate the types.
-      if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
-        req.setInvalid();
-        continue;
-      }
-
-      if (req.getLayoutConstraintLoc().isNull()) {
-        req.setInvalid();
-        continue;
-      }
-
-      break;
-    }
-
-    case RequirementReprKind::SameType:
-      if (validateType(req.getFirstTypeLoc(), lookupDC, options,
-                       resolver)) {
-        req.setInvalid();
-        continue;
-      }
-
-      if (validateType(req.getSecondTypeLoc(), lookupDC, options,
-                       resolver)) {
-        req.setInvalid();
-        continue;
-      }
-      
-      break;
-    }
-    
     if (builder && builder->addRequirement(&req))
       req.setInvalid();
   }
 }
 
+bool TypeChecker::validateRequirement(SourceLoc whereLoc, RequirementRepr &req,
+                                      DeclContext *lookupDC,
+                                      TypeResolutionOptions options,
+                                      GenericTypeResolver *resolver) {
+  if (req.isInvalid())
+    return true;
+
+  switch (req.getKind()) {
+  case RequirementReprKind::TypeConstraint: {
+    // Validate the types.
+    if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
+      req.setInvalid();
+      return true;
+    }
+
+    if (validateType(req.getConstraintLoc(), lookupDC, options, resolver)) {
+      req.setInvalid();
+      return true;
+    }
+
+    // FIXME: Feels too early to perform this check.
+    if (!req.getConstraint()->isExistentialType() &&
+        !req.getConstraint()->getClassOrBoundGenericClass()) {
+      diagnose(whereLoc, diag::requires_conformance_nonprotocol,
+               req.getSubjectLoc(), req.getConstraintLoc());
+      req.getConstraintLoc().setInvalidType(Context);
+      req.setInvalid();
+      return true;
+    }
+    return false;
+  }
+
+  case RequirementReprKind::LayoutConstraint: {
+    // Validate the types.
+    if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
+      req.setInvalid();
+      return true;
+    }
+
+    if (req.getLayoutConstraintLoc().isNull()) {
+      req.setInvalid();
+      return true;
+    }
+    return false;
+  }
+
+  case RequirementReprKind::SameType: {
+    if (validateType(req.getFirstTypeLoc(), lookupDC, options, resolver)) {
+      req.setInvalid();
+      return true;
+    }
+
+    if (validateType(req.getSecondTypeLoc(), lookupDC, options, resolver)) {
+      req.setInvalid();
+      return true;
+    }
+    return false;
+  }
+  }
+}
+
 void
 TypeChecker::prepareGenericParamList(GenericParamList *gp,
                                      DeclContext *dc) {
@@ -488,10 +524,7 @@
       // Infer requirements from it.
       if (builder && genericParams &&
           fn->getBodyResultTypeLoc().getTypeRepr()) {
-        unsigned depth = genericParams->getDepth();
-        builder->inferRequirements(fn->getBodyResultTypeLoc(),
-                                   /*minDepth=*/depth,
-                                   /*maxDepth=*/depth);
+        builder->inferRequirements(fn->getBodyResultTypeLoc());
       }
     }
   }
@@ -827,10 +860,7 @@
   // Infer requirements from it.
   if (genericParams && builder &&
       subscript->getElementTypeLoc().getTypeRepr()) {
-    unsigned depth = genericParams->getDepth();
-    builder->inferRequirements(subscript->getElementTypeLoc(),
-                               /*minDepth=*/depth,
-                               /*maxDepth=*/depth);
+    builder->inferRequirements(subscript->getElementTypeLoc());
   }
 
   // Check the indices.
@@ -1089,34 +1119,29 @@
 
 std::pair<bool, bool> TypeChecker::checkGenericArguments(
     DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner,
-    GenericSignature *genericSig, const TypeSubstitutionMap &substitutions,
+    GenericSignature *genericSig, TypeSubstitutionFn substitutions,
+    LookupConformanceFn conformances,
     UnsatisfiedDependency *unsatisfiedDependency,
     ConformanceCheckOptions conformanceOptions,
     GenericRequirementsCheckListener *listener) {
-  // Check each of the requirements.
-  ModuleDecl *module = dc->getParentModule();
-  for (const auto &req : genericSig->getRequirements()) {
-    Type firstType = req.getFirstType().subst(
-        QueryTypeSubstitutionMap{substitutions},
-        LookUpConformanceInModule(module));
-    if (firstType.isNull()) {
+  for (const auto &rawReq : genericSig->getRequirements()) {
+    auto req = rawReq.subst(substitutions, conformances);
+    if (!req) {
       // Another requirement will fail later; just continue.
       continue;
     }
 
-    Type secondType;
-    if (req.getKind() != RequirementKind::Layout)
-      secondType = req.getSecondType();
-    if (secondType) {
-      secondType = secondType.subst(QueryTypeSubstitutionMap{substitutions},
-                                    LookUpConformanceInModule(module));
-      if (secondType.isNull()) {
-        // Another requirement will fail later; just continue.
+    auto kind = req->getKind();
+    Type rawFirstType = rawReq.getFirstType();
+    Type firstType = req->getFirstType();
+    Type rawSecondType, secondType;
+    if (kind != RequirementKind::Layout) {
+      rawSecondType = rawReq.getSecondType();
+      secondType = req->getSecondType().subst(substitutions, conformances);
+      if (!secondType)
         continue;
-      }
     }
 
-    auto kind = req.getKind();
     if (listener && !listener->shouldCheck(kind, firstType, secondType))
       continue;
 
@@ -1157,10 +1182,10 @@
         diagnose(loc, diag::type_does_not_inherit, owner, firstType,
                  secondType);
 
-        diagnose(noteLoc, diag::type_does_not_inherit_requirement,
-                 req.getFirstType(), req.getSecondType(),
+        diagnose(noteLoc, diag::type_does_not_inherit_requirement, rawFirstType,
+                 rawSecondType,
                  genericSig->gatherGenericParamBindingsText(
-                     {req.getFirstType(), req.getSecondType()}, substitutions));
+                     {rawFirstType, rawSecondType}, substitutions));
 
         return std::make_pair(false, false);
       }
@@ -1171,10 +1196,10 @@
         // FIXME: Better location info for both diagnostics.
         diagnose(loc, diag::types_not_equal, owner, firstType, secondType);
 
-        diagnose(noteLoc, diag::types_not_equal_requirement, req.getFirstType(),
-                 req.getSecondType(),
+        diagnose(noteLoc, diag::types_not_equal_requirement, rawFirstType,
+                 rawSecondType,
                  genericSig->gatherGenericParamBindingsText(
-                     {req.getFirstType(), req.getSecondType()}, substitutions));
+                     {rawFirstType, rawSecondType}, substitutions));
 
         return std::make_pair(false, false);
       }
diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp
index 0a3131e..b2fa7ec 100644
--- a/lib/Sema/TypeCheckPattern.cpp
+++ b/lib/Sema/TypeCheckPattern.cpp
@@ -394,7 +394,7 @@
   // Unresolved member syntax '.Element' forms an EnumElement pattern. The
   // element will be resolved when we type-check the pattern.
   Pattern *visitUnresolvedMemberExpr(UnresolvedMemberExpr *ume) {
-    // We the unresolved member has an argument, turn it into a subpattern.
+    // If the unresolved member has an argument, turn it into a subpattern.
     Pattern *subPattern = nullptr;
     if (auto arg = ume->getArgument()) {
       subPattern = getSubExprPattern(arg);
@@ -402,11 +402,11 @@
     
     // FIXME: Compound names.
     return new (TC.Context) EnumElementPattern(
-                              TypeLoc(), ume->getDotLoc(),
+                              ume->getDotLoc(),
                               ume->getNameLoc().getBaseNameLoc(),
                               ume->getName().getBaseName(),
-                              nullptr,
-                              subPattern);
+                              subPattern,
+                              ume);
   }
   
   // Member syntax 'T.Element' forms a pattern if 'T' is an enum and the
@@ -1004,6 +1004,7 @@
                                       TypeResolutionOptions options,
                                       GenericTypeResolver *resolver,
                                       TypeLoc tyLoc) {
+recur:
   if (tyLoc.isNull()) {
     tyLoc = TypeLoc::withoutLoc(type);
   }
@@ -1377,6 +1378,14 @@
 
               return true;
             }
+          
+          // If we have the original expression parse tree, try reinterpreting
+          // it as an expr-pattern if enum element lookup failed, since `.foo`
+          // could also refer to a static member of the context type.
+          } else if (EEP->hasUnresolvedOriginalExpr()) {
+            P = new (Context) ExprPattern(EEP->getUnresolvedOriginalExpr(),
+                                          nullptr, nullptr);
+            goto recur;
           }
 
           diagnose(EEP->getLoc(), diag::enum_element_pattern_member_not_found,
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 17e3471..ddf4d8a 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -1073,7 +1073,8 @@
 
   // Next, add each of the requirements (mapped from the requirement's
   // interface types into the abstract type parameters).
-  auto source = RequirementSource::forAbstract(builder);
+  auto source =
+    GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
   for (auto &reqReq : reqSig->getRequirements()) {
     switch (reqReq.getKind()) {
     case RequirementKind::Conformance: {
@@ -1782,12 +1783,15 @@
     void emitDelayedDiags();
 
     ConformanceChecker(TypeChecker &tc, NormalProtocolConformance *conformance,
-                      bool suppressDiagnostics = true)
-      : WitnessChecker(tc, conformance->getProtocol(), conformance->getType(),
-                       conformance->getDeclContext()),
-        Conformance(conformance),
-        Loc(conformance->getLoc()),
-        SuppressDiagnostics(suppressDiagnostics) { }
+                       bool suppressDiagnostics = true)
+        : WitnessChecker(tc, conformance->getProtocol(), conformance->getType(),
+                         conformance->getDeclContext()),
+          Conformance(conformance), Loc(conformance->getLoc()),
+          SuppressDiagnostics(suppressDiagnostics) {
+      // The protocol may have only been validatedDeclForNameLookup'd until
+      // here, so fill in any information that's missing.
+      tc.validateDecl(conformance->getProtocol());
+    }
 
     /// Resolve all of the type witnesses.
     void resolveTypeWitnesses();
@@ -1806,6 +1810,10 @@
     /// directly as possible.
     void resolveSingleTypeWitness(AssociatedTypeDecl *assocType);
 
+    /// Check all of the protocols requirements are actually satisfied by a
+    /// the chosen type witnesses.
+    void ensureRequirementsAreSatisfied();
+
     /// Check the entire protocol conformance, ensuring that all
     /// witnesses are resolved and emitting any diagnostics.
     void checkConformance();
@@ -4447,6 +4455,28 @@
   addUsedConformances(conformance, visited);
 }
 
+void ConformanceChecker::ensureRequirementsAreSatisfied() {
+  auto proto = Conformance->getProtocol();
+  // Some other problem stopped the signature being computed.
+  if (!proto->isRequirementSignatureComputed())
+    return;
+
+  auto reqSig = proto->getRequirementSignature();
+
+  auto substitutions = SubstitutionMap::getProtocolSubstitutions(
+      proto, Conformance->getType(), ProtocolConformanceRef(Conformance));
+
+  auto result = TC.checkGenericArguments(
+      Conformance->getDeclContext(), Loc, Loc,
+      // FIXME: maybe this should be the conformance's type
+      proto->getDeclaredInterfaceType(), reqSig,
+      QuerySubstitutionMap{substitutions},
+      LookUpConformanceInSubstitutionMap{substitutions}, nullptr);
+
+  // Errors are emitted inside the checker.
+  (void)result;
+}
+
 #pragma mark Protocol conformance checking
 void ConformanceChecker::checkConformance() {
   assert(!Conformance->isComplete() && "Conformance is already complete");
@@ -4462,6 +4492,10 @@
   // Resolve all of the type witnesses.
   resolveTypeWitnesses();
 
+  // Resolution attempts to have the witnesses be correct by construction, but
+  // this isn't guaranteed, so let's double check.
+  ensureRequirementsAreSatisfied();
+
   // Ensure the conforming type is used.
   //
   // FIXME: This feels like the wrong place for this, but if we don't put
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 29e54c8..e0ee038 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -575,8 +575,9 @@
   for (auto tyR : genericArgs)
     args.push_back(tyR);
 
+  auto argumentOptions = options - TR_NonEnumInheritanceClauseOuterLayer;
   auto result = applyUnboundGenericArguments(type, genericDecl, loc, dc, args,
-                                             options, resolver,
+                                             argumentOptions, resolver,
                                              unsatisfiedDependency);
   if (!result)
     return result;
@@ -675,9 +676,11 @@
     assert(genericSig != nullptr);
     auto substitutions = BGT->getContextSubstitutions(BGT->getDecl());
 
-    auto result = checkGenericArguments(
-        dc, loc, noteLoc, UGT, genericSig,
-        substitutions, unsatisfiedDependency);
+    auto result =
+        checkGenericArguments(dc, loc, noteLoc, UGT, genericSig,
+                              QueryTypeSubstitutionMap{substitutions},
+                              LookUpConformanceInModule{dc->getParentModule()},
+                              unsatisfiedDependency);
 
     // Unsatisfied dependency case.
     if (result.first)
@@ -726,7 +729,7 @@
       return nullptr;
   } else {
     // Validate the declaration.
-    TC.validateDecl(typeDecl);
+    TC.validateDeclForNameLookup(typeDecl);
   }
 
   // If we didn't bail out with an unsatisfiedDependency,
@@ -1086,7 +1089,26 @@
                                 dyn_cast<GenericIdentTypeRepr>(comp), options,
                                 resolver, unsatisfiedDependency);
 
-    if (!type || type->hasError())
+    if (!type)
+      return type;
+
+    auto hasError = type->hasError();
+    if (options & TR_NonEnumInheritanceClauseOuterLayer) {
+      auto protocolOrClass =
+          hasError ? (isa<ProtocolDecl>(typeDecl) || isa<ClassDecl>(typeDecl))
+                   : (type->is<ProtocolType>() || type->is<ClassType>());
+      if (!protocolOrClass) {
+        auto diagnosedType = hasError ? typeDecl->getDeclaredInterfaceType() : type;
+        if (diagnosedType && /*FIXME:*/!hasError) {
+          TC.diagnose(comp->getIdLoc(),
+                      diag::inheritance_from_non_protocol_or_class,
+                      diagnosedType);
+          return ErrorType::get(diagnosedType);
+        }
+      }
+    }
+
+    if (hasError)
       return type;
 
     // If this is the first result we found, record it.
@@ -1318,6 +1340,16 @@
     return ErrorType::get(TC.Context);
   }
 
+  if (options & TR_NonEnumInheritanceClauseOuterLayer) {
+    auto protocolOrClass =
+        memberType->is<ProtocolType>() || memberType->is<ClassType>();
+    if (!protocolOrClass) {
+      TC.diagnose(comp->getIdLoc(),
+                  diag::inheritance_from_non_protocol_or_class, memberType);
+      return ErrorType::get(memberType);
+    }
+  }
+
   // If there are generic arguments, apply them now.
   if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
     memberType = TC.applyGenericArguments(
@@ -1357,8 +1389,9 @@
 
   // All remaining components use qualified lookup.
 
+  auto parentOptions = options - TR_NonEnumInheritanceClauseOuterLayer;
   // Resolve the parent type.
-  Type parentTy = resolveIdentTypeComponent(TC, DC, parentComps, options,
+  Type parentTy = resolveIdentTypeComponent(TC, DC, parentComps, parentOptions,
                                             diagnoseErrors, resolver,
                                             unsatisfiedDependency);
   if (!parentTy || parentTy->hasError()) return parentTy;
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index 7d001ab..e681c7a 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -348,7 +348,7 @@
   }
 
   // Cannot extend a bound generic type.
-  if (extendedType->isSpecialized() && extendedType->getAnyNominal()) {
+  if (extendedType->isSpecialized()) {
     TC.diagnose(ED->getLoc(), diag::extension_specialization,
                 extendedType->getAnyNominal()->getName())
       .highlight(ED->getExtendedTypeLoc().getSourceRange());
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index a331c60..aa56685 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -437,6 +437,11 @@
 
   /// Whether we are checking the outermost type of a computed property setter's newValue
   TR_ImmediateSetterNewValue = 0x1000000,
+
+  /// Whether we are checking the outermost layer of types in an inheritance
+  /// clause on something other than an enum (i.e. V, but not U or W, in class
+  /// T: U.V<W>)
+  TR_NonEnumInheritanceClauseOuterLayer = 0x2000000,
 };
 
 /// Option set describing how type resolution should work.
@@ -838,6 +843,9 @@
   void validateDecl(OperatorDecl *decl);
   void validateDecl(PrecedenceGroupDecl *decl);
 
+  /// Perform just enough validation for looking up names using the Decl.
+  void validateDeclForNameLookup(ValueDecl *D);
+
   /// Resolves the accessibility of the given declaration.
   void validateAccessibility(ValueDecl *D);
 
@@ -1065,7 +1073,7 @@
   }
 
   virtual void resolveDeclSignature(ValueDecl *VD) override {
-    validateDecl(VD);
+    validateDeclForNameLookup(VD);
   }
 
   virtual void bindExtension(ExtensionDecl *ext) override;
@@ -1185,6 +1193,11 @@
   /// \param nominal The generic type.
   void validateGenericTypeSignature(GenericTypeDecl *nominal);
 
+  bool validateRequirement(SourceLoc whereLoc, RequirementRepr &req,
+                           DeclContext *lookupDC,
+                           TypeResolutionOptions options = None,
+                           GenericTypeResolver *resolver = nullptr);
+
   /// Check the given set of generic arguments against the requirements in a
   /// generic signature.
   ///
@@ -1207,7 +1220,8 @@
   /// - (false, false) on failure
   std::pair<bool, bool> checkGenericArguments(
       DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner,
-      GenericSignature *genericSig, const TypeSubstitutionMap &substitutions,
+      GenericSignature *genericSig, TypeSubstitutionFn substitutions,
+      LookupConformanceFn conformances,
       UnsatisfiedDependency *unsatisfiedDependency,
       ConformanceCheckOptions conformanceOptions = ConformanceCheckFlags::Used,
       GenericRequirementsCheckListener *listener = nullptr);
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 98f18bb..65e5ea5 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1321,11 +1321,10 @@
     IdentifierID IID;
     TypeID TID = 0;
     bool isType = (recordID == XREF_TYPE_PATH_PIECE);
-    bool onlyInNominal = false;
     bool inProtocolExt = false;
     bool isStatic = false;
     if (isType)
-      XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
+      XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
     else
       XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
                                            isStatic);
@@ -1496,13 +1495,12 @@
       Identifier memberName;
       Optional<swift::CtorInitializerKind> ctorInit;
       bool isType = false;
-      bool onlyInNominal = false;
       bool inProtocolExt = false;
       bool isStatic = false;
       switch (recordID) {
       case XREF_TYPE_PATH_PIECE: {
         IdentifierID IID;
-        XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
+        XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
         memberName = getIdentifier(IID);
         isType = true;
         break;
@@ -1548,7 +1546,7 @@
         return nullptr;
       }
 
-      auto members = nominal->lookupDirect(memberName, onlyInNominal);
+      auto members = nominal->lookupDirect(memberName);
       values.append(members.begin(), members.end());
       filterValues(filterTy, M, genericSig, isType, inProtocolExt, isStatic,
                    ctorInit, values);
@@ -2551,10 +2549,14 @@
     if (declOrOffset.isComplete())
       return declOrOffset;
 
-    auto assocType = createDecl<AssociatedTypeDecl>(DC, SourceLoc(),
-                                                    getIdentifier(nameID),
-                                                    SourceLoc(), this,
-                                                    defaultDefinitionID);
+    // The where-clause information is pushed up into the protocol
+    // (specifically, into its requirement signature) and
+    // serialized/deserialized there, so the actual Decl doesn't need to store
+    // it.
+    TrailingWhereClause *trailingWhere = nullptr;
+    auto assocType = createDecl<AssociatedTypeDecl>(
+        DC, SourceLoc(), getIdentifier(nameID), SourceLoc(), trailingWhere,
+        this, defaultDefinitionID);
     declOrOffset = assocType;
 
     assocType->computeType();
@@ -3467,7 +3469,6 @@
                                        DeclTypeCursor.GetCurrentBitNo()));
 
     nominal->addExtension(extension);
-    extension->setValidated(true);
 
     break;
   }
@@ -3529,7 +3530,9 @@
   if (DAttrs)
     declOrOffset.get()->getAttrs().setRawAttributeChain(DAttrs);
 
-  return declOrOffset;
+  auto decl = declOrOffset.get();
+  decl->setValidationStarted();
+  return decl;
 }
 
 /// Translate from the Serialization function type repr enum values to the AST
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 3153e1e..25c7df7 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -982,6 +982,10 @@
                                                 Ty,
                                                 ctxConformances);
       break;
+    case ValueKind::InitExistentialOpaqueInst:
+      ResultVal = Builder.createInitExistentialOpaque(Loc, Ty, ConcreteTy,
+                                                      operand, ctxConformances);
+      break;
     case ValueKind::InitExistentialMetatypeInst:
       ResultVal = Builder.createInitExistentialMetatype(Loc, operand, Ty,
                                                         ctxConformances);
@@ -1343,16 +1347,17 @@
 
   UNARY_INSTRUCTION(CondFail)
   REFCOUNTING_INSTRUCTION(RetainValue)
-  UNARY_INSTRUCTION(UnmanagedRetainValue)
+  REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
   UNARY_INSTRUCTION(CopyValue)
   UNARY_INSTRUCTION(CopyUnownedValue)
   UNARY_INSTRUCTION(DestroyValue)
   REFCOUNTING_INSTRUCTION(ReleaseValue)
-  UNARY_INSTRUCTION(UnmanagedReleaseValue)
+  REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
   REFCOUNTING_INSTRUCTION(AutoreleaseValue)
-  UNARY_INSTRUCTION(UnmanagedAutoreleaseValue)
+  REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
   REFCOUNTING_INSTRUCTION(SetDeallocating)
   UNARY_INSTRUCTION(DeinitExistentialAddr)
+  UNARY_INSTRUCTION(DeinitExistentialOpaque)
   UNARY_INSTRUCTION(EndBorrowArgument)
   UNARY_INSTRUCTION(DestroyAddr)
   UNARY_INSTRUCTION(IsNonnull)
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index df0d237..85f57eb 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1803,18 +1803,17 @@
     return;
   }
 
+  bool isProtocolExt = D->getDeclContext()->getAsProtocolExtensionContext();
   if (auto type = dyn_cast<TypeDecl>(D)) {
     abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
     XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
                                         addIdentifierRef(type->getName()),
-                                        isa<ProtocolDecl>(
-                                          type->getDeclContext()));
+                                        isProtocolExt);
     return;
   }
 
   auto val = cast<ValueDecl>(D);
   auto ty = val->getInterfaceType()->getCanonicalType();
-  bool isProtocolExt = D->getDeclContext()->getAsProtocolExtensionContext();
   abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code];
   XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
                                        addTypeRef(ty),
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index 08b5c75..5e60637 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -315,7 +315,7 @@
   FuncTable[Ctx.getIdentifier(F.getName())] = NextFuncID++;
   Funcs.push_back(Out.GetCurrentBitNo());
   unsigned abbrCode = SILAbbrCodes[SILFunctionLayout::Code];
-  TypeID FnID = S.addTypeRef(F.getLoweredType().getSwiftType());
+  TypeID FnID = S.addTypeRef(F.getLoweredType().getSwiftRValueType());
   DEBUG(llvm::dbgs() << "SILFunction " << F.getName() << " @ BitNo "
                      << Out.GetCurrentBitNo() << " abbrCode " << abbrCode
                      << " FnID " << FnID << "\n");
@@ -581,7 +581,7 @@
       break;
     }
     case ValueKind::InitExistentialOpaqueInst: {
-      auto &IEOI = cast<InitExistentialRefInst>(SI);
+      auto &IEOI = cast<InitExistentialOpaqueInst>(SI);
       operand = IEOI.getOperand();
       Ty = IEOI.getType();
       FormalConcreteType = IEOI.getFormalConcreteType();
@@ -1047,6 +1047,7 @@
   case ValueKind::DeallocStackInst:
   case ValueKind::DeallocRefInst:
   case ValueKind::DeinitExistentialAddrInst:
+  case ValueKind::DeinitExistentialOpaqueInst:
   case ValueKind::DestroyAddrInst:
   case ValueKind::IsNonnullInst:
   case ValueKind::LoadInst:
@@ -1785,7 +1786,7 @@
 void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) {
   GlobalVarList[Ctx.getIdentifier(g.getName())] = NextGlobalVarID++;
   GlobalVarOffset.push_back(Out.GetCurrentBitNo());
-  TypeID TyID = S.addTypeRef(g.getLoweredType().getSwiftType());
+  TypeID TyID = S.addTypeRef(g.getLoweredType().getSwiftRValueType());
   DeclID dID = S.addDeclRef(g.getDecl());
   SILGlobalVarLayout::emitRecord(Out, ScratchRecord,
                                  SILAbbrCodes[SILGlobalVarLayout::Code],
diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp
index dc0d4ac..f193f73 100644
--- a/lib/Serialization/SerializedModuleLoader.cpp
+++ b/lib/Serialization/SerializedModuleLoader.cpp
@@ -96,7 +96,7 @@
   // FIXME: Which name should we be using here? Do we care about CPU subtypes?
   // FIXME: At the very least, don't hardcode "arch".
   llvm::SmallString<16> archFile{
-      ctx.LangOpts.getPlatformConditionValue("arch")};
+      ctx.LangOpts.getPlatformConditionValue(PlatformConditionKind::Arch)};
   llvm::SmallString<16> archDocFile{archFile};
   if (!archFile.empty()) {
     archFile += '.';
diff --git a/lib/Syntax/CMakeLists.txt b/lib/Syntax/CMakeLists.txt
index 6508584..1d20b1b 100644
--- a/lib/Syntax/CMakeLists.txt
+++ b/lib/Syntax/CMakeLists.txt
@@ -12,4 +12,5 @@
   SyntaxFactory.cpp
   SyntaxData.cpp
   TypeSyntax.cpp
+  UnknownSyntax.cpp
 )
diff --git a/lib/Syntax/DeclSyntax.cpp b/lib/Syntax/DeclSyntax.cpp
index f2fe755..c26d20e 100644
--- a/lib/Syntax/DeclSyntax.cpp
+++ b/lib/Syntax/DeclSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- DeclSyntax.cpp - Declaration Syntax Implementation -----*- C++ -*-===//
+//===--- DeclSyntax.cpp - Declaration Syntax Implementation ---------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -36,14 +36,16 @@
 UnknownDeclSyntaxData::UnknownDeclSyntaxData(RC<RawSyntax> Raw,
                                              const SyntaxData *Parent,
                                              CursorIndex IndexInParent)
-  : DeclSyntaxData(Raw, Parent, IndexInParent) {
-  assert(Raw->Kind == SyntaxKind::UnknownStmt);
+  : UnknownSyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Kind == SyntaxKind::UnknownDecl);
 }
 
 RC<UnknownDeclSyntaxData>
 UnknownDeclSyntaxData::make(RC<RawSyntax> Raw,
                             const SyntaxData *Parent,
                             CursorIndex IndexInParent) {
+  auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownDecl, Raw->Layout,
+                                    Raw->Presence);
   return RC<UnknownDeclSyntaxData> {
     new UnknownDeclSyntaxData {
       Raw, Parent, IndexInParent
@@ -55,7 +57,7 @@
 
 UnknownDeclSyntax::UnknownDeclSyntax(const RC<SyntaxData> Root,
                                      const UnknownDeclSyntaxData *Data)
-  : DeclSyntax(Root, Data) {}
+  : UnknownSyntax(Root, Data) {}
 
 #pragma mark - declaration-members Data
 
diff --git a/lib/Syntax/ExprSyntax.cpp b/lib/Syntax/ExprSyntax.cpp
index 9df2740..b7d8be9 100644
--- a/lib/Syntax/ExprSyntax.cpp
+++ b/lib/Syntax/ExprSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- ExprSyntax.cpp - Swift Expression Syntax Impl. ---------*- C++ -*-===//
+//===--- ExprSyntax.cpp - Swift Expression Syntax Impl. -------------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "swift/Syntax/ExprSyntax.h"
+#include "swift/Syntax/GenericSyntax.h"
 
 using namespace swift;
 using namespace swift::syntax;
@@ -41,7 +42,7 @@
 UnknownExprSyntaxData::UnknownExprSyntaxData(RC<RawSyntax> Raw,
                                              const SyntaxData *Parent,
                                              CursorIndex IndexInParent)
-  : ExprSyntaxData(Raw, Parent, IndexInParent) {
+  : UnknownSyntaxData(Raw, Parent, IndexInParent) {
   assert(Raw->Kind == SyntaxKind::UnknownExpr);
 }
 
@@ -49,9 +50,11 @@
 UnknownExprSyntaxData::make(RC<RawSyntax> Raw,
                             const SyntaxData *Parent,
                             CursorIndex IndexInParent) {
+  auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownExpr, Raw->Layout,
+                                    Raw->Presence);
   return RC<UnknownExprSyntaxData> {
     new UnknownExprSyntaxData {
-      Raw, Parent, IndexInParent
+      UnknownRaw, Parent, IndexInParent
     }
   };
 }
@@ -60,7 +63,7 @@
 
 UnknownExprSyntax::UnknownExprSyntax(const RC<SyntaxData> Root,
                                      const UnknownExprSyntaxData *Data)
-  : ExprSyntax(Root, Data) {}
+  : UnknownSyntax(Root, Data) {}
 
 #pragma mark - integer-literal-expression Data
 
@@ -97,7 +100,6 @@
   return make(Raw);
 }
 
-
 #pragma mark - integer-literal-expression API
 
 IntegerLiteralExprSyntax::
@@ -111,3 +113,428 @@
   return Data->replaceChild<IntegerLiteralExprSyntax>(NewDigits,
                                                       Cursor::Digits);
 }
+
+#pragma mark - symbolic-reference Data
+
+SymbolicReferenceExprSyntaxData::
+SymbolicReferenceExprSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent,
+                                CursorIndex IndexInParent)
+  : ExprSyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Layout.size() == 2);
+  syntax_assert_child_token(Raw,
+    SymbolicReferenceExprSyntax::Cursor::Identifier, tok::identifier);
+  syntax_assert_child_kind(Raw,
+    SymbolicReferenceExprSyntax::Cursor::GenericArgumentClause,
+    SyntaxKind::GenericArgumentClause);
+}
+
+RC<SymbolicReferenceExprSyntaxData>
+SymbolicReferenceExprSyntaxData::make(RC<RawSyntax> Raw,
+                                      const SyntaxData *Parent,
+     CursorIndex IndexInParent) {
+  return RC<SymbolicReferenceExprSyntaxData> {
+    new SymbolicReferenceExprSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<SymbolicReferenceExprSyntaxData>
+SymbolicReferenceExprSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::SymbolicReferenceExpr,
+    {
+      TokenSyntax::missingToken(tok::identifier, ""),
+      RawSyntax::missing(SyntaxKind::GenericArgumentClause),
+    },
+    SourcePresence::Present);
+  return make(Raw);
+}
+
+#pragma mark - symbolic-reference API
+
+SymbolicReferenceExprSyntax::
+SymbolicReferenceExprSyntax(const RC<SyntaxData> Root, const DataType *Data)
+  : ExprSyntax(Root, Data) {}
+
+RC<TokenSyntax> SymbolicReferenceExprSyntax::getIdentifier() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Identifier));
+}
+
+SymbolicReferenceExprSyntax SymbolicReferenceExprSyntax::
+withIdentifier(RC<TokenSyntax> NewIdentifier) const {
+  assert(NewIdentifier->getTokenKind() == tok::identifier);
+  return Data->replaceChild<SymbolicReferenceExprSyntax>(NewIdentifier,
+                                                         Cursor::Identifier);
+}
+
+llvm::Optional<GenericArgumentClauseSyntax>
+SymbolicReferenceExprSyntax::getGenericArgumentClause() const {
+  auto RawClause = getRaw()->getChild(Cursor::GenericArgumentClause);
+  if (RawClause->isMissing()) {
+    return llvm::None;
+  }
+
+  auto *MyData = getUnsafeData<SymbolicReferenceExprSyntax>();
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedGenericArgClause);
+  SyntaxData::realizeSyntaxNode<GenericArgumentClauseSyntax>(ChildPtr,
+                                                             RawClause, MyData,
+    cursorIndex(Cursor::GenericArgumentClause));
+
+  return llvm::Optional<GenericArgumentClauseSyntax> {
+    GenericArgumentClauseSyntax {
+      Root,
+      MyData->CachedGenericArgClause.get()
+    }
+  };
+}
+
+SymbolicReferenceExprSyntax SymbolicReferenceExprSyntax::
+withGenericArgumentClause(GenericArgumentClauseSyntax NewGenericArgs) const {
+  return Data->replaceChild<SymbolicReferenceExprSyntax>(
+    NewGenericArgs.getRaw(), Cursor::GenericArgumentClause);
+}
+
+#pragma mark - function-call-argument Data
+
+FunctionCallArgumentSyntaxData::
+FunctionCallArgumentSyntaxData(RC<RawSyntax> Raw,
+                               const SyntaxData *Parent,
+                               CursorIndex IndexInParent)
+  : SyntaxData(Raw, Parent, IndexInParent) {
+    syntax_assert_child_token(Raw, FunctionCallArgumentSyntax::Cursor::Label,
+                              tok::identifier);
+    syntax_assert_child_token_text(Raw,
+                                   FunctionCallArgumentSyntax::Cursor::Colon,
+                                   tok::colon, ":");
+    assert(
+      Raw->getChild(FunctionCallArgumentSyntax::Cursor::Expression)->isExpr());
+
+    syntax_assert_child_token_text(Raw,
+                                   FunctionCallArgumentSyntax::Cursor::Comma,
+                                   tok::comma, ",");
+}
+
+RC<FunctionCallArgumentSyntaxData>
+FunctionCallArgumentSyntaxData::make(RC<RawSyntax> Raw,
+                                     const SyntaxData *Parent,
+                                     CursorIndex IndexInParent) {
+  return RC<FunctionCallArgumentSyntaxData> {
+    new FunctionCallArgumentSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<FunctionCallArgumentSyntaxData> FunctionCallArgumentSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgument,
+                             {
+                               TokenSyntax::missingToken(tok::identifier, ""),
+                               TokenSyntax::missingToken(tok::colon, ":"),
+                               RawSyntax::missing(SyntaxKind::MissingExpr),
+                               TokenSyntax::missingToken(tok::comma, ",")
+                             },
+                             SourcePresence::Present);
+  return make(Raw);
+}
+
+#pragma mark - function-call-argument API
+
+FunctionCallArgumentSyntax::
+FunctionCallArgumentSyntax(const RC<SyntaxData> Root, const DataType *Data)
+  : Syntax(Root, Data) {}
+
+RC<TokenSyntax> FunctionCallArgumentSyntax::getLabel() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Label));
+}
+
+FunctionCallArgumentSyntax
+FunctionCallArgumentSyntax::withLabel(RC<TokenSyntax> NewLabel) const {
+  assert(NewLabel->getTokenKind() == tok::identifier);
+  return Data->replaceChild<FunctionCallArgumentSyntax>(NewLabel,
+                                                        Cursor::Label);
+}
+
+RC<TokenSyntax> FunctionCallArgumentSyntax::getColonToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Colon));
+}
+
+FunctionCallArgumentSyntax
+FunctionCallArgumentSyntax::withColonToken(RC<TokenSyntax> NewColon) const {
+  syntax_assert_token_is(NewColon, tok::colon, ":");
+  return Data->replaceChild<FunctionCallArgumentSyntax>(NewColon,
+                                                        Cursor::Colon);
+}
+
+llvm::Optional<ExprSyntax> FunctionCallArgumentSyntax::getExpression() const {
+
+  auto RawExpression = getRaw()->getChild(Cursor::Expression);
+  if (RawExpression->isMissing()) {
+    return llvm::None;
+  }
+
+  auto *MyData = getUnsafeData<FunctionCallArgumentSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedExpression);
+
+  SyntaxData::realizeSyntaxNode<ExprSyntax>(ChildPtr, RawExpression, MyData,
+                                            cursorIndex(Cursor::Expression));
+  
+  return ExprSyntax { Root, MyData->CachedExpression.get() };
+}
+
+FunctionCallArgumentSyntax
+FunctionCallArgumentSyntax::withExpression(ExprSyntax NewExpression) const {
+  return Data->replaceChild<FunctionCallArgumentSyntax>(NewExpression.getRaw(),
+                                                        Cursor::Expression);
+}
+
+RC<TokenSyntax> FunctionCallArgumentSyntax::getTrailingComma() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Comma));
+}
+
+FunctionCallArgumentSyntax FunctionCallArgumentSyntax::
+withTrailingComma(RC<TokenSyntax> NewTrailingComma) const {
+  syntax_assert_token_is(NewTrailingComma, tok::comma, ",");
+  return Data->replaceChild<FunctionCallArgumentSyntax>(NewTrailingComma,
+    FunctionCallArgumentSyntax::Cursor::Comma);
+}
+
+#pragma mark - function-call-argument-list Data
+
+FunctionCallArgumentListSyntaxData::
+FunctionCallArgumentListSyntaxData(const RC<RawSyntax> Raw,
+                                   const SyntaxData *Parent,
+                                   CursorIndex IndexInParent)
+  : SyntaxData(Raw, Parent, IndexInParent) {
+#ifndef NDEBUG
+  for (auto Child : Raw->Layout) {
+    assert(Child->Kind == SyntaxKind::FunctionCallArgument);
+  }
+#endif
+  for (size_t i = 0; i < Raw->Layout.size(); ++i) {
+    CachedArguments.emplace_back(nullptr);
+  }
+}
+
+RC<FunctionCallArgumentListSyntaxData>
+FunctionCallArgumentListSyntaxData::make(RC<RawSyntax> Raw,
+                                         const SyntaxData *Parent,
+                                         CursorIndex IndexInParent) {
+  return RC<FunctionCallArgumentListSyntaxData> {
+    new FunctionCallArgumentListSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<FunctionCallArgumentListSyntaxData>
+FunctionCallArgumentListSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgumentList, {},
+                             SourcePresence::Present);
+  return make(Raw);
+}
+
+#pragma mark - function-call-argument-list API
+
+FunctionCallArgumentListSyntax::
+FunctionCallArgumentListSyntax(const RC<SyntaxData> Root,
+                               const DataType *Data)
+  : Syntax(Root, Data) {}
+
+size_t
+FunctionCallArgumentListSyntax::getNumArguments() const {
+  return getRaw()->Layout.size();
+}
+
+FunctionCallArgumentSyntax
+FunctionCallArgumentListSyntax::getArgument(size_t Index) const {
+  assert(Index <= getRaw()->Layout.size());
+
+  auto RawArg = getRaw()->Layout[Index];
+
+  auto *MyData = getUnsafeData<FunctionCallArgumentListSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    MyData->CachedArguments.data() + Index);
+
+  SyntaxData::realizeSyntaxNode<FunctionCallArgumentSyntax>(ChildPtr, RawArg,
+                                                            MyData,
+                                                            Index);
+
+  return FunctionCallArgumentSyntax {
+    Root,
+    MyData->CachedArguments[Index].get()
+  };
+}
+
+FunctionCallArgumentListSyntax
+FunctionCallArgumentListSyntax::withAdditionalArgument(
+  FunctionCallArgumentSyntax AdditionalArgument) const {
+  auto NewRaw = getRaw()->append(AdditionalArgument.getRaw());
+  return Data->replaceSelf<FunctionCallArgumentListSyntax>(NewRaw);
+}
+
+#pragma mark - function-call-expression Data
+
+RC<FunctionCallArgumentListSyntaxData> CachedArgumentList;
+
+FunctionCallExprSyntaxData::FunctionCallExprSyntaxData(RC<RawSyntax> Raw,
+                           const SyntaxData *Parent,
+                           CursorIndex IndexInParent)
+    : ExprSyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Layout.size() == 4);
+  assert(Raw->getChild(FunctionCallExprSyntax::Cursor::CalledExpression)
+           ->isExpr());
+  syntax_assert_child_token_text(Raw, FunctionCallExprSyntax::Cursor::LeftParen,
+                                 tok::l_paren, "(");
+  syntax_assert_child_kind(Raw, FunctionCallExprSyntax::Cursor::ArgumentList,
+                           SyntaxKind::FunctionCallArgumentList);
+  syntax_assert_child_token_text(Raw,
+                                 FunctionCallExprSyntax::Cursor::RightParen,
+                                 tok::r_paren, ")");
+}
+
+RC<FunctionCallExprSyntaxData>
+FunctionCallExprSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
+                                 CursorIndex IndexInParent) {
+  return RC<FunctionCallExprSyntaxData> {
+    new FunctionCallExprSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<FunctionCallExprSyntaxData> FunctionCallExprSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionCallExpr,
+  {
+    RawSyntax::missing(SyntaxKind::MissingExpr),
+    TokenSyntax::missingToken(tok::l_paren, "("),
+    RawSyntax::missing(SyntaxKind::FunctionCallArgumentList),
+    TokenSyntax::missingToken(tok::r_paren, ")"),
+  },
+  SourcePresence::Present);
+  return make(Raw);
+}
+
+
+#pragma mark - function-call-expression API
+
+FunctionCallExprSyntax::FunctionCallExprSyntax(const RC<SyntaxData> Root,
+                                               const DataType *Data)
+  : ExprSyntax(Root, Data) {}
+
+ExprSyntax FunctionCallExprSyntax::getCalledExpression() const {
+  auto RawArg = getRaw()->getChild(Cursor::CalledExpression);
+
+  auto *MyData = getUnsafeData<FunctionCallExprSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedCalledExpression);
+
+  SyntaxData::realizeSyntaxNode<ExprSyntax>(
+    ChildPtr, RawArg, MyData, cursorIndex(Cursor::CalledExpression));
+
+  return ExprSyntax {
+    Root,
+    MyData->CachedCalledExpression.get(),
+  };
+}
+
+FunctionCallExprSyntax FunctionCallExprSyntax::
+withCalledExpression(ExprSyntax NewBaseExpression) const {
+  return Data->replaceChild<FunctionCallExprSyntax>(NewBaseExpression.getRaw(),
+                                                    Cursor::CalledExpression);
+}
+
+RC<TokenSyntax> FunctionCallExprSyntax::getLeftParen() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::LeftParen));
+}
+
+FunctionCallExprSyntax
+FunctionCallExprSyntax::withLeftParen(RC<TokenSyntax> NewLeftParen) const {
+  syntax_assert_token_is(NewLeftParen, tok::l_paren, "(");
+  return Data->replaceChild<FunctionCallExprSyntax>(NewLeftParen,
+                                                    Cursor::LeftParen);
+}
+
+FunctionCallArgumentListSyntax FunctionCallExprSyntax::getArgumentList() const {
+  auto RawArg = getRaw()->getChild(Cursor::ArgumentList);
+
+  auto *MyData = getUnsafeData<FunctionCallExprSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedArgumentList);
+
+  SyntaxData::realizeSyntaxNode<FunctionCallArgumentListSyntax>(
+    ChildPtr, RawArg, MyData, cursorIndex(Cursor::ArgumentList));
+  
+  return FunctionCallArgumentListSyntax {
+    Root,
+    MyData->CachedArgumentList.get(),
+  };
+}
+
+FunctionCallExprSyntax FunctionCallExprSyntax::
+withArgumentList(FunctionCallArgumentListSyntax NewArgumentList) const {
+  return Data->replaceChild<FunctionCallExprSyntax>(NewArgumentList.getRaw(),
+                                                    Cursor::ArgumentList);
+}
+
+RC<TokenSyntax> FunctionCallExprSyntax::getRightParen() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::RightParen));
+}
+
+FunctionCallExprSyntax
+FunctionCallExprSyntax::withRightParen(RC<TokenSyntax> NewRightParen) const {
+  syntax_assert_token_is(NewRightParen, tok::r_paren, ")");
+  return Data->replaceChild<FunctionCallExprSyntax>(NewRightParen,
+                                                    Cursor::RightParen);
+}
+
+#pragma mark - function-call-expression Builder
+
+FunctionCallExprSyntaxBuilder::FunctionCallExprSyntaxBuilder()
+  : CallLayout(FunctionCallExprSyntaxData::makeBlank()->getRaw()->Layout),
+    ListLayout(
+      FunctionCallArgumentListSyntaxData::makeBlank()->getRaw()->Layout) {}
+
+FunctionCallExprSyntaxBuilder &
+FunctionCallExprSyntaxBuilder::useLeftParen(RC<TokenSyntax> LeftParen) {
+  syntax_assert_token_is(LeftParen, tok::l_paren, "(");
+  CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::LeftParen)]
+    = LeftParen;
+  return *this;
+}
+
+FunctionCallExprSyntaxBuilder &FunctionCallExprSyntaxBuilder::
+appendArgument(FunctionCallArgumentSyntax AdditionalArgument) {
+  ListLayout.push_back(AdditionalArgument.getRaw());
+  return *this;
+}
+
+FunctionCallExprSyntaxBuilder &FunctionCallExprSyntaxBuilder::
+useCalledExpression(ExprSyntax CalledExpression) {
+  CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::CalledExpression)]
+    = CalledExpression.getRaw();
+  return *this;
+}
+
+FunctionCallExprSyntaxBuilder &
+FunctionCallExprSyntaxBuilder::useRightParen(RC<TokenSyntax> RightParen) {
+  syntax_assert_token_is(RightParen, tok::r_paren, ")");
+  CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::RightParen)]
+    = RightParen;
+  return *this;
+}
+
+FunctionCallExprSyntax FunctionCallExprSyntaxBuilder::build() const {
+  auto RawArgs = RawSyntax::make(SyntaxKind::FunctionCallArgumentList,
+                                 ListLayout, SourcePresence::Present);
+  auto RawCall = RawSyntax::make(SyntaxKind::FunctionCallExpr, CallLayout,
+                                 SourcePresence::Present)
+    ->replaceChild(FunctionCallExprSyntax::Cursor::ArgumentList, RawArgs);
+  auto Data = FunctionCallExprSyntaxData::make(RawCall);
+  return { Data, Data.get() };
+}
diff --git a/lib/Syntax/Format.cpp b/lib/Syntax/Format.cpp
index 94433ac..1da34c7 100644
--- a/lib/Syntax/Format.cpp
+++ b/lib/Syntax/Format.cpp
@@ -1,4 +1,4 @@
-//===--- Format.cpp - Declaration Syntax Formatting Impl. -------*- C++ -*-===//
+//===--- Format.cpp - Declaration Syntax Formatting Impl. -----------------===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/Syntax/GenericSyntax.cpp b/lib/Syntax/GenericSyntax.cpp
index 84ca22e..e48e33a 100644
--- a/lib/Syntax/GenericSyntax.cpp
+++ b/lib/Syntax/GenericSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- GenericSyntax.cpp - Swift Generic Syntax Implementation *- C++ -*-===//
+//===--- GenericSyntax.cpp - Swift Generic Syntax Implementation ----------===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/Syntax/LegacyASTTransformer.cpp b/lib/Syntax/LegacyASTTransformer.cpp
index f6c4edd..4356df0 100644
--- a/lib/Syntax/LegacyASTTransformer.cpp
+++ b/lib/Syntax/LegacyASTTransformer.cpp
@@ -1,4 +1,4 @@
-//===--- LegacyASTTransformer.cpp - Swift lib/AST -> lib/Syntax -*- C++ -*-===//
+//===--- LegacyASTTransformer.cpp - Swift lib/AST -> lib/Syntax -----------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -19,6 +19,7 @@
 #include "swift/Syntax/StmtSyntax.h"
 #include "swift/Syntax/SyntaxFactory.h"
 #include "swift/Syntax/TokenSyntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 using namespace swift;
 using namespace swift::syntax;
@@ -500,7 +501,7 @@
 RC<SyntaxData>
 LegacyASTTransformer::visitWhileStmt(WhileStmt *S,
                                      const SyntaxData *Parent,
-                                     const CursorIndex IndexInParent) {
+                                     const CursorIndex IndexInParent) { 
   return getUnknownStmt(S);
 }
 
diff --git a/lib/Syntax/RawSyntax.cpp b/lib/Syntax/RawSyntax.cpp
index 1d37ee8..30d5508 100644
--- a/lib/Syntax/RawSyntax.cpp
+++ b/lib/Syntax/RawSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- RawSyntax.cpp - Swift Raw Syntax Implementation --------*- C++ -*-===//
+//===--- RawSyntax.cpp - Swift Raw Syntax Implementation ------------------===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/Syntax/Status.md b/lib/Syntax/Status.md
index 97fba0c..1c8a324 100644
--- a/lib/Syntax/Status.md
+++ b/lib/Syntax/Status.md
@@ -72,6 +72,16 @@
 - octal-literal
   - `IntegerLiteralExprSyntax`
 
+- function-call-argument
+  - `FunctionCallArgumentSyntax`
+
+- function-call-argument-list
+  - `FunctionCallArgumentListSyntax`
+
+- function-call-expression
+- function-call-argument-clause
+  - `FunctionCallExprSyntax`
+
 ### Types
 
 - type
@@ -105,6 +115,15 @@
 - metatype-type
   - `MetatypeTypeSyntax`
 
+- tuple-type
+  - `TupleTypeSyntax`
+
+- tuple-type-element
+  - `TupleTypeElementSyntax`
+
+- tuple-type-element-list
+  - `TupleTypeElementListSyntax`
+
 ### Type Attributes
 
 - attribute
@@ -181,165 +200,163 @@
 
 ## Unrepresented Grammar Productions
 
-- argument-names
+These are categorized somewhat by difficulty and priority.
+
+### Easy
+
 - array-literal
 - array-literal-items
 - as-pattern
-- availability-argument
-- availability-arguments
-- availability-condition
-- binary-expression
-- binary-expressions
-- binary-operator
-- branch-statement
-- capture-list
-- capture-list-item
-- capture-list-items
-- capture-specifier
 - case-condition
-- case-item-list
 - case-label
-- catch-clause
-- catch-clauses
-- class-declaration
-- closure-expression
-- closure-parameter
-- closure-parameter-clause
-- closure-parameter-list
-- closure-signature
-- compilation-condition
-- compiler-control-statement
-- condition
-- condition-list
-- conditional-compilation-block
-- conditional-operator
-- constant-declaration
-- declaration-modifier
 - declaration-modifiers
-- defer-statement
-- deinitializer-declaration
-- dictionary-literal
-- dictionary-literal-item
-- dictionary-literal-items
-- didSet-clause
-- do-statement
+  - declaration-modifier
 - dynamic-type-expression
-- else-clause
-- else-directive-clause
-- elseif-directive-clause
-- elseif-directive-clauses
-- enum-case-pattern
-- enum-declaration
-- explicit-member-expression
-- expression-list
-- expression-pattern
-- extension-declaration
-- extension-members
 - floating-point-literal
-- for-in-statement
 - forced-value-expression
-- function-body
-- function-call-argument
-- function-call-argument-clause
-- function-call-argument-list
-- function-call-expression
-- function-declaration
-- function-result
-- function-signature
-- getter-clause
-- getter-keyword-clause
-- getter-setter-block
-- getter-setter-keyword-block
-- guard-statement
 - identifier-list
-- if-directive-clause
-- if-statement
 - implicit-member-expression
-- import-declaration
 - import-path
 - in-out-expression
-- infix-operator-declaration
-- infix-operator-group
-- initializer-declaration
-- initializer-head
-- interpolated-string-literal
 - interpolated-text
 - interpolated-text-item
 - is-pattern
 - key-path-expression
 - line-control-statement
-- operator-declaration
-- optional-binding-condition
 - optional-chaining-expression
 - optional-pattern
-- parameter
-- parameter-clause
-- parameter-list
 - parenthesized-expression
-- pattern
-- pattern-initializer
-- pattern-initializer-list
 - platform-condition
 - platform-version
-- playground-literal
 - postfix-operator-declaration
 - precedence-group-assignment
 - precedence-group-associativity
-- precedence-group-attribute
-- precedence-group-attributes
-- precedence-group-declaration
 - precedence-group-names
-- precedence-group-relation
-- prefix-expression
-- prefix-operator
-- prefix-operator-declaration
-- primary-expression
-- protocol-associated-type-declaration
-- protocol-composition-type
-- protocol-declaration
-- repeat-while-statement
-- selector-expression
-- setter-clause
-- setter-keyword-clause
-- setter-name
 - statement-label
 - static-string-literal
-- string-literal
-- subscript-declaration
 - swift-version
-- switch-case
-- switch-cases
-- switch-statement
 - throw-statement
-- tuple-element
-- tuple-element-list
-- tuple-expression
-- tuple-pattern
-- tuple-pattern-element
-- tuple-pattern-element-list
-- tuple-type
-- tuple-type-element
-- tuple-type-element-list
-- type-casting-operator
-- type-casting-pattern
 - value-binding-pattern
-- variable-declaration
 - where-clause
-- where-expression
+- dictionary-literal
+  - dictionary-literal-items
+    - dictionary-literal-item
+- capture-list
+    - capture-list-items
+      - capture-list-item
+- defer-statement
+
+### Medium
+
+- else-directive-clause
+- elseif-directive-clauses
+  - elseif-directive-clause
+- precedence-group-declaration
+- precedence-group-relation
+- expression-list
+- availability-condition
+  - availability-arguments
+    - availability-argument
+- switch-cases
+  - switch-case
+- constant-declaration
+- catch-clauses
+  - catch-clause
+- variable-declaration
+- do-statement
+- for-in-statement
+- guard-statement
+- case-item-list
+- import-declaration
+- if-directive-clause
+- if-statement
+  - else-clause
+- protocol-associated-type-declaration
+- repeat-while-statement
 - while-statement
+- tuple-expression
+  - tuple-element-list
+    - tuple-element
+- tuple-pattern
+  - tuple-pattern-element-list
+    - tuple-pattern-element
+- switch-statement
+- explicit-member-expression
+- optional-binding-condition
+- operator-declaration
+- selector-expression
+- protocol-composition-type
+- conditional-operator
+- deinitializer-declaration
+- didSet-clause
 - willSet-clause
-- willSet-didSet-block
+- pattern-initializer-list
+  - pattern-initializer
+- prefix-expression
+- prefix-operator-declaration
+- infix-operator-declaration
+  - infix-operator-group
+- binary-expression
+
+### Hard
+
+- protocol-declaration
+- closure-expression
+  - closure-signature
+    - closure-parameter-clause
+      - closure-parameter-list
+        - closure-parameter
+- extension-declaration
+- enum-declaration
+- class-declaration
+- getter-setter-block
+  - getter-setter-keyword-block
+  - getter-keyword-clause
+    - getter-clause
+  - setter-keyword-clause
+    - setter-clause
+      - setter-name
+- subscript-declaration
+- function-declaration
+  - function-body
+  - function-result
+  - function-signature
+    - parameter-clause
+      - parameter-list
+        - parameter
+- enum-case-pattern
+- initializer-declaration
+  - initializer-head
+- interpolated-string-literal
+- conditional-compilation-block
 
 ## Trivial and Intermediate Grammar Productions
 
+- binary-expressions
+- binary-operator
+- compilation-condition
+- capture-specifier
+- precedence-group-attributes
+- precedence-group-attribute
+- prefix-operator
+- type-casting-operator
+- willSet-didSet-block
 - architecture
+- string-literal
+- argument-names
 - array-literal-item
+- type-casting-pattern
 - assignment-operator
+- expression-pattern
 - binary-digit
 - binary-literal-character
 - binary-literal-characters
+- branch-statement
 - class-member
 - class-requirement
+- condition
+- condition-list
+- compiler-control-statement
 - control-transfer-statement
 - decimal-digit
 - decimal-digits
@@ -369,6 +386,7 @@
 - identifier-characters
 - identifier-head
 - if-directive
+- where-expression
 - implicit-parameter-name
 - initializer
 - initializer-body
@@ -388,6 +406,7 @@
 - operator-character
 - operator-characters
 - operator-head
+- pattern
 - postfix-expression
 - postfix-operator
 - postfix-self-expression
@@ -396,6 +415,7 @@
 - protocol-member
 - protocol-member-declaration
 - protocol-members
+- extension-members
 - protocol-method-declaration
 - protocol-property-declaration
 - protocol-subscript-declaration
@@ -407,6 +427,7 @@
 - raw-value-style-enum-case
 - raw-value-style-enum-case-clause
 - raw-value-style-enum-case-list
+- playground-literal
 - raw-value-style-enum-member
 - raw-value-style-enum-members
 - requirement
@@ -436,9 +457,5 @@
 - variable-declaration-head
 - wildcard-expression
 - wildcard-pattern
-
-## Intermediate Grammar Productions
-
-These productions don't need to be represented directly in a class hierarchy.
-
+- primary-expression
 - generic-argument
diff --git a/lib/Syntax/StmtSyntax.cpp b/lib/Syntax/StmtSyntax.cpp
index 7f32017..89b272c 100644
--- a/lib/Syntax/StmtSyntax.cpp
+++ b/lib/Syntax/StmtSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- StmtSyntax.cpp - Swift Statement Syntax Implementation -*- C++ -*-===//
+//===--- StmtSyntax.cpp - Swift Statement Syntax Implementation -----------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -27,7 +27,7 @@
 UnknownStmtSyntaxData::UnknownStmtSyntaxData(RC<RawSyntax> Raw,
                                              const SyntaxData *Parent,
                                              CursorIndex IndexInParent)
-  : StmtSyntaxData(Raw, Parent, IndexInParent) {
+  : UnknownSyntaxData(Raw, Parent, IndexInParent) {
   assert(Raw->Kind == SyntaxKind::UnknownStmt);
 }
 
@@ -35,9 +35,11 @@
 UnknownStmtSyntaxData::make(RC<RawSyntax> Raw,
                             const SyntaxData *Parent,
                             CursorIndex IndexInParent) {
+  auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownStmt, Raw->Layout,
+                                    Raw->Presence);
   return RC<UnknownStmtSyntaxData> {
     new UnknownStmtSyntaxData {
-      Raw, Parent, IndexInParent
+      UnknownRaw, Parent, IndexInParent
     }
   };
 }
@@ -46,7 +48,7 @@
 
 UnknownStmtSyntax::UnknownStmtSyntax(const RC<SyntaxData> Root,
                                      const UnknownStmtSyntaxData *Data)
-  : StmtSyntax(Root, Data) {}
+  : UnknownSyntax(Root, Data) {}
 
 #pragma mark fallthrough-statement Data
 
diff --git a/lib/Syntax/Syntax.cpp b/lib/Syntax/Syntax.cpp
index 0d7cc30..bd4d914 100644
--- a/lib/Syntax/Syntax.cpp
+++ b/lib/Syntax/Syntax.cpp
@@ -1,4 +1,4 @@
-//===--- Syntax.cpp - Swift Syntax Implementation ---------------*- C++ -*-===//
+//===--- Syntax.cpp - Swift Syntax Implementation -------------------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -55,16 +55,7 @@
   return Data->isExpr();
 }
 
-#pragma mark - unknown-syntax API
-
-UnknownSyntax::UnknownSyntax(const RC<SyntaxData> Root,
-                             UnknownSyntaxData *Data)
-  : Syntax(Root, Data) {}
-
-UnknownSyntax UnknownSyntax::make(RC<RawSyntax> Raw) {
-  auto Data = UnknownSyntaxData::make(Raw);
-  return UnknownSyntax {
-    Data, Data.get()
-  };
+bool Syntax::isUnknown() const {
+  return Data->isUnknown();
 }
 
diff --git a/lib/Syntax/SyntaxData.cpp b/lib/Syntax/SyntaxData.cpp
index 56ecd4b..bc21dbf 100644
--- a/lib/Syntax/SyntaxData.cpp
+++ b/lib/Syntax/SyntaxData.cpp
@@ -1,4 +1,4 @@
-//===--- SyntaxData.cpp - Swift Syntax Data Implementation ------*- C++ -*-===//
+//===--- SyntaxData.cpp - Swift Syntax Data Implementation ----------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -15,6 +15,7 @@
 #include "swift/Syntax/GenericSyntax.h"
 #include "swift/Syntax/TypeSyntax.h"
 #include "swift/Syntax/StmtSyntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 using namespace swift;
 using namespace swift::syntax;
@@ -61,21 +62,10 @@
   return Raw->isExpr();
 }
 
+bool SyntaxData::isUnknown() const {
+  return Raw->isUnknown();
+}
+
 void SyntaxData::dump(llvm::raw_ostream &OS) const {
   Raw->dump(OS, 0);
 }
-
-#pragma mark - unknown-syntax Data
-
-RC<UnknownSyntaxData> UnknownSyntaxData::make(RC<RawSyntax> Raw,
-                                              const SyntaxData *Parent,
-                                              CursorIndex IndexInParent) {
-  return RC<UnknownSyntaxData> {
-    new UnknownSyntaxData { Raw, Parent, IndexInParent }
-  };
-}
-
-bool UnknownSyntaxData::classof(const SyntaxData *SD) {
-  return SD->getKind() == SyntaxKind::Unknown;
-}
-
diff --git a/lib/Syntax/SyntaxFactory.cpp b/lib/Syntax/SyntaxFactory.cpp
index be37ef9..cd495f2 100644
--- a/lib/Syntax/SyntaxFactory.cpp
+++ b/lib/Syntax/SyntaxFactory.cpp
@@ -1,4 +1,4 @@
-//===--- SyntaxFactory.cpp - Swift Syntax Builder Implementation *- C++ -*-===//
+//===--- SyntaxFactory.cpp - Swift Syntax Builder Implementation ----------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -18,6 +18,7 @@
 #include "swift/Syntax/Syntax.h"
 #include "swift/Syntax/SyntaxFactory.h"
 #include "swift/Syntax/TokenSyntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
 
 using namespace swift;
 using namespace swift::syntax;
@@ -324,6 +325,8 @@
 
 #pragma mark - Expressions
 
+#pragma mark - integer-literal-expression
+
 IntegerLiteralExprSyntax
 SyntaxFactory::makeIntegerLiteralExpr(RC<TokenSyntax> Sign,
                                       RC<TokenSyntax> Digits) {
@@ -348,6 +351,101 @@
   return { Data, Data.get() };
 }
 
+#pragma mark - symbolic-reference
+
+SymbolicReferenceExprSyntax
+SyntaxFactory::makeSymbolicReferenceExpr(RC<TokenSyntax> Identifier,
+  llvm::Optional<GenericArgumentClauseSyntax> GenericArgs) {
+  auto Raw = RawSyntax::make(SyntaxKind::SymbolicReferenceExpr,
+    {
+      Identifier,
+      GenericArgs.hasValue()
+        ? GenericArgs.getValue().getRaw()
+        : RawSyntax::missing(SyntaxKind::GenericArgumentClause)
+    },
+    SourcePresence::Present);
+  auto Data = SymbolicReferenceExprSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+SymbolicReferenceExprSyntax SyntaxFactory::makeBlankSymbolicReferenceExpr() {
+  auto Data = SymbolicReferenceExprSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
+#pragma mark - function-call-argument
+
+FunctionCallArgumentSyntax SyntaxFactory::makeBlankFunctionCallArgument() {
+  auto Data = FunctionCallArgumentSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
+FunctionCallArgumentSyntax
+SyntaxFactory::makeFunctionCallArgument(RC<TokenSyntax> Label,
+                                        RC<TokenSyntax> Colon,
+                                        ExprSyntax ExpressionArgument,
+                                        RC<TokenSyntax> TrailingComma) {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgument,
+                             {
+                               Label,
+                               Colon,
+                               ExpressionArgument.getRaw(),
+                               TrailingComma
+                             },
+                             SourcePresence::Present);
+  auto Data = FunctionCallArgumentSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+#pragma mark - function-call-argument-list
+
+/// Make a function call argument list with the given arguments.
+FunctionCallArgumentListSyntax
+SyntaxFactory::makeFunctionCallArgumentList(
+  std::vector<FunctionCallArgumentSyntax> Arguments) {
+  RawSyntax::LayoutList Layout;
+  for (const auto &Arg : Arguments) {
+    Layout.push_back(Arg.getRaw());
+  }
+
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgumentList, Layout,
+                             SourcePresence::Present);
+  auto Data = FunctionCallArgumentListSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+
+FunctionCallArgumentListSyntax
+SyntaxFactory::makeBlankFunctionCallArgumentList() {
+  auto Data = FunctionCallArgumentListSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
+#pragma mark - function-call-expression
+
+FunctionCallExprSyntax
+SyntaxFactory::makeFunctionCallExpr(ExprSyntax CalledExpr,
+                                    RC<TokenSyntax> LeftParen,
+                                    FunctionCallArgumentListSyntax Arguments,
+                                    RC<TokenSyntax> RightParen) {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionCallExpr,
+                             {
+                               CalledExpr.getRaw(),
+                               LeftParen,
+                               Arguments.getRaw(),
+                               RightParen
+                             },
+                             SourcePresence::Present);
+  auto Data = FunctionCallExprSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+
+FunctionCallExprSyntax SyntaxFactory::makeBlankFunctionCallExpr() {
+  auto Data = FunctionCallExprSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
 
 #pragma mark - Tokens
 
@@ -771,16 +869,7 @@
 }
 
 TypeAttributeSyntax SyntaxFactory::makeBlankTypeAttribute() {
-  auto Raw = RawSyntax::make(SyntaxKind::TypeAttribute,
-                             {
-                               TokenSyntax::missingToken(tok::at_sign, "@"),
-                               TokenSyntax::missingToken(tok::identifier, ""),
-                               TokenSyntax::missingToken(tok::l_paren, "("),
-                               RawSyntax::missing(SyntaxKind::BalancedTokens),
-                               TokenSyntax::missingToken(tok::r_paren, ")"),
-                             },
-                             SourcePresence::Present);
-  auto Data = TypeAttributeSyntaxData::make(Raw);
+  auto Data = TypeAttributeSyntaxData::makeBlank();
   return TypeAttributeSyntax { Data, Data.get() };
 }
 
@@ -798,10 +887,7 @@
 }
 
 BalancedTokensSyntax SyntaxFactory::makeBlankBalancedTokens() {
-  auto Raw = RawSyntax::make(SyntaxKind::BalancedTokens,
-                             {},
-                             SourcePresence::Present);
-  auto Data = BalancedTokensSyntaxData::make(Raw);
+  auto Data = BalancedTokensSyntaxData::makeBlank();
   return BalancedTokensSyntax { Data, Data.get() };
 }
 
diff --git a/lib/Syntax/TokenSyntax.cpp b/lib/Syntax/TokenSyntax.cpp
index 297fb34..2212236 100644
--- a/lib/Syntax/TokenSyntax.cpp
+++ b/lib/Syntax/TokenSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- TokenSyntax.cpp - Swift Token Syntax Implementation ----*- C++ -*-===//
+//===--- TokenSyntax.cpp - Swift Token Syntax Implementation --------------===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/Syntax/Trivia.cpp b/lib/Syntax/Trivia.cpp
index ce1008c..f57738e 100644
--- a/lib/Syntax/Trivia.cpp
+++ b/lib/Syntax/Trivia.cpp
@@ -1,4 +1,4 @@
-//===--- Syntax.cpp - Swift Syntax Trivia Implementation --------*- C++ -*-===//
+//===--- Trivia.cpp - Swift Syntax Trivia Implementation ------------------===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/Syntax/TypeSyntax.cpp b/lib/Syntax/TypeSyntax.cpp
index 5b9d158..d36ecae 100644
--- a/lib/Syntax/TypeSyntax.cpp
+++ b/lib/Syntax/TypeSyntax.cpp
@@ -1,4 +1,4 @@
-//===--- TypeSyntax.cpp - Swift Type Syntax Implementation ------*- C++ -*-===//
+//===--- TypeSyntax.cpp - Swift Type Syntax Implementation ----------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -118,6 +118,19 @@
   };
 }
 
+RC<TypeAttributeSyntaxData> TypeAttributeSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::TypeAttribute,
+                             {
+                               TokenSyntax::missingToken(tok::at_sign, "@"),
+                               TokenSyntax::missingToken(tok::identifier, ""),
+                               TokenSyntax::missingToken(tok::l_paren, "("),
+                               RawSyntax::missing(SyntaxKind::BalancedTokens),
+                               TokenSyntax::missingToken(tok::r_paren, ")"),
+                             },
+                             SourcePresence::Present);
+  return make(Raw);
+}
+
 #pragma mark - type-attribute API
 
 TypeAttributeSyntax::TypeAttributeSyntax(RC<SyntaxData> Root,
diff --git a/lib/Syntax/UnknownSyntax.cpp b/lib/Syntax/UnknownSyntax.cpp
new file mode 100644
index 0000000..6533926
--- /dev/null
+++ b/lib/Syntax/UnknownSyntax.cpp
@@ -0,0 +1,99 @@
+//===--- UnknownSyntax.cpp - Swift Unknown  Syntax Implementation ---------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Syntax/TokenSyntax.h"
+#include "swift/Syntax/UnknownSyntax.h"
+
+using namespace swift;
+using namespace swift::syntax;
+
+#pragma mark - unknown-syntax Data
+
+UnknownSyntaxData::UnknownSyntaxData(const RC<RawSyntax> Raw,
+                                     const SyntaxData *Parent,
+                                     const CursorIndex IndexInParent)
+    : SyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->isUnknown());
+  for (auto RawChild : Raw->Layout) {
+    if (!RawChild->isToken()) {
+      CachedChildren.emplace_back(nullptr);
+    }
+  }
+}
+
+RC<UnknownSyntaxData> UnknownSyntaxData::make(RC<RawSyntax> Raw,
+                                              const SyntaxData *Parent,
+                                              CursorIndex IndexInParent) {
+
+  auto UnknownRaw = RawSyntax::make(SyntaxKind::Unknown, Raw->Layout,
+                                    Raw->Presence);
+
+  return RC<UnknownSyntaxData> {
+    new UnknownSyntaxData { UnknownRaw, Parent, IndexInParent }
+  };
+}
+
+#pragma mark - unknown-syntax API
+
+UnknownSyntax::UnknownSyntax(const RC<SyntaxData> Root,
+                             const UnknownSyntaxData *Data)
+  : Syntax(Root, Data) {}
+
+size_t UnknownSyntax::getNumChildren() const {
+  size_t Count = 0;
+  for (auto Child : getRaw()->Layout) {
+    if (Child->isToken()) {
+      continue;
+    }
+    ++Count;
+  }
+  return Count;
+}
+
+Syntax UnknownSyntax::getChild(const size_t N) const {
+  auto *MyData = getUnsafeData<UnknownSyntax>();
+
+  if (auto RealizedChild = MyData->CachedChildren[N]) {
+    return Syntax { Root, RealizedChild.get() };
+  }
+
+  assert(N < getNumChildren());
+  assert(N < getRaw()->Layout.size());
+
+  CursorIndex ChildLayoutIndex = 0;
+
+  for (size_t LayoutIndex = 0, Left = N;
+       LayoutIndex < getRaw()->Layout.size();
+       ++LayoutIndex) {
+    auto Child = getRaw()->Layout[LayoutIndex];
+    if (Child->isToken()) {
+      continue;
+    }
+    ChildLayoutIndex = LayoutIndex;
+    if (Left == 0) {
+      break;
+    }
+    --Left;
+  }
+
+  auto RawChild = getRaw()->Layout[ChildLayoutIndex];
+  assert(RawChild->Kind != SyntaxKind::Token);
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    MyData->CachedChildren.data() + N);
+
+  SyntaxData::realizeSyntaxNode<Syntax>(ChildPtr, RawChild, MyData,
+                                        ChildLayoutIndex);
+
+  return Syntax { Root, MyData->CachedChildren[N].get() };
+}
+
diff --git a/stdlib/public/SwiftShims/RefCount.h b/stdlib/public/SwiftShims/RefCount.h
index 7b59508..95f102b 100644
--- a/stdlib/public/SwiftShims/RefCount.h
+++ b/stdlib/public/SwiftShims/RefCount.h
@@ -745,6 +745,9 @@
   LLVM_ATTRIBUTE_NOINLINE
   bool tryIncrementSlow(RefCountBits oldbits);
 
+  LLVM_ATTRIBUTE_NOINLINE
+  bool tryIncrementNonAtomicSlow(RefCountBits oldbits);
+
   public:
   enum Initialized_t { Initialized };
 
@@ -859,6 +862,19 @@
     return true;
   }
 
+  bool tryIncrementNonAtomic() {
+    auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
+    if (!oldbits.hasSideTable() && oldbits.getIsDeiniting())
+      return false;
+
+    auto newbits = oldbits;
+    bool fast = newbits.incrementStrongExtraRefCount(1);
+    if (!fast)
+      return tryIncrementNonAtomicSlow(oldbits);
+    refCounts.store(newbits, std::memory_order_relaxed);
+    return true;
+  }
+
   // Simultaneously clear the pinned flag and decrement the reference
   // count. Call _swift_release_dealloc() if the reference count goes to zero.
   //
@@ -881,6 +897,11 @@
   }
 
   LLVM_ATTRIBUTE_ALWAYS_INLINE
+  bool decrementShouldDeinitNonAtomic(uint32_t dec) {
+    return doDecrementNonAtomic<DontClearPinnedFlag, DontPerformDeinit>(dec);
+  }
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
   void decrementAndMaybeDeinit(uint32_t dec) {
     doDecrement<DontClearPinnedFlag, DoPerformDeinit>(dec);
   }
@@ -979,7 +1000,12 @@
   // object may have a side table entry.
   template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
   bool doDecrementSideTable(RefCountBits oldbits, uint32_t dec);
-  
+
+  // Second slow path of doDecrementNonAtomic, where the
+  // object may have a side table entry.
+  template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
+  bool doDecrementNonAtomicSideTable(RefCountBits oldbits, uint32_t dec);
+
   // First slow path of doDecrement, where the object may need to be deinited.
   // Side table is handled in the second slow path, doDecrementSideTable().
   template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
@@ -1021,6 +1047,42 @@
 
     return deinitNow;
   }
+
+  // First slow path of doDecrementNonAtomic, where the object may need to be deinited.
+  // Side table is handled in the second slow path, doDecrementNonAtomicSideTable().
+  template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
+  bool doDecrementNonAtomicSlow(RefCountBits oldbits, uint32_t dec) {
+    bool deinitNow;
+    auto newbits = oldbits;
+
+    bool fast = newbits.decrementStrongExtraRefCount(dec, clearPinnedFlag);
+    if (fast) {
+      // Decrement completed normally. New refcount is not zero.
+      deinitNow = false;
+    }
+    else if (oldbits.hasSideTable()) {
+      // Decrement failed because we're on some other slow path.
+      return doDecrementNonAtomicSideTable<clearPinnedFlag,
+                                           performDeinit>(oldbits, dec);
+    }
+    else {
+      // Decrement underflowed. Begin deinit.
+      // LIVE -> DEINITING
+      deinitNow = true;
+      assert(!oldbits.getIsDeiniting());  // FIXME: make this an error?
+      newbits = oldbits;  // Undo failed decrement of newbits.
+      newbits.setStrongExtraRefCount(0);
+      newbits.setIsDeiniting(true);
+      if (clearPinnedFlag)
+        newbits.setIsPinned(false);
+    }
+    refCounts.store(newbits, std::memory_order_relaxed);
+    if (performDeinit && deinitNow) {
+      _swift_release_dealloc(getHeapObject());
+    }
+
+    return deinitNow;
+  }
   
   public:  // FIXME: access control hack
 
@@ -1045,8 +1107,6 @@
 
     return false;  // don't deinit
   }
-  
-  private:
 
   // This is independently specialized below for inline and out-of-line use.
   template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
@@ -1072,6 +1132,18 @@
                                               std::memory_order_relaxed));
   }
 
+  void incrementUnownedNonAtomic(uint32_t inc) {
+    auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
+    if (oldbits.hasSideTable())
+      return oldbits.getSideTable()->incrementUnownedNonAtomic(inc);
+
+    auto newbits = oldbits;
+    assert(newbits.getUnownedRefCount() != 0);
+    newbits.incrementUnownedRefCount(inc);
+    // FIXME: overflow check?
+    refCounts.store(newbits, std::memory_order_relaxed);
+  }
+
   // Decrement the unowned reference count.
   // Return true if the caller should free the object.
   bool decrementUnownedShouldFree(uint32_t dec) {
@@ -1086,7 +1158,7 @@
       newbits = oldbits;
       newbits.decrementUnownedRefCount(dec);
       if (newbits.getUnownedRefCount() == 0) {
-        // DEINITED -> FREED  or  DEINITED -> DEAD
+        // DEINITED -> FREED, or DEINITED -> DEAD
         // Caller will free the object. Weak decrement is handled by
         // HeapObjectSideTableEntry::decrementUnownedShouldFree.
         assert(newbits.getIsDeiniting());
@@ -1100,6 +1172,29 @@
     return performFree;
   }
 
+  bool decrementUnownedShouldFreeNonAtomic(uint32_t dec) {
+    auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
+
+    if (oldbits.hasSideTable())
+      return oldbits.getSideTable()->decrementUnownedShouldFreeNonAtomic(dec);
+
+    bool performFree;
+    auto newbits = oldbits;
+    newbits.decrementUnownedRefCount(dec);
+    if (newbits.getUnownedRefCount() == 0) {
+      // DEINITED -> FREED, or DEINITED -> DEAD
+      // Caller will free the object. Weak decrement is handled by
+      // HeapObjectSideTableEntry::decrementUnownedShouldFreeNonAtomic.
+      assert(newbits.getIsDeiniting());
+      performFree = true;
+    } else {
+      performFree = false;
+    }
+    // FIXME: underflow check?
+    refCounts.store(newbits, std::memory_order_relaxed);
+    return performFree;
+  }
+
   // Return unowned reference count.
   // Note that this is not equal to the number of outstanding unowned pointers.
   uint32_t getUnownedCount() const {
@@ -1146,6 +1241,16 @@
 
     return performFree;
   }
+
+  bool decrementWeakShouldCleanUpNonAtomic() {
+    auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
+
+    auto newbits = oldbits;
+    auto performFree = newbits.decrementWeakRefCount();
+    refCounts.store(newbits, std::memory_order_relaxed);
+
+    return performFree;
+  }
   
   // Return weak reference count.
   // Note that this is not equal to the number of outstanding weak pointers.
@@ -1226,9 +1331,13 @@
     return refCounts.doDecrement<clearPinnedFlag, performDeinit>(dec);
   }
 
+  template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
+  bool decrementNonAtomicStrong(uint32_t dec) {
+    return refCounts.doDecrementNonAtomic<clearPinnedFlag, performDeinit>(dec);
+  }
+
   void decrementFromOneNonAtomic() {
-    // FIXME: can there be a non-atomic implementation?
-    decrementStrong<DontClearPinnedFlag, DontPerformDeinit>(1);
+    decrementNonAtomicStrong<DontClearPinnedFlag, DontPerformDeinit>(1);
   }
   
   bool isDeiniting() const {
@@ -1243,6 +1352,16 @@
     return refCounts.tryIncrementAndPin();
   }
 
+  bool tryIncrementNonAtomic() {
+    return refCounts.tryIncrementNonAtomic();
+  }
+
+  bool tryIncrementAndPinNonAtomic() {
+    return refCounts.tryIncrementAndPinNonAtomic();
+  }
+
+  // Return weak reference count.
+  // Note that this is not equal to the number of outstanding weak pointers.
   uint32_t getCount() const {
     return refCounts.getCount();
   }
@@ -1257,6 +1376,10 @@
     return refCounts.incrementUnowned(inc);
   }
 
+  void incrementUnownedNonAtomic(uint32_t inc) {
+    return refCounts.incrementUnownedNonAtomic(inc);
+  }
+
   bool decrementUnownedShouldFree(uint32_t dec) {
     bool shouldFree = refCounts.decrementUnownedShouldFree(dec);
     if (shouldFree) {
@@ -1268,6 +1391,17 @@
     return shouldFree;
   }
 
+  bool decrementUnownedShouldFreeNonAtomic(uint32_t dec) {
+    bool shouldFree = refCounts.decrementUnownedShouldFreeNonAtomic(dec);
+    if (shouldFree) {
+      // DEINITED -> FREED
+      // Caller will free the object.
+      decrementWeakNonAtomic();
+    }
+
+    return shouldFree;
+  }
+
   uint32_t getUnownedCount() const {
     return refCounts.getUnownedCount();
   }
@@ -1301,6 +1435,19 @@
     delete this;
   }
 
+  void decrementWeakNonAtomic() {
+    // FIXME: assertions
+    // FIXME: optimize barriers
+    bool cleanup = refCounts.decrementWeakShouldCleanUpNonAtomic();
+    if (!cleanup)
+      return;
+
+    // Weak ref count is now zero. Delete the side table entry.
+    // FREED -> DEAD
+    assert(refCounts.getUnownedCount() == 0);
+    delete this;
+  }
+
   uint32_t getWeakCount() const {
     return refCounts.getWeakCount();
   }
@@ -1327,12 +1474,12 @@
 
   // Use slow path if we can't guarantee atomicity.
   if (oldbits.hasSideTable() || oldbits.getUnownedRefCount() != 1)
-    return doDecrementSlow<clearPinnedFlag, performDeinit>(oldbits, dec);
+    return doDecrementNonAtomicSlow<clearPinnedFlag, performDeinit>(oldbits, dec);
 
   auto newbits = oldbits;
   bool fast = newbits.decrementStrongExtraRefCount(dec, clearPinnedFlag);
   if (!fast)
-    return doDecrementSlow<clearPinnedFlag, performDeinit>(oldbits, dec);
+    return doDecrementNonAtomicSlow<clearPinnedFlag, performDeinit>(oldbits, dec);
 
   refCounts.store(newbits, std::memory_order_relaxed);
   return false;  // don't deinit
@@ -1359,12 +1506,28 @@
 
 template <>
 template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
+inline bool RefCounts<InlineRefCountBits>::
+doDecrementNonAtomicSideTable(InlineRefCountBits oldbits, uint32_t dec) {
+  auto side = oldbits.getSideTable();
+  return side->decrementNonAtomicStrong<clearPinnedFlag, performDeinit>(dec);
+}
+
+template <>
+template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
 inline bool RefCounts<SideTableRefCountBits>::
 doDecrementSideTable(SideTableRefCountBits oldbits, uint32_t dec) {
   swift::crash("side table refcount must not have "
                "a side table entry of its own");
 }
 
+template <>
+template <ClearPinnedFlag clearPinnedFlag, PerformDeinit performDeinit>
+inline bool RefCounts<SideTableRefCountBits>::
+doDecrementNonAtomicSideTable(SideTableRefCountBits oldbits, uint32_t dec) {
+  swift::crash("side table refcount must not have "
+               "a side table entry of its own");
+}
+
 
 template <> inline
 HeapObject* RefCounts<InlineRefCountBits>::getHeapObject() const {
diff --git a/stdlib/public/core/Dump.swift b/stdlib/public/core/Dump.swift
index d4a2ae6..c7a6399 100644
--- a/stdlib/public/core/Dump.swift
+++ b/stdlib/public/core/Dump.swift
@@ -12,6 +12,7 @@
 
 /// Dumps an object's contents using its mirror to the specified output stream.
 @discardableResult
+@_semantics("optimize.sil.specialize.generic.never")
 public func dump<T, TargetStream : TextOutputStream>(
   _ value: T,
   to target: inout TargetStream,
@@ -37,6 +38,7 @@
 
 /// Dumps an object's contents using its mirror to standard output.
 @discardableResult
+@_semantics("optimize.sil.specialize.generic.never")
 public func dump<T>(
   _ value: T,
   name: String? = nil,
@@ -55,6 +57,7 @@
 }
 
 /// Dump an object's contents. User code should use dump().
+@_semantics("optimize.sil.specialize.generic.never")
 internal func _dump_unlocked<TargetStream : TextOutputStream>(
   _ value: Any,
   to target: inout TargetStream,
@@ -153,6 +156,7 @@
 
 /// Dump information about an object's superclass, given a mirror reflecting
 /// that superclass.
+@_semantics("optimize.sil.specialize.generic.never")
 internal func _dumpSuperclass_unlocked<TargetStream : TextOutputStream>(
   mirror: Mirror,
   to target: inout TargetStream,
diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift
index 7384fb6..8ab4443 100644
--- a/stdlib/public/core/OutputStream.swift
+++ b/stdlib/public/core/OutputStream.swift
@@ -250,6 +250,7 @@
 func _opaqueSummary(_ metadata: Any.Type) -> UnsafePointer<CChar>?
 
 /// Do our best to print a value that cannot be printed directly.
+@_semantics("optimize.sil.specialize.generic.never")
 internal func _adHocPrint_unlocked<T, TargetStream : TextOutputStream>(
     _ value: T, _ mirror: Mirror, _ target: inout TargetStream,
     isDebugPrint: Bool
@@ -344,6 +345,7 @@
 }
 
 @inline(never)
+@_semantics("optimize.sil.specialize.generic.never")
 @_semantics("stdlib_binary_only")
 internal func _print_unlocked<T, TargetStream : TextOutputStream>(
   _ value: T, _ target: inout TargetStream
@@ -400,6 +402,7 @@
 // `debugPrint`
 //===----------------------------------------------------------------------===//
 
+@_semantics("optimize.sil.specialize.generic.never")
 @inline(never)
 public func _debugPrint_unlocked<T, TargetStream : TextOutputStream>(
     _ value: T, _ target: inout TargetStream
@@ -423,6 +426,7 @@
   _adHocPrint_unlocked(value, mirror, &target, isDebugPrint: true)
 }
 
+@_semantics("optimize.sil.specialize.generic.never")
 internal func _dumpPrint_unlocked<T, TargetStream : TextOutputStream>(
     _ value: T, _ mirror: Mirror, _ target: inout TargetStream
 ) {
diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
index 9a31ee7..9154c75 100644
--- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
+++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
@@ -86,7 +86,7 @@
 ///     byteArray += someBytes[n..<someBytes.count]
 % if mutable:
 ///
-/// Assigning into a ranged subscript of an `{$Self}` instance copies bytes
+/// Assigning into a ranged subscript of an `${Self}` instance copies bytes
 /// into the memory. The next `n` bytes of the memory that `someBytes`
 /// references are copied in this code:
 ///
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index 19bb361..fbe690a 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -164,10 +164,15 @@
     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}")
 
+    set(ld_EXECUTABLE ${CMAKE_LINKER})
+    if(${SWIFT_SDK_${prefix}_ARCH_${arch}_LINKER})
+      set(ld_EXECUTABLE ${SWIFT_SDK_${prefix}_ARCH_${arch}_LINKER})
+    endif()
+
     add_custom_command_target(section_magic_${arch_suffix}_begin_object
       COMMAND
           # Merge ImageInspectionInit.o + swift_sections.S(BEGIN) => swift_begin.o
-          ${CMAKE_LINKER} -r -o "${SWIFTLIB_DIR}/${arch_subdir}/swift_begin.o"
+          ${ld_EXECUTABLE} -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/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp
index 3797b6c..3a3bd61 100644
--- a/stdlib/public/runtime/HeapObject.cpp
+++ b/stdlib/public/runtime/HeapObject.cpp
@@ -344,6 +344,32 @@
   }
 }
 
+void swift::swift_nonatomic_unownedRetain(HeapObject *object)
+    SWIFT_CC(RegisterPreservingCC_IMPL) {
+  if (!isValidPointerForNativeRetain(object))
+    return;
+
+  object->refCounts.incrementUnownedNonAtomic(1);
+}
+
+void swift::swift_nonatomic_unownedRelease(HeapObject *object)
+    SWIFT_CC(RegisterPreservingCC_IMPL) {
+  if (!isValidPointerForNativeRetain(object))
+    return;
+
+  // Only class objects can be unowned-retained and unowned-released.
+  assert(object->metadata->isClassObject());
+  assert(static_cast<const ClassMetadata*>(object->metadata)->isTypeMetadata());
+
+  if (object->refCounts.decrementUnownedShouldFreeNonAtomic(1)) {
+    auto classMetadata = static_cast<const ClassMetadata*>(object->metadata);
+
+    SWIFT_RT_ENTRY_CALL(swift_slowDealloc)
+        (object, classMetadata->getInstanceSize(),
+         classMetadata->getInstanceAlignMask());
+  }
+}
+
 void swift::swift_unownedRetain_n(HeapObject *object, int n)
     SWIFT_CC(RegisterPreservingCC_IMPL) {
   if (!isValidPointerForNativeRetain(object))
@@ -369,6 +395,31 @@
   }
 }
 
+void swift::swift_nonatomic_unownedRetain_n(HeapObject *object, int n)
+    SWIFT_CC(RegisterPreservingCC_IMPL) {
+  if (!isValidPointerForNativeRetain(object))
+    return;
+
+  object->refCounts.incrementUnownedNonAtomic(n);
+}
+
+void swift::swift_nonatomic_unownedRelease_n(HeapObject *object, int n)
+    SWIFT_CC(RegisterPreservingCC_IMPL) {
+  if (!isValidPointerForNativeRetain(object))
+    return;
+
+  // Only class objects can be unowned-retained and unowned-released.
+  assert(object->metadata->isClassObject());
+  assert(static_cast<const ClassMetadata*>(object->metadata)->isTypeMetadata());
+
+  if (object->refCounts.decrementUnownedShouldFreeNonAtomic(n)) {
+    auto classMetadata = static_cast<const ClassMetadata*>(object->metadata);
+    SWIFT_RT_ENTRY_CALL(swift_slowDealloc)
+        (object, classMetadata->getInstanceSize(),
+         classMetadata->getInstanceAlignMask());
+  }
+}
+
 HeapObject *swift::swift_tryPin(HeapObject *object)
     SWIFT_CC(RegisterPreservingCC_IMPL) {
   assert(isValidPointerForNativeRetain(object));
@@ -449,6 +500,17 @@
     swift::swift_abortRetainUnowned(object);
 }
 
+void swift::swift_nonatomic_unownedRetainStrong(HeapObject *object)
+    SWIFT_CC(RegisterPreservingCC_IMPL) {
+  if (!isValidPointerForNativeRetain(object))
+    return;
+  assert(object->refCounts.getUnownedCount() &&
+         "object is not currently unowned-retained");
+
+  if (! object->refCounts.tryIncrementNonAtomic())
+    swift::swift_abortRetainUnowned(object);
+}
+
 void swift::swift_unownedRetainStrongAndRelease(HeapObject *object)
     SWIFT_CC(RegisterPreservingCC_IMPL) {
   if (!isValidPointerForNativeRetain(object))
@@ -465,6 +527,22 @@
   (void) dealloc;
 }
 
+void swift::swift_nonatomic_unownedRetainStrongAndRelease(HeapObject *object)
+    SWIFT_CC(RegisterPreservingCC_IMPL) {
+  if (!isValidPointerForNativeRetain(object))
+    return;
+  assert(object->refCounts.getUnownedCount() &&
+         "object is not currently unowned-retained");
+
+  if (! object->refCounts.tryIncrementNonAtomic())
+    swift::swift_abortRetainUnowned(object);
+
+  // This should never cause a deallocation.
+  bool dealloc = object->refCounts.decrementUnownedShouldFreeNonAtomic(1);
+  assert(!dealloc && "retain-strong-and-release caused dealloc?");
+  (void) dealloc;
+}
+
 void swift::swift_unownedCheck(HeapObject *object) {
   if (!isValidPointerForNativeRetain(object)) return;
   assert(object->refCounts.getUnownedCount() &&
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index aab8c9d..7d2257d 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -2819,7 +2819,7 @@
     /// The number of bytes remaining.
     size_t Remaining;
   };
-}
+} // end anonymous namespace
 
 // A statically-allocated pool.  It's zero-initialized, so this
 // doesn't cost us anything in binary size.
diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h
index 28d79f1..a9ca348 100644
--- a/stdlib/public/runtime/MetadataImpl.h
+++ b/stdlib/public/runtime/MetadataImpl.h
@@ -191,6 +191,11 @@
   static constexpr size_t stride = sizeof(T);
   static constexpr bool isPOD = false;
   static constexpr bool isBitwiseTakable = true;
+#ifdef SWIFT_STDLIB_USE_NONATOMIC_RC
+  static constexpr bool isAtomic = false;
+#else
+  static constexpr bool isAtomic = true;
+#endif
 
   static void destroy(T *addr) {
     Impl::release(*addr);
@@ -262,12 +267,20 @@
 struct SwiftRetainableBox :
     RetainableBoxBase<SwiftRetainableBox, HeapObject*> {
   static HeapObject *retain(HeapObject *obj) {
-    swift_retain(obj);
+    if (isAtomic) {
+      swift_retain(obj);
+    } else {
+      swift_nonatomic_retain(obj);
+    }
     return obj;
   }
 
   static void release(HeapObject *obj) {
-    swift_release(obj);
+    if (isAtomic) {
+      swift_release(obj);
+    } else {
+      swift_nonatomic_release(obj);
+    }
   }
 };
 
@@ -275,12 +288,20 @@
 struct SwiftUnownedRetainableBox :
     RetainableBoxBase<SwiftUnownedRetainableBox, HeapObject*> {
   static HeapObject *retain(HeapObject *obj) {
-    swift_unownedRetain(obj);
+    if (isAtomic) {
+      swift_unownedRetain(obj);
+    } else {
+      swift_nonatomic_unownedRetain(obj);
+    }
     return obj;
   }
 
   static void release(HeapObject *obj) {
-    swift_unownedRelease(obj);
+    if (isAtomic) {
+      swift_unownedRelease(obj);
+    } else {
+      swift_nonatomic_unownedRelease(obj);
+    }
   }
 
 #if SWIFT_OBJC_INTEROP
@@ -468,7 +489,11 @@
     swift_unknownRetain(obj);
     return obj;
 #else
-    swift_retain(static_cast<HeapObject *>(obj));
+    if (isAtomic) {
+      swift_retain(static_cast<HeapObject *>(obj));
+    } else {
+      swift_nonatomic_retain(static_cast<HeapObject *>(obj));
+    }
     return static_cast<HeapObject *>(obj);
 #endif
   }
@@ -477,7 +502,11 @@
 #if SWIFT_OBJC_INTEROP
     swift_unknownRelease(obj);
 #else
-    swift_release(static_cast<HeapObject *>(obj));
+    if (isAtomic) {
+      swift_release(static_cast<HeapObject *>(obj));
+    } else {
+      swift_nonatomic_release(static_cast<HeapObject *>(obj));
+    }
 #endif
   }
 };
diff --git a/stdlib/public/runtime/RefCount.cpp b/stdlib/public/runtime/RefCount.cpp
index 920df04..1d1b22b 100644
--- a/stdlib/public/runtime/RefCount.cpp
+++ b/stdlib/public/runtime/RefCount.cpp
@@ -2,11 +2,11 @@
 //
 // This source file is part of the Swift.org open source project
 //
-// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
 // Licensed under Apache License v2.0 with Runtime Library Exception
 //
-// See http://swift.org/LICENSE.txt for license information
-// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 //
 //===----------------------------------------------------------------------===//
 
@@ -55,6 +55,16 @@
 template bool RefCounts<SideTableRefCountBits>::tryIncrementSlow(SideTableRefCountBits oldbits);
 
 template <typename RefCountBits>
+bool RefCounts<RefCountBits>::tryIncrementNonAtomicSlow(RefCountBits oldbits) {
+  if (oldbits.hasSideTable())
+    return oldbits.getSideTable()->tryIncrementNonAtomic();
+  else
+    swift::swift_abortRetainOverflow();
+}
+template bool RefCounts<InlineRefCountBits>::tryIncrementNonAtomicSlow(InlineRefCountBits oldbits);
+template bool RefCounts<SideTableRefCountBits>::tryIncrementNonAtomicSlow(SideTableRefCountBits oldbits);
+
+template <typename RefCountBits>
 bool RefCounts<RefCountBits>::tryIncrementAndPinSlow(RefCountBits oldbits) {
   if (oldbits.hasSideTable())
     return oldbits.getSideTable()->tryIncrementAndPin();
@@ -66,8 +76,10 @@
 
 template <typename RefCountBits>
 bool RefCounts<RefCountBits>::tryIncrementAndPinNonAtomicSlow(RefCountBits oldbits) {
-  // No nonatomic implementation provided.
-  return tryIncrementAndPinSlow(oldbits);
+  if (oldbits.hasSideTable())
+    return oldbits.getSideTable()->tryIncrementAndPinNonAtomic();
+  else
+    swift::swift_abortRetainOverflow();
 }
 template bool RefCounts<InlineRefCountBits>::tryIncrementAndPinNonAtomicSlow(InlineRefCountBits oldbits);
 template bool RefCounts<SideTableRefCountBits>::tryIncrementAndPinNonAtomicSlow(SideTableRefCountBits oldbits);
diff --git a/stdlib/public/runtime/WeakReference.h b/stdlib/public/runtime/WeakReference.h
index aa8f4f4..34dd52e 100644
--- a/stdlib/public/runtime/WeakReference.h
+++ b/stdlib/public/runtime/WeakReference.h
@@ -2,11 +2,11 @@
 //
 // This source file is part of the Swift.org open source project
 //
-// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
 // Licensed under Apache License v2.0 with Runtime Library Exception
 //
-// See http://swift.org/LICENSE.txt for license information
-// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 //
 //===----------------------------------------------------------------------===//
 //
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
index 747e0bb..3cff8ce 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
@@ -79,7 +79,16 @@
           - Name: accessorsOnlyRenamedRetypedClass
             PropertyKind:    Class
             SwiftImportAsAccessors: true
+    Protocols:
+      - Name: ProtoWithVersionedUnavailableMember
+        Methods:
+          - Selector: requirement
+            MethodKind: Instance
+            ResultType: 'ForwardClass * _Nullable'
     Functions:
       - Name: acceptDoublePointer
         SwiftName: 'acceptPointer(_:)'
         Nullability: [ O ]
+    Tags:
+      - Name: SomeCStruct
+        SwiftName: ImportantCStruct
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
index b0a6023..06e48f9 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
@@ -2,6 +2,8 @@
 
 void acceptDoublePointer(double* _Nonnull ptr) __attribute__((swift_name("accept(_:)")));
 
+void oldAcceptDoublePointer(double* _Nonnull ptr) __attribute__((availability(swift, unavailable, replacement="acceptDoublePointer")));
+
 #ifdef __OBJC__
 
 __attribute__((objc_root_class))
@@ -13,5 +15,8 @@
 -(nonnull id)methodWithA:(nonnull id)a;
 @end
 
+#endif // __OBJC__
+
 #import <APINotesFrameworkTest/Properties.h>
-#endif
+#import <APINotesFrameworkTest/Protocols.h>
+#import <APINotesFrameworkTest/Types.h>
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h
index 93ab5b0..9d21bde 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h
@@ -1,3 +1,4 @@
+#ifdef __OBJC__
 #pragma clang assume_nonnull begin
 
 __attribute__((objc_root_class))
@@ -33,3 +34,4 @@
 @end
 
 #pragma clang assume_nonnull end
+#endif // __OBJC__
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Protocols.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Protocols.h
new file mode 100644
index 0000000..6a8840c
--- /dev/null
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Protocols.h
@@ -0,0 +1,11 @@
+#ifdef __OBJC__
+#pragma clang assume_nonnull begin
+
+@class ForwardClass; // used by API notes
+
+@protocol ProtoWithVersionedUnavailableMember
+- (nullable id)requirement;
+@end
+
+#pragma clang assume_nonnull end
+#endif // __OBJC__
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h
new file mode 100644
index 0000000..c44439f
--- /dev/null
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h
@@ -0,0 +1,7 @@
+#pragma clang assume_nonnull begin
+
+struct __attribute__((swift_name("VeryImportantCStruct"))) SomeCStruct {
+	int field;
+};
+
+#pragma clang assume_nonnull end
diff --git a/test/APINotes/versioned-objc.swift b/test/APINotes/versioned-objc.swift
new file mode 100644
index 0000000..4ff367c
--- /dev/null
+++ b/test/APINotes/versioned-objc.swift
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s
+// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 3 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-3 %s
+
+// REQUIRES: objc_interop
+
+import APINotesFrameworkTest
+
+// CHECK-DIAGS-4-NOT: versioned-objc.swift:[[@LINE-1]]:
+class ProtoWithVersionedUnavailableMemberImpl: ProtoWithVersionedUnavailableMember {
+  // CHECK-DIAGS-3: versioned-objc.swift:[[@LINE-1]]:7: error: type 'ProtoWithVersionedUnavailableMemberImpl' cannot conform to protocol 'ProtoWithVersionedUnavailableMember' because it has requirements that cannot be satisfied
+  func requirement() -> Any? { return nil }
+}
+
+let unrelatedDiagnostic: Int = nil
diff --git a/test/APINotes/versioned.swift b/test/APINotes/versioned.swift
index 85dd3e2..a3d7353 100644
--- a/test/APINotes/versioned.swift
+++ b/test/APINotes/versioned.swift
@@ -18,19 +18,41 @@
 func testRenamedTopLevel() {
   var value = 0.0
 
-  // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]
+  // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]:
   accept(&value)
   // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:3: error: 'accept' has been renamed to 'acceptPointer(_:)'
   // CHECK-DIAGS-3: note: 'accept' was introduced in Swift 4
 
-  // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]
+  // CHECK-DIAGS-3-NOT: versioned.swift:[[@LINE+1]]:
   acceptPointer(&value)
   // CHECK-DIAGS-4: versioned.swift:[[@LINE-1]]:3: error: 'acceptPointer' has been renamed to 'accept(_:)'
   // CHECK-DIAGS-4: note: 'acceptPointer' was obsoleted in Swift 4
 
   acceptDoublePointer(&value)
   // CHECK-DIAGS: versioned.swift:[[@LINE-1]]:3: error: 'acceptDoublePointer' has been renamed to
-  // CHECK-DIAGS-4: 'accept(_:)'
-  // CHECK-DIAGS-3: 'acceptPointer(_:)'
+  // CHECK-DIAGS-4-SAME: 'accept(_:)'
+  // CHECK-DIAGS-3-SAME: 'acceptPointer(_:)'
   // CHECK-DIAGS: note: 'acceptDoublePointer' was obsoleted in Swift 3
+
+  oldAcceptDoublePointer(&value)
+  // CHECK-DIAGS: versioned.swift:[[@LINE-1]]:3: error: 'oldAcceptDoublePointer' has been renamed to
+  // CHECK-DIAGS-4-SAME: 'accept(_:)'
+  // CHECK-DIAGS-3-SAME: 'acceptPointer(_:)'
+  // CHECK-DIAGS: note: 'oldAcceptDoublePointer' has been explicitly marked unavailable here
+
+  _ = SomeCStruct()
+  // CHECK-DIAGS: versioned.swift:[[@LINE-1]]:7: error: 'SomeCStruct' has been renamed to
+  // CHECK-DIAGS-4-SAME: 'VeryImportantCStruct'
+  // CHECK-DIAGS-3-SAME: 'ImportantCStruct'
+  // CHECK-DIAGS: note: 'SomeCStruct' was obsoleted in Swift 3
+
+  // CHECK-DIAGS-3-NOT: versioned.swift:[[@LINE+1]]:
+  _ = ImportantCStruct()
+  // CHECK-DIAGS-4: versioned.swift:[[@LINE-1]]:7: error: 'ImportantCStruct' has been renamed to 'VeryImportantCStruct'
+  // CHECK-DIAGS-4: note: 'ImportantCStruct' was obsoleted in Swift 4
+
+  // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]:
+  _ = VeryImportantCStruct()
+  // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:7: error: 'VeryImportantCStruct' has been renamed to 'ImportantCStruct'
+  // CHECK-DIAGS-3: note: 'VeryImportantCStruct' was introduced in Swift 4
 }
diff --git a/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some-Bridging-Header.h b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some-Bridging-Header.h
new file mode 100644
index 0000000..dc2b560
--- /dev/null
+++ b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some-Bridging-Header.h
@@ -0,0 +1,7 @@
+#import <Some/Submodule.h>
+
+@interface Thing
++ (void)fn:(KLASS*)arg;
+@end
+
+void bar(TYPE t);
diff --git a/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Headers/Some.h b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Headers/Some.h
new file mode 100644
index 0000000..ea7c87e
--- /dev/null
+++ b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Headers/Some.h
@@ -0,0 +1,2 @@
+typedef int TYPE;
+@class KLASS;
diff --git a/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Headers/Submodule.h b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Headers/Submodule.h
new file mode 100644
index 0000000..5d5f8f0
--- /dev/null
+++ b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Headers/Submodule.h
@@ -0,0 +1 @@
+int foo();
diff --git a/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Modules/module.modulemap b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Modules/module.modulemap
new file mode 100644
index 0000000..ccbb89c
--- /dev/null
+++ b/test/ClangImporter/MixedSource/Inputs/defer-supermodule-import/Some.framework/Modules/module.modulemap
@@ -0,0 +1,8 @@
+framework module Some  {
+  header "Some.h"
+  export *
+  module Submodule {
+    header "Submodule.h"
+    export *
+  }
+}
diff --git a/test/ClangImporter/MixedSource/defer-supermodule-import.swift b/test/ClangImporter/MixedSource/defer-supermodule-import.swift
new file mode 100644
index 0000000..0e6d505
--- /dev/null
+++ b/test/ClangImporter/MixedSource/defer-supermodule-import.swift
@@ -0,0 +1,21 @@
+// RUN: not %target-swift-frontend -F %S/Inputs/defer-supermodule-import -import-objc-header %S/Inputs/defer-supermodule-import/Some-Bridging-Header.h -typecheck %s 2>&1 | %FileCheck -check-prefix=HEADER-ERROR %s
+// HEADER-ERROR: Some-Bridging-Header.h:4:13: error: expected a type
+// HEADER-ERROR: Some-Bridging-Header.h:7:10: error: declaration of 'TYPE' must be imported from module 'Some' before it is required
+// REQUIRES: objc_interop
+
+// The bug we're testing here is that:
+//
+//  - Given a supermodule defining some types
+//  - Given a submodule of that supermodule
+//  - Given an _erroneous_ bridging header that imports the _submodule_ and tries
+//    to use the _supermodule's_ types
+//
+// That we emit an error. Previously we did not: Swift's "implicit supermodule
+// import" rule would fire _eagerly_, so by the time the submodule import was
+// complete the supermodule was also imported and the bridging header would pass
+// through without flagging the error. This made it possible to write textual
+// bridging headers that would not, themselves, be considered valid objc code as
+// far as clang (or more importantly: clang's PCH-generating pass) was
+// concerned.
+
+print(bar(foo()))
diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift
index 838a3b6..d6abc11 100644
--- a/test/Constraints/closures.swift
+++ b/test/Constraints/closures.swift
@@ -266,10 +266,8 @@
 // Make sure we cannot infer an () argument from an empty parameter list.
 func acceptNothingToInt (_: () -> Int) {}
 func testAcceptNothingToInt(ac1: @autoclosure () -> Int) {
-  // expected-note@-1{{parameter 'ac1' is implicitly non-escaping because it was declared @autoclosure}}
   acceptNothingToInt({ac1($0)})
   // expected-error@-1{{contextual closure type '() -> Int' expects 0 arguments, but 1 was used in closure body}}
-  // FIXME: expected-error@-2{{closure use of non-escaping parameter 'ac1' may allow it to escape}}
 }
 
 // <rdar://problem/23570873> QoI: Poor error calling map without being able to infer "U" (closure result inference)
diff --git a/test/Constraints/generic_super_constraint.swift b/test/Constraints/generic_super_constraint.swift
index 8e29a49..c227519 100644
--- a/test/Constraints/generic_super_constraint.swift
+++ b/test/Constraints/generic_super_constraint.swift
@@ -4,11 +4,14 @@
 class Derived: Base<Int> { }
 
 func foo<T>(_ x: T) -> Derived where T: Base<Int>, T: Derived {
+	// expected-warning@-1{{redundant superclass constraint 'T' : 'Base<Int>'}}
+	// expected-note@-2{{superclass constraint 'T' : 'Derived' written here}}
   return x
 }
 
 // FIXME: Should not be an error
-// expected-error@+1{{cannot be a subclass of both 'Base<T>' and 'Derived'}}
+// expected-error@+2{{generic parameter 'U' cannot be a subclass of both 'Derived' and 'Base<T>'}}
+// expected-note@+1{{superclass constraint 'U' : 'Base<T>' written here}}
 func bar<T, U>(_ x: U, y: T) -> (Derived, Int) where U: Base<T>, U: Derived {
   // FIXME
   // expected-error@+1{{cannot convert return expression}}
diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift
index 3b07ff8..1183a45 100644
--- a/test/Constraints/patterns.swift
+++ b/test/Constraints/patterns.swift
@@ -114,7 +114,8 @@
   ()
 case Watch.Edition: // TODO: should warn that cast can't succeed with currently known conformances
   ()
-case .HairForceOne: // expected-error{{enum case 'HairForceOne' not found in type 'HairType'}}
+// TODO: Bad error message
+case .HairForceOne: // expected-error{{cannot convert}}
   ()
 default:
   break
@@ -254,3 +255,53 @@
 if case let doesNotExist as SomeClass:AlsoDoesNotExist {}
 // expected-error@-1 {{use of undeclared type 'AlsoDoesNotExist'}}
 // expected-error@-2 {{variable binding in a condition requires an initializer}}
+
+// `.foo` and `.bar(...)` pattern syntax should also be able to match
+// static members as expr patterns
+
+struct StaticMembers: Equatable {
+  init() {}
+  init(_: Int) {}
+  init?(opt: Int) {}
+  static var prop = StaticMembers()
+  static var optProp: Optional = StaticMembers()
+
+  static func method(_: Int) -> StaticMembers { return prop }
+  static func method(withLabel: Int) -> StaticMembers { return prop }
+  static func optMethod(_: Int) -> StaticMembers? { return optProp }
+
+  static func ==(x: StaticMembers, y: StaticMembers) -> Bool { return true }
+}
+
+let staticMembers = StaticMembers()
+let optStaticMembers: Optional = StaticMembers()
+
+switch staticMembers {
+  case .init: break // expected-error{{cannot match values of type 'StaticMembers'}}
+  case .init(opt:): break // expected-error{{cannot match values of type 'StaticMembers'}}
+  case .init(): break
+
+  case .init(0): break
+  case .init(_): break // expected-error{{'_' can only appear in a pattern}}
+  case .init(let x): break // expected-error{{cannot appear in an expression}}
+  case .init(opt: 0): break // expected-error{{not unwrapped}}
+
+  case .prop: break
+  // TODO: repeated error message
+  case .optProp: break // expected-error* {{not unwrapped}}
+
+  case .method: break // expected-error{{cannot match}}
+  case .method(0): break
+  case .method(_): break // expected-error{{'_' can only appear in a pattern}}
+  case .method(let x): break // expected-error{{cannot appear in an expression}}
+
+  case .method(withLabel:): break // expected-error{{cannot match}}
+  case .method(withLabel: 0): break
+  case .method(withLabel: _): break // expected-error{{'_' can only appear in a pattern}}
+  case .method(withLabel: let x): break // expected-error{{cannot appear in an expression}}
+
+  case .optMethod: break // expected-error{{cannot match}}
+  case .optMethod(0): break // expected-error{{not unwrapped}}
+}
+
+_ = 0
diff --git a/test/DebugInfo/linetable.swift b/test/DebugInfo/linetable.swift
index e282ca4..b4706cb 100644
--- a/test/DebugInfo/linetable.swift
+++ b/test/DebugInfo/linetable.swift
@@ -1,7 +1,7 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests %s -emit-ir -g -o - | %FileCheck %s
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests %s -S -g -o - | %FileCheck %s --check-prefix ASM-CHECK
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 import Swift
 func markUsed<T>(_ t: T) {}
diff --git a/test/Demangle/Inputs/simplified-manglings.txt b/test/Demangle/Inputs/simplified-manglings.txt
index 20cb0b9..6eea81b 100644
--- a/test/Demangle/Inputs/simplified-manglings.txt
+++ b/test/Demangle/Inputs/simplified-manglings.txt
@@ -136,9 +136,9 @@
 _TtGSaGSqC5sugar7MyClass__ ---> [MyClass?]
 _TtaC9typealias5DWARF9DIEOffset ---> DWARF.DIEOffset
 _Ttas3Int ---> Int
-_TTRXFo_dSc_dSb_XFo_iSc_iSb_ ---> thunk
-_TTRXFo_dSi_dGSqSi__XFo_iSi_iGSqSi__ ---> thunk
-_TTRGrXFo_iV18switch_abstraction1A_ix_XFo_dS0__ix_ ---> thunk
+_TTRXFo_dSc_dSb_XFo_iSc_iSb_ ---> thunk for @callee_owned (@unowned UnicodeScalar) -> (@unowned Bool)
+_TTRXFo_dSi_dGSqSi__XFo_iSi_iGSqSi__ ---> thunk for @callee_owned (@unowned Int) -> (@unowned Int?)
+_TTRGrXFo_iV18switch_abstraction1A_ix_XFo_dS0__ix_ ---> thunk for @callee_owned (@in A) -> (@out A)
 _TFCF5types1gFT1bSb_T_L0_10Collection3zimfT_T_ ---> (g(b : Bool) -> ()).(Collection #2).zim() -> ()
 _TFF17capture_promotion22test_capture_promotionFT_FT_SiU_FT_Si_promote0 ---> (test_capture_promotion() -> () -> Int).(closure #1)
 _TFIVs8_Processi10_argumentsGSaSS_U_FT_GSaSS_ ---> _Process.(variable initialization expression)._arguments
@@ -160,7 +160,7 @@
 _TTSgSi__xyz ---> _TTSgSi__xyz
 _TTSg5Si___TTSg5Si___TFSqcfT_GSqx_ ---> specialized specialized Optional.init() -> A?
 _TTSg5Vs5UInt8___TFV10specialize3XXXcfT1tx_GS0_x_ ---> specialized XXX.init(t : A) -> XXX<A>
-_TPA__TTRXFo_oSSoSS_dSb_XFo_iSSiSS_dSb_31 ---> partial apply for thunk
+_TPA__TTRXFo_oSSoSS_dSb_XFo_iSSiSS_dSb_31 ---> partial apply for thunk for @callee_owned (@owned String, @owned String) -> (@unowned Bool)
 _TiC4Meow5MyCls9subscriptFT1iSi_Sf ---> MyCls.subscript(i : Int) -> Float
 _TF8manglingX22egbpdajGbuEbxfgehfvwxnFT_T_ ---> ليهمابتكلموشعربي؟() -> ()
 _TF8manglingX24ihqwcrbEcvIaIdqgAFGpqjyeFT_T_ ---> 他们为什么不说中文() -> ()
@@ -180,8 +180,8 @@
 _TTSf1cl35_TFF7specgen6callerFSiT_U_FTSiSi_T_Si___TF7specgen12take_closureFFTSiSi_T_T_ ---> specialized take_closure((Int, Int) -> ()) -> ()
 _TTSf1cl35_TFF7specgen6callerFSiT_U_FTSiSi_T_Si___TTSg5Si___TF7specgen12take_closureFFTSiSi_T_T_ ---> specialized specialized take_closure((Int, Int) -> ()) -> ()
 _TTSg5Si___TTSf1cl35_TFF7specgen6callerFSiT_U_FTSiSi_T_Si___TF7specgen12take_closureFFTSiSi_T_T_ ---> specialized specialized take_closure((Int, Int) -> ()) -> ()
-_TTSf1cpfr24_TF8capturep6helperFSiT__n___TTRXFo_dSi_dT__XFo_iSi_dT__ ---> specialized thunk
-_TTSf1cpfr24_TF8capturep6helperFSiT__n___TTRXFo_dSi_DT__XFo_iSi_DT__ ---> specialized thunk
+_TTSf1cpfr24_TF8capturep6helperFSiT__n___TTRXFo_dSi_dT__XFo_iSi_dT__ ---> specialized thunk for @callee_owned (@unowned Int) -> (@unowned ())
+_TTSf1cpfr24_TF8capturep6helperFSiT__n___TTRXFo_dSi_DT__XFo_iSi_DT__ ---> specialized thunk for @callee_owned (@unowned Int) -> (@unowned_inner_pointer ())
 _TTSf1cpi0_cpfl0_cpse0v4u123_cpg53globalinit_33_06E7F1D906492AE070936A9B58CBAE1C_token8_cpfr36_TFtest_capture_propagation2_closure___TF7specgen12take_closureFFTSiSi_T_T_ ---> specialized take_closure((Int, Int) -> ()) -> ()
 _TTSf0gs___TFVs11_StringCore15_invariantCheckfT_T_ ---> specialized _StringCore._invariantCheck() -> ()
 _TTSf2g___TTSf2s_d___TFVs11_StringCoreCfVs13_StringBufferS_ ---> specialized specialized _StringCore.init(_StringBuffer) -> _StringCore
@@ -198,6 +198,8 @@
 _TFC3red11BaseClassEHcfzT1aSi_S0_ ---> BaseClassEH.init(a : Int) throws -> BaseClassEH
 _TFe27mangling_generic_extensionsR_S_8RunciblerVS_3Foog1aSi ---> Foo<A where ...>.a.getter
 _TFe27mangling_generic_extensionsR_S_8RunciblerVS_3Foog1bx ---> Foo<A where ...>.b.getter
-_TTRXFo_iT__iT_zoPs5Error__XFo__dT_zoPS___ ---> thunk
+_TTRXFo_iT__iT_zoPs5Error__XFo__dT_zoPS___ ---> thunk for @callee_owned (@in ()) -> (@out (), @error @owned Error)
 _TFE1a ---> _TFE1a
 _TFC4testP33_83378C430F65473055F1BD53F3ADCDB71C5doFoofT_T_ ---> C.doFoo() -> ()
+_TTRXFo_oCSo13SKPhysicsBodydVSC7CGPointdVSC8CGVectordGSpV10ObjectiveC8ObjCBool___XFdCb_dS_dS0_dS1_dGSpS3____ ---> thunk for @callee_owned (@owned SKPhysicsBody, @unowned CGPoint, @unowned CGVector, @unowned UnsafeMutablePointer<ObjCBool>) -> ()
+_T0So13SKPhysicsBodyCSC7CGPointVSC8CGVectorVSpy10ObjectiveC8ObjCBoolVGIxxyyy_AbdFSpyAIGIyByyyy_TR ---> thunk for @callee_owned (@owned SKPhysicsBody, @unowned CGPoint, @unowned CGVector, @unowned UnsafeMutablePointer<ObjCBool>) -> ()
diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift
index e287aff..5b91c77 100644
--- a/test/Generics/associated_type_typo.swift
+++ b/test/Generics/associated_type_typo.swift
@@ -37,9 +37,9 @@
 
 // CHECK-GENERIC-LABEL: .typoAssoc4@
 // CHECK-GENERIC-NEXT: Requirements:
-// CHECK-GENERIC-NEXT:   τ_0_0 : P2 [Explicit @ {{.*}}:21]
-// CHECK-GENERIC-NEXT:   τ_0_0[.P2].AssocP2 : P1 [Explicit @ {{.*}}:21 -> Protocol requirement (P2)]
-// CHECK-GENERIC-NEXT:   τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [Explicit @ {{.*}}:53]
+// CHECK-GENERIC-NEXT:   τ_0_0 : P2 [τ_0_0: Explicit @ {{.*}}:21]
+// CHECK-GENERIC-NEXT:   τ_0_0[.P2].AssocP2 : P1 [τ_0_0: Explicit @ {{.*}}:21 -> Protocol requirement (P2)]
+// CHECK-GENERIC-NEXT:   τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [τ_0_0[.P2].AssocP2.assoc: Explicit @ {{.*}}:53]
 // CHECK-GENERIC-NEXT: Potential archetypes
 
 // <rdar://problem/19620340>
diff --git a/test/Generics/associated_type_where_clause.swift b/test/Generics/associated_type_where_clause.swift
new file mode 100644
index 0000000..3717b18
--- /dev/null
+++ b/test/Generics/associated_type_where_clause.swift
@@ -0,0 +1,128 @@
+// RUN: %target-typecheck-verify-swift -typecheck %s -verify -swift-version 4
+
+func needsSameType<T>(_: T.Type, _: T.Type) {}
+
+protocol Foo {}
+func needsFoo<T: Foo>(_: T.Type) {}
+
+protocol Foo2 {}
+func needsFoo2<T: Foo2>(_: T.Type) {}
+
+extension Int: Foo, Foo2 {}
+extension Float: Foo {}
+
+protocol Conforms {
+    associatedtype T where T: Foo
+}
+func needsConforms<X: Conforms>(_: X.Type) {
+    needsFoo(X.T.self)
+}
+struct ConcreteConforms: Conforms { typealias T = Int }
+struct ConcreteConforms2: Conforms { typealias T = Int }
+struct ConcreteConformsNonFoo2: Conforms { typealias T = Float }
+
+protocol NestedConforms {
+    associatedtype U where U: Conforms, U.T: Foo2
+
+    func foo(_: U)
+}
+extension NestedConforms { func foo(_: U) {} }
+func needsNestedConforms<X: NestedConforms>(_: X.Type) {
+    needsConforms(X.U.self)
+    needsFoo(X.U.T.self)
+    needsFoo2(X.U.T.self)
+}
+struct ConcreteNestedConforms: NestedConforms {
+    typealias U = ConcreteConforms
+}
+struct ConcreteNestedConformsInfer: NestedConforms {
+    func foo(_: ConcreteConforms) {}
+}
+struct BadConcreteNestedConforms: NestedConforms {
+    // expected-error@-1 {{type 'ConcreteConformsNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}}
+    typealias U = ConcreteConformsNonFoo2
+}
+struct BadConcreteNestedConformsInfer: NestedConforms {
+    // expected-error@-1 {{type 'ConcreteConformsNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}}
+    func foo(_: ConcreteConformsNonFoo2) {}
+}
+
+protocol NestedConformsDefault {
+    associatedtype U = ConcreteConforms where U: Conforms, U.T: Foo2
+}
+struct ConcreteNestedConformsDefaultDefaulted: NestedConformsDefault {}
+struct ConcreteNestedConformsDefault: NestedConformsDefault {
+    typealias U = ConcreteConforms2
+}
+func needsNestedConformsDefault<X: NestedConformsDefault>(_: X.Type) {
+    needsConforms(X.U.self)
+    needsFoo(X.U.T.self)
+    needsFoo2(X.U.T.self)
+}
+
+protocol NestedSameType {
+    associatedtype U: Conforms where U.T == Int
+
+    func foo(_: U)
+}
+extension NestedSameType { func foo(_: U) {} }
+func needsNestedSameType<X: NestedSameType>(_: X.Type) {
+    needsConforms(X.U.self)
+    needsSameType(X.U.T.self, Int.self)
+}
+struct BadConcreteNestedSameType: NestedSameType {
+    // expected-error@-1 {{'NestedSameType' requires the types 'ConcreteConformsNonFoo2.T' (aka 'Float') and 'Int' be equivalent}}
+    // expected-note@-2 {{requirement specified as 'Self.U.T' == 'Int' [with Self = BadConcreteNestedSameType]}}
+    typealias U = ConcreteConformsNonFoo2
+}
+struct BadConcreteNestedSameTypeInfer: NestedSameType {
+    // expected-error@-1 {{'NestedSameType' requires the types 'ConcreteConformsNonFoo2.T' (aka 'Float') and 'Int' be equivalent}}
+    // expected-note@-2 {{requirement specified as 'Self.U.T' == 'Int' [with Self = BadConcreteNestedSameTypeInfer]}}
+    func foo(_: ConcreteConformsNonFoo2) {}
+}
+
+protocol NestedSameTypeDefault {
+    associatedtype U: Conforms = ConcreteConforms where U.T == Int
+
+    func foo(_: U)
+}
+extension NestedSameTypeDefault { func foo(_: U) {} }
+func needsNestedSameTypeDefault<X: NestedSameTypeDefault>(_: X.Type) {
+    needsConforms(X.U.self)
+    needsSameType(X.U.T.self, Int.self)
+}
+struct ConcreteNestedSameTypeDefaultDefaulted: NestedSameTypeDefault {}
+struct ConcreteNestedSameTypeDefault: NestedSameTypeDefault {
+    typealias U = ConcreteConforms2
+}
+struct ConcreteNestedSameTypeDefaultInfer: NestedSameTypeDefault {
+    func foo(_: ConcreteConforms2) {}
+}
+
+protocol Inherits: NestedConforms {
+    associatedtype X: Conforms where X.T == U.T
+
+    func bar(_: X)
+}
+extension Inherits { func bar(_: X) {} }
+func needsInherits<X: Inherits>(_: X.Type) {
+    needsConforms(X.U.self)
+    needsConforms(X.X.self)
+    needsSameType(X.U.T.self, X.X.T.self)
+}
+struct ConcreteInherits: Inherits {
+    typealias U = ConcreteConforms
+    typealias X = ConcreteConforms
+}
+struct ConcreteInheritsDiffer: Inherits {
+    typealias U = ConcreteConforms
+    typealias X = ConcreteConforms2
+}
+/*
+FIXME: the sametype requirement gets dropped from the requirement signature
+(enumerateRequirements doesn't yield it), so this doesn't error as it should.
+struct BadConcreteInherits: Inherits {
+    typealias U = ConcreteConforms
+    typealias X = ConcreteConformsNonFoo2
+}
+*/
diff --git a/test/Generics/invalid.swift b/test/Generics/invalid.swift
index 917b013..d817ae1 100644
--- a/test/Generics/invalid.swift
+++ b/test/Generics/invalid.swift
@@ -9,7 +9,7 @@
 
 protocol he where A : B { // expected-error {{'where' clause cannot be attached to a protocol declaration}}
 
-  associatedtype vav where A : B // expected-error {{'where' clause cannot be attached to an associated type declaration}}
+  associatedtype vav where A : B // expected-error {{where clauses on associated types are fragile; use '-swift-version 4' to experiment.}}
 }
 
 
diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift
index 3e62aa4..bc580c9 100644
--- a/test/Generics/protocol_type_aliases.swift
+++ b/test/Generics/protocol_type_aliases.swift
@@ -15,9 +15,9 @@
 
 // CHECK-LABEL: .requirementOnNestedTypeAlias@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Q [Explicit @ 22:51]
-// CHECK-NEXT:   τ_0_0[.Q].B : P [Explicit @ 22:51 -> Protocol requirement (Q)]
-// CHECK-NEXT:   τ_0_0[.Q].B[.P].A == Int [Explicit @ 22:62]
+// CHECK-NEXT:   τ_0_0 : Q [τ_0_0: Explicit @ 22:51]
+// CHECK-NEXT:   τ_0_0[.Q].B : P [τ_0_0: Explicit @ 22:51 -> Protocol requirement (Q)]
+// CHECK-NEXT:   τ_0_0[.Q].B[.P].A == Int [τ_0_0[.Q].B[.P].X: Explicit @ 22:62]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q, τ_0_0.B.A == Int>
 func requirementOnNestedTypeAlias<T>(_: T) where T: Q, T.B.X == Int {}
 
@@ -34,19 +34,19 @@
 
 // CHECK-LABEL: .requirementOnConcreteNestedTypeAlias@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Q2 [Explicit @ 42:59]
-// CHECK-NEXT:   τ_0_0[.Q2].B : P2 [Explicit @ 42:59 -> Protocol requirement (Q2)]
-// CHECK-NEXT:   τ_0_0[.Q2].C == S<T.B.A> [Explicit @ 42:69]
-// CHECK-NEXT:   τ_0_0[.Q2].B[.P2].X == S<T.B.A> [Nested type match]
+// CHECK-NEXT:   τ_0_0 : Q2 [τ_0_0: Explicit @ 42:59]
+// CHECK-NEXT:   τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 42:59 -> Protocol requirement (Q2)]
+// CHECK-NEXT:   τ_0_0[.Q2].C == S<T.B.A> [τ_0_0[.Q2].C: Explicit @ 42:69]
+// CHECK-NEXT:   τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Nested type match]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == S<τ_0_0.B.A>>
 func requirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, T.C == T.B.X {}
 
 // CHECK-LABEL: .concreteRequirementOnConcreteNestedTypeAlias@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Q2 [Explicit @ 51:67]
-// CHECK-NEXT:   τ_0_0[.Q2].B : P2 [Explicit @ 51:67 -> Protocol requirement (Q2)]
-// CHECK-NEXT:   τ_0_0[.Q2].C == τ_0_0[.Q2].B[.P2].A [Explicit]
-// CHECK-NEXT:   τ_0_0[.Q2].B[.P2].X == S<T.B.A> [Nested type match]
+// CHECK-NEXT:   τ_0_0 : Q2 [τ_0_0: Explicit @ 51:67]
+// CHECK-NEXT:   τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 51:67 -> Protocol requirement (Q2)]
+// CHECK-NEXT:   τ_0_0[.Q2].C == τ_0_0[.Q2].B[.P2].A [τ_0_0[.Q2].C: Explicit]
+// CHECK-NEXT:   τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Nested type match]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == τ_0_0.B.A>
 func concreteRequirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, S<T.C> == T.B.X {}
 
diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift
index 2491c55..dc1be46 100644
--- a/test/Generics/requirement_inference.swift
+++ b/test/Generics/requirement_inference.swift
@@ -57,7 +57,7 @@
 class Box<T : Fox> {
 // CHECK-LABEL: .unpack@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Fox [Explicit]
+// CHECK-NEXT:   τ_0_0 : Fox [τ_0_0: Explicit]
   func unpack(_ x: X1<T>) {}
 }
 
@@ -77,11 +77,15 @@
 // CHECK-NEXT: Requirements:
 // CHECK-NEXT:   τ_0_0 : Canidae
 func inferSuperclassRequirement1<T : Carnivora>(_ v: V<T>) {}
+// expected-warning@-1{{redundant superclass constraint 'T' : 'Carnivora'}}
+// expected-note@-2{{superclass constraint 'T' : 'Canidae' written here}}
 
 // CHECK-LABEL: .inferSuperclassRequirement2@
 // CHECK-NEXT: Requirements:
 // CHECK-NEXT:   τ_0_0 : Canidae
 func inferSuperclassRequirement2<T : Canidae>(_ v: U<T>) {}
+// expected-warning@-1{{redundant superclass constraint 'T' : 'Carnivora'}}
+// expected-note@-2{{superclass constraint 'T' : 'Canidae' written here}}
 
 // ----------------------------------------------------------------------------
 // Same-type requirements
@@ -111,27 +115,27 @@
 
 // CHECK-LABEL: .inferSameType1@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : P3 [Inferred @ {{.*}}:32]
-// CHECK-NEXT:   τ_0_1 : P4 [Inferred @ {{.*}}:32]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P1 [Inferred @ {{.*}}:32 -> Protocol requirement (P3) -> Protocol requirement (P2)]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P2 [Inferred @ {{.*}}:32 -> Protocol requirement (P3)]
-// FIXME: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [Inferred]
+// CHECK-NEXT:   τ_0_0 : P3 [τ_0_0: Inferred @ {{.*}}:32]
+// CHECK-NEXT:   τ_0_1 : P4 [τ_0_1: Inferred @ {{.*}}:32]
+// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P1 [τ_0_0: Inferred @ {{.*}}:32 -> Protocol requirement (P3) -> Protocol requirement (P2)]
+// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Inferred @ {{.*}}:32 -> Protocol requirement (P3)]
+// FIXME: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0: Inferred]
 func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
 
 // CHECK-LABEL: .inferSameType2@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : P3 [Explicit @ {{.*}}:25]
-// CHECK-NEXT:   τ_0_1 : P4 [Explicit @ {{.*}}:33]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P1 [Explicit @ {{.*}}:25 -> Protocol requirement (P3) -> Protocol requirement (P2)]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P2 [Explicit @ {{.*}}:25 -> Protocol requirement (P3)]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [Explicit]
+// CHECK-NEXT:   τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:25]
+// CHECK-NEXT:   τ_0_1 : P4 [τ_0_1: Explicit @ {{.*}}:33]
+// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P1 [τ_0_0: Explicit @ {{.*}}:25 -> Protocol requirement (P3) -> Protocol requirement (P2)]
+// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Explicit @ {{.*}}:25 -> Protocol requirement (P3)]
+// CHECK-NEXT:   τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0[.P3].P3Assoc: Explicit]
 func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
 
 // CHECK-LABEL: .inferSameType3@
 // CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : PCommonAssoc1 [Explicit @ {{.*}}:25]
-// CHECK-NEXT:   τ_0_0 : PCommonAssoc2 [Explicit @ {{.*}}:74]
-// CHECK-NEXT:   τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [Explicit @ {{.*}}:66]
+// CHECK-NEXT:   τ_0_0 : PCommonAssoc1 [τ_0_0: Explicit @ {{.*}}:25]
+// CHECK-NEXT:   τ_0_0 : PCommonAssoc2 [τ_0_0: Explicit @ {{.*}}:74]
+// CHECK-NEXT:   τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [τ_0_0[.PCommonAssoc1].CommonAssoc: Explicit @ {{.*}}:66]
 // CHECK-NEXT: Potential archetypes
 func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {}
 
@@ -177,6 +181,8 @@
 // CHECK-LABEL: sameTypeConcrete2@
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.B == X3, τ_0_0.C == X3>
 func sameTypeConcrete2<T : P9 & P10>(_: T) where T.B : X3, T.C == T.B, T.C == X3 { }
+// expected-warning@-1{{redundant superclass constraint 'T.B' : 'X3'}}
+// expected-note@-2{{same-type constraint 'T.C' == 'X3' written here}}
 
 // Note: a standard-library-based stress test to make sure we don't inject
 // any additional requirements.
@@ -189,6 +195,13 @@
 	func f() { }
 }
 
+// CHECK-LABEL: X14.recursiveConcreteSameType
+// CHECK: Generic signature: <T, V where T == CountableRange<Int>>
+// CHECK-NEXT: Canonical generic signature: <τ_0_0, τ_1_0 where τ_0_0 == CountableRange<Int>>
+struct X14<T: Collection> where T.Iterator == IndexingIterator<T> {
+	func recursiveConcreteSameType<V>(_: V) where T == CountableRange<Int> { }
+}
+
 // rdar://problem/30478915
 protocol P11 {
   associatedtype A
diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift
index eac9a3e..4eb15ab 100644
--- a/test/Generics/superclass_constraint.swift
+++ b/test/Generics/superclass_constraint.swift
@@ -13,8 +13,13 @@
 
 class Other { }
 
-func f1<T : A>(_: T) where T : Other {} // expected-error{{generic parameter 'T' cannot be a subclass of both 'A' and 'Other'}}
+func f1<T : A>(_: T) where T : Other {} // expected-error{{generic parameter 'T' cannot be a subclass of both 'Other' and 'A'}}
+// expected-note@-1{{superclass constraint 'T' : 'A' written here}}
+
 func f2<T : A>(_: T) where T : B {}
+// expected-warning@-1{{redundant superclass constraint 'T' : 'A'}}
+// expected-note@-2{{superclass constraint 'T' : 'B' written here}}
+
 
 class GA<T> {}
 class GB<T> : GA<T> {}
@@ -27,10 +32,16 @@
 func f6<U : GA<T>, T : P>(_: T, _: U) {}
 func f7<U, T>(_: T, _: U) where U : GA<T>, T : P {}
 
-func f8<T : GA<A>>(_: T) where T : GA<B> {} // expected-error{{generic parameter 'T' cannot be a subclass of both 'GA<A>' and 'GA<B>'}}
+func f8<T : GA<A>>(_: T) where T : GA<B> {} // expected-error{{generic parameter 'T' cannot be a subclass of both 'GA<B>' and 'GA<A>'}}
+// expected-note@-1{{superclass constraint 'T' : 'GA<A>' written here}}
 
 func f9<T : GA<A>>(_: T) where T : GB<A> {}
+// expected-warning@-1{{redundant superclass constraint 'T' : 'GA<A>'}}
+// expected-note@-2{{superclass constraint 'T' : 'GB<A>' written here}}
+
 func f10<T : GB<A>>(_: T) where T : GA<A> {}
+// expected-warning@-1{{redundant superclass constraint 'T' : 'GA<A>'}}
+// expected-note@-2{{superclass constraint 'T' : 'GB<A>' written here}}
 
 func f11<T : GA<T>>(_: T) { } // expected-error{{superclass constraint 'T' : 'GA<T>' is recursive}}
 func f12<T : GA<U>, U : GB<T>>(_: T, _: U) { } // expected-error{{superclass constraint 'U' : 'GB<T>' is recursive}} // expected-error{{superclass constraint 'T' : 'GA<U>' is recursive}}
@@ -64,15 +75,15 @@
 
 // CHECK: superclassConformance1
 // CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C [Explicit @ {{.*}}:46]
-// CHECK-NEXT: τ_0_0 : P3 [Explicit @ {{.*}}:46 -> Superclass (C: P3)]
+// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:46]
+// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:46 -> Superclass (C: P3)]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
 func superclassConformance1<T>(t: T) where T : C, T : P3 {}
 
 // CHECK: superclassConformance2
 // CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C [Explicit @ {{.*}}:46]
-// CHECK-NEXT: τ_0_0 : P3 [Explicit @ {{.*}}:46 -> Superclass (C: P3)]
+// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:46]
+// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:46 -> Superclass (C: P3)]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
 func superclassConformance2<T>(t: T) where T : C, T : P3 {}
 
@@ -82,23 +93,27 @@
 
 // CHECK: superclassConformance3
 // CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C2 [Explicit @ {{.*}}:46]
-// CHECK-NEXT: τ_0_0 : P4 [Explicit @ {{.*}}:46 -> Superclass (C2: P4)]
+// CHECK-NEXT: τ_0_0 : C2 [τ_0_0: Explicit @ {{.*}}:46]
+// CHECK-NEXT: τ_0_0 : P4 [τ_0_0: Explicit @ {{.*}}:61 -> Superclass (C2: P4)]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C2>
 func superclassConformance3<T>(t: T) where T : C, T : P4, T : C2 {}
+// expected-warning@-1{{redundant superclass constraint 'T' : 'C'}}
+// expected-note@-2{{superclass constraint 'T' : 'C2' written here}}
 
 protocol P5: A { } // expected-error{{non-class type 'P5' cannot inherit from class 'A'}}
 
-protocol P6: A, Other { } // expected-error{{protocol 'P6' cannot be a subclass of both 'A' and 'Other'}}
+protocol P6: A, Other { } // expected-error{{protocol 'P6' cannot be a subclass of both 'Other' and 'A'}}
 // expected-error@-1{{non-class type 'P6' cannot inherit from class 'A'}}
 // expected-error@-2{{non-class type 'P6' cannot inherit from class 'Other'}}
+// expected-note@-3{{superclass constraint 'Self' : 'A' written here}}
 
 func takeA(_: A) { }
 func takeP5<T: P5>(_ t: T) {
 	takeA(t) // okay
 }
 
-protocol P7 { // expected-error{{'Self.Assoc' cannot be a subclass of both 'A' and 'Other'}}
+protocol P7 { // expected-error{{'Self.Assoc' cannot be a subclass of both 'Other' and 'A'}}
 	associatedtype Assoc: A, Other 
 	// FIXME: expected-error@-1{{multiple inheritance from classes 'A' and 'Other'}}
+	// FIXME weird location: expected-note@-3{{superclass constraint 'Self.Assoc' : 'A' written here}}
 }
diff --git a/test/IDE/print_ast_tc_decls_errors.swift b/test/IDE/print_ast_tc_decls_errors.swift
index f226d8a..2affaa9 100644
--- a/test/IDE/print_ast_tc_decls_errors.swift
+++ b/test/IDE/print_ast_tc_decls_errors.swift
@@ -157,7 +157,7 @@
 // NO-TYREPR: {{^}}protocol ProtocolWithInheritance4 : <<error type>>, FooProtocol {{{$}}
 // TYREPR: {{^}}protocol ProtocolWithInheritance4 : FooClass, FooProtocol {{{$}}
 
-protocol ProtocolWithInheritance5 : FooClass, BarClass {} // expected-error {{non-class type 'ProtocolWithInheritance5' cannot inherit from class 'FooClass'}} expected-error {{non-class type 'ProtocolWithInheritance5' cannot inherit from class 'BarClass'}} expected-error{{protocol 'ProtocolWithInheritance5' cannot be a subclass of both 'FooClass' and 'BarClass'}}
+protocol ProtocolWithInheritance5 : FooClass, BarClass {} // expected-error {{non-class type 'ProtocolWithInheritance5' cannot inherit from class 'FooClass'}} expected-error {{non-class type 'ProtocolWithInheritance5' cannot inherit from class 'BarClass'}} expected-error{{protocol 'ProtocolWithInheritance5' cannot be a subclass of both 'BarClass' and 'FooClass'}} // expected-note{{superclass constraint 'Self' : 'FooClass' written here}}
 // NO-TYREPR: {{^}}protocol ProtocolWithInheritance5 : <<error type>>, <<error type>> {{{$}}
 // TYREPR: {{^}}protocol ProtocolWithInheritance5 : FooClass, BarClass {{{$}}
 
diff --git a/test/IDE/print_usrs.swift b/test/IDE/print_usrs.swift
index aafed58..e05000d 100644
--- a/test/IDE/print_usrs.swift
+++ b/test/IDE/print_usrs.swift
@@ -173,9 +173,9 @@
     set {}
   }
 
-  // CHECK: [[@LINE+1]]:3 c:objc(cs)ObjCClass1(cm)initWithX:{{$}}
+  // CHECK: [[@LINE+1]]:3 c:objc(cs)ObjCClass1(im)initWithX:{{$}}
   init(x: Int) {}
-  // CHECK: [[@LINE+1]]:3 c:objc(cs)ObjCClass1(cm)init{{$}}
+  // CHECK: [[@LINE+1]]:3 c:objc(cs)ObjCClass1(im)init{{$}}
   init() {}
 
   // CHECK: [[@LINE+1]]:8 c:objc(cs)ObjCClass1(im)instanceFunc1:{{$}}
diff --git a/test/IDE/range_info_basics.swift b/test/IDE/range_info_basics.swift
index 9a0b919..9483408 100644
--- a/test/IDE/range_info_basics.swift
+++ b/test/IDE/range_info_basics.swift
@@ -159,7 +159,7 @@
 // CHECK4-NEXT: <Content>aaa = aaa + 3
 // CHECK4-NEXT: if aaa == 3 { aaa = 4 }</Content>
 // CHECK4-NEXT: <Type>Void</Type>
-// CHECK4-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK4-NEXT: <Context>swift_ide_test.(file).foo()</Context>
 // CHECK4-NEXT: <Referenced>aaa</Referenced><Type>@lvalue Int</Type>
 // CHECK4-NEXT: <ASTNodes>2</ASTNodes>
 // CHECK4-NEXT: <end>
@@ -169,7 +169,7 @@
 // CHECK5-NEXT: if aaa == 3 { aaa = 4 }
 // CHECK5-NEXT: return aaa</Content>
 // CHECK5-NEXT: <Type>Int</Type>
-// CHECK5-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK5-NEXT: <Context>swift_ide_test.(file).foo()</Context>
 // CHECK5-NEXT: <Referenced>aaa</Referenced><Type>@lvalue Int</Type>
 // CHECK5-NEXT: <ASTNodes>3</ASTNodes>
 // CHECK5-NEXT: <end>
@@ -178,7 +178,7 @@
 // CHECK6-NEXT: if aaa == 3 { aaa = 4 }
 // CHECK6-NEXT: return aaa</Content>
 // CHECK6-NEXT: <Type>Int</Type>
-// CHECK6-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK6-NEXT: <Context>swift_ide_test.(file).foo()</Context>
 // CHECK6-NEXT: <Referenced>aaa</Referenced><Type>@lvalue Int</Type>
 // CHECK6-NEXT: <ASTNodes>2</ASTNodes>
 // CHECK6-NEXT: <end>
@@ -189,7 +189,7 @@
 // CHECK7-NEXT:   b = b.bigEndian.bigEndian.byteSwapped
 // CHECK7-NEXT:   print(b + c)</Content>
 // CHECK7-NEXT: <Type>()</Type>
-// CHECK7-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK7-NEXT: <Context>swift_ide_test.(file).foo2()</Context>
 // CHECK7-NEXT: <Declared>b</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK7-NEXT: <Declared>c</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK7-NEXT: <Referenced>a</Referenced><Type>Int</Type>
@@ -203,7 +203,7 @@
 // CHECK8-NEXT:   s = s.increment()
 // CHECK8-NEXT:   return c + b</Content>
 // CHECK8-NEXT: <Type>Int</Type>
-// CHECK8-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK8-NEXT: <Context>swift_ide_test.(file).foo3(s:)</Context>
 // CHECK8-NEXT: <Declared>c</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK8-NEXT: <Referenced>s</Referenced><Type>@lvalue S1</Type>
 // CHECK8-NEXT: <Referenced>b</Referenced><Type>Int</Type>
@@ -216,7 +216,7 @@
 // CHECK9-NEXT:   let c = s.foo() + b
 // CHECK9-NEXT:   return c + b</Content>
 // CHECK9-NEXT: <Type>Int</Type>
-// CHECK9-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK9-NEXT: <Context>swift_ide_test.(file).foo4(s:)</Context>
 // CHECK9-NEXT: <Declared>b</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK9-NEXT: <Declared>c</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK9-NEXT: <Referenced>s</Referenced><Type>S1</Type>
@@ -228,7 +228,7 @@
 // CHECK10: <Kind>MultiStatement</Kind>
 // CHECK10-NEXT: <Content>let a = c.c.getC().c.getC().getC().getC()
 // CHECK10-NEXT:   let b = a.c.c.c.c.getC().getC()</Content>
-// CHECK10-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK10-NEXT: <Context>swift_ide_test.(file).foo5(c:)</Context>
 // CHECK10-NEXT: <Declared>a</Declared><OutscopeReference>true</OutscopeReference>
 // CHECK10-NEXT: <Declared>b</Declared><OutscopeReference>true</OutscopeReference>
 // CHECK10-NEXT: <Referenced>c</Referenced><Type>C1</Type>
@@ -240,7 +240,7 @@
 // CHECK11-NEXT: <Content>let a = c.c.getC().c.getC().getC().getC()
 // CHECK11-NEXT:   let b = a.c.c.c.c.getC().getC()
 // CHECK11-NEXT:   let d = a.c.getC().getC().c.c</Content>
-// CHECK11-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK11-NEXT: <Context>swift_ide_test.(file).foo5(c:)</Context>
 // CHECK11-NEXT: <Declared>a</Declared><OutscopeReference>true</OutscopeReference>
 // CHECK11-NEXT: <Declared>b</Declared><OutscopeReference>true</OutscopeReference>
 // CHECK11-NEXT: <Declared>d</Declared><OutscopeReference>true</OutscopeReference>
@@ -255,7 +255,7 @@
 // CHECK12-NEXT:   let d = a.c.getC().getC().c.c
 // CHECK12-NEXT:   return a.take(another: b).take(another: d)</Content>
 // CHECK12-NEXT: <Type>C1</Type>
-// CHECK12-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK12-NEXT: <Context>swift_ide_test.(file).foo5(c:)</Context>
 // CHECK12-NEXT: <Declared>a</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK12-NEXT: <Declared>b</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK12-NEXT: <Declared>d</Declared><OutscopeReference>false</OutscopeReference>
@@ -273,7 +273,7 @@
 // CHECK13-NEXT:     b = b.bigEndian.bigEndian.byteSwapped
 // CHECK13-NEXT:     print(b + c)</Content>
 // CHECK13-NEXT: <Type>()</Type>
-// CHECK13-NEXT: <Context>swift_ide_test.(file).func decl.explicit closure discriminator=0</Context>
+// CHECK13-NEXT: <Context>swift_ide_test.(file).foo6().explicit closure discriminator=0</Context>
 // CHECK13-NEXT: <Declared>a</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK13-NEXT: <Declared>b</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK13-NEXT: <Declared>c</Declared><OutscopeReference>false</OutscopeReference>
@@ -298,7 +298,7 @@
 // CHECK14-NEXT:       return 1
 // CHECK14-NEXT:     }()</Content>
 // CHECK14-NEXT: <Type>Int</Type>
-// CHECK14-NEXT: <Context>swift_ide_test.(file).func decl.explicit closure discriminator=0</Context>
+// CHECK14-NEXT: <Context>swift_ide_test.(file).foo6().explicit closure discriminator=0</Context>
 // CHECK14-NEXT: <Declared>a</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK14-NEXT: <Declared>b</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK14-NEXT: <Declared>c</Declared><OutscopeReference>false</OutscopeReference>
@@ -320,7 +320,7 @@
 // CHECK15-NEXT:       let c = a.byteSwapped
 // CHECK15-NEXT:       b = b.bigEndian.bigEndian.byteSwapped</Content>
 // CHECK15-NEXT: <Type>()</Type>
-// CHECK15-NEXT: <Context>swift_ide_test.(file).func decl.explicit closure discriminator=0.explicit closure discriminator=0</Context>
+// CHECK15-NEXT: <Context>swift_ide_test.(file).foo6().explicit closure discriminator=0.explicit closure discriminator=0</Context>
 // CHECK15-NEXT: <Declared>a</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK15-NEXT: <Declared>b</Declared><OutscopeReference>true</OutscopeReference>
 // CHECK15-NEXT: <Declared>c</Declared><OutscopeReference>true</OutscopeReference>
@@ -337,7 +337,7 @@
 // CHECK16-NEXT:       print(b + c)
 // CHECK16-NEXT:       return 1</Content>
 // CHECK16-NEXT: <Type>Int</Type>
-// CHECK16-NEXT: <Context>swift_ide_test.(file).func decl.explicit closure discriminator=0.explicit closure discriminator=0</Context>
+// CHECK16-NEXT: <Context>swift_ide_test.(file).foo6().explicit closure discriminator=0.explicit closure discriminator=0</Context>
 // CHECK16-NEXT: <Declared>a</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK16-NEXT: <Declared>b</Declared><OutscopeReference>false</OutscopeReference>
 // CHECK16-NEXT: <Declared>c</Declared><OutscopeReference>false</OutscopeReference>
@@ -350,7 +350,7 @@
 // CHECK17: <Kind>SingleExpression</Kind>
 // CHECK17-NEXT: <Content>print(b + c)</Content>
 // CHECK17-NEXT: <Type>()</Type>
-// CHECK17-NEXT: <Context>swift_ide_test.(file).func decl.explicit closure discriminator=0.explicit closure discriminator=0</Context>
+// CHECK17-NEXT: <Context>swift_ide_test.(file).foo6().explicit closure discriminator=0.explicit closure discriminator=0</Context>
 // CHECK17-NEXT: <Referenced>b</Referenced><Type>@lvalue Int</Type>
 // CHECK17-NEXT: <Referenced>c</Referenced><Type>Int</Type>
 // CHECK17-NEXT: <ASTNodes>1</ASTNodes>
@@ -362,7 +362,7 @@
 // CHECK18-NEXT:   case 2:
 // CHECK18-NEXT:     return 1</Content>
 // CHECK18-NEXT: <Type>Void</Type>
-// CHECK18-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK18-NEXT: <Context>swift_ide_test.(file).foo7(a:)</Context>
 // CHECK18-NEXT: <Entry>Multi</Entry>
 // CHECK18-NEXT: <ASTNodes>2</ASTNodes>
 // CHECK18-NEXT: <end>
@@ -371,7 +371,7 @@
 // CHECK19-NEXT: <Content>case 1:
 // CHECK19-NEXT:     return 0</Content>
 // CHECK19-NEXT: <Type>Void</Type>
-// CHECK19-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK19-NEXT: <Context>swift_ide_test.(file).foo7(a:)</Context>
 // CHECK19-NEXT: <ASTNodes>1</ASTNodes>
 // CHECK19-NEXT: <end>
 
@@ -381,7 +381,7 @@
 // CHECK20-NEXT:   default:
 // CHECK20-NEXT:     return a</Content>
 // CHECK20-NEXT: <Type>Void</Type>
-// CHECK20-NEXT: <Context>swift_ide_test.(file).func decl</Context>
+// CHECK20-NEXT: <Context>swift_ide_test.(file).foo7(a:)</Context>
 // CHECK20-NEXT: <Entry>Multi</Entry>
 // CHECK20-NEXT: <ASTNodes>2</ASTNodes>
 // CHECK20-NEXT: <end>
diff --git a/test/IDE/reconstruct_type_from_mangled_name_invalid.swift b/test/IDE/reconstruct_type_from_mangled_name_invalid.swift
index f001da0..80deae5 100644
--- a/test/IDE/reconstruct_type_from_mangled_name_invalid.swift
+++ b/test/IDE/reconstruct_type_from_mangled_name_invalid.swift
@@ -1,5 +1,5 @@
 // RUN: %target-swift-ide-test -reconstruct-type -source-filename %s | %FileCheck %s -implicit-check-not="FAILURE"
-// REQUIRES: rdar://problem/30680565
+// REQUIRES: rdar30680565
 
 struct GS<T> {
 // CHECK: decl: struct GS<T> for 'GS'
diff --git a/test/IRGen/abitypes.swift b/test/IRGen/abitypes.swift
index a4adaea..65c8398 100644
--- a/test/IRGen/abitypes.swift
+++ b/test/IRGen/abitypes.swift
@@ -551,7 +551,7 @@
 // arm64-ios:  [[STRUCTPTR:%.*]] = bitcast i64* [[COERCED]] to %TSC14FiveByteStructV
 // arm64-ios:  [[PTR0:%.*]] = getelementptr inbounds %TSC14FiveByteStructV, %TSC14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0
 // arm64-ios:  [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0
-// arm64-ios:  [[PTR2:%.*]] = getelementptr inbounds %Sb, %Sb* [[PTR1]], {{i.*}} 0, {{i.*}} 0
+// arm64-ios:  [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0
 // arm64-ios:  store i1 false, i1* [[PTR2]], align 8
 // arm64-ios:  [[ARG:%.*]] = load i64, i64* [[COERCED]]
 // arm64-ios:  call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]])
diff --git a/test/IRGen/asmname.swift b/test/IRGen/asmname.swift
index 86b5589..f55275d 100644
--- a/test/IRGen/asmname.swift
+++ b/test/IRGen/asmname.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 @_silgen_name("atan2") func atan2test(_ a: Double, _ b: Double) -> Double
 
diff --git a/test/IRGen/associated_types.swift b/test/IRGen/associated_types.swift
index 6b1a4da..2260286 100644
--- a/test/IRGen/associated_types.swift
+++ b/test/IRGen/associated_types.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 protocol Runcer {
   associatedtype Runcee
@@ -30,7 +30,7 @@
 class Pussycat<T : Runcible, U> {
   init() {} 
 
-  // CHECK: define hidden swiftcc void @_T016associated_types8PussycatC3eat{{[_0-9a-zA-Z]*}}F(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %C16associated_types8Pussycat* swiftself)
+  // CHECK: define hidden swiftcc void @_T016associated_types8PussycatC3eat{{[_0-9a-zA-Z]*}}F(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %T16associated_types8PussycatC* swiftself)
   func eat(_ what: T.RuncerType.Runcee, and: T.RuncerType, with: T) { }
 }
 
diff --git a/test/IRGen/bitcast.sil b/test/IRGen/bitcast.sil
index 02b8cc0..96c3c36 100644
--- a/test/IRGen/bitcast.sil
+++ b/test/IRGen/bitcast.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir| %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 sil_stage canonical
 
@@ -16,20 +16,20 @@
 
 protocol CP: class {}
 
-// CHECK-i386-LABEL: define{{( protected)?}} swiftcc i32 @bitcast_trivial(%C7bitcast1C*) {{.*}} {
-// CHECK-i386:         [[BUF:%.*]] = alloca %C7bitcast1C*, align 4
-// CHECK-i386:         store %C7bitcast1C* %0, %C7bitcast1C** [[BUF]]
-// CHECK-i386:         [[OUT_BUF:%.*]] = bitcast %C7bitcast1C** [[BUF]] to %Si*
-// CHECK-i386:         [[VALUE_BUF:%.*]] = getelementptr inbounds %Si, %Si* [[OUT_BUF]], i32 0, i32 0
+// CHECK-i386-LABEL: define{{( protected)?}} swiftcc i32 @bitcast_trivial(%T7bitcast1CC*) {{.*}} {
+// CHECK-i386:         [[BUF:%.*]] = alloca %T7bitcast1CC*, align 4
+// CHECK-i386:         store %T7bitcast1CC* %0, %T7bitcast1CC** [[BUF]]
+// CHECK-i386:         [[OUT_BUF:%.*]] = bitcast %T7bitcast1CC** [[BUF]] to %TSi*
+// CHECK-i386:         [[VALUE_BUF:%.*]] = getelementptr inbounds %TSi, %TSi* [[OUT_BUF]], i32 0, i32 0
 // CHECK-i386:         [[VALUE:%.*]] = load i32, i32* [[VALUE_BUF]], align 4
 // CHECK-i386:         ret i32 [[VALUE]]
 // CHECK-i386:       }
 
-// CHECK-x86_64-LABEL: define{{( protected)?}} swiftcc i64 @bitcast_trivial(%C7bitcast1C*) {{.*}} {
-// CHECK-x86_64:         [[BUF:%.*]] = alloca %C7bitcast1C*, align 8
-// CHECK-x86_64:         store %C7bitcast1C* %0, %C7bitcast1C** [[BUF]]
-// CHECK-x86_64:         [[OUT_BUF:%.*]] = bitcast %C7bitcast1C** [[BUF]] to %Si*
-// CHECK-x86_64:         [[VALUE_BUF:%.*]] = getelementptr inbounds %Si, %Si* [[OUT_BUF]], i32 0, i32 0
+// CHECK-x86_64-LABEL: define{{( protected)?}} swiftcc i64 @bitcast_trivial(%T7bitcast1CC*) {{.*}} {
+// CHECK-x86_64:         [[BUF:%.*]] = alloca %T7bitcast1CC*, align 8
+// CHECK-x86_64:         store %T7bitcast1CC* %0, %T7bitcast1CC** [[BUF]]
+// CHECK-x86_64:         [[OUT_BUF:%.*]] = bitcast %T7bitcast1CC** [[BUF]] to %TSi*
+// CHECK-x86_64:         [[VALUE_BUF:%.*]] = getelementptr inbounds %TSi, %TSi* [[OUT_BUF]], i32 0, i32 0
 // CHECK-x86_64:         [[VALUE:%.*]] = load i64, i64* [[VALUE_BUF]], align 8
 // CHECK-x86_64:         ret i64 [[VALUE]]
 // CHECK-x86_64:       }
@@ -54,15 +54,15 @@
   return %i : $Optional<Int>
 }
 
-// CHECK-i386-LABEL: define{{( protected)?}} swiftcc i32 @bitcast_ref(%C7bitcast1C*) {{.*}} {
+// CHECK-i386-LABEL: define{{( protected)?}} swiftcc i32 @bitcast_ref(%T7bitcast1CC*) {{.*}} {
 // CHECK-i386-NEXT:  entry:
-// CHECK-i386-NEXT:    [[VALUE:%.*]] = ptrtoint %C7bitcast1C* %0 to i32
+// CHECK-i386-NEXT:    [[VALUE:%.*]] = ptrtoint %T7bitcast1CC* %0 to i32
 // CHECK-i386-NEXT:    ret i32 [[VALUE]]
 // CHECK-i386-NEXT:  }
 
-// CHECK-x86_64-LABEL: define{{( protected)?}} swiftcc i64 @bitcast_ref(%C7bitcast1C*) {{.*}} {
+// CHECK-x86_64-LABEL: define{{( protected)?}} swiftcc i64 @bitcast_ref(%T7bitcast1CC*) {{.*}} {
 // CHECK-x86_64-NEXT:  entry:
-// CHECK-x86_64-NEXT:    [[VALUE:%.*]] = ptrtoint %C7bitcast1C* %0 to i64
+// CHECK-x86_64-NEXT:    [[VALUE:%.*]] = ptrtoint %T7bitcast1CC* %0 to i64
 // CHECK-x86_64-NEXT:    ret i64 [[VALUE]]
 // CHECK-x86_64-NEXT:  }
 sil @bitcast_ref: $@convention(thin) (C) -> Optional<C> {
@@ -88,12 +88,12 @@
 
 // CHECK-x86_64-LABEL: define hidden swiftcc i64 @unchecked_bitwise_cast(i64, i64) {{.*}} {
 // CHECK-x86_64-NEXT: entry:
-// CHECK-x86_64-NEXT: alloca <{ %Si, %Si }>, align 8
+// CHECK-x86_64-NEXT: alloca <{ %TSi, %TSi }>, align 8
 //   A bunch of GEPs happen here to get from Int to int.
 // CHECK-x86_64:      store i64 %{{.*}}, i64* %bitcast.elt._value, align 8
 // CHECK-x86_64:      store i64 %{{.*}}, i64* %bitcast.elt1._value, align 8
-// CHECK-x86_64-NEXT: %{{.*}} = bitcast <{ %Si, %Si }>* %bitcast to %Si*
-// CHECK-x86_64-NEXT: [[VAL:%.*]] = getelementptr inbounds %Si, %Si* %{{.*}}, i32 0, i32 0
+// CHECK-x86_64-NEXT: %{{.*}} = bitcast <{ %TSi, %TSi }>* %bitcast to %TSi*
+// CHECK-x86_64-NEXT: [[VAL:%.*]] = getelementptr inbounds %TSi, %TSi* %{{.*}}, i32 0, i32 0
 // CHECK-x86_64-NEXT: [[RESULT:%.*]] = load i64, i64* [[VAL]], align 8
 // CHECK-x86_64:      ret i64 [[RESULT]]
 // CHECK-x86_64-NEXT: }
@@ -107,7 +107,7 @@
 // CHECK-x86_64-LABEL: define hidden swiftcc i64 @trivial_bitwise_cast(i64, i64) {{.*}} {
 // CHECK-x86_64-NOT: trap
 // CHECK-x86_64-NOT: unreachable
-// CHECK-x86_64: bitcast <{ %Si, %Si }>* %bitcast to %Si*
+// CHECK-x86_64: bitcast <{ %TSi, %TSi }>* %bitcast to %TSi*
 // CHECK-x86_64: ret
 sil hidden [noinline] @trivial_bitwise_cast : $@convention(thin) (Int, Int) -> Int {
 bb0(%0 : $Int, %1 : $Int):
@@ -131,11 +131,11 @@
 }
 
 // CHECK-i386-LABEL: define{{( protected)?}} swiftcc i32 @unchecked_ref_cast_class_optional
-// CHECK-i386: ptrtoint %C7bitcast1A* %0 to i32
+// CHECK-i386: ptrtoint %T7bitcast1AC* %0 to i32
 // CHECK-i386-NEXT: ret i32
 
 // CHECK-x86_64-LABEL: define{{( protected)?}} swiftcc i64 @unchecked_ref_cast_class_optional
-// CHECK-x86_64: ptrtoint %C7bitcast1A* %0 to i64
+// CHECK-x86_64: ptrtoint %T7bitcast1AC* %0 to i64
 // CHECK-x86_64-NEXT: ret i64
 sil @unchecked_ref_cast_class_optional : $@convention(thin) (@owned A) -> @owned Optional<AnyObject> {
 bb0(%0 : $A):
diff --git a/test/IRGen/bitcast_different_size.sil b/test/IRGen/bitcast_different_size.sil
index 0ae508a..f4839af 100644
--- a/test/IRGen/bitcast_different_size.sil
+++ b/test/IRGen/bitcast_different_size.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s -verify | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 sil_stage canonical
 
diff --git a/test/IRGen/casts.sil b/test/IRGen/casts.sil
index 1203b76..ef94f22 100644
--- a/test/IRGen/casts.sil
+++ b/test/IRGen/casts.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -Xllvm -sil-disable-pass="External Defs To Decls" %s -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // XFAIL: linux
 
 sil_stage canonical
@@ -16,8 +16,8 @@
 sil_vtable A {}
 sil_vtable B {}
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc %C5casts1B* @unchecked_addr_cast(%C5casts1A** noalias nocapture dereferenceable({{.*}})) {{.*}} {
-// CHECK:         bitcast %C5casts1A** %0 to %C5casts1B**
+// CHECK-LABEL: define{{( protected)?}} swiftcc %T5casts1BC* @unchecked_addr_cast(%T5casts1AC** noalias nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK:         bitcast %T5casts1AC** %0 to %T5casts1BC**
 sil @unchecked_addr_cast : $(@in A) -> B {
 entry(%a : $*A):
   %b = unchecked_addr_cast %a : $*A to $*B
@@ -207,7 +207,7 @@
   unreachable
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_object* @checked_upcast(%C5casts1A*) {{.*}} {
+// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_object* @checked_upcast(%T5casts1AC*) {{.*}} {
 // -- Don't need to check conformance of an object to AnyObject.
 // CHECK-NOT:     call %objc_object* @swift_dynamicCastObjCProtocolConditional
 // CHECK:         phi %objc_object*
@@ -220,14 +220,14 @@
   unreachable
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc %C5casts1A* @checked_downcast_optional({{(i32|i64)}}) {{.*}} {
-// CHECK:         [[T0:%.*]] = inttoptr {{(i32|i64)}} %0 to %C5casts1A*
-// CHECK:         [[OBJ_PTR:%.*]] = bitcast %C5casts1A* [[T0]] to i8*
+// CHECK-LABEL: define{{( protected)?}} swiftcc %T5casts1AC* @checked_downcast_optional({{(i32|i64)}}) {{.*}} {
+// CHECK:         [[T0:%.*]] = inttoptr {{(i32|i64)}} %0 to %T5casts1AC*
+// CHECK:         [[OBJ_PTR:%.*]] = bitcast %T5casts1AC* [[T0]] to i8*
 // CHECK:         [[METADATA:%.*]] = call %swift.type* @_T05casts1ACMa()
 // CHECK:         [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to i8*
 // CHECK:         [[RESULT_PTR:%.*]] = call i8* @swift_rt_swift_dynamicCastClass(i8* [[OBJ_PTR]], i8* [[METADATA_PTR]])
-// CHECK:         [[RESULT:%.*]] = bitcast i8* [[RESULT_PTR]] to %C5casts1A*
-// CHECK:         [[COND:%.*]] = icmp ne %C5casts1A* [[RESULT]], null
+// CHECK:         [[RESULT:%.*]] = bitcast i8* [[RESULT_PTR]] to %T5casts1AC*
+// CHECK:         [[COND:%.*]] = icmp ne %T5casts1AC* [[RESULT]], null
 // CHECK:         br i1 [[COND]]
 sil @checked_downcast_optional : $@convention(thin) (Optional<A>) -> @owned A {
 entry(%a : $Optional<A>):
@@ -317,7 +317,7 @@
   return %x : $OB
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc %C5casts1B* @checked_object_to_object_casts(%C5casts1A*)
+// CHECK-LABEL: define{{( protected)?}} swiftcc %T5casts1BC* @checked_object_to_object_casts(%T5casts1AC*)
 // CHECK:         @swift_dynamicCastClassUnconditional
 sil @checked_object_to_object_casts : $@convention(thin) (A) -> B {
 entry(%a : $A):
@@ -325,7 +325,7 @@
   return %b : $B
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc %C5casts2OB* @checked_objc_object_to_object_casts(%C5casts2OA*)
+// CHECK-LABEL: define{{( protected)?}} swiftcc %T5casts2OBC* @checked_objc_object_to_object_casts(%T5casts2OAC*)
 // CHECK:         @swift_dynamicCastClassUnconditional
 sil @checked_objc_object_to_object_casts : $@convention(thin) (OA) -> OB {
 entry(%a : $OA):
diff --git a/test/IRGen/cf.sil b/test/IRGen/cf.sil
index 29993a9..606b888 100644
--- a/test/IRGen/cf.sil
+++ b/test/IRGen/cf.sil
@@ -1,10 +1,10 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -sdk %S/Inputs %s -emit-ir -import-cf-types | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // REQUIRES: objc_interop
 
 // CHECK: [[TYPE:%swift.type]] = type
-// CHECK: [[REFRIGERATOR:%CSo14CCRefrigerator]] = type
+// CHECK: [[REFRIGERATOR:%TSo14CCRefrigeratorC]] = type
 // CHECK: [[OBJC:%objc_object]] = type
 
 // CHECK: [[REFRIGERATOR_NAME:@.*]] = private unnamed_addr constant [20 x i8] c"So14CCRefrigeratorC\00"
diff --git a/test/IRGen/clang_inline.swift b/test/IRGen/clang_inline.swift
index c59b912..58eec15 100644
--- a/test/IRGen/clang_inline.swift
+++ b/test/IRGen/clang_inline.swift
@@ -12,7 +12,7 @@
 // RUN: %FileCheck %s < %t.ll
 // RUN: %FileCheck -check-prefix=NEGATIVE %s < %t.ll
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // XFAIL: linux
 
 #if IMPORT_EMPTY
@@ -21,7 +21,7 @@
 
 import gizmo
 
-// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline16CallStaticInlineC10ReturnZeros5Int64VyF(%C12clang_inline16CallStaticInline* swiftself) {{.*}} {
+// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline16CallStaticInlineC10ReturnZeros5Int64VyF(%T12clang_inline16CallStaticInlineC* swiftself) {{.*}} {
 class CallStaticInline {
   func ReturnZero() -> Int64 { return Int64(zero()) }
 }
@@ -29,7 +29,7 @@
 // CHECK-LABEL: define internal i32 @zero()
 // CHECK:         [[INLINEHINT_SSP_UWTABLE:#[0-9]+]] {
 
-// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline17CallStaticInline2C10ReturnZeros5Int64VyF(%C12clang_inline17CallStaticInline2* swiftself) {{.*}} {
+// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline17CallStaticInline2C10ReturnZeros5Int64VyF(%T12clang_inline17CallStaticInline2C* swiftself) {{.*}} {
 class CallStaticInline2 {
   func ReturnZero() -> Int64 { return Int64(wrappedZero()) }
 }
diff --git a/test/IRGen/clang_inline_reverse.swift b/test/IRGen/clang_inline_reverse.swift
index 2891dc8..f0d587b 100644
--- a/test/IRGen/clang_inline_reverse.swift
+++ b/test/IRGen/clang_inline_reverse.swift
@@ -2,19 +2,19 @@
 
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -sdk %S/Inputs -primary-file %s -emit-ir -module-name clang_inline | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // XFAIL: linux
 
 import gizmo
 
-// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline16CallStaticInlineC10ReturnZeros5Int64VyF(%C12clang_inline16CallStaticInline* swiftself) {{.*}} {
+// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline16CallStaticInlineC10ReturnZeros5Int64VyF(%T12clang_inline16CallStaticInlineC* swiftself) {{.*}} {
 class CallStaticInline {
   func ReturnZero() -> Int64 { return Int64(wrappedZero()) }
 }
 
 // CHECK-LABEL: define internal i32 @wrappedZero() {{#[0-9]+}} {
 
-// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline17CallStaticInline2C10ReturnZeros5Int64VyF(%C12clang_inline17CallStaticInline2* swiftself) {{.*}} {
+// CHECK-LABEL: define hidden swiftcc i64 @_T012clang_inline17CallStaticInline2C10ReturnZeros5Int64VyF(%T12clang_inline17CallStaticInline2C* swiftself) {{.*}} {
 class CallStaticInline2 {
   func ReturnZero() -> Int64 { return Int64(zero()) }
 }
diff --git a/test/IRGen/class_bounded_generics.swift b/test/IRGen/class_bounded_generics.swift
index a71fa83..242fe80 100644
--- a/test/IRGen/class_bounded_generics.swift
+++ b/test/IRGen/class_bounded_generics.swift
@@ -88,6 +88,9 @@
   // CHECK: [[INHERITED:%.*]] = load i8*, i8** %T.ClassBoundBinary, align 8
   // CHECK: [[INHERITED_WTBL:%.*]] = bitcast i8* [[INHERITED]] to i8**
   // CHECK: [[WITNESS:%.*]] = load i8*, i8** [[INHERITED_WTBL]], align 8
+  // FIXME: Redundant load of inherited conformance
+  // CHECK: [[INHERITED:%.*]] = load i8*, i8** %T.ClassBoundBinary, align 8
+  // CHECK: [[INHERITED_WTBL:%.*]] = bitcast i8* [[INHERITED]] to i8**
   // CHECK: [[WITNESS_FUNC:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %swift.type*, i8**)
   // CHECK: call swiftcc void [[WITNESS_FUNC]](%objc_object* swiftself %0, %swift.type* {{.*}}, i8** [[INHERITED_WTBL]])
   x.classBoundBinaryMethod(y)
diff --git a/test/IRGen/dynamic_cast.sil b/test/IRGen/dynamic_cast.sil
index 95e89e6..0f00bdb 100644
--- a/test/IRGen/dynamic_cast.sil
+++ b/test/IRGen/dynamic_cast.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 // We have to claim this is raw SIL because there are critical edges from non
 // cond_br instructions.
@@ -17,7 +17,7 @@
   var v: Int
 }
 
-// CHECK: [[INT:%Si]] = type <{ [[LLVM_PTRSIZE_INT:i(32|64)]] }>
+// CHECK: [[INT:%TSi]] = type <{ [[LLVM_PTRSIZE_INT:i(32|64)]] }>
 
 // CHECK-LABEL: define{{( protected)?}} swiftcc void @testUnconditional0(
 sil @testUnconditional0 : $@convention(thin) (@in P) -> () {
diff --git a/test/IRGen/dynamic_lookup.sil b/test/IRGen/dynamic_lookup.sil
index 337bd98..af7a081 100644
--- a/test/IRGen/dynamic_lookup.sil
+++ b/test/IRGen/dynamic_lookup.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // REQUIRES: objc_interop
 
 import Swift
diff --git a/test/IRGen/dynamic_self.sil b/test/IRGen/dynamic_self.sil
index c8cae59..07b2c34 100644
--- a/test/IRGen/dynamic_self.sil
+++ b/test/IRGen/dynamic_self.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 sil_stage canonical
 
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index 3210f64..3daf1d2 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime-%target-ptrsize
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 // We have to claim this is raw SIL because there are critical edges from non
 // cond_br instructions.
@@ -10,42 +10,42 @@
 import Swift
 
 // -- Singleton enum. The representation is just the singleton payload.
-// CHECK: %O4enum9Singleton = type <{ <{ i64, i64 }> }>
+// CHECK: %T4enum9SingletonO = type <{ <{ i64, i64 }> }>
 
 // -- Singleton enum with heap object ref payload. <rdar://problem/15679353>
-// CHECK: %O4enum12SingletonRef = type <{ %swift.refcounted* }>
+// CHECK: %T4enum12SingletonRefO = type <{ %swift.refcounted* }>
 
 // -- No-payload enums. The representation is just an enum tag.
-// CHECK: %O4enum10NoPayloads = type <{ i8 }>
-// CHECK: %O4enum11NoPayloads2 = type <{ i8 }>
+// CHECK: %T4enum10NoPayloadsO = type <{ i8 }>
+// CHECK: %T4enum11NoPayloads2O = type <{ i8 }>
 
 // -- Single-payload enum, no extra inhabitants in the payload type. The
 //    representation adds a tag bit to distinguish payload from enum tag:
 //      case x(i64): X0 X1 X2 ... X63 | 0, where X0...X63 are the payload bits
 //      case y:      0  0  0  ... 0   | 1
 //      case z:      1  0  0  ... 0   | 1
-// CHECK-64: %O4enum17SinglePayloadNoXI = type <{ [8 x i8], [1 x i8] }>
-// CHECK-64: %O4enum18SinglePayloadNoXI2 = type <{ [8 x i8], [1 x i8] }>
-// CHECK-32: %O4enum17SinglePayloadNoXI = type <{ [4 x i8], [1 x i8] }>
-// CHECK-32: %O4enum18SinglePayloadNoXI2 = type <{ [4 x i8], [1 x i8] }>
+// CHECK-64: %T4enum17SinglePayloadNoXIO = type <{ [8 x i8], [1 x i8] }>
+// CHECK-64: %T4enum18SinglePayloadNoXI2O = type <{ [8 x i8], [1 x i8] }>
+// CHECK-32: %T4enum17SinglePayloadNoXIO = type <{ [4 x i8], [1 x i8] }>
+// CHECK-32: %T4enum18SinglePayloadNoXI2O = type <{ [4 x i8], [1 x i8] }>
 
 // -- Single-payload enum, spare bits. The representation uses a tag bit
 //    out of the payload to distinguish payload from enum tag:
 //      case x(i3): X0 X1 X2 0 0 0 0 0
 //      case y:     0  0  0  1 0 0 0 0
 //      case z:     1  0  0  1 0 0 0 0
-// CHECK: %O4enum21SinglePayloadSpareBit = type <{ [8 x i8] }>
+// CHECK: %T4enum21SinglePayloadSpareBitO = type <{ [8 x i8] }>
 
 // -- Single-payload enum containing a no-payload enum as its payload.
 //    The representation takes extra inhabitants starting after the greatest
 //    discriminator value used by the nested no-payload enum.
-// CHECK: %O4enum19SinglePayloadNested = type <{ [1 x i8] }>
+// CHECK: %T4enum19SinglePayloadNestedO = type <{ [1 x i8] }>
 
 // -- Single-payload enum containing another single-payload enum as its
 //    payload.
 //    The representation takes extra inhabitants from the nested enum's payload
 //    that were unused by the nested enum.
-// CHECK: %O4enum25SinglePayloadNestedNested = type <{ [1 x i8] }>
+// CHECK: %T4enum019SinglePayloadNestedD0O = type <{ [1 x i8] }>
 
 // -- Multi-payload enum, no spare bits. The representation adds tag bits
 //    to discriminate payloads. No-payload cases all share a tag.
@@ -55,7 +55,7 @@
 //      case a:     0  0  0  ... 0  0  | 1 1
 //      case b:     1  0  0  ... 0  0  | 1 1
 //      case c:     0  1  0  ... 0  0  | 1 1
-// CHECK: %O4enum23MultiPayloadNoSpareBits = type <{ [8 x i8], [1 x i8] }>
+// CHECK: %T4enum23MultiPayloadNoSpareBitsO = type <{ [8 x i8], [1 x i8] }>
 
 // -- Multi-payload enum, one spare bit. The representation uses spare bits
 //    common to all payloads to partially discriminate payloads, with added
@@ -66,7 +66,7 @@
 //      case a:     0  0  0  0  0  0  0  1 | 1
 //      case b:     1  0  0  0  0  0  0  1 | 1
 //      case c:     0  1  0  0  0  0  0  1 | 1
-// CHECK: %O4enum23MultiPayloadOneSpareBit = type <{ [8 x i8], [1 x i8] }>
+// CHECK: %T4enum23MultiPayloadOneSpareBitO = type <{ [8 x i8], [1 x i8] }>
 
 // -- Multi-payload enum, two spare bits. Same as above, except we have enough
 //    spare bits not to require any added tag bits.
@@ -76,28 +76,28 @@
 //      case a:     0  0  0  0  0  0  1  1
 //      case b:     1  0  0  0  0  0  1  1
 //      case c:     0  1  0  0  0  0  1  1
-// CHECK: %O4enum24MultiPayloadTwoSpareBits = type <{ [8 x i8] }>
+// CHECK: %T4enum24MultiPayloadTwoSpareBitsO = type <{ [8 x i8] }>
 
-// CHECK-64: %O4enum30MultiPayloadSpareBitAggregates = type <{ [16 x i8] }>
+// CHECK-64: %T4enum30MultiPayloadSpareBitAggregatesO = type <{ [16 x i8] }>
 
-// CHECK-64: %O4enum18MultiPayloadNested = type <{ [9 x i8] }>
-// CHECK-32: %O4enum18MultiPayloadNested = type <{ [5 x i8] }>
+// CHECK-64: %T4enum18MultiPayloadNestedO = type <{ [9 x i8] }>
+// CHECK-32: %T4enum18MultiPayloadNestedO = type <{ [5 x i8] }>
 
 // 32-bit object references don't have enough spare bits.
-// CHECK-64: %O4enum27MultiPayloadNestedSpareBits = type <{ [8 x i8] }>
+// CHECK-64: %T4enum27MultiPayloadNestedSpareBitsO = type <{ [8 x i8] }>
 
 // -- Dynamic enums. The type layout is opaque; we dynamically bitcast to
 //    the element type.
-// CHECK: %O4enum20DynamicSinglePayload = type <{}>
-// CHECK: [[DYNAMIC_SINGLE_EMPTY_PAYLOAD:%GO4enum20DynamicSinglePayloadT__]] = type <{ [1 x i8] }>
+// CHECK: %T4enum20DynamicSinglePayloadO = type <{}>
+// CHECK: [[DYNAMIC_SINGLE_EMPTY_PAYLOAD:%T4enum20DynamicSinglePayloadOyytG]] = type <{ [1 x i8] }>
 
 // -- Address-only multi-payload enums. We can't use spare bits.
-// CHECK-64: %O4enum32MultiPayloadAddressOnlySpareBits = type <{ [16 x i8], [1 x i8] }>
-// CHECK-32: %O4enum32MultiPayloadAddressOnlySpareBits = type <{ [8 x i8], [1 x i8] }>
+// CHECK-64: %T4enum32MultiPayloadAddressOnlySpareBitsO = type <{ [16 x i8], [1 x i8] }>
+// CHECK-32: %T4enum32MultiPayloadAddressOnlySpareBitsO = type <{ [8 x i8], [1 x i8] }>
 
-// CHECK: [[DYNAMIC_SINGLETON:%O4enum16DynamicSingleton.*]] = type <{}>
+// CHECK: [[DYNAMIC_SINGLETON:%T4enum16DynamicSingletonO.*]] = type <{}>
 
-// CHECK: %O4enum40MultiPayloadLessThan32BitsWithEmptyCases = type <{ [1 x i8], [1 x i8] }>
+// CHECK: %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO = type <{ [1 x i8], [1 x i8] }>
 
 // -- Dynamic metadata template carries a value witness table pattern
 //    we fill in on instantiation.
@@ -196,7 +196,7 @@
 }
 
 // CHECK-64: define{{( protected)?}} swiftcc void @singleton_switch(i64, i64) {{.*}} {
-// CHECK-32: define{{( protected)?}} swiftcc void @singleton_switch(%O4enum9Singleton* noalias nocapture dereferenceable(16)) {{.*}} {
+// CHECK-32: define{{( protected)?}} swiftcc void @singleton_switch(%T4enum9SingletonO* noalias nocapture dereferenceable(16)) {{.*}} {
 sil @singleton_switch : $(Singleton) -> () {
 // CHECK-64: entry:
 // CHECK-32: entry:
@@ -215,12 +215,12 @@
 }
 
 // CHECK-64: define{{( protected)?}} swiftcc void @singleton_switch_arg(i64, i64) {{.*}} {
-// CHECK-32: define{{( protected)?}} swiftcc void @singleton_switch_arg(%O4enum9Singleton* noalias nocapture dereferenceable(16)) {{.*}} {
+// CHECK-32: define{{( protected)?}} swiftcc void @singleton_switch_arg(%T4enum9SingletonO* noalias nocapture dereferenceable(16)) {{.*}} {
 sil @singleton_switch_arg : $(Singleton) -> () {
 // CHECK-64: entry:
 // CHECK-32: entry:
 entry(%u : $Singleton):
-// CHECK-32:  [[CAST:%.*]] = bitcast %O4enum9Singleton* %0 to <{ i64, i64 }>*
+// CHECK-32:  [[CAST:%.*]] = bitcast %T4enum9SingletonO* %0 to <{ i64, i64 }>*
 // CHECK-32:  [[GEP1:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[CAST]], i32 0, i32 0
 // CHECK-32:  [[ELT1:%.*]] = load i64, i64* [[GEP1]]
 // CHECK-32:  [[GEP2:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[CAST]], i32 0, i32 1
@@ -246,11 +246,11 @@
   return %x : $()
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @singleton_switch_indirect(%O4enum9Singleton* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK: define{{( protected)?}} swiftcc void @singleton_switch_indirect(%T4enum9SingletonO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK: entry:
 // CHECK:   br label %[[DEST:[0-9]+]]
 // CHECK: ; <label>:[[DEST]]
-// CHECK:   [[ADDR:%.*]] = bitcast %O4enum9Singleton* %0 to <{ i64, i64 }>*
+// CHECK:   [[ADDR:%.*]] = bitcast %T4enum9SingletonO* %0 to <{ i64, i64 }>*
 // CHECK:   ret void
 // CHECK: }
 sil @singleton_switch_indirect : $(@inout Singleton) -> () {
@@ -268,9 +268,9 @@
 // CHECK-64:   [[B:%.*]] = insertvalue { i64, i64 } [[A]], i64 %1, 1
 // CHECK-64:   ret { i64, i64 } [[B]]
 // CHECK-64: }
-// CHECK-32: define{{( protected)?}} swiftcc void @singleton_inject(%O4enum9Singleton* noalias nocapture sret, i64, i64) {{.*}} {
+// CHECK-32: define{{( protected)?}} swiftcc void @singleton_inject(%T4enum9SingletonO* noalias nocapture sret, i64, i64) {{.*}} {
 // CHECK-32: entry:
-// CHECK-32:  [[CAST:%.*]] = bitcast %O4enum9Singleton* %0 to <{ i64, i64 }>*
+// CHECK-32:  [[CAST:%.*]] = bitcast %T4enum9SingletonO* %0 to <{ i64, i64 }>*
 // CHECK-32:  [[GEP1:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[CAST]], i32 0, i32 0
 // CHECK-32:                 store i64 %1, i64* [[GEP1]]
 // CHECK-32:  [[GEP2:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[CAST]], i32 0, i32 1
@@ -284,9 +284,9 @@
   return %u : $Singleton
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @singleton_inject_indirect(i64, i64, %O4enum9Singleton* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK: define{{( protected)?}} swiftcc void @singleton_inject_indirect(i64, i64, %T4enum9SingletonO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK: entry:
-// CHECK:   [[DATA_ADDR:%.*]] = bitcast %O4enum9Singleton* %2 to <{ i64, i64 }>*
+// CHECK:   [[DATA_ADDR:%.*]] = bitcast %T4enum9SingletonO* %2 to <{ i64, i64 }>*
 // CHECK:   [[DATA_0_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 0
 // CHECK:   store i64 %0, i64* [[DATA_0_ADDR]]
 // CHECK:   [[DATA_1_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 1
@@ -360,10 +360,10 @@
   return %x : $()
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @no_payload_switch_indirect(%O4enum10NoPayloads* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK: define{{( protected)?}} swiftcc void @no_payload_switch_indirect(%T4enum10NoPayloadsO* nocapture dereferenceable({{.*}})) {{.*}} {
 sil @no_payload_switch_indirect : $@convention(thin) (@inout NoPayloads) -> () {
 entry(%u : $*NoPayloads):
-// CHECK:   [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads, %O4enum10NoPayloads* %0, i32 0, i32 0
+// CHECK:   [[TAG_ADDR:%.*]] = getelementptr inbounds %T4enum10NoPayloadsO, %T4enum10NoPayloadsO* %0, i32 0, i32 0
 // CHECK:   [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]]
 // CHECK:   switch i8 [[TAG]]
   switch_enum_addr %u : $*NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest
@@ -409,9 +409,9 @@
   return %u : $NoPayloads
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @no_payload_inject_z_indirect(%O4enum10NoPayloads* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK: define{{( protected)?}} swiftcc void @no_payload_inject_z_indirect(%T4enum10NoPayloadsO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK: entry:
-// CHECK:   [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads, %O4enum10NoPayloads* %0, i32 0, i32 0
+// CHECK:   [[TAG_ADDR:%.*]] = getelementptr inbounds %T4enum10NoPayloadsO, %T4enum10NoPayloadsO* %0, i32 0, i32 0
 // CHECK:   store i8 2, i8* [[TAG_ADDR]]
 // CHECK:   ret void
 // CHECK: }
@@ -619,11 +619,11 @@
   return %u : $SinglePayloadNoXI2
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @single_payload_no_xi_inject_x_indirect([[WORD]], %O4enum18SinglePayloadNoXI2* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK: define{{( protected)?}} swiftcc void @single_payload_no_xi_inject_x_indirect([[WORD]], %T4enum18SinglePayloadNoXI2O* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK: entry:
-// CHECK:   [[DATA_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %1 to [[WORD]]*
+// CHECK:   [[DATA_ADDR:%.*]] = bitcast %T4enum18SinglePayloadNoXI2O* %1 to [[WORD]]*
 // CHECK:   store [[WORD]] %0, [[WORD]]* [[DATA_ADDR]]
-// CHECK:   [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2, %O4enum18SinglePayloadNoXI2* %1, i32 0, i32 1
+// CHECK:   [[T0:%.*]] = getelementptr inbounds %T4enum18SinglePayloadNoXI2O, %T4enum18SinglePayloadNoXI2O* %1, i32 0, i32 1
 // CHECK:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
 // CHECK:   store i1 false, i1* [[TAG_ADDR]]
 // CHECK:   ret void
@@ -647,11 +647,11 @@
   return %u : $SinglePayloadNoXI2
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @single_payload_no_xi_inject_y_indirect(%O4enum18SinglePayloadNoXI2* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK: define{{( protected)?}} swiftcc void @single_payload_no_xi_inject_y_indirect(%T4enum18SinglePayloadNoXI2O* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK: entry:
-// CHECK:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %0 to [[WORD]]*
+// CHECK:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum18SinglePayloadNoXI2O* %0 to [[WORD]]*
 // CHECK:   store [[WORD]] 0, [[WORD]]* [[PAYLOAD_ADDR]]
-// CHECK:   [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2, %O4enum18SinglePayloadNoXI2* %0, i32 0, i32 1
+// CHECK:   [[T0:%.*]] = getelementptr inbounds %T4enum18SinglePayloadNoXI2O, %T4enum18SinglePayloadNoXI2O* %0, i32 0, i32 1
 // CHECK:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
 // CHECK:   store i1 true, i1* [[TAG_ADDR]]
 // CHECK:   ret void
@@ -743,10 +743,10 @@
 }
 
 // CHECK-64: define{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_2([[WORD]], [[WORD]], [[WORD]], [[WORD]]) {{.*}} {
-// CHECK-32: define{{( protected)?}}  swiftcc void @aggregate_single_payload_unpack_2(%O4enum23AggregateSinglePayload2* noalias nocapture dereferenceable(16)) {{.*}} {
+// CHECK-32: define{{( protected)?}}  swiftcc void @aggregate_single_payload_unpack_2(%T4enum23AggregateSinglePayload2O* noalias nocapture dereferenceable(16)) {{.*}} {
 sil @aggregate_single_payload_unpack_2 : $@convention(thin) (AggregateSinglePayload2) -> () {
 entry(%u : $AggregateSinglePayload2):
-// CHECK-32:  [[CAST:%.*]] = bitcast %O4enum23AggregateSinglePayload2* %0 to { i32, i32, i32, i32 }*
+// CHECK-32:  [[CAST:%.*]] = bitcast %T4enum23AggregateSinglePayload2O* %0 to { i32, i32, i32, i32 }*
 // CHECK-32:  [[GEP:%.*]] = getelementptr inbounds {{.*}} [[CAST]], i32 0, i32 0
 // CHECK-32:  [[LOAD1:%.*]] = load i32, i32* [[GEP]]
 // CHECK-32:  [[LOAD2:%.*]] = load i32, i32* {{.*}}
@@ -783,10 +783,10 @@
 // CHECK-64:  %9 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %8, [[WORD]] %3, 3
 // CHECK-64:  ret { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %9
 
-// CHECK-32: define{{( protected)?}} swiftcc void @aggregate_single_payload_2_inject(%O4enum23AggregateSinglePayload2* noalias nocapture sret, i32, i32, i32, i32) {{.*}} {
+// CHECK-32: define{{( protected)?}} swiftcc void @aggregate_single_payload_2_inject(%T4enum23AggregateSinglePayload2O* noalias nocapture sret, i32, i32, i32, i32) {{.*}} {
 // CHECK-32:  [[TRUNC:%.*]] = trunc i32 %1 to i21
 // CHECK-32:  [[ZEXT:%.*]] = zext i21 [[TRUNC]] to i32
-// CHECK-32:  [[CAST:%.*]] = bitcast %O4enum23AggregateSinglePayload2* %0 to { i32, i32, i32, i32 }*
+// CHECK-32:  [[CAST:%.*]] = bitcast %T4enum23AggregateSinglePayload2O* %0 to { i32, i32, i32, i32 }*
 // CHECK-32:  [[GEP:%.*]] = getelementptr inbounds {{.*}} [[CAST]], i32 0, i32 0
 // CHECK-32:  store i32 [[ZEXT]], i32* [[GEP]]
 // CHECK-32:  store i32 %2, i32*
@@ -967,13 +967,13 @@
 
 sil @single_payload_spare_bit_switch_indirect : $@convention(thin) (@inout SinglePayloadSpareBit) -> () {
 entry(%u : $*SinglePayloadSpareBit):
-// CHECK-64:  [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64*
+// CHECK-64:  [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %0 to i64*
 // CHECK-64:  [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
 // CHECK-64:  switch i64 [[PAYLOAD]]
   switch_enum_addr %u : $*SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest
 
 // CHECK-64: ; <label>:
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i63*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %0 to i63*
 x_dest:
   %u2 = unchecked_take_enum_data_addr %u : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
   %a = function_ref @a : $@convention(thin) () -> ()
@@ -1003,10 +1003,10 @@
   return %u : $SinglePayloadSpareBit
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_x_indirect(i64, %O4enum21SinglePayloadSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_x_indirect(i64, %T4enum21SinglePayloadSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
 // CHECK-64:   [[T:%.*]] = trunc i64 %0 to i63
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %1 to i63*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %1 to i63*
 // CHECK-64:   store i63 [[T]], i63* [[DATA_ADDR]]
 // CHECK-64:   ret void
 // CHECK-64: }
@@ -1030,9 +1030,9 @@
   return %u : $SinglePayloadSpareBit
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_y_indirect(%O4enum21SinglePayloadSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_y_indirect(%T4enum21SinglePayloadSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %0 to i64*
 // --                0x8000_0000_0000_0000
 // CHECK-64:   store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]]
 // CHECK-64:   ret void
@@ -1146,7 +1146,7 @@
 // CHECK-64:     i64 4, label {{%.*}}
 // CHECK-64:   ]
 // CHECK-64: ; <label>
-// CHECK-64:   inttoptr [[WORD]] %0 to %C4enum1C*
+// CHECK-64:   inttoptr [[WORD]] %0 to %T4enum1CC*
 
 // CHECK-32: define{{( protected)?}} swiftcc void @single_payload_class_switch(i32) {{.*}} {
 // CHECK-32: entry:
@@ -1156,7 +1156,7 @@
 // CHECK-32:     i32 2, label {{%.*}}
 // CHECK-32:   ]
 // CHECK-32: ; <label>
-// CHECK-32:   inttoptr [[WORD]] %0 to %C4enum1C*
+// CHECK-32:   inttoptr [[WORD]] %0 to %T4enum1CC*
 
 sil @single_payload_class_switch : $(SinglePayloadClass) -> () {
 entry(%c : $SinglePayloadClass):
@@ -1270,8 +1270,8 @@
   case w
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @dynamic_single_payload_switch(%O4enum20DynamicSinglePayload* noalias nocapture, %swift.type* %T) {{.*}} {
-// CHECK:   [[OPAQUE_ENUM:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
+// CHECK: define{{( protected)?}} swiftcc void @dynamic_single_payload_switch(%T4enum20DynamicSinglePayloadO* noalias nocapture, %swift.type* %T) {{.*}} {
+// CHECK:   [[OPAQUE_ENUM:%.*]] = bitcast %T4enum20DynamicSinglePayloadO* %0 to %swift.opaque*
 // CHECK:   [[CASE_INDEX:%.*]] = call i32 @swift_rt_swift_getEnumCaseSinglePayload(%swift.opaque* [[OPAQUE_ENUM]], %swift.type* %T, i32 3)
 // CHECK:   switch i32 [[CASE_INDEX]], label {{%.*}} [
 // CHECK:     i32 -1, label {{%.*}}
@@ -1295,8 +1295,8 @@
   return %v : $()
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @dynamic_single_payload_inject_x(%O4enum20DynamicSinglePayload* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T) {{.*}} {
-// CHECK:   [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
+// CHECK: define{{( protected)?}} swiftcc void @dynamic_single_payload_inject_x(%T4enum20DynamicSinglePayloadO* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T) {{.*}} {
+// CHECK:   [[ADDR:%.*]] = bitcast %T4enum20DynamicSinglePayloadO* %0 to %swift.opaque*
 // CHECK:   call void @swift_rt_swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 -1, i32 3)
 sil @dynamic_single_payload_inject_x : $<T> (@in T) -> @out DynamicSinglePayload<T> {
 entry(%r : $*DynamicSinglePayload<T>, %t : $*T):
@@ -1305,8 +1305,8 @@
   return %v : $()
 }
 
-// CHECK: define{{( protected)?}} swiftcc void @dynamic_single_payload_inject_y(%O4enum20DynamicSinglePayload* noalias nocapture sret, %swift.type* %T) {{.*}} {
-// CHECK:   [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
+// CHECK: define{{( protected)?}} swiftcc void @dynamic_single_payload_inject_y(%T4enum20DynamicSinglePayloadO* noalias nocapture sret, %swift.type* %T) {{.*}} {
+// CHECK:   [[ADDR:%.*]] = bitcast %T4enum20DynamicSinglePayloadO* %0 to %swift.opaque*
 // CHECK:   call void @swift_rt_swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 0, i32 3)
 sil @dynamic_single_payload_inject_y : $<T> () -> @out DynamicSinglePayload<T> {
 entry(%r : $*DynamicSinglePayload<T>):
@@ -1486,12 +1486,12 @@
   return %v : $()
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_no_spare_bits_switch_indirect(%O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_no_spare_bits_switch_indirect(%T4enum23MultiPayloadNoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
 sil @multi_payload_no_spare_bits_switch_indirect : $(@inout MultiPayloadNoSpareBits) -> () {
 entry(%u : $*MultiPayloadNoSpareBits):
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadNoSpareBitsO, %T4enum23MultiPayloadNoSpareBitsO* %0, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8*
 // CHECK-64:   [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]]
 // CHECK-64:   switch i8 [[TAG]]
@@ -1501,11 +1501,11 @@
   switch_enum_addr %u : $*MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest
 
 // CHECK-64: ; <label>:[[X_DEST:[0-9]+]]
-// CHECK-64:   bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
+// CHECK-64:   bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i64*
 // CHECK-64: ; <label>:[[Y_DEST:[0-9]+]]
-// CHECK-64:   bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i32*
+// CHECK-64:   bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i32*
 // CHECK-64: ; <label>:[[Z_DEST:[0-9]+]]
-// CHECK-64:   bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i63*
+// CHECK-64:   bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i63*
 
 x_dest:
   %x = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
@@ -1545,11 +1545,11 @@
   return %u : $MultiPayloadNoSpareBits
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_x_indirect(i64, %O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_x_indirect(i64, %T4enum23MultiPayloadNoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %1 to i64*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadNoSpareBitsO* %1 to i64*
 // CHECK-64:   store i64 %0, i64* [[DATA_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %1, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadNoSpareBitsO, %T4enum23MultiPayloadNoSpareBitsO* %1, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8*
 // CHECK-64:   store i8 0, i8* [[TAG_ADDR]]
 // CHECK-64:   ret void
@@ -1600,11 +1600,11 @@
   return %u : $MultiPayloadNoSpareBits
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_a_indirect(%O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_a_indirect(%T4enum23MultiPayloadNoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i64*
 // CHECK-64:   store i64 0, i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadNoSpareBitsO, %T4enum23MultiPayloadNoSpareBitsO* %0, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8*
 // CHECK-64:   store i8 3, i8* [[TAG_ADDR]]
 // CHECK-64:   ret void
@@ -1734,9 +1734,9 @@
 
 sil @multi_payload_one_spare_bit_switch_indirect : $(@inout MultiPayloadOneSpareBit) -> () {
 entry(%u : $*MultiPayloadOneSpareBit):
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %0, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
 // CHECK-64:   [[TAG:%.*]] = load i1, i1* [[TAG_ADDR]]
 // CHECK-64:   switch i8 {{%.*}}
@@ -1746,19 +1746,19 @@
   switch_enum_addr %u : $*MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest
 
 // CHECK-64: ; <label>:[[X_PREDEST:[0-9]+]]
-// CHECK-64:   bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i62*
+// CHECK-64:   bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i62*
 
 // CHECK-64: ; <label>:[[Y_PREDEST:[0-9]+]]
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
 // --                                                   0x7FFF_FFFF_FFFF_FFFF
 // CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
 // CHECK-64:   store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i63*
+// CHECK-64:   bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i63*
 
 // CHECK-64: ; <label>:[[Z_PREDEST:[0-9]+]]
-// CHECK-64:   bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i61*
+// CHECK-64:   bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i61*
 
 x_dest:
   %x = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
@@ -1800,18 +1800,18 @@
   return %u : $MultiPayloadOneSpareBit
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_x_indirect(i64, %O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_x_indirect(i64, %T4enum23MultiPayloadOneSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
 // CHECK-64:   [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i62*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i62*
 // CHECK-64:   store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
 // --                                                   0x7FFF_FFFF_FFFF_FFFF
 // CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
 // CHECK-64:   store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %1, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
 // CHECK-64:   store i1 false, i1* [[TAG_ADDR]]
 // CHECK-64:   ret void
@@ -1841,20 +1841,20 @@
   return %u : $MultiPayloadOneSpareBit
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_y_indirect(i64, %O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_y_indirect(i64, %T4enum23MultiPayloadOneSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
 // CHECK-64:   [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i63*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i63*
 // CHECK-64:   store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]]
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
 // --                                                   0x7FFF_FFFF_FFFF_FFFF
 // CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
 // --                                                          0x8000_0000_0000_0000
 // CHECK-64:   [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], -9223372036854775808
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
 // CHECK-64:   store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %1, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
 // CHECK-64:   store i1 false, i1* [[TAG_ADDR]]
 // CHECK-64:   ret void
@@ -1894,12 +1894,12 @@
   return %u : $MultiPayloadOneSpareBit
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_a_indirect(%O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_a_indirect(%T4enum23MultiPayloadOneSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
 // --                0x8000_0000_0000_0000
 // CHECK-64:   store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]]
-// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1
+// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %0, i32 0, i32 1
 // CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
 // CHECK-64:   store i1 true, i1* [[TAG_ADDR]]
 // CHECK-64:   ret void
@@ -2040,16 +2040,16 @@
   return %u : $MultiPayloadTwoSpareBits
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_x_indirect(i64, %O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_x_indirect(i64, %T4enum24MultiPayloadTwoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
 // CHECK-64:   [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i62*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i62*
 // CHECK-64:   store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
 // --                                                   0x3FFF_FFFF_FFFF_FFFF
 // CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
 // CHECK-64:   store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
 // CHECK-64:   ret void
 // CHECK-64: }
@@ -2076,18 +2076,18 @@
   return %u : $MultiPayloadTwoSpareBits
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_y_indirect(i64, %O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_y_indirect(i64, %T4enum24MultiPayloadTwoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
 // CHECK-64:   [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60
-// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i60*
+// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i60*
 // CHECK-64:   store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]]
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
 // CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
 // --                                                   0x3FFF_FFFF_FFFF_FFFF
 // CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
 // --                                                         0x4000_0000_0000_0000
 // CHECK-64:   [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], 4611686018427387904
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
 // CHECK-64:   store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]]
 // CHECK-64:   ret void
 // CHECK-64: }
@@ -2125,9 +2125,9 @@
   return %u : $MultiPayloadTwoSpareBits
 }
 
-// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_a_indirect(%O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64: define{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_a_indirect(%T4enum24MultiPayloadTwoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
-// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %0 to i64*
+// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %0 to i64*
 // --                0xC000_0000_0000_0000
 // CHECK-64:   store i64 -4611686018427387904, i64* [[PAYLOAD_ADDR]]
 // CHECK-64:   ret void
@@ -2189,11 +2189,11 @@
 // CHECK-64:     i64 -9223372036854775800, label {{%.*}}
 // CHECK-64:   ]
 // -- Extract x(C)
-// CHECK-64:   inttoptr i64 %0 to %C4enum1C*
+// CHECK-64:   inttoptr i64 %0 to %T4enum1CC*
 // -- Extract y(D)
 // --                                     0x3fffffffffffffff
 // CHECK-64:   [[MASKED:%.*]] = and i64 %0, 4611686018427387903
-// CHECK-64:   inttoptr i64 [[MASKED]] to %C4enum1D*
+// CHECK-64:   inttoptr i64 [[MASKED]] to %T4enum1DC*
 
 // CHECK-32-LABEL: define{{( protected)?}} swiftcc void @multi_payload_classes_switch(i32) {{.*}} {
 // CHECK-32:   %1 = trunc i32 %0 to i8
@@ -2208,10 +2208,10 @@
 // CHECK-32:     i32 6, label {{%.*}}
 // CHECK-32:   ]
 // -- Extract x(C)
-// CHECK-32:   inttoptr i32 %0 to %C4enum1C*
+// CHECK-32:   inttoptr i32 %0 to %T4enum1CC*
 // -- Extract y(D)
 // CHECK-32:   [[MASKED:%.*]] = and i32 %0, -4
-// CHECK-32:   inttoptr i32 [[MASKED]] to %C4enum1D*
+// CHECK-32:   inttoptr i32 [[MASKED]] to %T4enum1DC*
 
 sil @multi_payload_classes_switch : $(MultiPayloadClasses) -> () {
 entry(%c : $MultiPayloadClasses):
@@ -2261,8 +2261,8 @@
 // CHECK-64: ; <label>:[[Y_DEST]]
 // --                                        0x3fffffffffffffff
 // CHECK-64:   [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903
-// CHECK-64:   [[Y_0:%.*]] = inttoptr i64 [[Y_MASKED]] to %C4enum1C*
-// CHECK-64:   [[Y_1:%.*]] = inttoptr i64 %1 to %C4enum1C*
+// CHECK-64:   [[Y_0:%.*]] = inttoptr i64 [[Y_MASKED]] to %T4enum1CC*
+// CHECK-64:   [[Y_1:%.*]] = inttoptr i64 %1 to %T4enum1CC*
 // CHECK-64: ; <label>:[[Z_DEST]]
 // --                                        0x3fffffffffffffff
 // CHECK-64:   [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903
@@ -2297,7 +2297,7 @@
 }
 
 // CHECK-LABEL: define{{( protected)?}} swiftcc void @multi_payload_nested_switch
-// CHECK:   %1 = bitcast %O4enum18MultiPayloadNested* %0 to { [[WORD]], i8 }*
+// CHECK:   %1 = bitcast %T4enum18MultiPayloadNestedO* %0 to { [[WORD]], i8 }*
 // CHECK:   %2 = getelementptr
 // CHECK:   %3 = load [[WORD]], [[WORD]]* %2
 // CHECK:   %4 = getelementptr
@@ -2331,9 +2331,9 @@
   case B(MultiPayloadInnerSpareBits)
 }
 
-// CHECK-64-LABEL: define{{( protected)?}} swiftcc void @multi_payload_nested_spare_bits_switch(%O4enum27MultiPayloadNestedSpareBits* noalias nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-64-LABEL: define{{( protected)?}} swiftcc void @multi_payload_nested_spare_bits_switch(%T4enum27MultiPayloadNestedSpareBitsO* noalias nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-64: entry:
-// CHECK-64:   %1 = bitcast %O4enum27MultiPayloadNestedSpareBits* %0 to [[WORD]]*
+// CHECK-64:   %1 = bitcast %T4enum27MultiPayloadNestedSpareBitsO* %0 to [[WORD]]*
 // CHECK-64:   %2 = load [[WORD]], [[WORD]]* %1
 // CHECK-64:   %3 = lshr [[WORD]] %2, 61
 // CHECK-64:   %4 = trunc [[WORD]] %3 to i1
@@ -2402,7 +2402,7 @@
   case Y(Builtin.Int32)
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc void @multi_payload_address_only_destroy(%O4enum28MultiPayloadAddressOnlyFixed* noalias nocapture dereferenceable({{.*}}))
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @multi_payload_address_only_destroy(%T4enum28MultiPayloadAddressOnlyFixedO* noalias nocapture dereferenceable({{.*}}))
 sil @multi_payload_address_only_destroy : $@convention(thin) (@in MultiPayloadAddressOnlyFixed) -> () {
 entry(%m : $*MultiPayloadAddressOnlyFixed):
   destroy_addr %m : $*MultiPayloadAddressOnlyFixed
@@ -2422,7 +2422,7 @@
   case Y(AddressOnlySpareBitsPayload)
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc void @multi_payload_address_only_spare_bits(%O4enum32MultiPayloadAddressOnlySpareBits* noalias nocapture dereferenceable({{.*}}))
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @multi_payload_address_only_spare_bits(%T4enum32MultiPayloadAddressOnlySpareBitsO* noalias nocapture dereferenceable({{.*}}))
 sil @multi_payload_address_only_spare_bits : $@convention(thin) (@in MultiPayloadAddressOnlySpareBits) -> () {
 entry(%m : $*MultiPayloadAddressOnlySpareBits):
   destroy_addr %m : $*MultiPayloadAddressOnlySpareBits
@@ -2561,7 +2561,7 @@
 weak var delegate: delegateProtocol?
 }
 
-// CHECK-64-LABEL: define{{( protected)?}} swiftcc void @weak_optional(%GSqV4enum17StructWithWeakVar_* noalias nocapture dereferenceable({{.*}}))
+// CHECK-64-LABEL: define{{( protected)?}} swiftcc void @weak_optional(%T4enum17StructWithWeakVarVSg* noalias nocapture dereferenceable({{.*}}))
 sil @weak_optional : $@convention(thin) (@in StructWithWeakVar?) -> () {
 entry(%x : $*StructWithWeakVar?):
   // CHECK-64:      icmp eq [[WORD]] {{%.*}}, 0
@@ -2714,8 +2714,8 @@
 // CHECK-64:         %6 = or i128 %5, 18446744073709551616
 
 // CHECK-LABEL: define linkonce_odr hidden i32 @_T04enum40MultiPayloadLessThan32BitsWithEmptyCasesOwug(%swift.opaque* %value
-// CHECK:  [[VAL00:%.*]] = bitcast %swift.opaque* %value to %O4enum40MultiPayloadLessThan32BitsWithEmptyCases*
-// CHECK:  [[VAL01:%.*]] = bitcast %O4enum40MultiPayloadLessThan32BitsWithEmptyCases* [[VAL00]] to i8*
+// CHECK:  [[VAL00:%.*]] = bitcast %swift.opaque* %value to %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO*
+// CHECK:  [[VAL01:%.*]] = bitcast %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO* [[VAL00]] to i8*
 // CHECK:  [[VAL02:%.*]] = load {{.*}} [[VAL01]]
 // CHECK:  [[VAL03:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1
 // CHECK:  [[VAL04:%.*]] = bitcast {{.*}} [[VAL03]] to i8*
@@ -2736,7 +2736,7 @@
 
 // CHECK: <label>:[[TLABEL]]
 // CHECK:  [[VAL03:%.*]] = trunc i32 %tag to i8
-// CHECK:  [[VAL04:%.*]] = bitcast %O4enum40MultiPayloadLessThan32BitsWithEmptyCases* [[VAL00]] to i8*
+// CHECK:  [[VAL04:%.*]] = bitcast %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO* [[VAL00]] to i8*
 // CHECK:  store i8 [[VAL03]], i8* [[VAL04]]
 // CHECK:  [[VAL05:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1
 // CHECK:  [[VAL06:%.*]] = bitcast [1 x i8]* [[VAL05]] to i8*
diff --git a/test/IRGen/enum_spare_bits.sil b/test/IRGen/enum_spare_bits.sil
index f9d4cf9..faf16ed 100644
--- a/test/IRGen/enum_spare_bits.sil
+++ b/test/IRGen/enum_spare_bits.sil
@@ -2,7 +2,7 @@
 // RUN: %build-irgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -Xllvm -new-mangling-for-tests %s -emit-ir | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // REQUIRES: objc_interop
 
 import Swift
@@ -17,15 +17,15 @@
   case A(C), B(D)
 }
 // can use spare bits—both payloads are Swift-defined classes
-// CHECK-32: %O15enum_spare_bits10SwiftClass = type <{ [4 x i8] }>
-// CHECK-64: %O15enum_spare_bits10SwiftClass = type <{ [8 x i8] }>
+// CHECK-32: %T15enum_spare_bits10SwiftClassO = type <{ [4 x i8] }>
+// CHECK-64: %T15enum_spare_bits10SwiftClassO = type <{ [8 x i8] }>
 
 enum ObjCClass {
   case A(NSObject), B(C)
 }
 // can't use spare bits—NSObject is an ObjC-defined class
-// CHECK-32: %O15enum_spare_bits9ObjCClass = type <{ [4 x i8] }>
-// CHECK-64: %O15enum_spare_bits9ObjCClass = type <{ [8 x i8], [1 x i8] }>
+// CHECK-32: %T15enum_spare_bits9ObjCClassO = type <{ [4 x i8] }>
+// CHECK-64: %T15enum_spare_bits9ObjCClassO = type <{ [8 x i8], [1 x i8] }>
 
 @objc @unsafe_no_objc_tagged_pointer
 protocol NoTaggedPointers {}
@@ -34,24 +34,24 @@
   case A(AnyObject), B(C)
 }
 // can't use spare bits—existential may be bound to tagged pointer type
-// CHECK-32: %O15enum_spare_bits11Existential = type <{ [4 x i8] }>
-// CHECK-64: %O15enum_spare_bits11Existential = type <{ [8 x i8], [1 x i8] }>
+// CHECK-32: %T15enum_spare_bits11ExistentialO = type <{ [4 x i8] }>
+// CHECK-64: %T15enum_spare_bits11ExistentialO = type <{ [8 x i8], [1 x i8] }>
 
 enum ExistentialNoTaggedPointers {
   case A(NoTaggedPointers), B(C)
 }
 // can use spare bits—@unsafe_no_objc_tagged_pointer says it's ok
-// CHECK-32: %O15enum_spare_bits27ExistentialNoTaggedPointers = type <{ [4 x i8] }>
-// CHECK-64: %O15enum_spare_bits27ExistentialNoTaggedPointers = type <{ [8 x i8] }>
+// CHECK-32: %T15enum_spare_bits27ExistentialNoTaggedPointersO = type <{ [4 x i8] }>
+// CHECK-64: %T15enum_spare_bits27ExistentialNoTaggedPointersO = type <{ [8 x i8] }>
 
 enum Archetype<T: AnyObject> {
   case A(T), B(C)
 }
 // can't use spare bits—archetype may be bound to tagged pointer type
-// CHECK-32: [[ARCHETYPE:%GO15enum_spare_bits9ArchetypeCS_1C_]] = type <{ [4 x i8], [1 x i8] }>
-// CHECK-32: [[ARCHETYPE_OBJC:%GO15enum_spare_bits9ArchetypeCSo8NSObject_]] = type <{ [4 x i8], [1 x i8] }>
-// CHECK-64: [[ARCHETYPE:%GO15enum_spare_bits9ArchetypeCS_1C_]] = type <{ [8 x i8], [1 x i8] }>
-// CHECK-64: [[ARCHETYPE_OBJC:%GO15enum_spare_bits9ArchetypeCSo8NSObject_]] = type <{ [8 x i8], [1 x i8] }>
+// CHECK-32: [[ARCHETYPE:%T15enum_spare_bits9ArchetypeOyAA1CCG]] = type <{ [4 x i8], [1 x i8] }>
+// CHECK-32: [[ARCHETYPE_OBJC:%T15enum_spare_bits9ArchetypeOySo8NSObjectCG]] = type <{ [4 x i8], [1 x i8] }>
+// CHECK-64: [[ARCHETYPE:%T15enum_spare_bits9ArchetypeOyAA1CCG]] = type <{ [8 x i8], [1 x i8] }>
+// CHECK-64: [[ARCHETYPE_OBJC:%T15enum_spare_bits9ArchetypeOySo8NSObjectCG]] = type <{ [8 x i8], [1 x i8] }>
 
 sil_global @swiftClass: $SwiftClass
 sil_global @objcClass: $ObjCClass
diff --git a/test/IRGen/fixlifetime.sil b/test/IRGen/fixlifetime.sil
index d00ad60..c6d0d6a 100644
--- a/test/IRGen/fixlifetime.sil
+++ b/test/IRGen/fixlifetime.sil
@@ -2,31 +2,31 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-sil -emit-ir -disable-llvm-optzns -Ounchecked %s | %FileCheck --check-prefix=CHECK-%target-runtime %s
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-sil -emit-ir -disable-llvm-optzns -Onone %s | %FileCheck --check-prefix=ONONE %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 // At -Onone we don't run the LLVM ARC optimizer, so the fixLifetime call is
 // unnecessary.
 // ONONE-NOT: @__swift_fixLifetime
 
-// CHECK-objc-LABEL: define{{( protected)?}} swiftcc void @test(%C11fixlifetime1C*, %objc_object*, i8**, i8*, %swift.refcounted*, %V11fixlifetime3Agg* noalias nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-objc-LABEL: define{{( protected)?}} swiftcc void @test(%T11fixlifetime1CC*, %objc_object*, i8**, i8*, %swift.refcounted*, %T11fixlifetime3AggV* noalias nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-objc: entry:
-// CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
+// CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC*)*)(%T11fixlifetime1CC*
 // CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%objc_object*)*)(%objc_object*
 // CHECK-objc:  call void @__swift_fixLifetime(%swift.refcounted*
-// CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
+// CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC*)*)(%T11fixlifetime1CC*
 // CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%objc_object*)*)(%objc_object*
 // CHECK-objc:  call void @__swift_fixLifetime(%swift.refcounted*
-// CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C**)*)(%C11fixlifetime1C**
+// CHECK-objc:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC**)*)(%T11fixlifetime1CC**
 
-// CHECK-native-LABEL: define{{( protected)?}} swiftcc void @test(%C11fixlifetime1C*, %swift.refcounted*, i8**, i8*, %swift.refcounted*, %V11fixlifetime3Agg* noalias nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-native-LABEL: define{{( protected)?}} swiftcc void @test(%T11fixlifetime1CC*, %swift.refcounted*, i8**, i8*, %swift.refcounted*, %T11fixlifetime3AggV* noalias nocapture dereferenceable({{.*}})) {{.*}} {
 // CHECK-native: entry:
-// CHECK-native:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
+// CHECK-native:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC*)*)(%T11fixlifetime1CC*
 // CHECK-native:  call void @__swift_fixLifetime(%swift.refcounted*
 // CHECK-native:  call void @__swift_fixLifetime(%swift.refcounted*
-// CHECK-native:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
+// CHECK-native:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC*)*)(%T11fixlifetime1CC*
 // CHECK-native:  call void @__swift_fixLifetime(%swift.refcounted*
 // CHECK-native:  call void @__swift_fixLifetime(%swift.refcounted*
-// CHECK-native:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C**)*)(%C11fixlifetime1C**
+// CHECK-native:  call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC**)*)(%T11fixlifetime1CC**
 
 sil_stage canonical
 
diff --git a/test/IRGen/function_types.sil b/test/IRGen/function_types.sil
index 876004f..9e36338 100644
--- a/test/IRGen/function_types.sil
+++ b/test/IRGen/function_types.sil
@@ -1,21 +1,18 @@
-// RUN: %swift -target x86_64-apple-macosx10.9 -module-name function_types %s -emit-ir -o - | %FileCheck %s
-// RUN: %swift -target i386-apple-ios7.1 %s -module-name function_types -emit-ir -o - | %FileCheck %s
-// RUN: %swift -target x86_64-apple-ios7.1 %s -module-name function_types -emit-ir -o - | %FileCheck %s
-// RUN: %swift -target armv7-apple-ios7.1 %s -module-name function_types -emit-ir -o - | %FileCheck %s
-// RUN: %swift -target arm64-apple-ios7.1 %s -module-name function_types -emit-ir -o - | %FileCheck %s
-// RUN: %swift -target x86_64-unknown-linux-gnu -disable-objc-interop %s -module-name function_types -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target x86_64-apple-macosx10.9 -module-name function_types -assume-parsing-unqualified-ownership-sil %s -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target i386-apple-ios7.1 %s -module-name function_types -assume-parsing-unqualified-ownership-sil -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target x86_64-apple-ios7.1 %s -module-name function_types -assume-parsing-unqualified-ownership-sil -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target armv7-apple-ios7.1 %s -module-name function_types -assume-parsing-unqualified-ownership-sil -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target arm64-apple-ios7.1 %s -module-name function_types -assume-parsing-unqualified-ownership-sil -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target x86_64-unknown-linux-gnu -disable-objc-interop %s -module-name function_types -assume-parsing-unqualified-ownership-sil -emit-ir -o - | %FileCheck %s
 
 // REQUIRES: CODEGENERATOR=X86
 // REQUIRES: CODEGENERATOR=ARM
 
-// FIXME: SR-3603 test is failing after being unintentionally disabled for a while
-// REQUIRES: SR3603
- 
 import Builtin
 
 sil_stage canonical
 
-// CHECK-LABEL: define{{( protected)?}} i8* @thin_func_value(i8*) {{.*}} {
+// CHECK-LABEL: define{{( protected)?}} swiftcc i8* @thin_func_value(i8*) {{.*}} {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    ret i8* %0
 // CHECK-NEXT:  }
@@ -24,7 +21,7 @@
   return %x : $@convention(thin) () -> ()
 }
 
-// CHECK-LABEL: define{{( protected)?}} { i8*, %swift.refcounted* } @thick_func_value(i8*, %swift.refcounted*) {{.*}} {
+// CHECK-LABEL: define{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @thick_func_value(i8*, %swift.refcounted*) {{.*}} {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    call void @swift_rt_swift_retain(%swift.refcounted* %1) {{#[0-9]+}}
 // CHECK-NEXT:    call void @swift_rt_swift_release(%swift.refcounted* %1) {{#[0-9]+}}
@@ -39,11 +36,9 @@
   return %x : $() -> ()
 }
 
-// CHECK-LABEL: define{{( protected)?}} { i8*, i8** } @thin_witness_value(i8*, i8**) {{.*}} {
+// CHECK-LABEL: define{{( protected)?}} swiftcc i8* @thin_witness_value(i8*) {{.*}} {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[T0:%.*]] = insertvalue { i8*, i8** } undef, i8* %0, 0
-// CHECK-NEXT:    [[T1:%.*]] = insertvalue { i8*, i8** } [[T0]], i8** %1, 1
-// CHECK-NEXT:    ret { i8*, i8** } [[T1]]
+// CHECK-NEXT:    ret i8* %0
 // CHECK-NEXT:  }
 sil @thin_witness_value : $@convention(thin) (@convention(witness_method) () -> ()) -> @convention(witness_method) () -> () {
 entry(%x : $@convention(witness_method) () -> ()):
@@ -54,9 +49,9 @@
 
 sil @out_void_return : $@convention(thin) () -> @out X
 
-// CHECK-LABEL: define{{( protected)?}} void @use_void_return_value(%V14function_types1X* noalias nocapture sret) {{.*}} {
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @use_void_return_value(%T14function_types1XV* noalias nocapture sret) {{.*}} {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @out_void_return(%V14function_types1X* noalias nocapture sret %0)
+// CHECK-NEXT:    call swiftcc void @out_void_return(%T14function_types1XV* noalias nocapture sret %0)
 // CHECK-NEXT:    ret void
 // CHECK-NEXT:  }
 sil @use_void_return_value : $@convention(thin) () -> @out X {
@@ -66,7 +61,7 @@
   return %z : $()
 }
 
-// CHECK-LABEL: define{{( protected)?}} i1 @test_is_nonnull_function(i8*, %swift.refcounted*) {{.*}} {
+// CHECK-LABEL: define{{( protected)?}} swiftcc i1 @test_is_nonnull_function(i8*, %swift.refcounted*) {{.*}} {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:  %2 = icmp ne i8* %0, null
 // CHECK-NEXT:  ret i1 %2
@@ -78,7 +73,7 @@
   return %3 : $Builtin.Int1                                 // id: %5
 }
 
-// CHECK-LABEL: define{{( protected)?}} i8* @test_function_to_pointer(i8*)
+// CHECK-LABEL: define{{( protected)?}} swiftcc i8* @test_function_to_pointer(i8*)
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    ret i8* %0
 sil @test_function_to_pointer : $@convention(thin) (@convention(thin) () -> ()) -> Builtin.RawPointer {
@@ -87,7 +82,7 @@
   return %1 : $Builtin.RawPointer
 }
 
-// CHECK-LABEL: define{{( protected)?}} i8* @test_pointer_to_function(i8*)
+// CHECK-LABEL: define{{( protected)?}} swiftcc i8* @test_pointer_to_function(i8*)
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    ret i8* %0
 sil @test_pointer_to_function : $@convention(thin) (Builtin.RawPointer) -> @convention(thin) () -> () {
diff --git a/test/IRGen/generic_class_anyobject.swift b/test/IRGen/generic_class_anyobject.swift
index 3e47b8b..f5d9d4c 100644
--- a/test/IRGen/generic_class_anyobject.swift
+++ b/test/IRGen/generic_class_anyobject.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // REQUIRES: objc_interop
 
 func foo<T: AnyObject>(_ x: T) -> T { return x }
diff --git a/test/IRGen/generic_classes_objc.sil b/test/IRGen/generic_classes_objc.sil
index ba563fa..e476e6f 100644
--- a/test/IRGen/generic_classes_objc.sil
+++ b/test/IRGen/generic_classes_objc.sil
@@ -2,7 +2,7 @@
 // RUN: %build-irgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -Xllvm -new-mangling-for-tests %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // REQUIRES: objc_interop
 
 import Builtin
diff --git a/test/IRGen/generic_ternary.swift b/test/IRGen/generic_ternary.swift
index 5a240cb..ed7c99d 100644
--- a/test/IRGen/generic_ternary.swift
+++ b/test/IRGen/generic_ternary.swift
@@ -1,10 +1,10 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 // <rdar://problem/13793646>
 struct OptionalStreamAdaptor<T : IteratorProtocol> {
-  // CHECK: define hidden swiftcc void @_T015generic_ternary21OptionalStreamAdaptorV4next{{[_0-9a-zA-Z]*}}F(%Sq{{.*}}* noalias nocapture sret, %swift.type* %"OptionalStreamAdaptor<T>", %V15generic_ternary21OptionalStreamAdaptor* nocapture swiftself dereferenceable({{.*}}))
+  // CHECK: define hidden swiftcc void @_T015generic_ternary21OptionalStreamAdaptorV4next{{[_0-9a-zA-Z]*}}F(%TSq{{.*}}* noalias nocapture sret, %swift.type* %"OptionalStreamAdaptor<T>", %T15generic_ternary21OptionalStreamAdaptorV* nocapture swiftself dereferenceable({{.*}}))
   mutating
   func next() -> Optional<T.Element> {
     return x[0].next()
diff --git a/test/IRGen/indirect_return.swift b/test/IRGen/indirect_return.swift
index 2cb0b95..8d0957fb 100644
--- a/test/IRGen/indirect_return.swift
+++ b/test/IRGen/indirect_return.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 // CHECK: define hidden swiftcc void @_T015indirect_return11generic_get{{[_0-9a-zA-Z]*}}F
 func generic_get<T>(p: UnsafeMutablePointer<T>) -> T {
diff --git a/test/IRGen/infinite_archetype.swift b/test/IRGen/infinite_archetype.swift
index 5a974f3..f6b503d 100644
--- a/test/IRGen/infinite_archetype.swift
+++ b/test/IRGen/infinite_archetype.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 protocol Fooable {
   associatedtype Foo
diff --git a/test/IRGen/lazy_multi_file.swift b/test/IRGen/lazy_multi_file.swift
index dc4274e..fd343b2 100644
--- a/test/IRGen/lazy_multi_file.swift
+++ b/test/IRGen/lazy_multi_file.swift
@@ -1,17 +1,17 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -primary-file %s %S/Inputs/lazy_multi_file_helper.swift -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
-// CHECK: %C15lazy_multi_file8Subclass = type <{ %swift.refcounted, %[[OPTIONAL_INT_TY:GSqSi_]], [{{[0-9]+}} x i8], %SS }>
+// CHECK: %T15lazy_multi_file8SubclassC = type <{ %swift.refcounted, %[[OPTIONAL_INT_TY:TSiSg]], [{{[0-9]+}} x i8], %TSS }>
 // CHECK: %[[OPTIONAL_INT_TY]] = type <{ [{{[0-9]+}} x i8], [1 x i8] }>
-// CHECK: %V15lazy_multi_file13LazyContainer = type <{ %[[OPTIONAL_INT_TY]] }>
+// CHECK: %T15lazy_multi_file13LazyContainerV = type <{ %[[OPTIONAL_INT_TY]] }>
 
 class Subclass : LazyContainerClass {
   final var str = "abc"
 
-  // CHECK-LABEL: @_T015lazy_multi_file8SubclassC6getStrSSyF(%C15lazy_multi_file8Subclass* swiftself) {{.*}} {
+  // CHECK-LABEL: @_T015lazy_multi_file8SubclassC6getStrSSyF(%T15lazy_multi_file8SubclassC* swiftself) {{.*}} {
   func getStr() -> String {
-    // CHECK: = getelementptr inbounds %C15lazy_multi_file8Subclass, %C15lazy_multi_file8Subclass* %0, i32 0, i32 3
+    // CHECK: = getelementptr inbounds %T15lazy_multi_file8SubclassC, %T15lazy_multi_file8SubclassC* %0, i32 0, i32 3
     return str
   }
 }
diff --git a/test/IRGen/metatype_casts.sil b/test/IRGen/metatype_casts.sil
index 2c2a2cc..598440a 100644
--- a/test/IRGen/metatype_casts.sil
+++ b/test/IRGen/metatype_casts.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // XFAIL: linux
 
 import Swift
@@ -68,8 +68,8 @@
 class OtherClass : SomeClass {}
 sil_vtable OtherClass {}
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc void @value_metatype_cast(%C14metatype_casts9SomeClass*)
-// CHECK:         [[T0:%.*]] = bitcast %C14metatype_casts9SomeClass* %0 to %swift.type**
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @value_metatype_cast(%T14metatype_casts9SomeClassC*)
+// CHECK:         [[T0:%.*]] = bitcast %T14metatype_casts9SomeClassC* %0 to %swift.type**
 // CHECK:         [[T1:%.*]] = load %swift.type*, %swift.type** [[T0]]
 // CHECK:         [[T2:%.*]] = icmp eq %swift.type* [[T1]], {{.*}} @_T014metatype_casts10OtherClassCMf
 sil @value_metatype_cast : $@convention(thin) (SomeClass) -> () {
diff --git a/test/IRGen/nondominant.sil b/test/IRGen/nondominant.sil
index e4c58c5..11740b8 100644
--- a/test/IRGen/nondominant.sil
+++ b/test/IRGen/nondominant.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 import Builtin
 
diff --git a/test/IRGen/objc_alloc.sil b/test/IRGen/objc_alloc.sil
index 364ac71..2d95809 100644
--- a/test/IRGen/objc_alloc.sil
+++ b/test/IRGen/objc_alloc.sil
@@ -2,7 +2,7 @@
 // RUN: %build-irgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 // REQUIRES: objc_interop
 
 sil_stage canonical
diff --git a/test/IRGen/protocol_extensions.sil b/test/IRGen/protocol_extensions.sil
index aea3760..2bd52c1 100644
--- a/test/IRGen/protocol_extensions.sil
+++ b/test/IRGen/protocol_extensions.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 import Builtin
 
diff --git a/test/IRGen/select_enum_single_payload.sil b/test/IRGen/select_enum_single_payload.sil
index a187bb0..f3d0aae 100644
--- a/test/IRGen/select_enum_single_payload.sil
+++ b/test/IRGen/select_enum_single_payload.sil
@@ -1,5 +1,5 @@
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s --check-prefix=CHECK-%target-ptrsize
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 sil_stage canonical
 
diff --git a/test/IRGen/sil_witness_methods.sil b/test/IRGen/sil_witness_methods.sil
index 3681428..4e0d3dc 100644
--- a/test/IRGen/sil_witness_methods.sil
+++ b/test/IRGen/sil_witness_methods.sil
@@ -85,7 +85,7 @@
   return %m : $@thick Foo.Type
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @generic_type_generic_method_witness(%swift.opaque* noalias nocapture, %swift.type* %Z, %T19sil_witness_methods3BarC{{(.1)?}}** noalias nocapture swiftself dereferenceable(8), %swift.type* %Self, i8** %SelfWitnessTable)
+// CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @generic_type_generic_method_witness(%swift.opaque* noalias nocapture, %swift.type* %Z, %T19sil_witness_methods3BarC{{.*}}** noalias nocapture swiftself dereferenceable(8), %swift.type* %Self, i8** %SelfWitnessTable)
 sil @generic_type_generic_method_witness : $@convention(witness_method) <T, U, V, Z> (@in Z, @in Bar<T, U, V>) -> @thick Bar<T, U, V>.Type {
 entry(%z : $*Z, %x : $*Bar<T, U, V>):
   %t = metatype $@thick T.Type
diff --git a/test/IRGen/witness_method.sil b/test/IRGen/witness_method.sil
index de663e7..9aff540 100644
--- a/test/IRGen/witness_method.sil
+++ b/test/IRGen/witness_method.sil
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 sil_stage canonical
 
@@ -60,14 +60,14 @@
   }
 }
 
-// CHECK-LABEL: define{{( protected)?}} swiftcc void @testGenericWitnessMethod(%swift.opaque* noalias nocapture sret, %V14witness_method6SyncUp* noalias nocapture, %swift.type* %T)
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @testGenericWitnessMethod(%swift.opaque* noalias nocapture sret, %T14witness_method6SyncUpV* noalias nocapture, %swift.type* %T)
 // CHECK: entry:
 // CHECK:   [[METADATA:%.*]] = call %swift.type* @_T014witness_method6SyncUpVMa(%swift.type* %T)
 // CHECK:   [[WTABLE:%.*]] = call i8** @_T014witness_method6SyncUpVyxGAA7SynergyAAlWa(%swift.type* [[METADATA]])
 // CHECK:   [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[WTABLE]], i32 1
 // CHECK:   [[WITNESS_FN:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
 // CHECK:   [[WITNESS:%.*]] = bitcast i8* [[WITNESS_FN]] to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
-// CHECK:   [[ARG:%.*]] = bitcast %V14witness_method6SyncUp* %1 to %swift.opaque*
+// CHECK:   [[ARG:%.*]] = bitcast %T14witness_method6SyncUpV* %1 to %swift.opaque*
 // CHECK:   call swiftcc void [[WITNESS]](%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture swiftself [[ARG]], %swift.type* [[METADATA]], i8** [[WTABLE]])
 // CHECK:   ret void
 
diff --git a/test/IRGen/witness_method_phi.sil b/test/IRGen/witness_method_phi.sil
index d00962e..4447936 100644
--- a/test/IRGen/witness_method_phi.sil
+++ b/test/IRGen/witness_method_phi.sil
@@ -10,7 +10,6 @@
   br bb1(%1 : $@convention(witness_method) <T: P> (@in P) -> ())
 
 // CHECK:         phi i8* [ %0, %entry ]
-// CHECK-NEXT:    phi i8** [ %T.P, %entry ]
 bb1(%2 : $@convention(witness_method) <T: P> (@in P) -> ()):
   unreachable
 }
diff --git a/test/Index/kinds.swift b/test/Index/kinds.swift
index c550867..1ddd0bf 100644
--- a/test/Index/kinds.swift
+++ b/test/Index/kinds.swift
@@ -43,10 +43,16 @@
 class AClass {
   // CHECK: [[@LINE-1]]:7 | class/Swift | AClass | s:14swift_ide_test6AClassC | Def | rel: 0
 
-  // InstanceMethod
-  func instanceMethod() {}
-  // CHECK: [[@LINE-1]]:8 | instance-method/Swift | instanceMethod() | s:14swift_ide_test6AClassC14instanceMethodyyF | Def,RelChild | rel: 1
-  // CHECK-NEXT:  RelChild | AClass | s:14swift_ide_test6AClassC
+  // InstanceMethod + Parameters
+  func instanceMethod(a: Int, b b: Int, _ c: Int, d _: Int, _: Int) {}
+  // CHECK: [[@LINE-1]]:8 | instance-method/Swift | instanceMethod(a:b:_:d:_:) | s:14swift_ide_test6AClassC14instanceMethodySi1a_Si1bSiSi1dSitF | Def,RelChild | rel: 1
+  // CHECK-NEXT: RelChild | AClass | s:14swift_ide_test6AClassC
+  // CHECK: [[@LINE-3]]:23 | param/Swift | a | s:14swift_ide_test6AClassC14instanceMethodySi1a_Si1bSiSi1dSitFAEL_Siv | Def,RelChild | rel: 1
+  // CHECK-NEXT: RelChild | instanceMethod(a:b:_:d:_:) | s:14swift_ide_test6AClassC14instanceMethodySi1a_Si1bSiSi1dSitF
+  // CHECK-NOT: [[@LINE-5]]:33 | param/Swift | b | s:{{.*}} | Def,RelChild | rel: 1
+  // CHECK-NOT: [[@LINE-6]]:43 | param/Swift | c | s:{{.*}} | Def,RelChild | rel: 1
+  // CHECK-NOT: [[@LINE-7]]:53 | param/Swift | d | s:{{.*}} | Def,RelChild | rel: 1
+  // CHECK-NOT: [[@LINE-8]]:61 | param/Swift | _ | s:{{.*}} | Def,RelChild | rel: 1
 
   // ClassMethod
   class func classMethod() {}
diff --git a/test/Index/roles.swift b/test/Index/roles.swift
index ba39b63..757a19a 100644
--- a/test/Index/roles.swift
+++ b/test/Index/roles.swift
@@ -37,13 +37,15 @@
     // CHECK: [[@LINE-1]]:3 | function/acc-get/Swift | getter:z | s:14swift_ide_test1zSifg | Def,RelChild,RelAcc | rel: 1
 
     return y
-    // CHECK: [[@LINE-1]]:12 | variable/Swift | y | s:14swift_ide_test1ySiv | Ref,Read | rel: 0
+    // CHECK: [[@LINE-1]]:12 | variable/Swift | y | s:14swift_ide_test1ySiv | Ref,Read,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | getter:z | s:14swift_ide_test1zSifg
   }
   set {
     // CHECK: [[@LINE-1]]:3 | function/acc-set/Swift | setter:z | s:14swift_ide_test1zSifs | Def,RelChild,RelAcc | rel: 1
 
     y = newValue
-    // CHECK: [[@LINE-1]]:5 | variable/Swift | y | s:14swift_ide_test1ySiv | Ref,Writ | rel: 0
+    // CHECK: [[@LINE-1]]:5 | variable/Swift | y | s:14swift_ide_test1ySiv | Ref,Writ,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | setter:z | s:14swift_ide_test1zSifs
   }
 }
 // Write + Read of z
@@ -54,22 +56,40 @@
 // CHECK: [[@LINE-4]]:5 | function/acc-get/Swift | getter:z | s:14swift_ide_test1zSifg | Ref,Call,Impl | rel: 0
 
 // Call
-func aCalledFunction() {}
-// CHECK: [[@LINE-1]]:6 | function/Swift | aCalledFunction() | s:14swift_ide_test15aCalledFunctionyyF | Def | rel: 0
+func aCalledFunction(a: Int, b: inout Int) {
+// CHECK: [[@LINE-1]]:6 | function/Swift | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF | Def | rel: 0
+// CHECK: [[@LINE-2]]:22 | param/Swift | a | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF
+// CHECK: [[@LINE-4]]:30 | param/Swift | b | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF
 
-aCalledFunction()
-// CHECK: [[@LINE-1]]:1 | function/Swift | aCalledFunction() | s:14swift_ide_test15aCalledFunctionyyF | Ref,Call | rel: 0
+  var _ = a + b
+  // CHECK: [[@LINE-1]]:11 | param/Swift | a | s:{{.*}} | Ref,Read,RelCont | rel: 1
+  // CHECK-NEXT: RelCont | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF
+  // CHECK: [[@LINE-3]]:15 | param/Swift | b | s:{{.*}} | Ref,Read,RelCont | rel: 1
+  // CHECK-NEXT: RelCont | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF
+
+  b = a + 1
+  // CHECK: [[@LINE-1]]:3 | param/Swift | b | s:{{.*}} | Ref,Writ,RelCont | rel: 1
+  // CHECK-NEXT: RelCont | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF
+  // CHECK: [[@LINE-3]]:7 | param/Swift | a | s:{{.*}} | Ref,Read,RelCont | rel: 1
+  // CHECK-NEXT: RelCont | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF
+}
+
+aCalledFunction(a: 1, b: &z)
+// CHECK: [[@LINE-1]]:1 | function/Swift | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF | Ref,Call | rel: 0
+// CHECK: [[@LINE-2]]:27 | variable/Swift | z | s:14swift_ide_test1zSiv | Ref,Read,Writ | rel: 0
 
 func aCaller() {
   // CHECK: [[@LINE-1]]:6 | function/Swift | aCaller() | s:14swift_ide_test7aCalleryyF | Def | rel: 0
 
-  aCalledFunction()
-  // CHECK: [[@LINE-1]]:3 | function/Swift | aCalledFunction() | s:14swift_ide_test15aCalledFunctionyyF | Ref,Call,RelCall | rel: 1
-  // CHECK-NEXT: RelCall | aCaller() | s:14swift_ide_test7aCalleryyF
+  aCalledFunction(a: 1, b: &z)
+  // CHECK: [[@LINE-1]]:3 | function/Swift | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF | Ref,Call,RelCall,RelCont | rel: 1
+  // CHECK-NEXT: RelCall,RelCont | aCaller() | s:14swift_ide_test7aCalleryyF
 }
 
-let _ = aCalledFunction
-// CHECK: [[@LINE-1]]:9 | function/Swift | aCalledFunction() | s:14swift_ide_test15aCalledFunctionyyF | Ref | rel: 0
+let aRef = aCalledFunction
+// CHECK: [[@LINE-1]]:12 | function/Swift | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF | Ref | rel: 0
 
 // RelationChildOf, Implicit
 struct AStruct {
@@ -82,15 +102,16 @@
     // CHECK-NEXT: RelChild | AStruct | s:14swift_ide_test7AStructV
 
     x += 1
-    // CHECK: [[@LINE-1]]:5 | instance-property/Swift | x | s:14swift_ide_test7AStructV1xSiv | Ref,Read,Writ | rel: 0
-    // CHECK: [[@LINE-2]]:5 | function/acc-get/Swift | getter:x | s:14swift_ide_test7AStructV1xSifg | Ref,Call,Impl,RelRec,RelCall | rel: 2
-    // CHECK-NEXT: RelCall | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
+    // CHECK: [[@LINE-1]]:5 | instance-property/Swift | x | s:14swift_ide_test7AStructV1xSiv | Ref,Read,Writ,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
+    // CHECK: [[@LINE-3]]:5 | function/acc-get/Swift | getter:x | s:14swift_ide_test7AStructV1xSifg | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+    // CHECK-NEXT: RelCall,RelCont | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
     // CHECK-NEXT: RelRec | AStruct | s:14swift_ide_test7AStructV
-    // CHECK: [[@LINE-5]]:5 | function/acc-set/Swift | setter:x | s:14swift_ide_test7AStructV1xSifs | Ref,Call,Impl,RelRec,RelCall | rel: 2
-    // CHECK-NEXT: RelCall | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
+    // CHECK: [[@LINE-6]]:5 | function/acc-set/Swift | setter:x | s:14swift_ide_test7AStructV1xSifs | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+    // CHECK-NEXT: RelCall,RelCont | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
     // CHECK-NEXT: RelRec | AStruct | s:14swift_ide_test7AStructV
-    // CHECK: [[@LINE-8]]:7 | function/infix-operator/Swift | +=(_:_:) | s:s2peoiySiz_SitF | Ref,Call,RelCall | rel: 1
-    // CHECK-NEXT: RelCall | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
+    // CHECK: [[@LINE-9]]:7 | function/infix-operator/Swift | +=(_:_:) | s:s2peoiySiz_SitF | Ref,Call,RelCall,RelCont | rel: 1
+    // CHECK-NEXT: RelCall,RelCont | aMethod() | s:14swift_ide_test7AStructV7aMethodyyF
   }
 
   // RelationChildOf, RelationAccessorOf
@@ -243,3 +264,47 @@
 // CHECK: [[@LINE-2]]:22 | instance-method/Swift | foo() | s:14swift_ide_test6AClassC3fooSiyF | Ref,Call,Dyn,RelRec | rel: 1
 // CHECK-NEXT: RelRec | AClass | s:14swift_ide_test6AClassC
 
+// RelationContainedBy
+let contained = 2
+// CHECK: [[@LINE-1]]:5 | variable/Swift | contained | s:14swift_ide_test9containedSiv | Def | rel: 0
+
+func containing() {
+// CHECK: [[@LINE-1]]:6 | function/Swift | containing() | s:14swift_ide_test10containingyyF | Def | rel: 0
+  let _ = contained
+  // CHECK: [[@LINE-1]]:11 | variable/Swift | contained | s:14swift_ide_test9containedSiv | Ref,Read,RelCont | rel: 1
+  // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+
+  var x = contained
+  // CHECK: [[@LINE-1]]:11 | variable/Swift | contained | s:14swift_ide_test9containedSiv | Ref,Read,RelCont | rel: 1
+  // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+
+  struct LocalStruct {
+    var i: AClass = AClass(x: contained)
+    // CHECK: [[@LINE-1]]:12 | class/Swift | AClass | s:14swift_ide_test6AClassC | Ref,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+    // CHECK: [[@LINE-3]]:21 | class/Swift | AClass | s:14swift_ide_test6AClassC | Ref,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+    // CHECK: [[@LINE-5]]:31 | variable/Swift | contained | s:14swift_ide_test9containedSiv | Ref,Read,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+
+    init(i _: AClass) {}
+    // CHECK: [[@LINE-1]]:15 | class/Swift | AClass | s:14swift_ide_test6AClassC | Ref,RelCont | rel: 1
+    // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+
+    func inner() -> Int {
+      let _: AClass = AClass(x: contained)
+      // CHECK: [[@LINE-1]]:14 | class/Swift | AClass | s:14swift_ide_test6AClassC | Ref,RelCont | rel: 1
+      // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+      // CHECK: [[@LINE-3]]:23 | class/Swift | AClass | s:14swift_ide_test6AClassC | Ref,RelCont | rel: 1
+      // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+      // CHECK: [[@LINE-5]]:33 | variable/Swift | contained | s:14swift_ide_test9containedSiv | Ref,Read,RelCont | rel: 1
+      // CHECK-NEXT: RelCont | containing() | s:14swift_ide_test10containingyyF
+
+      aCalledFunction(a: 1, b: &z)
+      // CHECK: [[@LINE-1]]:7 | function/Swift | aCalledFunction(a:b:) | s:14swift_ide_test15aCalledFunctionySi1a_Siz1btF | Ref,Call,RelCall,RelCont | rel: 1
+      // CHECK-NEXT: RelCall,RelCont | containing() | s:14swift_ide_test10containingyyF
+
+      return contained
+    }
+  }
+}
diff --git a/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h b/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
index fe1cef5..439ee9f 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
@@ -67,6 +67,9 @@
 
 @end
 
+@interface PettableOverextendedMetaphor: NSObject <Pettable>
+@end
+
 @protocol Fungible
 @end
 
diff --git a/test/Inputs/comment_to_something_conversion.swift b/test/Inputs/comment_to_something_conversion.swift
index 5f118e3..83cf5d1 100644
--- a/test/Inputs/comment_to_something_conversion.swift
+++ b/test/Inputs/comment_to_something_conversion.swift
@@ -11,7 +11,7 @@
 
 /// Aaa.  init().
 public init() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>init()</Name><USR>c:objc(cs)A010_AttachToEntities(cm)init</USR><Declaration>public init()</Declaration><Abstract><Para>Aaa.  init().</Para></Abstract></Function>]
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>init()</Name><USR>c:objc(cs)A010_AttachToEntities(im)init</USR><Declaration>public init()</Declaration><Abstract><Para>Aaa.  init().</Para></Abstract></Function>]
 
 /// Aaa.  subscript(i: Int).
 public subscript(i: Int) -> Int {
diff --git a/test/Interpreter/generic_subscript.swift b/test/Interpreter/generic_subscript.swift
new file mode 100644
index 0000000..8e8a4d4
--- /dev/null
+++ b/test/Interpreter/generic_subscript.swift
@@ -0,0 +1,132 @@
+//===--- generic_subscript.swift ------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+// RUN: %target-run-simple-swift
+// REQUIRES: executable_test
+//
+
+import StdlibUnittest
+
+
+var GenericSubscriptTestSuite = TestSuite("GenericSubscript")
+
+struct S<T> : P {
+  typealias Element = T
+  var t: T
+
+  subscript<U>(a: (T) -> U, b: (U) -> T) -> U {
+    get {
+      print(T.self)
+      print(U.self)
+
+      return a(t)
+    }
+    set {
+      print(T.self)
+      print(U.self)
+
+      t = b(newValue)
+    }
+  }
+}
+
+protocol P {
+  associatedtype Element
+  subscript<U>(a: (Element) -> U, b: (U) -> Element) -> U { get set }
+}
+
+func increment<T : P>(p: inout T) where T.Element == String {
+  p[{Int($0)!}, {String($0)}] += 1
+}
+
+GenericSubscriptTestSuite.test("Basic") {
+  var s = S<String>(t: "0")
+  increment(p: &s)
+  expectEqual(s.t, "1")
+}
+
+protocol AnySubscript {
+  subscript(k: AnyHashable) -> Any? { get set }
+}
+
+struct AnyDictionary : AnySubscript {
+  var dict: [AnyHashable : Any] = [:]
+
+  subscript(k: AnyHashable) -> Any? {
+    get {
+      return dict[k]
+    }
+    set {
+      dict[k] = newValue
+    }
+  }
+}
+
+extension AnySubscript {
+  subscript<K : Hashable, V>(k k: K) -> V? {
+    get {
+      return self[k] as! V?
+    }
+    set {
+      self[k] = newValue
+    }
+  }
+}
+
+GenericSubscriptTestSuite.test("ProtocolExtensionConcrete") {
+  var dict = AnyDictionary()
+
+  func doIt(dict: inout AnyDictionary) {
+    dict["a" ] = 0
+    dict[k: "a"]! += 1
+  }
+
+  doIt(dict: &dict)
+
+  expectEqual(dict["a"]! as! Int, 1)
+  expectEqual(dict[k: "a"]!, 1)
+}
+
+GenericSubscriptTestSuite.test("ProtocolExtensionAbstract") {
+  var dict = AnyDictionary()
+
+  func doIt<T : AnySubscript>(dict: inout T) {
+    dict["a" ] = 0
+    dict[k: "a"]! += 1
+  }
+
+  doIt(dict: &dict)
+
+  expectEqual(dict["a"]! as! Int, 1)
+  expectEqual(dict[k: "a"]!, 1)
+}
+
+protocol GenericSubscript : AnySubscript {
+  subscript<K : Hashable, V>(k k: K) -> V? { get set }
+}
+
+extension AnyDictionary : GenericSubscript { }
+
+GenericSubscriptTestSuite.test("ProtocolExtensionWitness") {
+  var dict = AnyDictionary()
+
+  func doIt<T : GenericSubscript>(dict: inout T) {
+    dict["a" ] = 0
+    dict[k: "a"]! += 1
+  }
+
+  doIt(dict: &dict)
+
+  expectEqual(dict["a"]! as! Int, 1)
+  expectEqual(dict[k: "a"]!, 1)
+}
+
+runAllTests()
diff --git a/test/NameBinding/scope_map.swift b/test/NameBinding/scope_map.swift
index ae85d46..4067a15 100644
--- a/test/NameBinding/scope_map.swift
+++ b/test/NameBinding/scope_map.swift
@@ -368,7 +368,7 @@
 // CHECK-EXPANDED: {{^}}  `-BraceStmt {{.*}} [142:41 - 155:1] expanded
 // CHECK-EXPANDED-NEXT: {{^}} `-PatternBinding {{.*}} entry 0 [143:7 - 155:1] expanded
 // CHECK-EXPANDED-NEXT: {{^}}    `-AfterPatternBinding {{.*}} entry 0 [143:17 - 155:1] expanded
-// CHECK-EXPANDED-NEXT: {{^}}      |-Accessors {{.*}} scope_map.(file).func decl.computed@{{.*}}scope_map.swift:143:7 [143:21 - 149:3] expanded
+// CHECK-EXPANDED-NEXT: {{^}}      |-Accessors {{.*}} scope_map.(file).funcWithComputedProperties(i:).computed@{{.*}}scope_map.swift:143:7 [143:21 - 149:3] expanded
 // CHECK-EXPANDED-NEXT: {{^}}       |-AbstractFunctionDecl {{.*}} _ [144:5 - 145:5] expanded
 // CHECK-EXPANDED-NEXT: {{^}}        `-AbstractFunctionParams {{.*}} _ param 0:0 [144:5 - 145:5] expanded
 // CHECK-EXPANDED: {{^}}          `-BraceStmt {{.*}} [144:9 - 145:5] expanded
diff --git a/test/Parse/enum.swift b/test/Parse/enum.swift
index b7989a7..63296e1 100644
--- a/test/Parse/enum.swift
+++ b/test/Parse/enum.swift
@@ -3,7 +3,7 @@
 // FIXME: this test only passes on platforms which have Float80.
 // <rdar://problem/19508460> Floating point enum raw values are not portable
 
-// REQUIRES: CPU=i386 || CPU=x86_64
+// REQUIRES: CPU=i386_or_x86_64
 
 enum Empty {}
 
diff --git a/test/Parse/matching_patterns.swift b/test/Parse/matching_patterns.swift
index d7766ec..57dd399 100644
--- a/test/Parse/matching_patterns.swift
+++ b/test/Parse/matching_patterns.swift
@@ -100,7 +100,7 @@
     }
 
     switch foo {
-    case .Naught: // expected-error{{enum case 'Naught' not found in type 'Foo'}}
+    case .Naught: // expected-error{{pattern cannot match values of type 'Foo'}}
       ()
     case .A, .B, .C:
       ()
@@ -137,7 +137,7 @@
 var notAnEnum = 0
 
 switch notAnEnum {
-case .Foo: // expected-error{{enum case 'Foo' not found in type 'Int'}}
+case .Foo: // expected-error{{pattern cannot match values of type 'Int'}}
   ()
 }
 
@@ -264,10 +264,8 @@
 // expected-error@-1{{'+++' is not a prefix unary operator}}
   ()
 case (_, var e, 3) +++ (1, 2, 3):
-// expected-error@-1{{binary operator '+++' cannot be applied to operands of type '(_, <<error type>>, Int)' and '(Int, Int, Int)'}}
-// expected-note@-2{{expected an argument list of type '((Int, Int, Int), (Int, Int, Int))'}}
-// expected-error@-3{{'var' binding pattern cannot appear in an expression}}
-// expected-error@-4{{'var' binding pattern cannot appear in an expression}}
+// expected-error@-1{{'_' can only appear in a pattern}}
+// expected-error@-2{{'var' binding pattern cannot appear in an expression}}
   ()
 }
 
diff --git a/test/Parse/switch.swift b/test/Parse/switch.swift
index 6741c3b..7e2b81ae 100644
--- a/test/Parse/switch.swift
+++ b/test/Parse/switch.swift
@@ -264,7 +264,7 @@
 
 func enumElementSyntaxOnTuple() {
   switch (1, 1) {
-  case .Bar: // expected-error {{enum case 'Bar' not found in type '(Int, Int)'}}
+  case .Bar: // expected-error {{pattern cannot match values of type '(Int, Int)'}}
     break
   default:
     break
diff --git a/test/PrintAsObjC/extensions.swift b/test/PrintAsObjC/extensions.swift
index 49fd2e1..6b6974a 100644
--- a/test/PrintAsObjC/extensions.swift
+++ b/test/PrintAsObjC/extensions.swift
@@ -84,7 +84,7 @@
   func anyOldMethod() {}
 }
 
-// CHECK-LABEL: @interface GenericClass (SWIFT_EXTENSION(extensions))
+// CHECK-LABEL: @interface GenericClass<T> (SWIFT_EXTENSION(extensions))
 // CHECK-NEXT: - (void)bar;
 // CHECK-NEXT: @end
 extension GenericClass {
@@ -115,3 +115,17 @@
   class func fromColor(_ color: NSColor) -> NSString? { return nil; }
 }
 
+// CHECK-LABEL: @interface PettableContainer<T> (SWIFT_EXTENSION(extensions))
+// CHECK-NEXT: - (PettableContainer<T> * _Nonnull)duplicate SWIFT_WARN_UNUSED_RESULT;
+// CHECK-NEXT: - (PettableContainer<T> * _Nonnull)duplicate2 SWIFT_WARN_UNUSED_RESULT;
+// CHECK-NEXT: - (PettableContainer<PettableOverextendedMetaphor *> * _Nonnull)duplicate3 SWIFT_WARN_UNUSED_RESULT;
+// CHECK-NEXT: - (T _Nonnull)extract SWIFT_WARN_UNUSED_RESULT;
+// CHECK-NEXT: - (T _Nullable)extract2 SWIFT_WARN_UNUSED_RESULT;
+// CHECK-NEXT: @end
+extension PettableContainer {
+  func duplicate() -> PettableContainer { fatalError() }
+  func duplicate2() -> PettableContainer<T> { fatalError() }
+  func duplicate3() -> PettableContainer<PettableOverextendedMetaphor> { fatalError() }
+  func extract() -> T { fatalError() }
+  func extract2() -> T? { fatalError() }
+}
diff --git a/test/Runtime/weak-reference-racetests.swift b/test/Runtime/weak-reference-racetests.swift
index a3235f5..40a1a2c 100644
--- a/test/Runtime/weak-reference-racetests.swift
+++ b/test/Runtime/weak-reference-racetests.swift
@@ -1,5 +1,6 @@
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
+// UNSUPPORTED: nonatomic_rc
 
 import StdlibUnittest
 
diff --git a/test/SIL/Parser/opaque_values_parse.sil b/test/SIL/Parser/opaque_values_parse.sil
index cf286a1..1ae6709 100644
--- a/test/SIL/Parser/opaque_values_parse.sil
+++ b/test/SIL/Parser/opaque_values_parse.sil
@@ -1,9 +1,54 @@
 // RUN: %target-sil-opt -enable-sil-opaque-values -enable-sil-verify-all -emit-sorted-sil %s | %FileCheck %s
 
 import Builtin
+import Swift
 
 sil_stage canonical
 
+protocol Foo {
+  func foo()
+}
+
+struct S : Foo {
+  func foo()
+  init()
+}
+
+// CHECK-LABEL: sil @castOpaque : $@convention(thin) (Int) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Int):
+// CHECK:  unconditional_checked_cast_opaque [[ARG]] : $Int to $Foo
+// CHECK-LABEL: } // end sil function 'castOpaque'
+sil @castOpaque : $@convention(thin) (Int) -> () {
+bb0(%0 : $Int):
+  %c = unconditional_checked_cast_opaque %0 : $Int to $Foo
+  %t = tuple ()
+  return %t : $()
+}
+
+// CHECK-LABEL: sil @initDeinitExistentialOpaque : $@convention(thin) <T> (@in T) -> () {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:  [[IE:%.*]] = init_existential_opaque [[ARG]] : $T, $T, $Any
+// CHECK:  deinit_existential_opaque [[IE]] : $Any
+// CHECK-LABEL: } // end sil function 'initDeinitExistentialOpaque'
+sil @initDeinitExistentialOpaque : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : $T):
+  %i = init_existential_opaque %0 : $T, $T, $Any
+  %d = deinit_existential_opaque %i : $Any
+  %t = tuple ()
+  return %t : $()
+}
+
+// CHECK-LABEL: sil @openExistentialOpaque : $@convention(thin) (@in Foo) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Foo):
+// CHECK:  open_existential_opaque [[ARG]] : $Foo to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C496") Foo
+// CHECK-LABEL: } // end sil function 'openExistentialOpaque'
+sil @openExistentialOpaque : $@convention(thin) (@in Foo) -> () {
+bb0(%0 : $Foo):
+  %o = open_existential_opaque %0 : $Foo to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C496") Foo
+  %t = tuple ()
+  return %t : $()
+}
+
 // Test @callee_guaranteed parsing.
 // ----
 
@@ -38,15 +83,6 @@
 // Test @in_guaranteed parsing.
 // ----
 
-protocol Foo {
-  func foo()
-}
-
-struct S : Foo {
-  func foo()
-  init()
-}
-
 sil @doWithS : $@convention(method) (S) -> ()
 
 // CHECK-LABEL: sil hidden [transparent] [thunk] @parse_mutating : $@convention(witness_method) (@in_guaranteed S) -> () {
diff --git a/test/SIL/Parser/undef.sil b/test/SIL/Parser/undef.sil
index 68c83d6..fadb388 100644
--- a/test/SIL/Parser/undef.sil
+++ b/test/SIL/Parser/undef.sil
@@ -244,14 +244,6 @@
   bridge_object_to_word undef : $Builtin.BridgeObject to $Builtin.Word
   // CHECK: thin_to_thick_function undef : $@convention(thin) () -> () to $() -> ()
   thin_to_thick_function undef : $@convention(thin) () -> () to $() -> ()
-  // CHECK: thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
-  thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
-  // CHECK: objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
-  objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
-  // CHECK: objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
-  objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
-  // CHECK: objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
-  objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
   // CHECK: is_nonnull undef : $C
   is_nonnull undef : $C
 
diff --git a/test/SIL/Parser/undef_objc.sil b/test/SIL/Parser/undef_objc.sil
new file mode 100644
index 0000000..b4119cd
--- /dev/null
+++ b/test/SIL/Parser/undef_objc.sil
@@ -0,0 +1,23 @@
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil %s | %target-sil-opt -assume-parsing-unqualified-ownership-sil | %FileCheck %s
+// REQUIRES: objc_interop
+
+sil_stage raw
+
+import Builtin
+import Swift
+
+protocol P { }
+class C { }
+
+sil @general_test : $() -> () {
+bb0:
+  // CHECK: thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
+  thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
+  // CHECK: objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
+  objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
+  // CHECK: objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
+  objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
+  // CHECK: objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
+  objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
+  unreachable
+}
diff --git a/test/SIL/Serialization/opaque_values_serialize.sil b/test/SIL/Serialization/opaque_values_serialize.sil
index 680516d..945b17a 100644
--- a/test/SIL/Serialization/opaque_values_serialize.sil
+++ b/test/SIL/Serialization/opaque_values_serialize.sil
@@ -9,6 +9,51 @@
 sil_stage canonical
 
 import Builtin
+import Swift
+
+protocol Foo {
+  func foo()
+}
+
+struct S : Foo {
+  func foo()
+  init()
+}
+
+// CHECK-LABEL: sil @castOpaque : $@convention(thin) (Int) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Int):
+// CHECK:  unconditional_checked_cast_opaque [[ARG]] : $Int to $Foo
+// CHECK-LABEL: } // end sil function 'castOpaque'
+sil @castOpaque : $@convention(thin) (Int) -> () {
+bb0(%0 : $Int):
+  %c = unconditional_checked_cast_opaque %0 : $Int to $Foo
+  %t = tuple ()
+  return %t : $()
+}
+
+// CHECK-LABEL: sil @initDeinitExistentialOpaque : $@convention(thin) <T> (@in T) -> () {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:  [[IE:%.*]] = init_existential_opaque [[ARG]] : $T, $T, $Any
+// CHECK:  deinit_existential_opaque [[IE]] : $Any
+// CHECK-LABEL: } // end sil function 'initDeinitExistentialOpaque'
+sil @initDeinitExistentialOpaque : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : $T):
+  %i = init_existential_opaque %0 : $T, $T, $Any
+  %d = deinit_existential_opaque %i : $Any
+  %t = tuple ()
+  return %t : $()
+}
+
+// CHECK-LABEL: sil @openExistentialOpaque : $@convention(thin) (@in Foo) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Foo):
+// CHECK:  open_existential_opaque [[ARG]] : $Foo to $@opened({{.*}}) Foo
+// CHECK-LABEL: } // end sil function 'openExistentialOpaque'
+sil @openExistentialOpaque : $@convention(thin) (@in Foo) -> () {
+bb0(%0 : $Foo):
+  %o = open_existential_opaque %0 : $Foo to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C496") Foo
+  %t = tuple ()
+  return %t : $()
+}
 
 // Test @in/@out serialization.
 // ----
@@ -25,15 +70,6 @@
 // Test @in_guaranteed serialization.
 // ----
 
-protocol Foo {
-  func foo()
-}
-
-struct S : Foo {
-  func foo()
-  init()
-}
-
 sil @doWithS : $@convention(method) (S) -> ()
 
 // CHECK-LABEL: sil hidden [transparent] [thunk] @serialize_mutating : $@convention(witness_method) (@in_guaranteed S) -> () {
diff --git a/test/SIL/ownership-verifier/use_verifier.sil b/test/SIL/ownership-verifier/use_verifier.sil
index 7405276..782008b 100644
--- a/test/SIL/ownership-verifier/use_verifier.sil
+++ b/test/SIL/ownership-verifier/use_verifier.sil
@@ -528,17 +528,18 @@
   destroy_value %1 : $SuperKlass
   br bb3
 
-bb2:
+bb2(%2 : @owned $Builtin.NativeObject):
+  destroy_value %2 : $Builtin.NativeObject
   br bb3
 
 bb3:
-  %2 = metatype $@thick SuperKlass.Type
-  checked_cast_br %2 : $@thick SuperKlass.Type to $@thick SubKlass.Type, bb4, bb5
+  %3 = metatype $@thick SuperKlass.Type
+  checked_cast_br %3 : $@thick SuperKlass.Type to $@thick SubKlass.Type, bb4, bb5
 
-bb4(%3 : @trivial $@thick SubKlass.Type):
+bb4(%4 : @trivial $@thick SubKlass.Type):
   br bb6
 
-bb5:
+bb5(%5 : @trivial $@thick SuperKlass.Type):
   br bb6
 
 bb6:
diff --git a/test/SILGen/accessors.swift b/test/SILGen/accessors.swift
index 1f74097..3f124b0 100644
--- a/test/SILGen/accessors.swift
+++ b/test/SILGen/accessors.swift
@@ -65,7 +65,7 @@
 // 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: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout A, @thick A.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $A
 // SEMANTIC SIL TODO: This is an issue caused by the callback for materializeForSet in the class case taking the value as @inout when it should really take it as @guaranteed.
 // CHECK-NEXT: store [[BORROWED_ARG_LHS]] to [init] [[TEMP2]] : $*A
@@ -128,7 +128,7 @@
 // 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: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
 // CHECK-NEXT: store [[BORROWED_ARG_RHS]] to [init] [[TEMP2]] : $*B
 // CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type
@@ -154,7 +154,7 @@
 // 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: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
 // CHECK-NEXT: store [[BORROWED_ARG_LHS]] to [init] [[TEMP2]] : $*B
 // CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type
diff --git a/test/SILGen/addressors.swift b/test/SILGen/addressors.swift
index ec23481..fe274de 100644
--- a/test/SILGen/addressors.swift
+++ b/test/SILGen/addressors.swift
@@ -331,6 +331,14 @@
 // CHECK:   store [[VALUE]] to [[T2]] : $*Int32
 // CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
 
+//   materializeForSet callback for G.value
+// CHECK-LABEL: sil hidden [transparent] @_T010addressors1GC5values5Int32VfmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout G, @thick G.Type) -> () {
+// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*G, [[SELFTYPE:%3]] : $@thick G.Type):
+// CHECK:   [[T0:%.*]] = project_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   [[OWNER:%.*]] = load [[T0]]
+// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
+// CHECK:   dealloc_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+
 //   materializeForSet for G.value
 // CHECK-LABEL: sil hidden [transparent] @_T010addressors1GC5values5Int32Vfm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed G) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $G):
@@ -355,14 +363,6 @@
 // CHECK:   [[RESULT:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
 // CHECK:   return [[RESULT]]
 
-//   materializeForSet callback for G.value
-// CHECK-LABEL: sil hidden [transparent] @_T010addressors1GC5values5Int32VfmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout G, @thick G.Type) -> () {
-// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*G, [[SELFTYPE:%3]] : $@thick G.Type):
-// CHECK:   [[T0:%.*]] = project_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
-// CHECK:   [[OWNER:%.*]] = load [[T0]]
-// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
-// CHECK:   dealloc_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
-
 class H {
   var data: UnsafeMutablePointer<Int32> = UnsafeMutablePointer.allocate(capacity: 100)
 
@@ -451,6 +451,14 @@
 // CHECK:   store [[VALUE]] to [[T2]] : $*Int32
 // CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
 
+//   materializeForSet callback for I.value
+// CHECK-LABEL: sil hidden [transparent] @_T010addressors1IC5values5Int32VfmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout I, @thick I.Type) -> () {
+// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*I, [[SELFTYPE:%3]] : $@thick I.Type):
+// CHECK:   [[T0:%.*]] = project_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   [[OWNER:%.*]] = load [[T0]]
+// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   dealloc_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+
 // CHECK-LABEL: sil hidden [transparent] @_T010addressors1IC5values5Int32Vfm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed I) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $I):
 //   Call the addressor.
@@ -474,14 +482,6 @@
 // CHECK:   [[RESULT:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
 // CHECK:   return [[RESULT]]
 
-//   materializeForSet callback for I.value
-// CHECK-LABEL: sil hidden [transparent] @_T010addressors1IC5values5Int32VfmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout I, @thick I.Type) -> () {
-// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*I, [[SELFTYPE:%3]] : $@thick I.Type):
-// CHECK:   [[T0:%.*]] = project_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
-// CHECK:   [[OWNER:%.*]] = load [[T0]]
-// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
-// CHECK:   dealloc_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
-
 struct RecInner {
   subscript(i: Int32) -> Int32 {
     mutating get { return i }
diff --git a/test/SILGen/c_materializeForSet_linkage.swift b/test/SILGen/c_materializeForSet_linkage.swift
index 0825c55..3d9b221 100644
--- a/test/SILGen/c_materializeForSet_linkage.swift
+++ b/test/SILGen/c_materializeForSet_linkage.swift
@@ -19,8 +19,8 @@
 // CHECK-LABEL: sil shared [transparent] [fragile] @_T0SC7NSPointV1xSffm
 // CHECK-LABEL: sil shared [transparent] [fragile] @_T0SC7NSPointV1ySffm
 
-// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1xSffm
-// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1ySffm
-
 // CHECK-LABEL: sil shared @_T0So16NSReferencePointC1xSffmytfU_
+// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1xSffm
+
 // CHECK-LABEL: sil shared @_T0So16NSReferencePointC1ySffmytfU_
+// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1ySffm
diff --git a/test/SILGen/casts.swift b/test/SILGen/casts.swift
index 3e9a92f..e493c45 100644
--- a/test/SILGen/casts.swift
+++ b/test/SILGen/casts.swift
@@ -16,11 +16,20 @@
 
 // CHECK-LABEL: sil hidden @_T05casts3isa{{[_0-9a-zA-Z]*}}F
 func isa(b: B) -> Bool {
-  // CHECK: checked_cast_br {{%.*}}, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
-  // CHECK: [[YES]]({{%.*}}):
+  // CHECK: bb0([[ARG:%.*]] : $B):
+  // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+  // CHECK:   [[COPIED_BORROWED_ARG:%.*]] = copy_value [[BORROWED_ARG]]
+  // CHECK:   checked_cast_br [[COPIED_BORROWED_ARG]] : $B to $D, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
+  //
+  // CHECK: [[YES]]([[CASTED_VALUE:%.*]] : $D):
   // CHECK:   integer_literal {{.*}} -1
-  // CHECK: [[NO]]:
+  // CHECK:   destroy_value [[CASTED_VALUE]]
+  // CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
+  //
+  // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $B):
+  // CHECK:   destroy_value [[ORIGINAL_VALUE]]
   // CHECK:   integer_literal {{.*}} 0
+  // CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
   return b is D
 }
 
@@ -42,15 +51,22 @@
   return b as! T
 }
 
+// This is making sure that we do not have the default propagating behavior in
+// the address case.
+//
 // CHECK-LABEL: sil hidden @_T05casts12is_archetype{{[_0-9a-zA-Z]*}}F
 func is_archetype<T : B>(b: B, _: T) -> Bool {
-  // CHECK: checked_cast_br {{%.*}}, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
-  // CHECK: [[YES]]({{%.*}}):
+  // CHECK: bb0([[ARG1:%.*]] : $B, [[ARG2:%.*]] : $T):
+  // CHECK:   checked_cast_br {{%.*}}, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
+  // CHECK: [[YES]]([[CASTED_ARG:%.*]] : $T):
   // CHECK:   integer_literal {{.*}} -1
-  // CHECK: [[NO]]:
+  // CHECK:   destroy_value [[CASTED_ARG]]
+  // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $B):
+  // CHCEK:   destroy_value [[CASTED_ARG]]
   // CHECK:   integer_literal {{.*}} 0
   return b is T
 }
+// CHECK: } // end sil function '_T05casts12is_archetype{{[_0-9a-zA-Z]*}}F'
 
 // CHECK: sil hidden @_T05casts20downcast_conditional{{[_0-9a-zA-Z]*}}F
 // CHECK:   checked_cast_br {{%.*}} : $B to $D
diff --git a/test/SILGen/constrained_extensions.swift b/test/SILGen/constrained_extensions.swift
index 61223b0..e6820ca 100644
--- a/test/SILGen/constrained_extensions.swift
+++ b/test/SILGen/constrained_extensions.swift
@@ -10,8 +10,9 @@
 
   // CHECK-LABEL: sil @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifg : $@convention(method) (@guaranteed Array<Int>) -> Int
   // CHECK-LABEL: sil @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifs : $@convention(method) (Int, @inout Array<Int>) -> ()
+  // CHECK-LABEL: sil [transparent] [fragile] @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>, @thick Array<Int>.Type) -> ()
   // CHECK-LABEL: sil [transparent] [fragile] @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
-  // CHECK-LABEL: sil [transparent] [fragile] @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>, @thick Array<Int>.Type) -> ()
+
   public var instanceProperty: Element {
     get {
       return self[0]
@@ -70,8 +71,8 @@
 
   // CHECK-LABEL: sil @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fg : $@convention(method) <Key, Value where Key == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
   // CHECK-LABEL: sil @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fs : $@convention(method) <Key, Value where Key == Int> (@in Value, @inout Dictionary<Int, Value>) -> ()
+  // CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fmytfU_ : $@convention(method) <Key, Value where Key == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>, @thick Dictionary<Int, Value>.Type) -> ()
   // CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fm : $@convention(method) <Key, Value where Key == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
-  // CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fmytfU_ : $@convention(thin) <Key, Value where Key == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>, @thick Dictionary<Int, Value>.Type) -> ()
   public var instanceProperty: Value {
     get {
       return self[0]!
diff --git a/test/SILGen/generic_casts.swift b/test/SILGen/generic_casts.swift
index 959d179..6269058 100644
--- a/test/SILGen/generic_casts.swift
+++ b/test/SILGen/generic_casts.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
 
 protocol ClassBound : class {}
 protocol NotClassBound {}
@@ -57,16 +57,21 @@
 func class_archetype_to_class_archetype
 <T:ClassBound, U:ClassBound>(_ t:T) -> U {
   return t as! U
-  // CHECK: unconditional_checked_cast_addr {{.*}} T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
-  // CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
-  // CHECK: return [[DOWNCAST]] : $U
+  // Error bridging can change the identity of class-constrained archetypes.
+  // CHECK-objc: unconditional_checked_cast_addr {{.*}} T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
+  // CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
+  // CHECK-objc: return [[DOWNCAST]] : $U
+
+  // CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $T to $U
 }
 
 // CHECK-LABEL: sil hidden @_TF13generic_casts34class_archetype_is_class_archetype{{.*}}
 func class_archetype_is_class_archetype
 <T:ClassBound, U:ClassBound>(_ t:T, u:U.Type) -> Bool {
   return t is U
-  // CHECK: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
+  // Error bridging can change the identity of class-constrained archetypes.
+  // CHECK-objc: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
+  // CHECK-native: checked_cast_br {{.*}} : $T to $U
 }
 
 // CHECK-LABEL: sil hidden @_TF13generic_casts38opaque_archetype_to_addr_only_concrete{{.*}}
@@ -156,16 +161,19 @@
 func class_existential_to_class_archetype
 <T:ClassBound>(_ p:ClassBound) -> T {
   return p as! T
-  // CHECK: unconditional_checked_cast_addr {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
-  // CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
-  // CHECK: return [[DOWNCAST]] : $T
+  // CHECK-objc: unconditional_checked_cast_addr {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
+  // CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
+  // CHECK-objc: return [[DOWNCAST]] : $T
+
+  // CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $ClassBound to $T
 }
 
 // CHECK-LABEL: sil hidden @_TF13generic_casts36class_existential_is_class_archetype{{.*}}
 func class_existential_is_class_archetype
 <T:ClassBound>(_ p:ClassBound, _: T) -> Bool {
   return p is T
-  // CHECK: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
+  // CHECK-objc: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
+  // CHECK-native: checked_cast_br {{.*}} : $ClassBound to $T
 }
 
 // CHECK-LABEL: sil hidden @_TF13generic_casts40opaque_existential_to_addr_only_concrete{{.*}}
diff --git a/test/SILGen/if_while_binding.swift b/test/SILGen/if_while_binding.swift
index 2f0d3c1..93d8159 100644
--- a/test/SILGen/if_while_binding.swift
+++ b/test/SILGen/if_while_binding.swift
@@ -309,8 +309,8 @@
   // CHECK:   [[DERIVED_CLS_SOME:%.*]] = enum $Optional<DerivedClass>, #Optional.some!enumelt.1, [[DERIVED_CLS]] : $DerivedClass
   // CHECK:   br [[MERGE:bb[0-9]+]]([[DERIVED_CLS_SOME]] : $Optional<DerivedClass>)
 
-  // CHECK: [[ISBASEBB]]:
-  // CHECK:   destroy_value [[CLS]] : $BaseClass
+  // CHECK: [[ISBASEBB]]([[BASECLASS:%.*]] : $BaseClass):
+  // CHECK:   destroy_value [[BASECLASS]] : $BaseClass
   // CHECK:   = enum $Optional<DerivedClass>, #Optional.none!enumelt
   // CHECK:   br [[MERGE]](
 
diff --git a/test/SILGen/lifetime.swift b/test/SILGen/lifetime.swift
index 39a4ab5..47cad67 100644
--- a/test/SILGen/lifetime.swift
+++ b/test/SILGen/lifetime.swift
@@ -380,7 +380,7 @@
   // CHECK: [[ADDR:%.*]] = pointer_to_address [[PTR]]
   // CHECK: [[MARKED_ADDR:%.*]] = mark_dependence [[ADDR]] : $*Aleph on [[R2]]
   // CHECK: {{.*}}([[CALLBACK_ADDR:%.*]] : 
-  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout RefWithProp, @thick RefWithProp.Type) -> ()
+  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout RefWithProp, @thick RefWithProp.Type) -> ()
   // CHECK: [[TEMP:%.*]] = alloc_stack $RefWithProp
   // CHECK: store [[R2]] to [init] [[TEMP]]
   // CHECK: apply [[CALLBACK]]({{.*}}, [[STORAGE]], [[TEMP]], {{%.*}})
diff --git a/test/SILGen/materializeForSet.swift b/test/SILGen/materializeForSet.swift
index c92c9d6..7f3d867 100644
--- a/test/SILGen/materializeForSet.swift
+++ b/test/SILGen/materializeForSet.swift
@@ -6,6 +6,14 @@
 // The ordering here is unfortunate: we generate the property
 // getters and setters after we've processed the decl.
 
+  // CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Base, [[SELFTYPE:%.*]] : $@thick Base.Type):
+// CHECK:   [[T0:%.*]] = load_borrow [[SELF]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T2:%.*]] = load [trivial] [[T1]] : $*Int
+// CHECK:   [[SETTER:%.*]] = function_ref @_T017materializeForSet4BaseC8computedSifs
+// CHECK:   apply [[SETTER]]([[T2]], [[T0]])
+
 // CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet4BaseC8computedSifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed Base) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $Base):
 // CHECK:   [[ADDR:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
@@ -13,21 +21,13 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[ADDR]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[ADDR]]
-// CHECK:   [[T0:%.*]] = function_ref @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> ()
+// CHECK:   [[T0:%.*]] = function_ref @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> ()
 // CHECK:   [[T2:%.*]] = thin_function_to_pointer [[T0]]
 // CHECK:   [[T3:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T2]] : $Builtin.RawPointer
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[T3]] : $Optional<Builtin.RawPointer>)
 // CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // CHECK: }
 
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () {
-// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Base, [[SELFTYPE:%.*]] : $@thick Base.Type):
-// CHECK:   [[T0:%.*]] = load_borrow [[SELF]]
-// CHECK:   [[T1:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
-// CHECK:   [[T2:%.*]] = load [trivial] [[T1]] : $*Int
-// CHECK:   [[SETTER:%.*]] = function_ref @_T017materializeForSet4BaseC8computedSifs
-// CHECK:   apply [[SETTER]]([[T2]], [[T0]])
-
 // CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet4BaseC6storedSifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed Base) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $Base):
 // CHECK:   [[T0:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.stored
@@ -68,6 +68,21 @@
 // an abstraction pattern present.
 
 extension Derived : Abstractable {}
+
+// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction6ResultQzycfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
+// CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
+// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[RESULT_ADDR]] : $*@callee_owned () -> @out Int
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @_T0SiIxr_SiIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
+// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [[REABSTRACTOR]]([[VALUE]])
+// CHECK-NEXT: [[FN:%.*]] = class_method [[SELF]] : $Base, #Base.storedFunction!setter.1 : (Base) -> (@escaping () -> Int) -> ()
+// CHECK-NEXT: apply [[FN]]([[NEWVALUE]], [[SELF]])
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+
 // CHECK: sil hidden [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction{{[_0-9a-zA-Z]*}}fmTW
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived):
 // CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
@@ -92,17 +107,17 @@
 // CHECK-NEXT: dealloc_stack [[TEMP]]
 // CHECK-NEXT: return [[T0]]
 
-// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction6ResultQzycfmytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
+// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP19finalStoredFunction6ResultQzycfmytfU_TW :
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
 // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
 // CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
 // CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
 // CHECK-NEXT: [[VALUE:%.*]] = load [take] [[RESULT_ADDR]] : $*@callee_owned () -> @out Int
-// CHECK-NEXT: function_ref
+// CHECK-NEXT: // function_ref
 // CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @_T0SiIxr_SiIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
 // CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [[REABSTRACTOR]]([[VALUE]])
-// CHECK-NEXT: [[FN:%.*]] = class_method [[SELF]] : $Base, #Base.storedFunction!setter.1 : (Base) -> (@escaping () -> Int) -> ()
-// CHECK-NEXT: apply [[FN]]([[NEWVALUE]], [[SELF]])
+// CHECK-NEXT: [[ADDR:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.finalStoredFunction
+// CHECK-NEXT: assign [[NEWVALUE]] to [[ADDR]]
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 
@@ -125,19 +140,18 @@
 // CHECK-NEXT: [[T0:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
 // CHECK-NEXT: return [[T0]]
 
-// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP19finalStoredFunction6ResultQzycfmytfU_TW :
-// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
-// CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
-// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
-// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
-// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[RESULT_ADDR]] : $*@callee_owned () -> @out Int
-// CHECK-NEXT: // function_ref
-// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @_T0SiIxr_SiIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
-// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [[REABSTRACTOR]]([[VALUE]])
-// CHECK-NEXT: [[ADDR:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.finalStoredFunction
-// CHECK-NEXT: assign [[NEWVALUE]] to [[ADDR]]
-// CHECK-NEXT: tuple ()
-// CHECK-NEXT: return
+// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZytfU_TW
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*@thick Derived.Type, %3 : $@thick Derived.Type.Type):
+// CHECK-NEXT: [[SELF:%.*]] = load_borrow %2 : $*@thick Derived.Type
+// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[SELF]] : $@thick Derived.Type to $@thick Base.Type
+// CHECK-NEXT: [[BUFFER:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
+// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[BUFFER]] : $*@callee_owned () -> @out Int
+// CHECK:      [[REABSTRACTOR:%.*]] = function_ref @_T0SiIxr_SiIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
+// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [[REABSTRACTOR]]([[VALUE]]) : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
+// CHECK:      [[SETTER_FN:%.*]] = function_ref @_T017materializeForSet4BaseC14staticFunctionSiycfsZ : $@convention(method) (@owned @callee_owned () -> Int, @thick Base.Type) -> ()
+// CHECK-NEXT: apply [[SETTER_FN]]([[NEWVALUE]], [[BASE_SELF]]) : $@convention(method) (@owned @callee_owned () -> Int, @thick Base.Type) -> ()
+// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT: return [[RESULT]] : $()
 
 // CHECK-LABEL: sil hidden [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZTW
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $@thick Derived.Type):
@@ -153,26 +167,13 @@
 // CHECK-NEXT: destroy_addr [[OUT]] : $*@callee_owned () -> Int
 // CHECK-NEXT: store [[NEWVALUE]] to [init] [[RESULT_ADDR]] : $*@callee_owned () -> @out Int
 // CHECK-NEXT: [[ADDR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_owned () -> @out Int to $Builtin.RawPointer
-// CHECK:      [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> ()
-// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer
+// CHECK:      [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> ()
+// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer
 // CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] : $Builtin.RawPointer
 // CHECK-NEXT: [[RESULT:%.*]] = tuple ([[ADDR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
 // CHECK-NEXT: dealloc_stack [[OUT]] : $*@callee_owned () -> Int
 // CHECK-NEXT: return [[RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZytfU_TW
-// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*@thick Derived.Type, %3 : $@thick Derived.Type.Type):
-// CHECK-NEXT: [[SELF:%.*]] = load_borrow %2 : $*@thick Derived.Type
-// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[SELF]] : $@thick Derived.Type to $@thick Base.Type
-// CHECK-NEXT: [[BUFFER:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
-// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[BUFFER]] : $*@callee_owned () -> @out Int
-// CHECK:      [[REABSTRACTOR:%.*]] = function_ref @_T0SiIxr_SiIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
-// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [[REABSTRACTOR]]([[VALUE]]) : $@convention(thin) (@owned @callee_owned () -> @out Int) -> Int
-// CHECK:      [[SETTER_FN:%.*]] = function_ref @_T017materializeForSet4BaseC14staticFunctionSiycfsZ : $@convention(method) (@owned @callee_owned () -> Int, @thick Base.Type) -> ()
-// CHECK-NEXT: apply [[SETTER_FN]]([[NEWVALUE]], [[BASE_SELF]]) : $@convention(method) (@owned @callee_owned () -> Int, @thick Base.Type) -> ()
-// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
-// CHECK-NEXT: return [[RESULT]] : $()
-
 protocol ClassAbstractable : class {
   associatedtype Result
   var storedFunction: () -> Result { get set }
@@ -212,7 +213,7 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C6storedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C6storedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
 // CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
 // CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
@@ -231,7 +232,7 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C8computedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C8computedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
 // CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
 // CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
@@ -244,22 +245,7 @@
     didSet {}
   }
 
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet012HasStoredDidC0C6storedSifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasStoredDidSet) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
-// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasStoredDidSet):
-// CHECK:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
-// CHECK:   [[T0:%.*]] = function_ref @_T017materializeForSet012HasStoredDidC0C6storedSifg
-// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
-// CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
-// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> ()
-// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
-// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
-// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
-// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
-// CHECK: }
-}
-
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () {
+// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () {
 // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*HasStoredDidSet, [[METATYPE:%.*]] : $@thick HasStoredDidSet.Type):
 // CHECK:   [[SELF_VALUE:%.*]] = load_borrow [[SELF]] : $*HasStoredDidSet
 // CHECK:   [[BUFFER_ADDR:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
@@ -269,6 +255,21 @@
 // CHECK:   return
 // CHECK: }
 
+// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet012HasStoredDidC0C6storedSifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasStoredDidSet) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasStoredDidSet):
+// CHECK:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T0:%.*]] = function_ref @_T017materializeForSet012HasStoredDidC0C6storedSifg
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
+// CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
+// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
+// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
+// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+}
+
 class HasWeak {
   weak var weakvar: HasWeak?
 }
@@ -279,7 +280,7 @@
 // CHECK:   [[T1:%.*]] = load_weak [[T0]] : $*@sil_weak Optional<HasWeak>
 // CHECK:   store [[T1]] to [init] [[T2]] : $*Optional<HasWeak>
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[T0:%.*]] = function_ref @_T017materializeForSet7HasWeakC7weakvarACSgXwfmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () 
+// CHECK:   [[T0:%.*]] = function_ref @_T017materializeForSet7HasWeakC7weakvarACSgXwfmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () 
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, {{.*}} : $Optional<Builtin.RawPointer>)
 // CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // CHECK: }
@@ -336,10 +337,13 @@
 // CHECK: }
 
 // CHECK-LABEL:  sil hidden [transparent] [thunk] @_T017materializeForSet4BillVAA8TotalledAaaDP5totalSifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Bill) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
-// CHECK:  bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Bill):
-// CHECK:    [[T0:%.*]] = function_ref @_T017materializeForSet4BillV5totalSifm
-// CHECK:    [[T1:%.*]] = apply [[T0]]([[BUFFER]], [[STORAGE]], [[SELF]])
-// CHECK:    return [[T1]] :
+// CHECK:        bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Bill):
+// CHECK:          [[T0:%.*]] = function_ref @_T017materializeForSet4BillV5totalSifm
+// CHECK-NEXT:     [[T1:%.*]] = apply [[T0]]([[BUFFER]], [[STORAGE]], [[SELF]])
+// CHECK-NEXT:     [[LEFT:%.*]] = tuple_extract [[T1]]
+// CHECK-NEXT:     [[RIGHT:%.*]] = tuple_extract [[T1]]
+// CHECK-NEXT:     [[T1:%.*]] = tuple ([[LEFT]] : $Builtin.RawPointer, [[RIGHT]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT:     return [[T1]] :
 
 protocol AddressOnlySubscript {
   associatedtype Index
@@ -355,6 +359,47 @@
 
 func increment(_ x: inout Int) { x += 1 }
 
+// Generic subscripts.
+
+protocol GenericSubscriptProtocol {
+  subscript<T>(_: T) -> T { get set }
+}
+
+struct GenericSubscriptWitness : GenericSubscriptProtocol {
+  subscript<T>(_: T) -> T { get { } set { } }
+}
+
+// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufmytfU_ : $@convention(method) <T> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericSubscriptWitness, @thick GenericSubscriptWitness.Type) -> () {
+// CHECK:       bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*GenericSubscriptWitness, %3 : $@thick GenericSubscriptWitness.Type):
+// CHECK:         [[BUFFER:%.*]] = project_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer
+// CHECK-NEXT:    [[INDICES:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*T
+// CHECK:         [[SETTER:%.*]] = function_ref @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufs : $@convention(method) <τ_0_0> (@in τ_0_0, @in τ_0_0, @inout GenericSubscriptWitness) -> ()
+// CHECK-NEXT:    apply [[SETTER]]<T>([[INDICES]], [[BUFFER]], %2) : $@convention(method) <τ_0_0> (@in τ_0_0, @in τ_0_0, @inout GenericSubscriptWitness) -> ()
+// CHECK-NEXT:    dealloc_value_buffer $*T in %1 : $*Builtin.UnsafeValueBuffer
+// CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT:    return [[RESULT]] : $()
+
+// CHECK-LABEL sil hidden [transparent] [thunk] @_T017materializeForSet23GenericSubscriptWitnessVAA0dE8ProtocolAaaDP9subscriptqd__qd__clufmTW : $@convention(witness_method) <τ_0_0> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in τ_0_0, @inout GenericSubscriptWitness) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK:      bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*T, %3 : $*GenericSubscriptWitness):
+// CHECK-NEXT:   [[BUFFER:%.*]] = alloc_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer
+// CHECK-NEXT:   copy_addr %2 to [initialization] [[BUFFER]] : $*T
+// CHECK-NEXT:   [[VALUE:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*T
+// CHECK-NEXT:   [[SELF:%.*]] = load [trivial] %3 : $*GenericSubscriptWitness
+// CHECK:        [[GETTER:%.*]] = function_ref @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufg : $@convention(method) <τ_0_0> (@in τ_0_0, GenericSubscriptWitness) -> @out τ_0_0
+// CHECK-NEXT:   apply [[GETTER]]<T>([[VALUE]], %2, [[SELF]]) : $@convention(method) <τ_0_0> (@in τ_0_0, GenericSubscriptWitness) -> @out τ_0_0
+// CHECK-NEXT:   [[VALUE_PTR:%.*]] = address_to_pointer [[VALUE]] : $*T to $Builtin.RawPointer
+// CHECK:        [[CALLBACK:%.*]] = function_ref @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufmytfU_
+// CHECK-NEXT:   [[CALLBACK_PTR:%.*]] = thin_function_to_pointer [[CALLBACK]] : $@convention(method) <τ_0_0> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericSubscriptWitness, @thick GenericSubscriptWitness.Type) -> () to $Builtin.RawPointer
+// CHECK-NEXT:   [[CALLBACK_OPTIONAL:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_PTR]] : $Builtin.RawPointer
+// CHECK-NEXT:   [[RESULT:%.*]] = tuple ([[VALUE_PTR]] : $Builtin.RawPointer, [[CALLBACK_OPTIONAL]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT:   return [[RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+
+extension GenericSubscriptProtocol {
+  subscript<T>(t: T) -> T { get { } set { } }
+}
+
+struct GenericSubscriptDefaultWitness : GenericSubscriptProtocol { }
+
 // Test for materializeForSet vs static properties of structs.
 
 protocol Beverage {
@@ -435,6 +480,18 @@
 
 struct TuxedoPanda : Panda { }
 
+// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
+
+  // FIXME: Useless re-abstractions
+
+  // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVACIxir_AcCIxyd_TR : $@convention(thin) (TuxedoPanda, @owned @callee_owned (@in TuxedoPanda) -> @out TuxedoPanda) -> TuxedoPanda
+
+  // CHECK: function_ref @_T017materializeForSet5PandaPAAE1xxxcfs : $@convention(method) <τ_0_0 where τ_0_0 : Panda> (@owned @callee_owned (@in τ_0_0) -> @out τ_0_0, @inout τ_0_0) -> ()
+
+  // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVACIxyd_AcCIxir_TR : $@convention(thin) (@in TuxedoPanda, @owned @callee_owned (TuxedoPanda) -> TuxedoPanda) -> @out TuxedoPanda
+
+// CHECK: }
+
 // CHECK-LABEL: sil hidden [transparent] [thunk] @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmTW
 
 // Call the getter:
@@ -454,19 +511,7 @@
 
 // The callback:
 
-  // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
-
-// CHECK: }
-
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
-
-  // FIXME: Useless re-abstractions
-
-  // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVACIxir_AcCIxyd_TR : $@convention(thin) (TuxedoPanda, @owned @callee_owned (@in TuxedoPanda) -> @out TuxedoPanda) -> TuxedoPanda
-
-  // CHECK: function_ref @_T017materializeForSet5PandaPAAE1xxxcfs : $@convention(method) <τ_0_0 where τ_0_0 : Panda> (@owned @callee_owned (@in τ_0_0) -> @out τ_0_0, @inout τ_0_0) -> ()
-
-  // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVACIxyd_AcCIxir_TR : $@convention(thin) (@in TuxedoPanda, @owned @callee_owned (TuxedoPanda) -> TuxedoPanda) -> @out TuxedoPanda
+  // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
 
 // CHECK: }
 
diff --git a/test/SILGen/opaque_values_silgen.swift b/test/SILGen/opaque_values_silgen.swift
index a6e20bb..e8387d6 100644
--- a/test/SILGen/opaque_values_silgen.swift
+++ b/test/SILGen/opaque_values_silgen.swift
@@ -290,3 +290,93 @@
 func s190___return_foo_var() -> Foo {
   return foo_var
 }
+
+// Tests deinit of opaque existentials
+// ---
+// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s200______use_foo_varyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[GLOBAL:%.*]] = global_addr {{.*}} : $*Foo
+// CHECK:   [[LOAD_GLOBAL:%.*]] = load [copy] [[GLOBAL]] : $*Foo
+// CHECK:   [[OPEN_VAR:%.*]] = open_existential_opaque [[LOAD_GLOBAL]] : $Foo
+// CHECK:   [[WITNESS:%.*]] = witness_method $@opened
+// CHECK:   apply [[WITNESS]]
+// CHECK:   destroy_value [[OPEN_VAR]]
+// CHECK:   deinit_existential_opaque [[LOAD_GLOBAL]] : $Foo
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s200______use_foo_varyyF'
+func s200______use_foo_var() {
+  foo_var.foo()
+}
+
+// Tests composition erasure of opaque existentials + copy into of opaques
+// ---
+// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s210______compErasures5Error_psAC_AA3FoopF : $@convention(thin) (@in Error & Foo) -> @owned Error {
+// CHECK: bb0([[ARG:%.*]] : $Error & Foo):
+// CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+// CHECK:   [[OPAQUE_ARG:%.*]] = open_existential_opaque [[BORROWED_ARG]] : $Error & Foo to $@opened({{.*}}) Error & Foo
+// CHECK:   [[EXIST_BOX:%.*]] = alloc_existential_box $Error, $@opened({{.*}}) Error & Foo
+// CHECK:   [[PROJ_BOX:%.*]] = project_existential_box $@opened({{.*}}) Error & Foo in [[EXIST_BOX]]
+// CHECK:   [[COPY_OPAQUE:%.*]] = copy_value [[OPAQUE_ARG]] : $@opened({{.*}}) Error & Foo
+// CHECK:   store [[COPY_OPAQUE]] to [init] [[PROJ_BOX]] : $*@opened({{.*}}) Error & Foo
+// CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
+// CHECK:   destroy_value [[ARG]] : $Error & Foo
+// CHECK:   return [[EXIST_BOX]] : $Error
+// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s210______compErasures5Error_psAC_AA3FoopF'
+func s210______compErasure(_ x: Foo & Error) -> Error {
+  return x
+}
+
+// Tests that existential boxes can contain opaque types
+// ---
+// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s220_____openExistBoxSSs5Error_pF : $@convention(thin) (@owned Error) -> @owned String {
+// CHECK: bb0([[ARG:%.*]] : $Error):
+// CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+// CHECK:   [[OPAQUE_ARG:%.*]] = open_existential_box [[BORROWED_ARG]] : $Error to $@opened({{.*}}) Error
+// CHECK:   [[RET_STRING:%.*]] = apply{{.*}}<@opened({{.*}}) Error>([[OPAQUE_ARG]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : Error> (@in_guaranteed τ_0_0) -> @owned String
+// CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
+// CHECK:   destroy_value [[ARG]] : $Error
+// CHECK:   return [[RET_STRING]] : $String
+// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s220_____openExistBoxSSs5Error_pF'
+func s220_____openExistBox(_ x: Error) -> String {
+  return x._domain
+}
+
+// Tests LogicalPathComponent's writeback for opaque value types
+// ---
+// CHECK-LABEL: sil @_T0s10DictionaryV20opaque_values_silgenE22inoutAccessOfSubscriptyq_3key_tF : $@convention(method) <Key, Value where Key : Hashable> (@in Value, @inout Dictionary<Key, Value>) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Value, [[ARG1:%.*]] : $*Dictionary<Key, Value>):
+// CHECK:   [[OPTIONAL_ALLOC:%.*]] = alloc_stack $Optional<Value>
+// CHECK:   switch_enum_addr [[OPTIONAL_ALLOC]] : $*Optional<Value>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb2:
+// CHECK:   [[OPTIONAL_LOAD:%.*]] = load [take] [[OPTIONAL_ALLOC]] : $*Optional<Value>
+// CHECK:   apply {{.*}}<Key, Value>([[OPTIONAL_LOAD]], {{.*}}, [[ARG1]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '_T0s10DictionaryV20opaque_values_silgenE22inoutAccessOfSubscriptyq_3key_tF'
+
+// Tests materializeForSet's createSetterCallback for opaque values
+// ---
+// CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV20opaque_values_silgenE9subscriptq_Sgq_cfmytfU_ : $@convention(method) <Key, Value where Key : Hashable> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Key, Value>, @thick Dictionary<Key, Value>.Type) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Builtin.RawPointer, [[ARG1:%.*]] : $*Builtin.UnsafeValueBuffer, [[ARG2:%.*]] : $*Dictionary<Key, Value>, [[ARG3:%.*]] : $@thick Dictionary<Key, Value>.Type):
+// CHECK:   [[PROJ_VAL1:%.*]] = project_value_buffer $Value in [[ARG1]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   [[LOAD_VAL1:%.*]] = load [take] [[PROJ_VAL1]] : $*Value
+// CHECK:   [[ADDR_VAL0:%.*]] = pointer_to_address [[ARG0]] : $Builtin.RawPointer to [strict] $*Optional<Value>
+// CHECK:   [[LOAD_VAL0:%.*]] = load [take] [[ADDR_VAL0]] : $*Optional<Value>
+// CHECK:   apply {{.*}}<Key, Value>([[LOAD_VAL0]], [[LOAD_VAL1]], [[ARG2]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '_T0s10DictionaryV20opaque_values_silgenE9subscriptq_Sgq_cfmytfU_'
+extension Dictionary {
+  public subscript(key: Value) -> Value? {
+    @inline(__always)
+    get {
+      return key
+    }
+    set(newValue) {
+    }
+  }
+  
+  public mutating func inoutAccessOfSubscript(key: Value) {
+    func increment(x: inout Value) { }
+
+    increment(x: &self[key]!)
+  }
+}
diff --git a/test/SILGen/optional-cast.swift b/test/SILGen/optional-cast.swift
index 1ca7fa4..e2ed3eb 100644
--- a/test/SILGen/optional-cast.swift
+++ b/test/SILGen/optional-cast.swift
@@ -30,8 +30,8 @@
 // CHECK-NEXT: br [[CONT:bb[0-9]+]]
 //
 //   If not, destroy_value the A and inject nothing into x.
-// CHECK:    [[NOT_B]]:
-// CHECK-NEXT: destroy_value [[VAL]]
+// CHECK:    [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : $A):
+// CHECK-NEXT: destroy_value [[ORIGINAL_VALUE]]
 // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<B>, #Optional.none
 // CHECK-NEXT: br [[CONT]]
 //
@@ -111,8 +111,8 @@
 // CHECK-NEXT: br [[SWITCH_OB2:bb[0-9]+]](
 //
 //   If not, inject nothing into an optional.
-// CHECK:    [[NOT_B]]:
-// CHECK-NEXT: destroy_value [[VAL]]
+// CHECK:    [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : $A):
+// CHECK-NEXT: destroy_value [[ORIGINAL_VALUE]]
 // CHECK-NEXT: enum $Optional<B>, #Optional.none!enumelt
 // CHECK-NEXT: br [[SWITCH_OB2]](
 //
@@ -174,9 +174,10 @@
 // CHECK:         [[VAL:%.*]] = unchecked_enum_data [[ARG_COPY]]
 // CHECK-NEXT:    [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional<B>, #Optional.some
 // CHECK-NEXT:    checked_cast_br [[VAL]] : $AnyObject to $B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]]
-// CHECK:       [[IS_B]](
-// CHECK:       [[NOT_B]]:
-// CHECK:         destroy_value [[VAL]]
+// CHECK:       [[IS_B]]([[CASTED_VALUE:%.*]] : $B):
+// CHECK:         store [[CASTED_VALUE]] to [init] [[X_VALUE]]
+// CHECK:       [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : $AnyObject):
+// CHECK:         destroy_value [[ORIGINAL_VALUE]]
 // CHECK: } // end sil function '_T04main3bazys9AnyObject_pSgF'
 func baz(_ y : AnyObject?) {
   var x = (y as? B)
diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift
index e54101b..3e66fde 100644
--- a/test/SILGen/properties.swift
+++ b/test/SILGen/properties.swift
@@ -227,7 +227,7 @@
   // -- writeback to val.ref.val_prop
   // CHECK: 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: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> ()
+  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> ()
   // CHECK: [[REF_MAT:%.*]] = alloc_stack $Ref
   // CHECK: store [[VAL_REF]] to [init] [[REF_MAT]]
   // CHECK: [[T0:%.*]] = metatype $@thick Ref.Type
diff --git a/test/SILGen/protocol_resilience.swift b/test/SILGen/protocol_resilience.swift
index 8b7b32c..35e64a5 100644
--- a/test/SILGen/protocol_resilience.swift
+++ b/test/SILGen/protocol_resilience.swift
@@ -120,8 +120,8 @@
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE26mutablePropertyWithDefaultSifg
 // CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE26mutablePropertyWithDefaultSifs
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifm
 // CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifmytfU_
+// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifm
   public var mutablePropertyWithDefault: Int {
     get { return 0 }
     set { }
@@ -136,8 +136,8 @@
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE33mutableGenericPropertyWithDefault1TQzfg
 // CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE33mutableGenericPropertyWithDefault1TQzfs
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfm
 // CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfmytfU_
+// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfm
   public var mutableGenericPropertyWithDefault: T {
     get {
       return T(default: ())
@@ -149,8 +149,8 @@
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE9subscript1TQzAFcfg
 // CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE9subscript1TQzAFcfs
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfm
 // CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfmytfU_
+// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfm
   public subscript(x: T) -> T {
     get {
       return x
@@ -162,8 +162,8 @@
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE36mutatingGetterWithNonMutatingDefaultSifg
 // CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE36mutatingGetterWithNonMutatingDefaultSifs
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifm
 // CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifmytfU_
+// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifm
   public var mutatingGetterWithNonMutatingDefault: Int {
     get {
       return 0
diff --git a/test/SILOptimizer/address_lowering.sil b/test/SILOptimizer/address_lowering.sil
index 1e937e8..db8221f 100644
--- a/test/SILOptimizer/address_lowering.sil
+++ b/test/SILOptimizer/address_lowering.sil
@@ -5,12 +5,12 @@
 sil_stage canonical
 // CHECK: sil_stage lowered
 
-// CHECK-LABEL: sil hidden @addrlower_identity : $@convention(thin) <T> (@in T) -> @out T {
+// CHECK-LABEL: sil hidden @f010_addrlower_identity : $@convention(thin) <T> (@in T) -> @out T {
 // CHECK: bb0(%0 : $*T, %1 : $*T):
 // CHECK: copy_addr [take] %1 to [initialization] %0 : $*T
 // CHECK: return %{{.*}} : $()
-// CHECK-LABEL: } // end sil function 'addrlower_identity'
-sil hidden @addrlower_identity : $@convention(thin) <T> (@in T) -> @out T {
+// CHECK-LABEL: } // end sil function 'f010_addrlower_identity'
+sil hidden @f010_addrlower_identity : $@convention(thin) <T> (@in T) -> @out T {
 bb0(%0 : $T):
   return %0 : $T
 }
@@ -29,7 +29,7 @@
 // Test returning an opaque tuple of tuples as a concrete tuple.
 // The multiResult call is specialized, but the SIL result convention does not change.
 // ---
-// CHECK-LABEL: sil @f030_callMultiResult : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64, Builtin.Int64, Builtin.Int64) {
+// CHECK-LABEL: sil @f021_callMultiResult : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64, Builtin.Int64, Builtin.Int64) {
 // CHECK: bb0(%0 : $Builtin.Int64):
 // CHECK:  %[[FN:.*]] = function_ref @f020_multiResult : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0, @out τ_0_0)
 // CHECK:  %[[IN:.*]] = alloc_stack $Builtin.Int64
@@ -39,16 +39,16 @@
 // CHECK:  %[[OUT3:.*]] = alloc_stack $Builtin.Int64
 // CHECK:  %{{.*}} = apply %[[FN]]<Builtin.Int64>(%[[OUT1]], %[[OUT2]], %[[OUT3]], %[[IN]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0, @out τ_0_0)
 // CHECK:  %[[R3:.*]] = load %[[OUT3]] : $*Builtin.Int64
-// CHECK:  %[[R2:.*]] = load %[[OUT2]] : $*Builtin.Int64
-// CHECK:  %[[R1:.*]] = load %[[OUT1]] : $*Builtin.Int64
 // CHECK:  dealloc_stack %[[OUT3]] : $*Builtin.Int64
+// CHECK:  %[[R2:.*]] = load %[[OUT2]] : $*Builtin.Int64
 // CHECK:  dealloc_stack %[[OUT2]] : $*Builtin.Int64
+// CHECK:  %[[R1:.*]] = load %[[OUT1]] : $*Builtin.Int64
 // CHECK:  dealloc_stack %[[OUT1]] : $*Builtin.Int64
 // CHECK:  dealloc_stack %[[IN]] : $*Builtin.Int64
 // CHECK:  %[[R:.*]] = tuple (%[[R1]] : $Builtin.Int64, %[[R2]] : $Builtin.Int64, %[[R3]] : $Builtin.Int64)
 // CHECK:  return %[[R]] : $(Builtin.Int64, Builtin.Int64, Builtin.Int64)
-// CHECK-LABEL: } // end sil function 'f030_callMultiResult'
-sil @f030_callMultiResult : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64, Builtin.Int64, Builtin.Int64) {
+// CHECK-LABEL: } // end sil function 'f021_callMultiResult'
+sil @f021_callMultiResult : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64, Builtin.Int64, Builtin.Int64) {
 bb0(%0 : $Builtin.Int64):
   %1 = function_ref @f020_multiResult : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0, @out τ_0_0)
   %2 = apply %1<Builtin.Int64>(%0) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0, @out τ_0_0)
@@ -58,3 +58,318 @@
   %6 = tuple (%3 : $Builtin.Int64, %4 : $Builtin.Int64, %5 : $Builtin.Int64)
   return %6 : $(Builtin.Int64, Builtin.Int64, Builtin.Int64)
 }
+
+// CHECK-LABEL: sil @f030_returnPair : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
+// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
+// CHECK:   %[[LOCAL:.*]] = alloc_stack $T
+// CHECK:   copy_addr %2 to [initialization] %[[LOCAL]] : $*T
+// CHECK:   copy_addr [take] %[[LOCAL]] to [initialization] %0 : $*T
+// CHECK:   copy_addr [take] %2 to [initialization] %1 : $*T
+// CHECK:   %[[R:.*]] = tuple ()
+// CHECK:   dealloc_stack %[[LOCAL]] : $*T
+// CHECK:   return %[[R]] : $()
+// CHECK-LABEL: } // end sil function 'f030_returnPair'
+sil @f030_returnPair : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
+bb0(%0 : $T):
+  %2 = copy_value %0 : $T
+  %3 = tuple (%2 : $T, %0 : $T)
+  return %3 : $(T, T)
+}
+
+// CHECK-LABEL: sil @f031_unusedIndirect : $@convention(thin) <T> (@in T) -> @out T {
+// CHECK: bb0(%0 : $*T, %1 : $*T):
+// CHECK:   %[[LOC2:.*]] = alloc_stack $T
+// CHECK:   %[[OUT2:.*]] = alloc_stack $T
+// CHECK:   %[[LOC1:.*]] = alloc_stack $T
+// CHECK:   %[[OUT1:.*]] = alloc_stack $T
+// CHECK:   %[[LOC0:.*]] = alloc_stack $T
+// CHECK:   // function_ref f030_returnPair
+// CHECK:   %7 = function_ref @f030_returnPair : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0)
+// CHECK:   copy_addr %1 to [initialization] %[[LOC0]] : $*T
+// CHECK:   %[[IN:.*]] = alloc_stack $T
+// CHECK:   copy_addr [take] %[[LOC0]] to [initialization] %[[IN]] : $*T
+// CHECK:   %11 = apply %7<T>(%[[OUT1]], %[[OUT2]], %[[IN]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0)
+// CHECK:   dealloc_stack %[[IN]] : $*T
+// CHECK:   copy_addr %[[OUT1]] to [initialization] %[[LOC1]] : $*T
+// CHECK:   copy_addr %[[OUT2]] to [initialization] %[[LOC2]] : $*T
+// CHECK:   destroy_addr %[[OUT1]] : $*T
+// CHECK:   destroy_addr %[[OUT2]] : $*T
+// CHECK:   destroy_addr %[[LOC1]] : $*T
+// CHECK:   destroy_addr %1 : $*T
+// CHECK:   copy_addr [take] %[[LOC2]] to [initialization] %0 : $*T
+// CHECK:   %[[R:.*]] = tuple ()
+// CHECK:   dealloc_stack %[[LOC0]] : $*T
+// CHECK:   dealloc_stack %[[OUT1]] : $*T
+// CHECK:   dealloc_stack %[[LOC1]] : $*T
+// CHECK:   dealloc_stack %[[OUT2]] : $*T
+// CHECK:   dealloc_stack %[[LOC2]] : $*T
+// CHECK:   return %[[R]] : $()
+// CHECK-LABEL: } // end sil function 'f031_unusedIndirect'
+sil @f031_unusedIndirect : $@convention(thin) <T> (@in T) -> @out T {
+bb0(%0 : $T):
+  %2 = function_ref @f030_returnPair : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0)
+  %3 = copy_value %0 : $T
+  %4 = apply %2<T>(%3) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> (@out τ_0_0, @out τ_0_0)
+  %5 = tuple_extract %4 : $(T, T), 0
+  %6 = copy_value %5 : $T
+  %7 = tuple_extract %4 : $(T, T), 1
+  %8 = copy_value %7 : $T
+  destroy_value %4 : $(T, T)
+  destroy_value %6 : $T
+  destroy_value %0 : $T
+  return %8 : $T
+}
+
+sil hidden @f040_consumeArg : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : $T):
+  destroy_value %0 : $T
+  %3 = tuple ()
+  return %3 : $()
+}
+
+// CHECK-LABEL: sil @f041_opaqueArg : $@convention(thin) <T> (@in T) -> () {
+// CHECK: bb0(%0 : $*T):
+// CHECK:  %[[LOC:.*]] = alloc_stack $T
+// CHECK:  %[[FN:.*]] = function_ref @f040_consumeArg : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+// CHECK:  copy_addr %0 to [initialization] %[[LOC]] : $*T
+// CHECK:  %[[ARG:.*]] = alloc_stack $T
+// CHECK:  copy_addr [take] %[[LOC]] to [initialization] %[[ARG]] : $*T
+// CHECK:  %{{.*}} = apply %[[FN]]<T>(%[[ARG]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+// CHECK:  dealloc_stack %[[ARG]] : $*T
+// CHECK:  destroy_addr %0 : $*T
+// CHECK:  %[[R:.*]] = tuple ()
+// CHECK:  dealloc_stack %[[LOC]] : $*T
+// CHECK:  return %[[R]] : $()
+// CHECK-LABEL: } // end sil function 'f041_opaqueArg'
+sil @f041_opaqueArg : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : $T):
+  %2 = function_ref @f040_consumeArg : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+  %3 = copy_value %0 : $T
+  %4 = apply %2<T>(%3) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+  destroy_value %0 : $T
+  %6 = tuple ()
+  return %6 : $()
+}
+
+// CHECK-LABEL: sil @f050_storeinout : $@convention(thin) <T> (@inout T, @inout T, @in T) -> () {
+// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
+// CHECK:   %[[PREV2:.*]] = alloc_stack $T
+// CHECK:   %[[ARG2:.*]] = alloc_stack $T
+// CHECK:   %[[PREV1:.*]] = alloc_stack $T
+// CHECK:   %[[ARG1:.*]] = alloc_stack $T
+// CHECK:   debug_value_addr %0 : $*T, var, name "t", argno 1
+// CHECK:   debug_value_addr %1 : $*T, var, name "u", argno 2
+// CHECK:   debug_value_addr %2 : $*T
+// CHECK:   copy_addr %2 to [initialization] %[[ARG1]] : $*T
+// CHECK:   copy_addr [take] %0 to [initialization] %[[PREV1]] : $*T
+// CHECK:   copy_addr [take] %[[ARG1]] to [initialization] %0 : $*T
+// CHECK:   destroy_addr %[[PREV1]] : $*T
+// CHECK:   copy_addr %2 to [initialization] %[[ARG2]] : $*T
+// CHECK:   copy_addr [take] %1 to [initialization] %[[PREV2]] : $*T
+// CHECK:   copy_addr [take] %[[ARG2]] to [initialization] %1 : $*T
+// CHECK:   destroy_addr %[[PREV2]] : $*T
+// CHECK:   destroy_addr %2 : $*T
+// CHECK:   %19 = tuple ()
+// CHECK:   dealloc_stack %[[ARG1]] : $*T
+// CHECK:   dealloc_stack %[[PREV1]] : $*T
+// CHECK:   dealloc_stack %[[ARG2]] : $*T
+// CHECK:   dealloc_stack %[[PREV2]] : $*T
+// CHECK:   return %19 : $()
+// CHECK-LABEL: } // end sil function 'f050_storeinout'
+sil @f050_storeinout : $@convention(thin) <T> (@inout T, @inout T, @in T) -> () {
+bb0(%0 : $*T, %1 : $*T, %2 : $T):
+  debug_value_addr %0 : $*T, var, name "t", argno 1
+  debug_value_addr %1 : $*T, var, name "u", argno 2
+  debug_value %2 : $T, let, name "x", argno 3
+  %6 = copy_value %2 : $T
+  %7 = load %0 : $*T
+  store %6 to %0 : $*T
+  destroy_value %7 : $T
+  %10 = copy_value %2 : $T
+  %11 = load %1 : $*T
+  store %10 to %1 : $*T
+  destroy_value %11 : $T
+  destroy_value %2 : $T
+  %15 = tuple ()
+  return %15 : $()
+}
+
+sil hidden @f060_mutate : $@convention(thin) <T> (@inout T, @in T) -> () {
+bb0(%0 : $*T, %1 : $T):
+  %4 = copy_value %1 : $T
+  %5 = load %0 : $*T
+  store %4 to %0 : $*T
+  destroy_value %5 : $T
+  destroy_value %1 : $T
+  %9 = tuple ()
+  return %9 : $()
+}
+
+// CHECK-LABEL: sil @f061_callinout : $@convention(thin) <T> (@in T) -> () {
+// CHECK: bb0(%0 : $*T):
+// CHECK:   %[[LOC2:.*]] = alloc_stack $T
+// CHECK:   %[[LOC1:.*]] = alloc_stack $T
+// CHECK:   %[[INOUT:.*]] = alloc_stack $T, var, name "u"
+// CHECK:   copy_addr %0 to [initialization] %[[LOC1]] : $*T
+// CHECK:   copy_addr [take] %[[LOC1]] to [initialization] %[[INOUT]] : $*T
+// CHECK:   %[[FN:.*]] = function_ref @f060_mutate : $@convention(thin) <τ_0_0> (@inout τ_0_0, @in τ_0_0) -> ()
+// CHECK:   copy_addr %0 to [initialization] %[[LOC2]] : $*T
+// CHECK:   %[[IN:.*]] = alloc_stack $T
+// CHECK:   copy_addr [take] %[[LOC2]] to [initialization] %[[IN]] : $*T
+// CHECK:   %{{.*}} = apply %[[FN]]<T>(%[[INOUT]], %[[IN]]) : $@convention(thin) <τ_0_0> (@inout τ_0_0, @in τ_0_0) -> ()
+// CHECK:   dealloc_stack %[[IN]] : $*T
+// CHECK:   destroy_addr %[[INOUT]] : $*T
+// CHECK:   destroy_addr %0 : $*T
+// CHECK:   %[[R:.*]] = tuple ()
+// CHECK:   dealloc_stack %[[INOUT]] : $*T
+// CHECK:   dealloc_stack %[[LOC1]] : $*T
+// CHECK:   dealloc_stack %[[LOC2]] : $*T
+// CHECK:   return %[[R]] : $()
+// CHECK-LABEL: } // end sil function 'f061_callinout'
+sil @f061_callinout : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : $T):
+  %1 = alloc_stack $T, var, name "u"
+  %3 = copy_value %0 : $T
+  store %3 to %1 : $*T
+  %5 = function_ref @f060_mutate : $@convention(thin) <τ_0_0> (@inout τ_0_0, @in τ_0_0) -> ()
+  %6 = copy_value %0 : $T
+  %7 = apply %5<T>(%1, %6) : $@convention(thin) <τ_0_0> (@inout τ_0_0, @in τ_0_0) -> ()
+  destroy_addr %1 : $*T
+  destroy_value %0 : $T
+  %10 = tuple ()
+  dealloc_stack %1 : $*T
+  return %10 : $()
+}
+
+public protocol C : class {}
+
+// CHECK-LABEL: sil @f070_mixedResult1 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @owned C) {
+// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $C):
+// CHECK:   copy_addr [take] %1 to [initialization] %0 : $*T
+// CHECK:   return %2 : $C
+// CHECK-LABEL: } // end sil function 'f070_mixedResult1'
+sil @f070_mixedResult1 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @owned C) {
+bb0(%0 : $T, %1 : $C):
+  %4 = tuple (%0 : $T, %1 : $C)
+  return %4 : $(T, C)
+}
+
+// CHECK-LABEL: sil @f071_mixedResult2 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @out T, @owned C, @owned C) {
+// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T, %3 : $C):
+// CHECK:   %[[L:.*]] = alloc_stack $T
+// CHECK:   copy_addr %2 to [initialization] %[[L]] : $*T
+// CHECK:   strong_retain %3 : $C
+// CHECK:   copy_addr [take] %[[L]] to [initialization] %0 : $*T
+// CHECK:   copy_addr [take] %2 to [initialization] %1 : $*T
+// CHECK:   %[[T:.*]] = tuple (%3 : $C, %3 : $C)
+// CHECK:   dealloc_stack %[[L]] : $*T
+// CHECK:   return %[[T]] : $(C, C)
+// CHECK-LABEL: } // end sil function 'f071_mixedResult2'
+sil @f071_mixedResult2 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @out T, @owned C, @owned C) {
+bb0(%0 : $T, %1 : $C):
+  %4 = copy_value %0 : $T
+  strong_retain %1 : $C
+  %6 = tuple (%4 : $T, %0 : $T, %1 : $C, %1 : $C)
+  return %6 : $(T, T, C, C)
+}
+
+// CHECK-LABEL: sil @f072_callMixedResult1 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @owned C) {
+// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $C):
+// CHECK:   %[[LOUT:.*]] = alloc_stack $T
+// CHECK:   %[[OUT:.*]] = alloc_stack $T
+// CHECK:   %[[LIN:.*]] = alloc_stack $T
+// CHECK:   // function_ref f070_mixedResult1
+// CHECK:   %[[F:.*]] = function_ref @f070_mixedResult1 : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @owned C)
+// CHECK:   copy_addr %1 to [initialization] %[[LIN]] : $*T
+// CHECK:   strong_retain %2 : $C
+// CHECK:   %[[IN:.*]] = alloc_stack $T
+// CHECK:   copy_addr [take] %[[LIN]] to [initialization] %[[IN]] : $*T
+// CHECK:   %11 = apply %[[F]]<T>(%[[OUT]], %[[IN]], %2) : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @owned C)
+// CHECK:   dealloc_stack %[[IN]] : $*T
+// CHECK:   copy_addr %[[OUT]] to [initialization] %[[LOUT]] : $*T
+// CHECK:   strong_retain %11 : $C
+// CHECK:   destroy_addr %[[OUT]] : $*T
+// CHECK:   strong_release %11 : $C
+// CHECK:   strong_release %2 : $C
+// CHECK:   destroy_addr %1 : $*T
+// CHECK:   copy_addr [take] %[[LOUT]] to [initialization] %0 : $*T
+// CHECK:   dealloc_stack %[[LIN]] : $*T
+// CHECK:   dealloc_stack %[[OUT]] : $*T
+// CHECK:   dealloc_stack %[[LOUT]] : $*T
+// CHECK:   return %11 : $C
+// CHECK-LABEL: } // end sil function 'f072_callMixedResult1'
+sil @f072_callMixedResult1 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @owned C) {
+bb0(%0 : $T, %1 : $C):
+  %4 = function_ref @f070_mixedResult1 : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @owned C)
+  %5 = copy_value %0 : $T
+  strong_retain %1 : $C
+  %7 = apply %4<T>(%5, %1) : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @owned C)
+  %8 = tuple_extract %7 : $(T, C), 0
+  %9 = copy_value %8 : $T
+  %10 = tuple_extract %7 : $(T, C), 1
+  strong_retain %10 : $C
+  destroy_value %7 : $(T, C)
+  strong_release %1 : $C
+  destroy_value %0 : $T
+  %15 = tuple (%9 : $T, %10 : $C)
+  return %15 : $(T, C)
+}
+
+// CHECK-LABEL: sil @f073_callMixedResult2 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @out T, @owned C, @owned C) {
+// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T, %3 : $C):
+// CHECK:   %[[LOC2:.*]] = alloc_stack $T
+// CHECK:   %[[OUT2:.*]] = alloc_stack $T
+// CHECK:   %[[LOC1:.*]] = alloc_stack $T
+// CHECK:   %[[OUT1:.*]] = alloc_stack $T
+// CHECK:   %[[LOC0:.*]] = alloc_stack $T
+// CHECK:   %[[F:.*]] = function_ref @f071_mixedResult2 : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @out τ_0_0, @owned C, @owned C)
+// CHECK:   copy_addr %2 to [initialization] %[[LOC0]] : $*T
+// CHECK:   strong_retain %3 : $C
+// CHECK:   %[[IN:.*]] = alloc_stack $T
+// CHECK:   copy_addr [take] %[[LOC0]] to [initialization] %[[IN]] : $*T
+// CHECK:   %[[R:.*]] = apply %[[F]]<T>(%[[OUT1]], %[[OUT2]], %[[IN]], %3) : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @out τ_0_0, @owned C, @owned C)
+// CHECK:   %[[T2:.*]] = tuple_extract %[[R]] : $(C, C), 1
+// CHECK:   %[[T1:.*]] = tuple_extract %[[R]] : $(C, C), 0
+// CHECK:   dealloc_stack %[[IN]] : $*T
+// CHECK:   copy_addr %[[OUT1]] to [initialization] %[[LOC1]] : $*T
+// CHECK:   copy_addr %[[OUT2]] to [initialization] %[[LOC2]] : $*T
+// CHECK:   strong_retain %[[T1]] : $C
+// CHECK:   strong_retain %[[T2]] : $C
+// CHECK:   destroy_addr %[[OUT1]] : $*T
+// CHECK:   destroy_addr %[[OUT2]] : $*T
+// CHECK:   strong_release %[[T1]] : $C
+// CHECK:   strong_release %[[T2]] : $C
+// CHECK:   strong_release %3 : $C
+// CHECK:   destroy_addr %2 : $*T
+// CHECK:   copy_addr [take] %[[LOC1]] to [initialization] %0 : $*T
+// CHECK:   copy_addr [take] %[[LOC2]] to [initialization] %1 : $*T
+// CHECK:   %[[T:.*]] = tuple (%[[T1]] : $C, %[[T2]] : $C)
+// CHECK:   dealloc_stack %[[LOC0]] : $*T
+// CHECK:   dealloc_stack %[[OUT1]] : $*T
+// CHECK:   dealloc_stack %[[LOC1]] : $*T
+// CHECK:   dealloc_stack %[[OUT2]] : $*T
+// CHECK:   dealloc_stack %[[LOC2]] : $*T
+// CHECK:   return %[[T]] : $(C, C)
+// CHECK-LABEL: } // end sil function 'f073_callMixedResult2'
+sil @f073_callMixedResult2 : $@convention(thin) <T> (@in T, @owned C) -> (@out T, @out T, @owned C, @owned C) {
+bb0(%0 : $T, %1 : $C):
+  %4 = function_ref @f071_mixedResult2 : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @out τ_0_0, @owned C, @owned C)
+  %5 = copy_value %0 : $T
+  strong_retain %1 : $C
+  %7 = apply %4<T>(%5, %1) : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> (@out τ_0_0, @out τ_0_0, @owned C, @owned C)
+  %8 = tuple_extract %7 : $(T, T, C, C), 0
+  %9 = copy_value %8 : $T
+  %10 = tuple_extract %7 : $(T, T, C, C), 1
+  %11 = copy_value %10 : $T
+  %12 = tuple_extract %7 : $(T, T, C, C), 2
+  strong_retain %12 : $C
+  %14 = tuple_extract %7 : $(T, T, C, C), 3
+  strong_retain %14 : $C
+  destroy_value %7 : $(T, T, C, C)
+  strong_release %1 : $C
+  destroy_value %0 : $T
+  %19 = tuple (%9 : $T, %11 : $T, %12 : $C, %14 : $C)
+  return %19 : $(T, T, C, C)
+}
+
+sil_default_witness_table C {}
diff --git a/test/SILOptimizer/capture_promotion_generic_context.sil b/test/SILOptimizer/capture_promotion_generic_context.sil
index 1eb5b86..b7b2812 100644
--- a/test/SILOptimizer/capture_promotion_generic_context.sil
+++ b/test/SILOptimizer/capture_promotion_generic_context.sil
@@ -35,16 +35,11 @@
   return %k : $@callee_owned () -> Int
 }
 
-// Applying the caller's substitutions to a generic closure callee would also
-// be disastrous, but it appears that capture promotion currently bails out
-// on generic closures. This test is included to ensure there aren't regressions
-// if capture promotion is ever generalized to generic closures.
-
 protocol P {}
 
-// TODO: Ought to be promotable, but currently is not.
-// rdar://problem/28948735
-// CHECK-LABEL: sil @generic_promotable_box
+// CHECK-LABEL: sil @_TTSf2n_i__generic_promotable_box : $@convention(thin) <T> (@in T, Builtin.Int32) -> Builtin.Int32
+// CHECK:       bb0(%0 : $*T, %1 : $Builtin.Int32):
+// CHECK-NEXT:    return %1 : $Builtin.Int32
 
 sil @generic_promotable_box : $@convention(thin) <T> (@in T, <τ_0_0> { var τ_0_0 } <Int>) -> Int {
 entry(%0 : $*T, %b : $<τ_0_0> { var τ_0_0 } <Int>):
@@ -54,8 +49,12 @@
 }
 
 // CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic
-// CHECK:         [[F:%.*]] = function_ref @generic_promotable_box
-// CHECK:         partial_apply [[F]]<U>(
+// CHECK:       bb0(%0 : $*T, %1 : $*U, %2 : $Builtin.Int32):
+// CHECK-NEXT:    destroy_addr %0 : $*T
+// CHECK-NEXT:    destroy_addr %1 : $*U
+// CHECK:         [[F:%.*]] = function_ref @_TTSf2n_i__generic_promotable_box : $@convention(thin) <τ_0_0> (@in τ_0_0, Builtin.Int32) -> Builtin.Int32
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [[F]]<U>(%2)
+// CHECK-NEXT:    return [[CLOSURE]]
 
 sil @call_generic_promotable_box_from_different_generic : $@convention(thin) <T, U: P> (@in T, @in U, Int) -> @owned @callee_owned (@in U) -> Int {
 entry(%0 : $*T, %1 : $*U, %2 : $Int):
diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil
index 10e8c82..f101457 100644
--- a/test/SILOptimizer/cse.sil
+++ b/test/SILOptimizer/cse.sil
@@ -720,104 +720,6 @@
   %33 = return %32 : $()
 }
 
-// CHECK-LABEL: sil @cse_value_metatype
-// CHECK: value_metatype $@objc_metatype
-// CHECK: objc_metatype_to_object
-// CHECK-NOT: value_metatype $@objc_metatype
-// CHECK: strong_release
-// CHECK: return
-sil @cse_value_metatype : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
-bb0(%0 : $T):
-  %2 = value_metatype $@objc_metatype T.Type, %0 : $T
-  %4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
-  %5 = value_metatype $@objc_metatype T.Type, %0 : $T
-  %7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
-  strong_release %0 : $T
-  %9 = tuple (%4: $AnyObject, %7: $AnyObject)
-  return %9 : $(AnyObject, AnyObject)
-}
-
-
-@objc(XX) protocol XX {
-}
-
-// CHECK-LABEL: sil @cse_existential_metatype
-// CHECK: existential_metatype $@objc_metatype
-// CHECK: objc_existential_metatype_to_object
-// CHECK-NOT: existential_metatype $@objc_metatype
-// CHECK: strong_release
-// CHECK: return
-sil @cse_existential_metatype : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
-bb0(%0 : $XX):
-  %2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
-  %4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
-  %5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
-  %6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
-  strong_release %0 : $XX
-  %7 = tuple (%4: $AnyObject, %6: $AnyObject)
-  return %7 : $(AnyObject, AnyObject)
-}
-
-// CHECK-LABEL: sil @nocse_existential_metatype_addr
-// CHECK: store
-// CHECK: existential_metatype $@thick Any.Type
-// CHECK: store
-// CHECK: existential_metatype $@thick Any.Type
-// CHECK: return
-sil @nocse_existential_metatype_addr : $@convention(thin) (@owned B, @owned B) -> (@thick Any.Type, @thick Any.Type) {
-bb0(%0 : $B, %1 : $B):
-  %2 = alloc_stack $Any
-  %3 = init_existential_addr %2 : $*Any, $B
-  store %0 to %3 : $*B
-  %5 = existential_metatype $@thick Any.Type, %2 : $*Any
-  store %1 to %3 : $*B
-  %7 = existential_metatype $@thick Any.Type, %2 : $*Any
-  strong_release %1 : $B
-  strong_release %0 : $B
-  %99 = tuple (%5 : $@thick Any.Type, %7 : $@thick Any.Type)
-  dealloc_stack %2 : $*Any
-  return %99 : $(@thick Any.Type, @thick Any.Type)
-}
-
-
-// CHECK-LABEL: sil @cse_objc_metatype_to_object
-// CHECK: value_metatype $@objc_metatype
-// CHECK: objc_metatype_to_object
-// CHECK-NOT: value_metatype $@objc_metatype
-// CHECK-NOT: objc_metatype_to_object
-// CHECK: strong_release
-// CHECK: return
-sil @cse_objc_metatype_to_object : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
-bb0(%0 : $T):
-  %2 = value_metatype $@objc_metatype T.Type, %0 : $T
-  %4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
-  %5 = value_metatype $@objc_metatype T.Type, %0 : $T
-  %7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
-  strong_release %0 : $T
-  %9 = tuple (%4: $AnyObject, %7: $AnyObject)
-  return %9 : $(AnyObject, AnyObject)
-}
-
-
-// CHECK-LABEL: sil @cse_objc_existential_metatype_to_object
-// CHECK: existential_metatype $@objc_metatype
-// CHECK: objc_existential_metatype_to_object
-// CHECK-NOT: existential_metatype $@objc_metatype
-// CHECK-NOT: objc_existential_metatype_to_object
-// CHECK: strong_release
-// CHECK: return
-sil @cse_objc_existential_metatype_to_object : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
-bb0(%0 : $XX):
-  %2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
-  %4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
-  %5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
-  %6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
-  strong_release %0 : $XX
-  %7 = tuple (%4: $AnyObject, %6: $AnyObject)
-  return %7 : $(AnyObject, AnyObject)
-}
-
-
 // CHECK-LABEL: sil @cse_raw_pointer_to_ref
 // CHECK: raw_pointer_to_ref
 // CHECK-NOT: raw_pointer_to_ref
@@ -937,24 +839,6 @@
   return %3: $(Builtin.Int1, Builtin.Int1)
 }
 
-
-@objc
-class XXX {
-}
-
-// CHECK-LABEL: sil @cse_objc_to_thick_metatype
-// CHECK: objc_to_thick_metatype
-// CHECK-NOT: objc_to_thick_metatype
-// CHECK: tuple
-// CHECK: return
-sil @cse_objc_to_thick_metatype : $@convention(thin) (@objc_metatype XXX.Type) -> (@thick XXX.Type, @thick XXX.Type) {
-bb0(%0 : $@objc_metatype XXX.Type):
-  %1 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
-  %2 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
-  %3 = tuple (%1: $@thick XXX.Type, %2: $@thick XXX.Type)
-  return %3: $(@thick XXX.Type, @thick XXX.Type)
-}
-
 // CHECK-LABEL: sil @cse_bridge_object_to_ref
 // CHECK: bridge_object_to_ref
 // CHECK-NOT: bridge_object_to_ref
diff --git a/test/SILOptimizer/cse_objc.sil b/test/SILOptimizer/cse_objc.sil
index 0d0a71c..40d3be1 100644
--- a/test/SILOptimizer/cse_objc.sil
+++ b/test/SILOptimizer/cse_objc.sil
@@ -154,6 +154,118 @@
   return %13 : $()
 }
 
+// CHECK-LABEL: sil @cse_value_metatype
+// CHECK: value_metatype $@objc_metatype
+// CHECK: objc_metatype_to_object
+// CHECK-NOT: value_metatype $@objc_metatype
+// CHECK: strong_release
+// CHECK: return
+sil @cse_value_metatype : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
+bb0(%0 : $T):
+  %2 = value_metatype $@objc_metatype T.Type, %0 : $T
+  %4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
+  %5 = value_metatype $@objc_metatype T.Type, %0 : $T
+  %7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
+  strong_release %0 : $T
+  %9 = tuple (%4: $AnyObject, %7: $AnyObject)
+  return %9 : $(AnyObject, AnyObject)
+}
+
+// CHECK-LABEL: sil @cse_existential_metatype
+// CHECK: existential_metatype $@objc_metatype
+// CHECK: objc_existential_metatype_to_object
+// CHECK-NOT: existential_metatype $@objc_metatype
+// CHECK: strong_release
+// CHECK: return
+sil @cse_existential_metatype : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
+bb0(%0 : $XX):
+  %2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
+  %4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
+  %5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
+  %6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
+  strong_release %0 : $XX
+  %7 = tuple (%4: $AnyObject, %6: $AnyObject)
+  return %7 : $(AnyObject, AnyObject)
+}
+
+class B {}
+
+// CHECK-LABEL: sil @nocse_existential_metatype_addr
+// CHECK: store
+// CHECK: existential_metatype $@thick Any.Type
+// CHECK: store
+// CHECK: existential_metatype $@thick Any.Type
+// CHECK: return
+sil @nocse_existential_metatype_addr : $@convention(thin) (@owned B, @owned B) -> (@thick Any.Type, @thick Any.Type) {
+bb0(%0 : $B, %1 : $B):
+  %2 = alloc_stack $Any
+  %3 = init_existential_addr %2 : $*Any, $B
+  store %0 to %3 : $*B
+  %5 = existential_metatype $@thick Any.Type, %2 : $*Any
+  store %1 to %3 : $*B
+  %7 = existential_metatype $@thick Any.Type, %2 : $*Any
+  strong_release %1 : $B
+  strong_release %0 : $B
+  %99 = tuple (%5 : $@thick Any.Type, %7 : $@thick Any.Type)
+  dealloc_stack %2 : $*Any
+  return %99 : $(@thick Any.Type, @thick Any.Type)
+}
+
+
+// CHECK-LABEL: sil @cse_objc_metatype_to_object
+// CHECK: value_metatype $@objc_metatype
+// CHECK: objc_metatype_to_object
+// CHECK-NOT: value_metatype $@objc_metatype
+// CHECK-NOT: objc_metatype_to_object
+// CHECK: strong_release
+// CHECK: return
+sil @cse_objc_metatype_to_object : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
+bb0(%0 : $T):
+  %2 = value_metatype $@objc_metatype T.Type, %0 : $T
+  %4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
+  %5 = value_metatype $@objc_metatype T.Type, %0 : $T
+  %7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
+  strong_release %0 : $T
+  %9 = tuple (%4: $AnyObject, %7: $AnyObject)
+  return %9 : $(AnyObject, AnyObject)
+}
+
+
+// CHECK-LABEL: sil @cse_objc_existential_metatype_to_object
+// CHECK: existential_metatype $@objc_metatype
+// CHECK: objc_existential_metatype_to_object
+// CHECK-NOT: existential_metatype $@objc_metatype
+// CHECK-NOT: objc_existential_metatype_to_object
+// CHECK: strong_release
+// CHECK: return
+sil @cse_objc_existential_metatype_to_object : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
+bb0(%0 : $XX):
+  %2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
+  %4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
+  %5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
+  %6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
+  strong_release %0 : $XX
+  %7 = tuple (%4: $AnyObject, %6: $AnyObject)
+  return %7 : $(AnyObject, AnyObject)
+}
+
+@objc
+class XXX {
+}
+
+// CHECK-LABEL: sil @cse_objc_to_thick_metatype
+// CHECK: objc_to_thick_metatype
+// CHECK-NOT: objc_to_thick_metatype
+// CHECK: tuple
+// CHECK: return
+sil @cse_objc_to_thick_metatype : $@convention(thin) (@objc_metatype XXX.Type) -> (@thick XXX.Type, @thick XXX.Type) {
+bb0(%0 : $@objc_metatype XXX.Type):
+  %1 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
+  %2 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
+  %3 = tuple (%1: $@thick XXX.Type, %2: $@thick XXX.Type)
+  return %3: $(@thick XXX.Type, @thick XXX.Type)
+}
+
 sil_vtable Bar {
   #Bar.init!initializer.1: _TFC4test3BarcfMS0_FT_S0_	// test.Bar.init (test.Bar.Type)() -> test.Bar
   #Bar.walk!1: _TFC4test3Bar4walkfS0_FT_T_	// test.Bar.walk (test.Bar)() -> ()
diff --git a/test/SILOptimizer/devirt_materializeForSet.swift b/test/SILOptimizer/devirt_materializeForSet.swift
index e84bc40..77b805b 100644
--- a/test/SILOptimizer/devirt_materializeForSet.swift
+++ b/test/SILOptimizer/devirt_materializeForSet.swift
@@ -5,7 +5,7 @@
 
 // CHECK-LABEL: sil [transparent] [fragile] [thunk] @_T024devirt_materializeForSet7BaseFooCAA0F0AaaDP3barSSfmTW
 // CHECK: checked_cast_br [exact] %{{.*}} : $BaseFoo to $ChildFoo
-// CHECK: thin_function_to_pointer %{{.*}} : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout ChildFoo, @thick ChildFoo.Type) -> () to $Builtin.RawPointer
+// CHECK: thin_function_to_pointer %{{.*}} : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout ChildFoo, @thick ChildFoo.Type) -> () to $Builtin.RawPointer
 // CHECK: enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, %{{.*}} : $Builtin.RawPointer
 // CHECK: tuple (%{{.*}} : $Builtin.RawPointer, %{{.*}} : $Optional<Builtin.RawPointer>)
 
diff --git a/test/SILOptimizer/existential_type_propagation.sil b/test/SILOptimizer/existential_type_propagation.sil
index 814ae81..d43dec7 100644
--- a/test/SILOptimizer/existential_type_propagation.sil
+++ b/test/SILOptimizer/existential_type_propagation.sil
@@ -253,18 +253,17 @@
 // Check that sil-combine does not crash on this example and does not generate a wrong
 // upcast.
 // CHECK-LABEL: sil @silcombine_dont_generate_wrong_upcasts_during_devirt
-// CHECK-NOT: upcast
-// CHECK: witness_method $XXX, #PPP.foo!1 : {{.*}} : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
-// CHECK-NOT: upcast
+// CHECK: [[SELF:%.*]] = unchecked_ref_cast %0 : $BBB to $XXX
+// CHECK: [[WITNESS_THUNK:%.*]] = function_ref @_TTWC4nix23XXXS_3PPPS_FS1_3foofT_T_ : $@convention(witness_method) (@guaranteed XXX) -> ()
+// CHECK: apply [[WITNESS_THUNK]]([[SELF]])
 // CHECK: return
 sil @silcombine_dont_generate_wrong_upcasts_during_devirt: $@convention(thin) (@owned BBB) -> () {
 bb0(%0 : $BBB):
   strong_retain %0 : $BBB
   %3 = init_existential_ref %0 : $BBB : $BBB, $PPP
   %5 = open_existential_ref %3 : $PPP to $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP
-  %6 = witness_method $XXX, #PPP.foo!1, %5 : $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
+  %6 = witness_method $BBB, #PPP.foo!1, %5 : $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
   %7 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
-  %8 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
   strong_release %3 : $PPP
   %9 = tuple ()
   strong_release %0 : $BBB
@@ -279,8 +278,6 @@
 // CHECK-NOT: witness_method
 // CHECK: [[FR1:%.*]] = function_ref @_TTWC4nix23XXXS_3PPPS_FS1_3foofT_T_
 // CHECK: apply [[FR1]](%0)
-// CHECK: [[FR2:%.*]] = function_ref @_TTWC4nix23XXXS_3PPPS_FS1_3foofT_T_
-// CHECK: apply [[FR2]](%0)
 // CHECK: return
 sil @silcombine_devirt_both_applies_of_witness_method : $@convention(thin) (@owned XXX) -> () {
 bb0(%0 : $XXX):
@@ -289,7 +286,6 @@
   %5 = open_existential_ref %3 : $PPP to $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP
   %6 = witness_method $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP, #PPP.foo!1, %5 : $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
   %7 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
-  %8 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
   strong_release %3 : $PPP
   %9 = tuple ()
   strong_release %0 : $XXX
diff --git a/test/SILOptimizer/ownership_model_eliminator.sil b/test/SILOptimizer/ownership_model_eliminator.sil
index bedfe79..70288dd 100644
--- a/test/SILOptimizer/ownership_model_eliminator.sil
+++ b/test/SILOptimizer/ownership_model_eliminator.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -ownership-model-eliminator %s | %FileCheck %s
+// RUN: %target-sil-opt -enable-sil-ownership -ownership-model-eliminator %s | %FileCheck %s
 
 sil_stage canonical
 
@@ -10,7 +10,7 @@
 class C {}
 
 // CHECK-LABEL: sil @load : $@convention(thin) (@in Builtin.NativeObject, @in Builtin.Int32) -> () {
-// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : $*Builtin.Int32):
+// CHECK: bb0([[ARG1:%[0-9]+]] : @trivial $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : @trivial $*Builtin.Int32):
 // CHECK: [[LOAD2:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject
 // CHECK: apply {{%[0-9]+}}([[LOAD2]])
 // CHECK: [[LOAD3:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject
@@ -19,7 +19,7 @@
 // CHECK: [[LOAD4:%[0-9]+]] = load [[ARG2]] : $*Builtin.Int32
 // CHECK: apply {{%[0-9]+}}([[LOAD4]])
 sil @load : $@convention(thin) (@in Builtin.NativeObject, @in Builtin.Int32) -> () {
-bb0(%0 : $*Builtin.NativeObject, %1 : $*Builtin.Int32):
+bb0(%0 : @trivial $*Builtin.NativeObject, %1 : @trivial $*Builtin.Int32):
   %use_native_object_func = function_ref @use_native_object : $@convention(thin) (@owned Builtin.NativeObject) -> ()
   %use_int32_func = function_ref @use_int32 : $@convention(thin) (Builtin.Int32) -> ()
 
@@ -37,28 +37,32 @@
 }
 
 // CHECK-LABEL: sil @store : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject, @in Builtin.Int32, Builtin.Int32) -> ()
-// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : $Builtin.NativeObject, [[ARG3:%[0-9]+]] : $*Builtin.Int32, [[ARG4:%[0-9]+]] : $Builtin.Int32):
+// CHECK: bb0([[ARG1:%[0-9]+]] : @trivial $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : @unowned $Builtin.NativeObject, [[ARG3:%[0-9]+]] : @trivial $*Builtin.Int32, [[ARG4:%[0-9]+]] : @trivial $Builtin.Int32):
+// CHECK: strong_retain [[ARG2]]
+// CHECK: strong_retain [[ARG2]]
 // CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.NativeObject
 // CHECK: [[OLDVAL:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject
 // CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.NativeObject
 // CHECK: strong_release [[OLDVAL]]
 // CHECK: store [[ARG4]] to [[ARG3]] : $*Builtin.Int32
 sil @store : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject, @in Builtin.Int32, Builtin.Int32) -> () {
-bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject, %2 : $*Builtin.Int32, %3 : $Builtin.Int32):
-  store %1 to [init] %0 : $*Builtin.NativeObject
-  store %1 to [assign] %0 : $*Builtin.NativeObject
+bb0(%0 : @trivial $*Builtin.NativeObject, %1 : @unowned $Builtin.NativeObject, %2 : @trivial $*Builtin.Int32, %3 : @trivial $Builtin.Int32):
+  %4 = copy_value %1 : $Builtin.NativeObject
+  %5 = copy_value %1 : $Builtin.NativeObject
+  store %4 to [init] %0 : $*Builtin.NativeObject
+  store %5 to [assign] %0 : $*Builtin.NativeObject
   store %3 to [trivial] %2 : $*Builtin.Int32
   %9999 = tuple()
   return %9999 : $()
 }
 
 // CHECK-LABEL: sil @borrow : $@convention(thin) (@in Builtin.NativeObject) -> () {
-// CHECK: bb0([[ARG:%[0-9]+]] : $*Builtin.NativeObject):
+// CHECK: bb0([[ARG:%[0-9]+]] : @trivial $*Builtin.NativeObject):
 // CHECK: [[BORROWED_VALUE:%[0-9]+]] = load [[ARG]] : $*Builtin.NativeObject
 // CHECK: unchecked_ref_cast [[BORROWED_VALUE]]
 // CHECK-NOT: end_borrow
 sil @borrow : $@convention(thin) (@in Builtin.NativeObject) -> () {
-bb0(%0 : $*Builtin.NativeObject):
+bb0(%0 : @trivial $*Builtin.NativeObject):
   %1 = load_borrow %0 : $*Builtin.NativeObject
   %2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $Builtin.NativeObject
   end_borrow %1 from %0 : $Builtin.NativeObject, $*Builtin.NativeObject
@@ -69,12 +73,12 @@
 sil @opaque_function : $@convention(thin) () -> ()
 
 // CHECK-LABEL: sil @copy_value_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
-// CHECK: bb0([[ARG1:%.*]] : $Builtin.NativeObject):
+// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject):
 // CHECK: strong_retain [[ARG1]]
 // CHECK: strong_release [[ARG1]]
 // CHECK: return [[ARG1]]
 sil @copy_value_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
-bb0(%0 : $Builtin.NativeObject):
+bb0(%0 : @owned $Builtin.NativeObject):
   %1 = function_ref @opaque_function : $@convention(thin) () -> ()
   %2 = copy_value %0 : $Builtin.NativeObject
   apply %1() : $@convention(thin) () -> ()
@@ -83,28 +87,30 @@
 }
 
 // CHECK-LABEL: sil @begin_borrow_store_borrow : $@convention(thin) (@owned Builtin.NativeObject) -> () {
-// CHECK: bb0([[ARG:%.*]] : $Builtin.NativeObject):
+// CHECK: bb0([[ARG:%.*]] : @owned $Builtin.NativeObject):
 // CHECK-NEXT: [[MEM:%.*]] = alloc_stack $Builtin.NativeObject
 // CHECK-NEXT: store [[ARG]] to [[MEM]] : $*Builtin.NativeObject
 // CHECK-NEXT: dealloc_stack [[MEM]] : $*Builtin.NativeObject
+// CHECK-NEXT: strong_release [[ARG]]
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 // CHECK: } // end sil function 'begin_borrow_store_borrow'
 sil @begin_borrow_store_borrow : $@convention(thin) (@owned Builtin.NativeObject) -> () {
-bb0(%0 : $Builtin.NativeObject):
+bb0(%0 : @owned $Builtin.NativeObject):
   %1 = begin_borrow %0 : $Builtin.NativeObject
   end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
   %2 = alloc_stack $Builtin.NativeObject
-  store_borrow %0 to %2 : $*Builtin.NativeObject
-  end_borrow %2 from %0 : $*Builtin.NativeObject, $Builtin.NativeObject
+  %3 = begin_borrow %0 : $Builtin.NativeObject
+  store_borrow %3 to %2 : $*Builtin.NativeObject
+  end_borrow %3 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
   dealloc_stack %2 : $*Builtin.NativeObject
-
+  destroy_value %0 : $Builtin.NativeObject
   %9999 = tuple()
   return %9999 : $()
 }
 
 // CHECK-LABEL: sil @copy_unowned_value_test : $@convention(thin) (@owned @sil_unowned Builtin.NativeObject) -> () {
-// CHECK: bb0([[ARG:%.*]] : $@sil_unowned Builtin.NativeObject):
+// CHECK: bb0([[ARG:%.*]] : @owned $@sil_unowned Builtin.NativeObject):
 // CHECK-NEXT: strong_retain_unowned [[ARG]] : $@sil_unowned Builtin.NativeObject
 // CHECK-NEXT: [[OWNED_ARG:%.*]] = unowned_to_ref [[ARG]] : $@sil_unowned Builtin.NativeObject to $Builtin.NativeObject
 // CHECK-NEXT: strong_release [[OWNED_ARG]] : $Builtin.NativeObject
@@ -112,7 +118,7 @@
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 sil @copy_unowned_value_test : $@convention(thin) (@owned @sil_unowned Builtin.NativeObject) -> () {
-bb0(%0 : $@sil_unowned Builtin.NativeObject):
+bb0(%0 : @owned $@sil_unowned Builtin.NativeObject):
   %1 = copy_unowned_value %0 : $@sil_unowned Builtin.NativeObject
   destroy_value %1 : $Builtin.NativeObject
   destroy_value %0 : $@sil_unowned Builtin.NativeObject
@@ -121,14 +127,14 @@
 }
 
 // CHECK-LABEL: sil @unmanaged_retain_release_test : $@convention(thin) (@owned Builtin.NativeObject, @owned C) -> () {
-// CHECK: bb0([[ARG1:%.*]] : $Builtin.NativeObject, [[ARG2:%.*]] : $C):
+// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $C):
 // CHECK: strong_retain [[ARG1]] : $Builtin.NativeObject
 // CHECK: autorelease_value [[ARG2]] : $C
 // CHECK: strong_release [[ARG1]] : $Builtin.NativeObject
 // CHECK: strong_release [[ARG1]] : $Builtin.NativeObject
 // CHECK: } // end sil function 'unmanaged_retain_release_test'
 sil @unmanaged_retain_release_test : $@convention(thin) (@owned Builtin.NativeObject, @owned C) -> () {
-bb0(%0 : $Builtin.NativeObject, %1 : $C):
+bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $C):
   unmanaged_retain_value %0 : $Builtin.NativeObject
   unmanaged_autorelease_value %1 : $C
   br bb1
@@ -136,6 +142,35 @@
 bb1:
   unmanaged_release_value %0 : $Builtin.NativeObject
   destroy_value %0 : $Builtin.NativeObject
+  destroy_value %1 : $C
+  %9999 = tuple()
+  return %9999 : $()
+}
+
+// CHECK-LABEL: sil @checked_cast_br_lowered : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+// CHECK: bb0([[ARG:%.*]] : @owned $Builtin.NativeObject):
+// CHECK:   checked_cast_br [[ARG]] : $Builtin.NativeObject to $C, [[SUCCBB:bb[0-9]+]], [[FAILBB:bb[0-9]+]]
+//
+// CHECK: [[SUCCBB]]([[CASTED_VALUE:%.*]] : @owned $C):
+// CHECK-NEXT:   strong_release [[CASTED_VALUE]]
+// CHECK-NEXT:   br bb3
+//
+// CHECK: [[FAILBB]]:
+// CHECK-NEXT:   strong_release [[ARG]]
+// CHECK-NEXT:   br bb3
+sil @checked_cast_br_lowered : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : @owned $Builtin.NativeObject):
+  checked_cast_br %0 : $Builtin.NativeObject to $C, bb1, bb2
+
+bb1(%1 : @owned $C):
+  destroy_value %1 : $C
+  br bb3
+
+bb2(%2 : @owned $Builtin.NativeObject):
+  destroy_value %2 : $Builtin.NativeObject
+  br bb3
+
+bb3:
   %9999 = tuple()
   return %9999 : $()
 }
diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil
index 47ac926..2b31c1a 100644
--- a/test/SILOptimizer/sil_combine.sil
+++ b/test/SILOptimizer/sil_combine.sil
@@ -1969,34 +1969,6 @@
   init()
 }
 
-// CHECK-LABEL: sil @remove_release_objc_metatype_to_object
-// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
-sil @remove_release_objc_metatype_to_object : $@convention(thin) () -> () {
-bb0:
-  %0 = metatype $@thick XXImpl.Type                // user: %1
-  %1 = thick_to_objc_metatype %0 : $@thick XXImpl.Type to $@objc_metatype XXImpl.Type // user: %2
-  %2 = objc_metatype_to_object %1 : $@objc_metatype XXImpl.Type to $AnyObject // users: %3, %4
-  debug_value %2 : $AnyObject  // id: %3
-  strong_release %2 : $AnyObject                  // id: %4
-  %5 = tuple ()                                   // user: %6
-  return %5 : $()                                 // id: %6
-}
-
-// CHECK-LABEL: sil @remove_release_objc_existential_metatype_to_object
-// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
-sil @remove_release_objc_existential_metatype_to_object: $@convention(thin) (@owned XX) -> () {
-bb0(%0 : $XX):
-  debug_value %0 : $XX                   // id: %1
-  %2 = existential_metatype $@thick XX.Type, %0 : $XX // user: %3
-  %3 = thick_to_objc_metatype %2 : $@thick XX.Type to $@objc_metatype XX.Type // user: %4
-  %4 = objc_existential_metatype_to_object %3 : $@objc_metatype XX.Type to $AnyObject // users: %5, %6
-  debug_value %4 : $AnyObject, let, name "obj1" // id: %5
-  strong_release %4 : $AnyObject                  // id: %6
-  strong_release %0 : $XX                         // id: %7
-  %8 = tuple ()                                   // user: %9
-  return %8 : $()                                 // id: %9
-}
-
 // CHECK-LABEL: sil @unowned_round_trips : $@convention(thin) (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) -> (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) {
 // CHECK: bb0(
 // CHECK-NEXT: tuple
diff --git a/test/SILOptimizer/sil_combine_objc.sil b/test/SILOptimizer/sil_combine_objc.sil
index e631e6d..ed1e877 100644
--- a/test/SILOptimizer/sil_combine_objc.sil
+++ b/test/SILOptimizer/sil_combine_objc.sil
@@ -151,3 +151,39 @@
   return %4 : $Int
 }
 
+@objc(XX) protocol XX {
+}
+
+class XXImpl : XX {
+  @objc deinit
+  init()
+}
+
+// CHECK-LABEL: sil @remove_release_objc_metatype_to_object
+// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
+sil @remove_release_objc_metatype_to_object : $@convention(thin) () -> () {
+bb0:
+  %0 = metatype $@thick XXImpl.Type                // user: %1
+  %1 = thick_to_objc_metatype %0 : $@thick XXImpl.Type to $@objc_metatype XXImpl.Type // user: %2
+  %2 = objc_metatype_to_object %1 : $@objc_metatype XXImpl.Type to $AnyObject // users: %3, %4
+  debug_value %2 : $AnyObject  // id: %3
+  strong_release %2 : $AnyObject                  // id: %4
+  %5 = tuple ()                                   // user: %6
+  return %5 : $()                                 // id: %6
+}
+
+// CHECK-LABEL: sil @remove_release_objc_existential_metatype_to_object
+// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
+sil @remove_release_objc_existential_metatype_to_object: $@convention(thin) (@owned XX) -> () {
+bb0(%0 : $XX):
+  debug_value %0 : $XX                   // id: %1
+  %2 = existential_metatype $@thick XX.Type, %0 : $XX // user: %3
+  %3 = thick_to_objc_metatype %2 : $@thick XX.Type to $@objc_metatype XX.Type // user: %4
+  %4 = objc_existential_metatype_to_object %3 : $@objc_metatype XX.Type to $AnyObject // users: %5, %6
+  debug_value %4 : $AnyObject, let, name "obj1" // id: %5
+  strong_release %4 : $AnyObject                  // id: %6
+  strong_release %0 : $XX                         // id: %7
+  %8 = tuple ()                                   // user: %9
+  return %8 : $()                                 // id: %9
+}
+
diff --git a/test/Sema/circular_decl_checking.swift b/test/Sema/circular_decl_checking.swift
index 28998c9..1e556fb 100644
--- a/test/Sema/circular_decl_checking.swift
+++ b/test/Sema/circular_decl_checking.swift
@@ -44,9 +44,8 @@
 
 
 protocol AProtocol {
+  // FIXME: Should produce an error here, but it's currently causing problems.
   associatedtype e : e
-  // expected-error@-1 {{type 'e' references itself}}
-  // expected-note@-2 {{type declared here}}
 }
 
 
diff --git a/test/Serialization/Inputs/alias.swift b/test/Serialization/Inputs/alias.swift
index eff05c2..6786981 100644
--- a/test/Serialization/Inputs/alias.swift
+++ b/test/Serialization/Inputs/alias.swift
@@ -26,3 +26,8 @@
   }
 }
 public typealias BaseAlias = Base
+
+public protocol ProtoWrapper {}
+extension ProtoWrapper {
+  public typealias Boolean = Bool
+}
diff --git a/test/Serialization/Inputs/has_xref.swift b/test/Serialization/Inputs/has_xref.swift
index 46d3759..48aa625 100644
--- a/test/Serialization/Inputs/has_xref.swift
+++ b/test/Serialization/Inputs/has_xref.swift
@@ -3,6 +3,7 @@
 
 public func numeric(_ x: MyInt64) {}
 public func conditional(_ x: AliasWrapper.Boolean) {}
+public func conditional2(_ x: ProtoWrapper.Boolean) {}
 public func longInt(_ x: Int.EspeciallyMagicalInt) {}
 
 public func numericArray(_ x: IntSlice) {}
diff --git a/test/Serialization/xref.swift b/test/Serialization/xref.swift
index db2c249..547976d 100644
--- a/test/Serialization/xref.swift
+++ b/test/Serialization/xref.swift
@@ -14,6 +14,7 @@
 
 numeric(42)
 conditional(true)
+conditional2(true)
 longInt(42)
 numericArray([42])
 
diff --git a/test/attr/attr_specialize.swift b/test/attr/attr_specialize.swift
index 32b2fd9..83438fc 100644
--- a/test/attr/attr_specialize.swift
+++ b/test/attr/attr_specialize.swift
@@ -50,6 +50,7 @@
   @_specialize(where T == Int)
   @_specialize(where T == T) // expected-error{{Only concrete type same-type requirements are supported by '_specialize' attribute}}
   @_specialize(where T == S<T>) // expected-error{{Only concrete type same-type requirements are supported by '_specialize' attribute}}
+	// expected-error@-1{{same-type constraint 'T' == 'S<T>' is recursive}}
   @_specialize(where T == Int, U == Int) // expected-error{{use of undeclared type 'U'}}
   func noGenericParams() {}
 
@@ -115,6 +116,8 @@
 @_specialize(where X:_Trivial(8), Y == Int)
 @_specialize(where X == Int, Y == Int)
 @_specialize(where X == Int, X == Int) // expected-error{{too few type parameters are specified in '_specialize' attribute (got 1, but expected 2)}} expected-error{{Missing constraint for 'Y' in '_specialize' attribute}}
+// expected-warning@-1{{redundant same-type constraint 'X' == 'Int'}}
+// expected-note@-2{{same-type constraint 'X' == 'Int' written here}}
 @_specialize(where Y:_Trivial(32), X == Float)
 @_specialize(where X1 == Int, Y1 == Int) // expected-error{{use of undeclared type 'X1'}} expected-error{{use of undeclared type 'Y1'}} expected-error{{too few type parameters are specified in '_specialize' attribute (got 0, but expected 2)}} expected-error{{Missing constraint for 'X' in '_specialize' attribute}} expected-error{{Missing constraint for 'Y' in '_specialize' attribute}}
 public func funcWithTwoGenericParameters<X, Y>(x: X, y: Y) {
diff --git a/test/decl/inherit/inherit.swift b/test/decl/inherit/inherit.swift
index 05e9069..5c45988 100644
--- a/test/decl/inherit/inherit.swift
+++ b/test/decl/inherit/inherit.swift
@@ -30,11 +30,15 @@
 // Protocol composition in inheritance clauses
 struct S3 : P, P & Q { } // expected-error {{duplicate inheritance from 'P'}}
                          // expected-error @-1 {{protocol composition is neither allowed nor needed here}}
+                         // expected-error @-2 {{'Q' requires that 'S3' inherit from 'A'}}
+                         // expected-note @-3 {{requirement specified as 'Self' : 'A' [with Self = S3]}}
 struct S4 : P, P { }     // expected-error {{duplicate inheritance from 'P'}}
 struct S6 : P & { }      // expected-error {{expected identifier for type name}}
                          // expected-error @-1 {{protocol composition is neither allowed nor needed here}}
 struct S7 : protocol<P, Q> { }  // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
                                 // expected-error @-1 {{protocol composition is neither allowed nor needed here}}{{13-22=}} {{26-27=}}
+                                // expected-error @-2 {{'Q' requires that 'S7' inherit from 'A'}}
+                                // expected-note @-3 {{requirement specified as 'Self' : 'A' [with Self = S7]}}
 
 class GenericBase<T> {}
 
diff --git a/test/decl/protocol/protocols.swift b/test/decl/protocol/protocols.swift
index a57bba5..f82826b 100644
--- a/test/decl/protocol/protocols.swift
+++ b/test/decl/protocol/protocols.swift
@@ -36,7 +36,7 @@
   v1.creator = "Me"                   // expected-error {{cannot assign to property: 'creator' is a get-only property}}
 }
 
-protocol Bogus : Int {} // expected-error{{inheritance from non-protocol type 'Int'}}
+protocol Bogus : Int {} // expected-error{{inheritance from non-protocol, non-class type 'Int'}}
 
 // Explicit conformance checks (successful).
 
diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift
index d559d82..5b61cb1 100644
--- a/test/decl/protocol/req/recursion.swift
+++ b/test/decl/protocol/req/recursion.swift
@@ -20,17 +20,18 @@
   // expected-note@-1{{type declared here}}
   // expected-note@-2{{protocol requires nested type 'Z'; do you want to add it?}}
 
-  associatedtype Z2 = Z3 // expected-note{{type declared here}}
+  associatedtype Z2 = Z3
   // expected-note@-1{{protocol requires nested type 'Z2'; do you want to add it?}}
-  associatedtype Z3 = Z2 // expected-error{{associated type 'Z2' references itself}}
+  associatedtype Z3 = Z2
   // expected-note@-1{{protocol requires nested type 'Z3'; do you want to add it?}}
 
-  associatedtype Z4 = Self.Z4 // expected-error{{associated type 'Z4' is not a member type of 'Self'}}
-  // expected-note@-1{{protocol requires nested type 'Z4'; do you want to add it?}}
+  associatedtype Z4 = Self.Z4 // expected-error{{associated type 'Z4' references itself}}
+  // expected-note@-1{{type declared here}}
+  // expected-note@-2{{protocol requires nested type 'Z4'; do you want to add it?}}
 
   associatedtype Z5 = Self.Z6
   // expected-note@-1{{protocol requires nested type 'Z5'; do you want to add it?}}
-  associatedtype Z6 = Self.Z5 // expected-error{{associated type 'Z5' is not a member type of 'Self'}}
+  associatedtype Z6 = Self.Z5
   // expected-note@-1{{protocol requires nested type 'Z6'; do you want to add it?}}
 }
 
diff --git a/test/expr/capture/noescape-error.swift b/test/expr/capture/noescape-error.swift
new file mode 100644
index 0000000..448d20a
--- /dev/null
+++ b/test/expr/capture/noescape-error.swift
@@ -0,0 +1,11 @@
+// RUN: %target-swift-frontend -typecheck -verify %s
+
+class C {}
+class D {}
+
+func f1(f : (inout Int) -> ()) {}
+
+func f2(f : (inout Any) -> ()) {
+    // TODO: Error here is still pretty bad...
+    f1 { f(&$0) } // expected-error{{conversion from 'Int' to 'Any'}}
+}
diff --git a/test/lit.cfg b/test/lit.cfg
index a7f618b..dd05346 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -465,6 +465,9 @@
 config.available_features.add("OS=" + run_os)
 config.available_features.add("PTRSIZE=" + run_ptrsize)
 
+if run_cpu == "i386" or run_cpu == "x86_64":
+  config.available_features.add("CPU=i386_or_x86_64")
+
 config.available_features.add("SWIFT_VERSION=" + swift_version)
 
 if "optimized_stdlib" in config.available_features:
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index dc33f68..0184045 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -68,6 +68,9 @@
 if "@SWIFT_STDLIB_ENABLE_RESILIENCE@" == "TRUE":
     config.available_features.add("resilient_stdlib")
 
+if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE":
+    config.available_features.add("nonatomic_rc")
+
 if "@SWIFT_HAVE_WORKING_STD_REGEX@" == "FALSE":
     config.available_features.add('broken_std_regex')
 
diff --git a/test/stdlib/CommandLine.swift b/test/stdlib/CommandLine.swift
index cfbfa55..6b0e851 100644
--- a/test/stdlib/CommandLine.swift
+++ b/test/stdlib/CommandLine.swift
@@ -7,6 +7,7 @@
 // RUN: %target-build-swift %t/CommandLineStressTest.o %t/CommandLineStressTestSwift.o -o %t/CommandLineStressTest
 // RUN: %target-run %t/CommandLineStressTest foo bar baz qux quux corge grault garply waldo fred plugh xyzzy and thud
 // REQUIRES: executable_test
+// UNSUPPORTED: nonatomic_rc
 
 // This file is an empty stub to call into the command line stress test which
 // houses `main`.
diff --git a/test/stdlib/DispatchDeprecationWatchOS.swift b/test/stdlib/DispatchDeprecationWatchOS.swift
index 3341bb3..bbc5fc6 100644
--- a/test/stdlib/DispatchDeprecationWatchOS.swift
+++ b/test/stdlib/DispatchDeprecationWatchOS.swift
@@ -1,5 +1,5 @@
 // RUN: %swift -typecheck -target i386-apple-watchos2.0 -verify -sdk %sdk %s
-// REQUIRES: OS=watchos
+// REQUIRES: CPU=i386, OS=watchos
 // REQUIRES: objc_interop
 
 import Foundation
diff --git a/test/stdlib/TestData.swift b/test/stdlib/TestData.swift
index 97954b7..4d106bb 100644
--- a/test/stdlib/TestData.swift
+++ b/test/stdlib/TestData.swift
@@ -991,9 +991,7 @@
 DataTests.test("test_repeatingValueInitialization") { TestData().test_repeatingValueInitialization() }
 
 // XCTest does not have a crash detection, whereas lit does
-DataTests.test("bounding failure subdata")
-        .skip(.always("fails with resilient stdlib (rdar://problem/30560514)"))
-        .code {
+DataTests.test("bounding failure subdata") {
     let data = "Hello World".data(using: .utf8)!
     expectCrashLater()
     let c = data.subdata(in: 5..<200)
@@ -1051,7 +1049,9 @@
     data.append("hello", count: Int.min)
 }
 
-DataTests.test("bounding failure subscript") {
+DataTests.test("bounding failure subscript")
+        .skip(.always("fails with resilient stdlib (rdar://problem/30560514)"))
+        .code {
     var data = "Hello World".data(using: .utf8)!
     expectCrashLater()
     data[100] = 4
diff --git a/test/stmt/Inputs/Foundation-with-NSError.swift b/test/stmt/Inputs/Foundation-with-NSError.swift
new file mode 100644
index 0000000..0005b24
--- /dev/null
+++ b/test/stmt/Inputs/Foundation-with-NSError.swift
@@ -0,0 +1 @@
+public class NSError: Error {}
diff --git a/test/stmt/errors_nonobjc.swift b/test/stmt/errors_nonobjc.swift
new file mode 100644
index 0000000..2c3369d
--- /dev/null
+++ b/test/stmt/errors_nonobjc.swift
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %target-swift-frontend -emit-module -module-name Foundation -o %t/Foundation.swiftmodule %S/Inputs/Foundation-with-NSError.swift
+// RUN: %target-swift-frontend -I %t -typecheck -verify %s
+// UNSUPPORTED: objc_interop
+
+import Foundation
+
+// Catching `as NSError` ought *not* to be exhaustive when ObjC interop is
+// disabled. It's just another error type.
+
+func bar() throws {}
+
+func foo() {
+  do {
+    try bar() // expected-error{{enclosing catch is not exhaustive}}
+  } catch _ as NSError {
+  }
+}
diff --git a/test/stmt/errors_objc.swift b/test/stmt/errors_objc.swift
new file mode 100644
index 0000000..42caa10
--- /dev/null
+++ b/test/stmt/errors_objc.swift
@@ -0,0 +1,14 @@
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s
+// REQUIRES: objc_interop
+
+import Foundation
+
+// Catching `as NSError` ought to be exhaustive when ObjC interop is enabled.
+func bar() throws {}
+
+func foo() {
+  do {
+    try bar()
+  } catch _ as NSError {
+  }
+}
diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift
index b33944c..f927ee7 100644
--- a/test/stmt/statements.swift
+++ b/test/stmt/statements.swift
@@ -247,7 +247,7 @@
 
 func brokenSwitch(_ x: Int) -> Int {
   switch x {
-  case .Blah(var rep): // expected-error{{enum case 'Blah' not found in type 'Int'}}
+  case .Blah(var rep): // expected-error{{pattern cannot match values of type 'Int'}}
     return rep
   }
 }
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftIndexing.cpp b/tools/SourceKit/lib/SwiftLang/SwiftIndexing.cpp
index 8e3d9aa..f9256f0 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftIndexing.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftIndexing.cpp
@@ -65,6 +65,8 @@
   }
 
   Action startSourceEntity(const IndexSymbol &symbol) override {
+    if (symbol.symInfo.Kind == SymbolKind::Parameter)
+      return Skip;
 
     // report any parent relations to this reference
     if (symbol.roles & (SymbolRoleSet)SymbolRole::RelationBaseOf) {
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
index 31e8986..765dd8e 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
@@ -724,8 +724,6 @@
 
   DelayedStringRetriever OverUSRsStream(SS);
 
-  SmallVector<std::pair<unsigned, unsigned>, 4> OverUSROffs;
-
   ide::walkOverriddenDecls(VD,
     [&](llvm::PointerUnion<const ValueDecl*, const clang::NamedDecl*> D) {
       OverUSRsStream.startPiece();
diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp
index 03ac94c..12a4da6 100644
--- a/tools/sil-opt/SILOpt.cpp
+++ b/tools/sil-opt/SILOpt.cpp
@@ -240,6 +240,8 @@
   Invocation.getLangOptions().DisableAvailabilityChecking = true;
   Invocation.getLangOptions().EnableAccessControl = false;
   Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false;
+  Invocation.getLangOptions().EnableObjCInterop =
+    llvm::Triple(Target).isOSDarwin();
 
   Invocation.getLangOptions().ASTVerifierProcessCount =
       ASTVerifierProcessCount;
diff --git a/tools/swift-syntax-format/swift-syntax-format.cpp b/tools/swift-syntax-format/swift-syntax-format.cpp
index 5ceed50..4d41650 100644
--- a/tools/swift-syntax-format/swift-syntax-format.cpp
+++ b/tools/swift-syntax-format/swift-syntax-format.cpp
@@ -1,4 +1,4 @@
-//===--- swift-syntax-test.cpp - Reflection Syntax testing application ----===//
+//===--- swift-syntax-format.cpp - Reflection Syntax testing application --===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/unittests/Syntax/CMakeLists.txt b/unittests/Syntax/CMakeLists.txt
index bdb109f..d812d93 100644
--- a/unittests/Syntax/CMakeLists.txt
+++ b/unittests/Syntax/CMakeLists.txt
@@ -6,7 +6,9 @@
   StmtSyntaxTests.cpp
   ThreadSafeCachingTests.cpp
   TriviaTests.cpp
-  TypeSyntaxTests.cpp)
+  TypeSyntaxTests.cpp
+  UnknownSyntaxTests.cpp
+  )
 
 target_link_libraries(SwiftSyntaxTests
   swiftSyntax)
diff --git a/unittests/Syntax/ExprSyntaxTests.cpp b/unittests/Syntax/ExprSyntaxTests.cpp
index 4be2a07..ae95b65 100644
--- a/unittests/Syntax/ExprSyntaxTests.cpp
+++ b/unittests/Syntax/ExprSyntaxTests.cpp
@@ -9,3 +9,480 @@
 #pragma mark - integer-literal-expression
 
 // TODO
+
+#pragma mark - symbolic-reference
+
+TEST(ExprSyntaxTests, SymbolicReferenceExprGetAPIs) {
+  {
+    auto Array = SyntaxFactory::makeIdentifier("Array", {}, {});
+    auto IntType = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
+    GenericArgumentClauseBuilder ArgBuilder;
+    ArgBuilder
+      .useLeftAngleBracket(SyntaxFactory::makeLeftAngleToken({}, {}))
+      .useRightAngleBracket(SyntaxFactory::makeRightAngleToken({}, {}))
+      .addGenericArgument(llvm::None, IntType);
+
+    auto GenericArgs = ArgBuilder.build();
+
+    auto Ref = SyntaxFactory::makeSymbolicReferenceExpr(Array, GenericArgs);
+
+    ASSERT_EQ(Ref.getIdentifier(), Array);
+
+    auto GottenArgs = Ref.getGenericArgumentClause().getValue();
+    auto GottenArgs2 = Ref.getGenericArgumentClause().getValue();
+    ASSERT_TRUE(GottenArgs.hasSameIdentityAs(GottenArgs2));
+
+    {
+      llvm::SmallString<48> Scratch;
+      llvm::raw_svector_ostream OS(Scratch);
+      GottenArgs.print(OS);
+      ASSERT_EQ(OS.str().str(), "<Int>");
+    }
+  }
+}
+
+TEST(ExprSyntaxTests, SymbolicReferenceExprMakeAPIs) {
+  auto Array = SyntaxFactory::makeIdentifier("Array", {}, {});
+  auto IntType = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
+  GenericArgumentClauseBuilder ArgBuilder;
+  ArgBuilder
+    .useLeftAngleBracket(SyntaxFactory::makeLeftAngleToken({}, {}))
+    .useRightAngleBracket(SyntaxFactory::makeRightAngleToken({}, {}))
+    .addGenericArgument(llvm::None, IntType);
+  auto GenericArgs = ArgBuilder.build();
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankSymbolicReferenceExpr().print(OS);
+    EXPECT_EQ(OS.str().str(), "");
+  }
+
+  {
+    auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto BlankArgs = SyntaxFactory::makeBlankGenericArgumentClause();
+
+    SyntaxFactory::makeSymbolicReferenceExpr(Foo, BlankArgs).print(OS);
+    EXPECT_EQ(OS.str().str(), "foo");
+  }
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeSymbolicReferenceExpr(Array, GenericArgs).print(OS);
+    ASSERT_EQ(OS.str().str(), "Array<Int>");
+  }
+}
+
+TEST(ExprSyntaxTests, SymbolicReferenceExprWithAPIs) {
+  auto Array = SyntaxFactory::makeIdentifier("Array", {}, {});
+  auto IntType = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
+  GenericArgumentClauseBuilder ArgBuilder;
+  ArgBuilder
+    .useLeftAngleBracket(SyntaxFactory::makeLeftAngleToken({}, {}))
+    .useRightAngleBracket(SyntaxFactory::makeRightAngleToken({}, {}))
+    .addGenericArgument(llvm::None, IntType);
+  auto GenericArgs = ArgBuilder.build();
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankSymbolicReferenceExpr()
+      .withIdentifier(Array)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "Array");
+  }
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankSymbolicReferenceExpr()
+      .withGenericArgumentClause(GenericArgs)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "<Int>");
+  }
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankSymbolicReferenceExpr()
+      .withIdentifier(Array)
+      .withGenericArgumentClause(GenericArgs)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "Array<Int>");
+  }
+}
+
+#pragma mark - function-call-argument
+
+TEST(ExprSyntaxTests, FunctionCallArgumentGetAPIs) {
+  auto X = SyntaxFactory::makeIdentifier("x", {}, {});
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+
+  {
+    auto Arg = SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef,
+                                                       Comma);
+
+    ASSERT_EQ(X, Arg.getLabel());
+    ASSERT_EQ(Colon, Arg.getColonToken());
+
+    auto GottenExpr = Arg.getExpression().getValue();
+    auto GottenExpr2 = Arg.getExpression().getValue();
+    ASSERT_TRUE(GottenExpr.hasSameIdentityAs(GottenExpr2));
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    GottenExpr.print(OS);
+    ASSERT_EQ("foo", OS.str().str());
+
+    ASSERT_EQ(Comma, Arg.getTrailingComma());
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallArgumentMakeAPIs) {
+  auto X = SyntaxFactory::makeIdentifier("x", {}, {});
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallArgument().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallArgument()
+      .withExpression(SymbolicRef).print(OS);
+    ASSERT_EQ(OS.str().str(), "foo");
+  }
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef, Comma)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "x: foo, ");
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallArgumentWithAPIs) {
+  auto X = SyntaxFactory::makeIdentifier("x", {}, {});
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+
+  {
+    llvm::SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallArgument()
+      .withLabel(X)
+      .withColonToken(Colon)
+      .withExpression(SymbolicRef)
+      .withTrailingComma(Comma)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "x: foo, ");
+  }
+}
+
+#pragma mark - function-call-argument-list
+
+namespace {
+FunctionCallArgumentListSyntax getFullArgumentList() {
+  auto X = SyntaxFactory::makeIdentifier("x", {}, {});
+  auto Y = SyntaxFactory::makeIdentifier("y", {}, {});
+  auto Z = SyntaxFactory::makeIdentifier("z", {}, {});
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+
+  auto Arg = SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef,
+                                                     Comma);
+
+  return SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .withAdditionalArgument(Arg)
+    .withAdditionalArgument(Arg.withLabel(Y))
+    .withAdditionalArgument(Arg.withLabel(Z).withTrailingComma(NoComma));
+}
+
+FunctionCallArgumentListSyntax getLabellessArgumentList() {
+  auto NoSign = TokenSyntax::missingToken(tok::oper_prefix, "");
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto TwoDigits = SyntaxFactory::makeIntegerLiteralToken("2", {}, {});
+  auto ThreeDigits = SyntaxFactory::makeIntegerLiteralToken("3", {}, {});
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(NoSign, OneDigits);
+  auto NoLabel = TokenSyntax::missingToken(tok::identifier, "");
+  auto NoColon = TokenSyntax::missingToken(tok::colon, ":");
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+  auto Two = SyntaxFactory::makeIntegerLiteralExpr(NoSign, TwoDigits);
+  auto Three = SyntaxFactory::makeIntegerLiteralExpr(NoSign, ThreeDigits);
+
+  auto OneArg = SyntaxFactory::makeFunctionCallArgument(NoLabel, NoColon, One,
+                                                        Comma);
+  auto TwoArg = SyntaxFactory::makeFunctionCallArgument(NoLabel, NoColon, Two,
+                                                        Comma);
+  auto ThreeArg = SyntaxFactory::makeFunctionCallArgument(NoLabel, NoColon,
+                                                          Three, NoComma);
+
+  return SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .withAdditionalArgument(OneArg)
+    .withAdditionalArgument(TwoArg)
+    .withAdditionalArgument(ThreeArg);
+}
+}
+
+TEST(ExprSyntaxTests, FunctionCallArgumentListGetAPIs) {
+  auto X = SyntaxFactory::makeIdentifier("x", {}, {});
+  auto Y = SyntaxFactory::makeIdentifier("y", {}, {});
+  auto Z = SyntaxFactory::makeIdentifier("z", {}, {});
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+
+  auto Arg = SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef,
+                                                     Comma);
+
+  auto ArgList = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .withAdditionalArgument(Arg)
+    .withAdditionalArgument(Arg.withLabel(Y))
+    .withAdditionalArgument(Arg.withLabel(Z).withTrailingComma(NoComma));
+
+  ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+
+  {
+    llvm::SmallString<16> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto GottenArg1 = ArgList.getArgument(0);
+    auto GottenArg1_2 = ArgList.getArgument(0);
+    ASSERT_TRUE(GottenArg1.hasSameIdentityAs(GottenArg1_2));
+    GottenArg1.print(OS);
+    ASSERT_EQ(OS.str().str(), "x: foo, ");
+  }
+
+  {
+    llvm::SmallString<16> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto GottenArg2 = ArgList.getArgument(1);
+    auto GottenArg2_2 = ArgList.getArgument(1);
+    ASSERT_TRUE(GottenArg2.hasSameIdentityAs(GottenArg2_2));
+    GottenArg2.print(OS);
+    ASSERT_EQ(OS.str().str(), "y: foo, ");
+  }
+
+  {
+    llvm::SmallString<16> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto GottenArg3 = ArgList.getArgument(2);
+    auto GottenArg3_2 = ArgList.getArgument(2);
+    ASSERT_TRUE(GottenArg3.hasSameIdentityAs(GottenArg3_2));
+    GottenArg3.print(OS);
+    ASSERT_EQ(OS.str().str(), "z: foo");
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallArgumentListMakeAPIs) {
+  {
+    llvm::SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallArgumentList().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+  {
+    auto X = SyntaxFactory::makeIdentifier("x", {}, {});
+    auto Y = SyntaxFactory::makeIdentifier("y", {}, {});
+    auto Z = SyntaxFactory::makeIdentifier("z", {}, {});
+    auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+    auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+    auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo,
+                                                                llvm::None);
+    auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+    auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+
+    auto Arg = SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef,
+                                                       Comma);
+
+    std::vector<FunctionCallArgumentSyntax> Args {
+      Arg, Arg.withLabel(Y), Arg.withLabel(Z).withTrailingComma(NoComma)
+    };
+
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto ArgList = SyntaxFactory::makeFunctionCallArgumentList(Args);
+    ArgList.print(OS);
+    ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+    ASSERT_EQ(OS.str().str(), "x: foo, y: foo, z: foo");
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallArgumentListWithAPIs) {
+  auto ArgList = getFullArgumentList();
+  llvm::SmallString<64> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+  ArgList.print(OS);
+  ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+  ASSERT_EQ(OS.str().str(), "x: foo, y: foo, z: foo");
+}
+
+#pragma mark - function-call-expression
+
+TEST(ExprSyntaxTests, FunctionCallExprGetAPIs) {
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto LeftParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto ArgList = getFullArgumentList();
+  auto RightParen = SyntaxFactory::makeRightParenToken({}, {});
+
+  auto Call = SyntaxFactory::makeFunctionCallExpr(SymbolicRef, LeftParen,
+                                                  ArgList, RightParen);
+
+  {
+    auto GottenExpression1 = Call.getCalledExpression();
+    auto GottenExpression2 = Call.getCalledExpression();
+    ASSERT_TRUE(GottenExpression1.hasSameIdentityAs(GottenExpression2));
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    GottenExpression1.print(OS);
+    ASSERT_EQ(OS.str().str(), "foo");
+  }
+
+  ASSERT_EQ(LeftParen, Call.getLeftParen());
+  ASSERT_EQ(RightParen, Call.getRightParen());
+
+  {
+    auto GottenArgs1 = Call.getArgumentList();
+    auto GottenArgs2 = Call.getArgumentList();
+    ASSERT_TRUE(GottenArgs1.hasSameIdentityAs(GottenArgs2));
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    GottenArgs1.print(OS);
+    ASSERT_EQ(OS.str().str(), "x: foo, y: foo, z: foo");
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallExprMakeAPIs) {
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto LeftParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto ArgList = getFullArgumentList();
+  auto RightParen = SyntaxFactory::makeRightParenToken({}, {});
+
+  {
+    auto Call = SyntaxFactory::makeFunctionCallExpr(SymbolicRef, LeftParen,
+                                                    ArgList, RightParen);
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    Call.print(OS);
+    ASSERT_EQ(OS.str().str(), "foo(x: foo, y: foo, z: foo)");
+  }
+
+  {
+    llvm::SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallExpr().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallExprWithAPIs) {
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+  auto LeftParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto ArgList = getFullArgumentList();
+  auto RightParen = SyntaxFactory::makeRightParenToken({}, {});
+
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallExpr()
+      .withCalledExpression(SymbolicRef)
+      .withLeftParen(LeftParen)
+      .withRightParen(RightParen)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "foo()");
+  }
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallExpr()
+      .withCalledExpression(SymbolicRef)
+      .withLeftParen(LeftParen)
+      .withArgumentList(getLabellessArgumentList())
+      .withRightParen(RightParen)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "foo(1, 2, 3)");
+  }
+}
+
+TEST(ExprSyntaxTests, FunctionCallExprBuilderAPIs) {
+  FunctionCallExprSyntaxBuilder CallBuilder;
+
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    CallBuilder.build().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+
+  auto LeftParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto RightParen = SyntaxFactory::makeRightParenToken({}, {});
+
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    CallBuilder.useLeftParen(LeftParen);
+    CallBuilder.useRightParen(RightParen);
+    CallBuilder.build().print(OS);
+    ASSERT_EQ(OS.str().str(), "()");
+  }
+
+  auto NoSign = TokenSyntax::missingToken(tok::oper_prefix, "");
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto TwoDigits = SyntaxFactory::makeIntegerLiteralToken("2", {}, {});
+  auto ThreeDigits = SyntaxFactory::makeIntegerLiteralToken("3", {}, {});
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(NoSign, OneDigits);
+  auto NoLabel = TokenSyntax::missingToken(tok::identifier, "");
+  auto NoColon = TokenSyntax::missingToken(tok::colon, ":");
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None);
+
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    CallBuilder.useCalledExpression(SymbolicRef);
+    CallBuilder.build().print(OS);
+    ASSERT_EQ(OS.str().str(), "foo()");
+  }
+
+  auto OneArg = SyntaxFactory::makeFunctionCallArgument(NoLabel, NoColon, One,
+                                                        Comma);
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    CallBuilder.appendArgument(OneArg);
+    CallBuilder.build().print(OS);
+    ASSERT_EQ(OS.str().str(), "foo(1, )");
+  }
+
+  {
+    llvm::SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    CallBuilder.appendArgument(OneArg.withTrailingComma(NoComma));
+    CallBuilder.build().print(OS);
+    ASSERT_EQ(OS.str().str(), "foo(1, 1)");
+  }
+}
diff --git a/unittests/Syntax/ThreadSafeCachingTests.cpp b/unittests/Syntax/ThreadSafeCachingTests.cpp
index 9718330..d4e55b1 100644
--- a/unittests/Syntax/ThreadSafeCachingTests.cpp
+++ b/unittests/Syntax/ThreadSafeCachingTests.cpp
@@ -4,18 +4,78 @@
 #include "llvm/ADT/SmallString.h"
 #include "gtest/gtest.h"
 
+#include <future>
 #include <thread>
+#include <queue>
 
 using namespace swift;
 using namespace swift::syntax;
 
-static void getExpressionFrom(ReturnStmtSyntax Return,
-                              uintptr_t *DataPointer) {
+static uintptr_t getExpressionFrom(ReturnStmtSyntax Return) {
   auto Expression = Return.getExpression().getValue();
-  auto Data = Expression.getDataPointer();
-  *DataPointer = reinterpret_cast<uintptr_t>(Data);
+  return reinterpret_cast<uintptr_t>(Expression.getDataPointer());
 }
 
+class Pool {
+  static constexpr size_t NumThreads = 2;
+  using FuncTy = std::function<uintptr_t(ReturnStmtSyntax)>;
+  std::vector<std::thread> Workers;
+  std::queue<std::function<void()>> Tasks;
+  std::mutex QueueLock;
+  std::condition_variable Condition;
+  bool Stop;
+
+public:
+  Pool() : Stop(false) {
+    for(size_t i = 0; i < NumThreads; ++i)
+      Workers.emplace_back([this] {
+        while (true) {
+          std::function<void()> Task;
+          {
+            std::unique_lock<std::mutex> L(QueueLock);
+
+            Condition.wait(L, [this]{
+              return Stop || !Tasks.empty();
+            });
+
+            if(Stop && Tasks.empty()) {
+              return;
+            }
+
+            Task = std::move(Tasks.front());
+            Tasks.pop();
+          }
+
+          Task();
+        }
+      });
+  }
+
+  std::future<uintptr_t> run(FuncTy Func, ReturnStmtSyntax Return) {
+    auto Task = std::make_shared<std::packaged_task<uintptr_t()>>(
+      std::bind(Func, Return));
+
+    auto Future = Task->get_future();
+    {
+      std::unique_lock<std::mutex> L(QueueLock);
+      Tasks.emplace([Task](){ (*Task)(); });
+    }
+    Condition.notify_one();
+    return Future;
+  }
+
+  ~Pool() {
+    {
+      std::lock_guard<std::mutex> L(QueueLock);
+      Stop = true;
+    }
+    Condition.notify_all();
+    for(auto &Worker : Workers) {
+      Worker.join();
+    }
+  }
+};
+
 // Tests that, when multiple threads ask for a child node of the same syntax
 // node:
 // - Only one thread inserts the realized child into the parent
@@ -26,29 +86,22 @@
   auto One = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
   auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr(Minus, One);
 
+  Pool P;
+
   for (unsigned i = 0; i < 10000; ++i) {
-    llvm::SmallString<48> Scratch;
-    llvm::raw_svector_ostream OS(Scratch);
     auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
 
-    uintptr_t FirstDataPointer;
-    uintptr_t SecondDataPointer;
+    auto Future1 = P.run(getExpressionFrom, Return);
+    auto Future2 = P.run(getExpressionFrom, Return);
 
-    std::thread first(getExpressionFrom, Return, &FirstDataPointer);
-    std::thread second(getExpressionFrom, Return, &SecondDataPointer);
-    first.join();
-    second.join();
+    auto FirstDataPointer = Future1.get();
+    auto SecondDataPointer = Future2.get();
 
     auto DataPointer = reinterpret_cast<uintptr_t>(
       Return.getExpression().getValue().getDataPointer());
 
     ASSERT_EQ(FirstDataPointer, SecondDataPointer);
     ASSERT_EQ(FirstDataPointer, DataPointer);
-
-    if (FirstDataPointer != SecondDataPointer ||
-        FirstDataPointer != DataPointer) {
-      break;
-    }
   }
 }
 
diff --git a/unittests/Syntax/TriviaTests.cpp b/unittests/Syntax/TriviaTests.cpp
index beca54f..3890cdc 100644
--- a/unittests/Syntax/TriviaTests.cpp
+++ b/unittests/Syntax/TriviaTests.cpp
@@ -255,9 +255,9 @@
 }
 
 TEST(TriviaTests, size) {
-  ASSERT_EQ(Trivia().size(), 0);
-  ASSERT_EQ(Trivia::spaces(1).size(), 1);
+  ASSERT_EQ(Trivia().size(), size_t(0));
+  ASSERT_EQ(Trivia::spaces(1).size(), size_t(1));
 
   // Trivia doesn't currently coalesce on its own.
-  ASSERT_EQ((Trivia::spaces(1) + Trivia::spaces(1)).size(), 2);
+  ASSERT_EQ((Trivia::spaces(1) + Trivia::spaces(1)).size(), size_t(2));
 }
diff --git a/unittests/Syntax/UnknownSyntaxTests.cpp b/unittests/Syntax/UnknownSyntaxTests.cpp
new file mode 100644
index 0000000..9173e51
--- /dev/null
+++ b/unittests/Syntax/UnknownSyntaxTests.cpp
@@ -0,0 +1,191 @@
+#include "swift/Syntax/ExprSyntax.h"
+#include "swift/Syntax/GenericSyntax.h"
+#include "swift/Syntax/SyntaxFactory.h"
+#include "swift/Syntax/UnknownSyntax.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using llvm::None;
+using llvm::SmallString;
+
+using namespace swift;
+using namespace swift::syntax;
+
+SymbolicReferenceExprSyntax getCannedSymbolicRef() {
+  // First, make a symbolic reference to an 'Array<Int>'
+  auto Array = SyntaxFactory::makeIdentifier("Array", {}, {});
+  auto IntType = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
+  GenericArgumentClauseBuilder ArgBuilder;
+  ArgBuilder
+    .useLeftAngleBracket(SyntaxFactory::makeLeftAngleToken({}, {}))
+    .useRightAngleBracket(SyntaxFactory::makeRightAngleToken({}, {}))
+    .addGenericArgument(llvm::None, IntType);
+
+  return SyntaxFactory::makeSymbolicReferenceExpr(Array, ArgBuilder.build());
+}
+
+FunctionCallExprSyntax getCannedFunctionCall() {
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto RParen = SyntaxFactory::makeRightParenToken({}, {});
+
+  auto Label = SyntaxFactory::makeIdentifier("elements", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto NoSign = TokenSyntax::missingToken(tok::oper_prefix, "");
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(NoSign, OneDigits);
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+
+  auto Arg = SyntaxFactory::makeFunctionCallArgument(Label, Colon, One,
+                                                     NoComma);
+  auto Args = SyntaxFactory::makeFunctionCallArgumentList({ Arg });
+
+  return SyntaxFactory::makeFunctionCallExpr(getCannedSymbolicRef(), LParen,
+                                             Args, RParen);
+}
+
+TEST(UnknownSyntaxTests, UnknownSyntaxMakeAPIs) {
+  {
+    auto SymbolicRef = getCannedSymbolicRef();
+
+    // Print the known symbolic reference. It should print as "Array<Int>".
+    SmallString<48> KnownScratch;
+    llvm::raw_svector_ostream KnownOS(KnownScratch);
+    SymbolicRef.print(KnownOS);
+    ASSERT_EQ(KnownOS.str().str(), "Array<Int>");
+
+    // Wrap that symbolic reference as an UnknownSyntax. This has the same
+    // RawSyntax layout but with the Unknown Kind.
+    auto UnknownSymbolicRefData = UnknownSyntaxData::make(SymbolicRef.getRaw());
+
+    auto Unknown = UnknownSyntax {
+      UnknownSymbolicRefData,
+      UnknownSymbolicRefData.get()
+    };
+
+    // Print the unknown syntax. It should also print as "Array<Int>".
+    SmallString<48> UnknownScratch;
+    llvm::raw_svector_ostream UnknownOS(UnknownScratch);
+    Unknown.print(UnknownOS);
+
+    ASSERT_EQ(KnownOS.str().str(), UnknownOS.str().str());
+  }
+}
+
+TEST(UnknownSyntaxTests, UnknownSyntaxGetAPIs) {
+  auto Call = getCannedFunctionCall();
+
+  // Function call child 0 -> layout child 0 -> called expression
+  {
+    // Pull the called expression from the function call, which should print
+    // as "Array<Int>"
+    SmallString<48> KnownScratch;
+    llvm::raw_svector_ostream KnownOS(KnownScratch);
+    auto GottenExpr = Call.getCalledExpression();
+    GottenExpr.print(KnownOS);
+
+    // Wrap that call as an UnknownExprSyntax. This has the same
+    // RawSyntax layout but with the UnknownExpr Kind.
+    auto UnknownCallData = UnknownExprSyntaxData::make(Call.getRaw());
+
+    auto Unknown = UnknownExprSyntax {
+      UnknownCallData,
+      UnknownCallData.get()
+    };
+
+    ASSERT_EQ(Unknown.getNumChildren(), size_t(2));
+
+    // Get the second child from the unknown call, which is the argument list.
+    // This should print the same as the known one: "elements: 1"
+    SmallString<48> UnknownScratch;
+    llvm::raw_svector_ostream UnknownOS(UnknownScratch);
+    auto ExprGottenFromUnknown = Unknown.getChild(0)
+      .castTo<SymbolicReferenceExprSyntax>();
+    ExprGottenFromUnknown.print(UnknownOS);
+
+    ASSERT_EQ(KnownOS.str().str(), UnknownOS.str().str());
+
+    auto ExprGottenFromUnknown2 = Unknown.getChild(0);
+    ASSERT_TRUE(ExprGottenFromUnknown
+                .hasSameIdentityAs(ExprGottenFromUnknown2));
+  }
+
+  // Function call child 1 -> layout child 2 -> function call argument list
+  {
+    // Pull the argument list from the function call, which should print
+    // as "elements: 1"
+    SmallString<48> KnownScratch;
+    llvm::raw_svector_ostream KnownOS(KnownScratch);
+    auto GottenArgs = Call.getArgumentList();
+    GottenArgs.print(KnownOS);
+
+    // Wrap that symbolic reference as an UnknownSyntax. This has the same
+    // RawSyntax layout but with the Unknown Kind.
+    auto UnknownCallData = UnknownSyntaxData::make(Call.getRaw());
+
+    auto Unknown = UnknownSyntax {
+      UnknownCallData,
+      UnknownCallData.get()
+    };
+
+    ASSERT_EQ(Unknown.getNumChildren(), size_t(2));
+
+    // Get the second child from the unknown call, which is the argument list.
+    // This should print the same as the known one: "elements: 1"
+    SmallString<48> UnknownScratch;
+    llvm::raw_svector_ostream UnknownOS(UnknownScratch);
+    auto ArgsGottenFromUnknown = Unknown.getChild(1)
+      .castTo<FunctionCallArgumentListSyntax>();
+    ArgsGottenFromUnknown.print(UnknownOS);
+
+    ASSERT_EQ(KnownOS.str().str(), UnknownOS.str().str());
+
+    auto ArgsGottenFromUnknown2 = Unknown.getChild(1);
+    ASSERT_TRUE(ArgsGottenFromUnknown
+                  .hasSameIdentityAs(ArgsGottenFromUnknown2));
+  }
+}
+
+TEST(UnknownSyntaxTests, EmbedUnknownExpr) {
+  auto SymbolicRef = getCannedSymbolicRef();
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto RParen = SyntaxFactory::makeRightParenToken({}, {});
+  auto EmptyArgs = SyntaxFactory::makeBlankFunctionCallArgumentList();
+
+  SmallString<48> KnownScratch;
+  llvm::raw_svector_ostream KnownOS(KnownScratch);
+  auto CallWithKnownExpr = SyntaxFactory::makeFunctionCallExpr(SymbolicRef,
+                                                               LParen,
+                                                               EmptyArgs,
+                                                               RParen);
+  CallWithKnownExpr.print(KnownOS);
+
+  // Let's make a function call expression where the called expression is
+  // actually unknown. It should print the same and have the same structure
+  // as one with a known called expression.
+  auto UnknownSymbolicRefData =
+    UnknownExprSyntaxData::make(SymbolicRef.getRaw());
+
+  auto UnknownSymbolicRef = UnknownExprSyntax {
+    UnknownSymbolicRefData,
+    UnknownSymbolicRefData.get()
+  }.castTo<ExprSyntax>();
+
+  SmallString<48> UnknownScratch;
+  llvm::raw_svector_ostream UnknownOS(UnknownScratch);
+
+  auto CallWithUnknownExpr = CallWithKnownExpr
+    .withCalledExpression(UnknownSymbolicRef);
+
+  CallWithUnknownExpr.print(UnknownOS);
+
+  ASSERT_EQ(KnownOS.str().str(), UnknownOS.str().str());
+}
+
+TEST(UnknownSyntaxTests, EmbedUnknownDecl) {
+  // TODO
+}
+
+TEST(UnknownSyntaxTests, EmbedUnknownStmt) {
+  // TODO
+}
+
diff --git a/utils/build-presets.ini b/utils/build-presets.ini
index 7ee57ad..2d5b62e 100644
--- a/utils/build-presets.ini
+++ b/utils/build-presets.ini
@@ -188,6 +188,21 @@
 skip-test-tvos-host
 skip-test-watchos-host
 
+[preset: buildbot,tools=RA,stdlib=RD,single-thread]
+mixin-preset=
+    mixin_buildbot_tools_RA_stdlib_RD
+
+dash-dash
+
+# Enable non-atomic build of the stdlib
+swift-stdlib-use-nonatomic-rc=true
+
+# Don't run host tests for iOS, tvOS and watchOS platforms to make the build
+# faster.
+skip-test-ios-host
+skip-test-tvos-host
+skip-test-watchos-host
+
 [preset: buildbot,tools=R,stdlib=RD]
 mixin-preset=
     mixin_buildbot_tools_R_stdlib_RD
diff --git a/utils/build-script-impl b/utils/build-script-impl
index 9f832ab..c1e12b2 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -71,6 +71,7 @@
     swift-stdlib-build-type     "Debug"          "the CMake build variant for Swift"
     swift-stdlib-enable-assertions "1"           "enable assertions in Swift"
     swift-stdlib-enable-resilience "0"           "build the Swift stdlib and overlays with resilience enabled"
+    swift-stdlib-use-nonatomic-rc "0"            "build the Swift stdlib and overlays with nonatomic reference count operations enabled"
     swift-stdlib-sil-serialize-all "1"           "build the Swift stdlib and overlays with all method bodies serialized"
     lldb-build-type             "Debug"          "the CMake build variant for LLDB"
     llbuild-build-type          "Debug"          "the CMake build variant for llbuild"
@@ -1654,6 +1655,9 @@
     if [[ $(is_cmake_release_build_type "${SWIFT_BUILD_TYPE}") ]] ; then
         echo -n " -fno-stack-protector"
     fi
+    if [[ "$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}")" == "TRUE" ]]; then
+        echo -n " -DSWIFT_STDLIB_USE_NONATOMIC_RC"
+    fi
 }
 
 function cmake_config_opt() {
@@ -2113,6 +2117,7 @@
                     -DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}"
                     -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}")
                     -DSWIFT_STDLIB_ENABLE_RESILIENCE:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_RESILIENCE}")
+                    -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}")
                     -DSWIFT_STDLIB_SIL_SERIALIZE_ALL:BOOL=$(true_false "${SWIFT_STDLIB_SIL_SERIALIZE_ALL}")
                     -DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}"
                     -DSWIFT_NATIVE_CLANG_TOOLS_PATH:STRING="${native_clang_tools_path}"
diff --git a/utils/rusage.py b/utils/rusage.py
index b2354f2..e37e359 100755
--- a/utils/rusage.py
+++ b/utils/rusage.py
@@ -91,7 +91,7 @@
 args = parser.parse_args()
 if len(args.remainder) == 0:
     parser.print_help()
-    exit(1)
+    sys.exit(1)
 
 if args.enforce:
     if args.time is not None:
diff --git a/utils/sil-mode.el b/utils/sil-mode.el
index 371d66a..6d390d0 100644
--- a/utils/sil-mode.el
+++ b/utils/sil-mode.el
@@ -51,7 +51,7 @@
                     font-lock-keyword-face)
 
    ;; Highlight attributes written in [...].
-   '("\\[\\(.+\\)\\]" 1 font-lock-keyword-face)
+   '("\\[\\(.+?\\)\\]" 1 font-lock-keyword-face)
 
    ;; SIL Instructions - Allocation/Deallocation.
    `(,(regexp-opt '("alloc_stack" "alloc_ref" "alloc_ref_dynamic" "alloc_box"
@@ -121,7 +121,8 @@
    ;; Protocol and Protocol Composition Types
    `(,(regexp-opt '("init_existential_addr" "deinit_existential_addr"
                     "open_existential_addr"
-                    "init_existential_opaque" "open_existential_opaque"
+                    "init_existential_opaque" "deinit_existential_opaque"
+                    "open_existential_opaque"
                     "alloc_existential_box" "project_existential_box"
                     "open_existential_box" "dealloc_existential_box"
                     "init_existential_ref" "open_existential_ref"
diff --git a/utils/swift_build_support/swift_build_support/products/product.py b/utils/swift_build_support/swift_build_support/products/product.py
index f9df4a5..f3f841a 100644
--- a/utils/swift_build_support/swift_build_support/products/product.py
+++ b/utils/swift_build_support/swift_build_support/products/product.py
@@ -26,7 +26,7 @@
 
         The name of the source code directory of this product.
         It provides a customization point for Product subclasses. It is set to
-        the value of product_name() by default for this reason. 
+        the value of product_name() by default for this reason.
         """
         return cls.product_name()
 
diff --git a/utils/vim/syntax/sil.vim b/utils/vim/syntax/sil.vim
index c2bad45..1aea5ad 100644
--- a/utils/vim/syntax/sil.vim
+++ b/utils/vim/syntax/sil.vim
@@ -36,7 +36,7 @@
 syn keyword swiftKeyword metatype value_metatype existential_metatype skipwhite
 syn keyword swiftKeyword retain_value release_value tuple tuple_extract tuple_element_addr struct struct_extract struct_element_addr ref_element_addr skipwhite
 syn keyword swiftKeyword init_enum_data_addr unchecked_enum_data unchecked_take_enum_data_addr inject_enum_addr skipwhite
-syn keyword swiftKeyword init_existential_addr init_existential_opaque init_existential_metatype deinit_existential_addr open_existential_addr open_existential_box open_existential_metatype init_existential_ref open_existential_ref open_existential_opaque skipwhite
+syn keyword swiftKeyword init_existential_addr init_existential_opaque init_existential_metatype deinit_existential_addr deinit_existential_opaque open_existential_addr open_existential_box open_existential_metatype init_existential_ref open_existential_ref open_existential_opaque skipwhite
 syn keyword swiftKeyword upcast address_to_pointer pointer_to_address pointer_to_thin_function unchecked_addr_cast unchecked_ref_cast unchecked_ref_cast_addr ref_to_raw_pointer ref_to_bridge_object ref_to_unmanaged unmanaged_to_ref raw_pointer_to_ref skipwhite
 syn keyword swiftKeyword convert_function thick_to_objc_metatype thin_function_to_pointer objc_to_thick_metatype thin_to_thick_function is_nonnull unchecked_ref_bit_cast unchecked_trivial_bit_cast bridge_object_to_ref bridge_object_to_word unchecked_bitwise_cast skipwhite
 syn keyword swiftKeyword objc_existential_metatype_to_object objc_metatype_to_object objc_protocol skipwhite
diff --git a/validation-test/BuildSystem/LTO/object-files-do-have-bitcode.test-sh b/validation-test/BuildSystem/LTO/object-files-do-have-bitcode.test-sh
index 5d76bf4..67f0c59 100755
--- a/validation-test/BuildSystem/LTO/object-files-do-have-bitcode.test-sh
+++ b/validation-test/BuildSystem/LTO/object-files-do-have-bitcode.test-sh
@@ -13,14 +13,14 @@
 # REQUIRES: OS=macosx
 # RUN: %s %swift_obj_root
 
-if [[ -n "$(find $1/lib -iname '*.cpp.o' -type f -exec file {} \; | grep -v -e bitcode -e bit-code)" ]]; then
+if find $1/lib -iname '*.cpp.o' -type f -exec file {} \; | grep -q -v -e bitcode -e bit-code; then
     echo "Found a ./lib non-bitcode object file!"
     exit 1
 else
     echo "All ./lib object files are bit-code files!"
 fi
 
-if [[ -n "$(find $1/unittests -iname '*.cpp.o' -type f -exec file {} \; | grep -v -e bitcode -e bit-code)" ]]; then
+if find $1/unittests -iname '*.cpp.o' -type f -exec file {} \; | grep -q -v -e bitcode -e bit-code; then
     echo "Found a ./unittests non-bitcode object file!"
     exit 1
 else
diff --git a/validation-test/BuildSystem/LTO/target-libraries-do-not-have-bitcode.test-sh b/validation-test/BuildSystem/LTO/target-libraries-do-not-have-bitcode.test-sh
index 6ce1fd8..5404295 100755
--- a/validation-test/BuildSystem/LTO/target-libraries-do-not-have-bitcode.test-sh
+++ b/validation-test/BuildSystem/LTO/target-libraries-do-not-have-bitcode.test-sh
@@ -34,7 +34,7 @@
     mkdir -p "${LIB_TEMP_DIR}"
     cd "${LIB_TEMP_DIR}"
     ar -x ${ARCHIVE}
-    if [[ -n "$(find ./ -iname '*.o' -exec file {} \; | grep -e bitcode -e bit-code)" ]]; then
+    if find ./ -iname '*.o' -exec file {} \; | grep -q -e bitcode -e bit-code; then
         echo "Found bitcode file in thin archive: ${ARCHIVE}"
         exit 1
     else
@@ -78,7 +78,7 @@
         cd ${arch}
         ar -x "${LIB_ARCHIVE_DIR}/${THIN_ARCHIVE}"
 
-        if [[ -n "$(find ./ -iname '*.o' -exec file {} \; | grep -e bitcode -e bit-code)" ]]; then
+        if find ./ -iname '*.o' -exec file {} \; | grep -q -e bitcode -e bit-code; then
             echo "Found bitcode file in thin archive: ${THIN_ARCHIVE}. Taken from thick archive: ${ARCHIVE}"
             exit 1
         else
diff --git a/validation-test/StdlibUnittest/RaceTest.swift b/validation-test/StdlibUnittest/RaceTest.swift
index a63fd18..53c0e2c 100644
--- a/validation-test/StdlibUnittest/RaceTest.swift
+++ b/validation-test/StdlibUnittest/RaceTest.swift
@@ -1,5 +1,6 @@
 // RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out
 // RUN: %target-run %t.out | %FileCheck %s
+// UNSUPPORTED: nonatomic_rc
 
 import StdlibUnittest
 #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
diff --git a/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift b/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift
new file mode 100644
index 0000000..479b7b8
--- /dev/null
+++ b/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift
@@ -0,0 +1,9 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+{extension{func 丏(UInt=1 + 1 + 1 as?Int){a
diff --git a/validation-test/compiler_crashers/28703-swift-typebase-getdesugaredtype.swift b/validation-test/compiler_crashers/28703-swift-typebase-getdesugaredtype.swift
new file mode 100644
index 0000000..e4d7ab4
--- /dev/null
+++ b/validation-test/compiler_crashers/28703-swift-typebase-getdesugaredtype.swift
@@ -0,0 +1,9 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+func b(UInt=1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 as?Int){a
diff --git a/validation-test/compiler_crashers/28704-swift-newmangling-astmangler-appendcontext-swift-declcontext-const.swift b/validation-test/compiler_crashers/28704-swift-newmangling-astmangler-appendcontext-swift-declcontext-const.swift
new file mode 100644
index 0000000..56a136a
--- /dev/null
+++ b/validation-test/compiler_crashers/28704-swift-newmangling-astmangler-appendcontext-swift-declcontext-const.swift
@@ -0,0 +1,9 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol A{var f={struct ManagedBuffer{var f=(t:f
diff --git a/validation-test/compiler_crashers/28705-swift-typebase-getcanonicaltype.swift b/validation-test/compiler_crashers/28705-swift-typebase-getcanonicaltype.swift
new file mode 100644
index 0000000..2483570
--- /dev/null
+++ b/validation-test/compiler_crashers/28705-swift-typebase-getcanonicaltype.swift
@@ -0,0 +1,13 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+{
+struct c{}func t(UInt= 1 + 1 + 1 + 1 as?Int){
+{{
+protocol P{extension{class C:P{
+protocol defaulImplementation unon
diff --git a/validation-test/compiler_crashers_2/0074-rdar28544316.swift b/validation-test/compiler_crashers_2/0074-rdar28544316.swift
new file mode 100644
index 0000000..f967f8d
--- /dev/null
+++ b/validation-test/compiler_crashers_2/0074-rdar28544316.swift
@@ -0,0 +1,38 @@
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+// REQUIRES: asserts
+
+class PropertyDataSource<O: PropertyHosting> {
+}
+
+protocol TableViewCellFactoryType {
+    associatedtype Item
+}
+
+public protocol PropertyHosting {
+    associatedtype PType: Hashable, EntityOwned
+}
+
+public protocol EntityOwned: class {
+    associatedtype Owner
+}
+
+public protocol PropertyType: class {
+}
+
+func useType<T>(cellType: T.Type) {
+}
+
+final class PropertyTableViewAdapter<Factory: TableViewCellFactoryType>
+    where
+    Factory.Item: PropertyType,
+    Factory.Item.Owner: PropertyHosting,
+    Factory.Item.Owner.PType == Factory.Item
+{
+    typealias Item = Factory.Item
+    
+    let dataManager: PropertyDataSource<Factory.Item.Owner>
+    init(dataManager: PropertyDataSource<Factory.Item.Owner>) {
+      useType(cellType: Factory.Item.Owner.self)
+      self.dataManager = dataManager
+    }
+}
diff --git a/validation-test/compiler_crashers_2/0076-sr3500.swift b/validation-test/compiler_crashers_2/0076-sr3500.swift
new file mode 100644
index 0000000..2a514fe
--- /dev/null
+++ b/validation-test/compiler_crashers_2/0076-sr3500.swift
@@ -0,0 +1,12 @@
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+
+protocol A {
+  associatedtype Coordinate: Strideable
+  func doSomething(_: Range<Coordinate>) -> Coordinate.Stride
+}
+
+extension A where Coordinate == Int {
+  func extensionFunc(_ range: Range<Coordinate>) {
+    _ = doSomething(range)
+  }
+}
diff --git a/validation-test/compiler_crashers_2/0079-rdar30354669.swift b/validation-test/compiler_crashers_2/0079-rdar30354669.swift
new file mode 100644
index 0000000..6dacf98
--- /dev/null
+++ b/validation-test/compiler_crashers_2/0079-rdar30354669.swift
@@ -0,0 +1,30 @@
+// RUN: not --crash %target-swift-frontend -primary-file %s -emit-ir
+
+public func ==<T: EquatableMetaType>(lhs: T, rhs: T) -> Bool {
+    return type(of: lhs) == type(of: lhs)
+}
+
+
+public protocol EquatableMetaType {
+}
+
+
+class Block : Equatable, EquatableMetaType {
+}
+
+extension Array where Element : Block {
+    func indexByType(of: Element) -> Array.Index? {
+        let count = self.count
+        var result: Array.Index = 0
+        
+        for i in self {
+            if i == of {
+                return result
+            }
+            if result < count {
+                result += 1
+            }
+        }
+        return nil
+    }
+}
diff --git a/validation-test/compiler_crashers_2_fixed/0077-sr3884.swift b/validation-test/compiler_crashers_2_fixed/0077-sr3884.swift
new file mode 100644
index 0000000..d50643c
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0077-sr3884.swift
@@ -0,0 +1,22 @@
+// RUN: %target-swift-frontend %s -emit-ir
+
+protocol DataSourceItem { }
+
+protocol TableDataSourceItem : DataSourceItem { }
+
+
+class DataSource<T : DataSourceItem> { }
+
+class TableDataSource<T : TableDataSourceItem>: DataSource<T> { }
+
+
+class DataSourceBuilder<T : TableDataSourceItem, U : TableDataSource<T>> { }
+
+class TableDataSourceBuilder<T : TableDataSourceItem, U : TableDataSource<T>> : DataSourceBuilder<T, U> { }
+
+
+enum MyItem: TableDataSourceItem { }
+
+class MyBuilder : TableDataSourceBuilder<MyItem, TableDataSource<MyItem>> { }
+
+let builder = MyBuilder()
diff --git a/validation-test/compiler_crashers_2_fixed/0078-sr4059.swift b/validation-test/compiler_crashers_2_fixed/0078-sr4059.swift
new file mode 100644
index 0000000..a073b13
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0078-sr4059.swift
@@ -0,0 +1,9 @@
+// RUN: %target-swift-frontend %s -emit-ir
+
+class Base {
+  init<S: Sequence>(_ s: S) where S.Iterator.Element == UInt8 { }
+}
+
+class Sub: Base {
+  init(_ b: [UInt8]) { super.init(b) }
+}
\ No newline at end of file
diff --git a/validation-test/compiler_crashers_fixed/28445-gp-getouterparameters-proto-getdeclcontext-getgenericparamsofcontext-failed.swift b/validation-test/compiler_crashers_fixed/28445-gp-getouterparameters-proto-getdeclcontext-getgenericparamsofcontext-failed.swift
index 240c285..18fddac 100644
--- a/validation-test/compiler_crashers_fixed/28445-gp-getouterparameters-proto-getdeclcontext-getgenericparamsofcontext-failed.swift
+++ b/validation-test/compiler_crashers_fixed/28445-gp-getouterparameters-proto-getdeclcontext-getgenericparamsofcontext-failed.swift
@@ -6,6 +6,9 @@
 // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
 // RUN: not %target-swift-frontend %s -emit-ir
+// FIXME(huonw): where clauses on associatedtypes broke this
+// XFAIL: *
+// REQUIRES: asserts
 class A{let f= <c
 protocol A{
 typealias e:A{}
diff --git a/validation-test/compiler_crashers_fixed/28547-env-dependent-type-in-non-generic-context.swift b/validation-test/compiler_crashers_fixed/28547-env-dependent-type-in-non-generic-context.swift
index 5d170bb..d8533f9 100644
--- a/validation-test/compiler_crashers_fixed/28547-env-dependent-type-in-non-generic-context.swift
+++ b/validation-test/compiler_crashers_fixed/28547-env-dependent-type-in-non-generic-context.swift
@@ -6,5 +6,8 @@
 // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
 // RUN: not %target-swift-frontend %s -emit-ir
+// FIXME(huonw): where clauses on associatedtypes broke this
+// XFAIL: *
+// REQUIRES: asserts
 class A:a
 protocol a{typealias B:A.B
diff --git a/validation-test/lit.site.cfg.in b/validation-test/lit.site.cfg.in
index 7c6b75f..9c4fce1 100644
--- a/validation-test/lit.site.cfg.in
+++ b/validation-test/lit.site.cfg.in
@@ -68,6 +68,9 @@
 if "@SWIFT_STDLIB_ENABLE_RESILIENCE@" == "TRUE":
     config.available_features.add("resilient_stdlib")
 
+if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE":
+    config.available_features.add("nonatomic_rc")
+
 if "@CMAKE_GENERATOR@" == "Xcode":
     xcode_bin_dir = os.path.join(config.llvm_obj_root, "@LLVM_BUILD_TYPE@",
                                  'bin')
diff --git a/validation-test/stdlib/ArrayBridging.swift b/validation-test/stdlib/ArrayBridging.swift
index 626fe4c..a6bea01 100644
--- a/validation-test/stdlib/ArrayBridging.swift
+++ b/validation-test/stdlib/ArrayBridging.swift
@@ -9,6 +9,7 @@
 
 // REQUIRES: objc_interop
 // REQUIRES: executable_test
+// UNSUPPORTED: nonatomic_rc
 
 import StdlibUnittest
 import Foundation
diff --git a/validation-test/stdlib/AtomicInt.swift b/validation-test/stdlib/AtomicInt.swift
index 52701c0..b076bce 100644
--- a/validation-test/stdlib/AtomicInt.swift
+++ b/validation-test/stdlib/AtomicInt.swift
@@ -4,6 +4,7 @@
 // RUN: %target-build-swift -module-name a %s -o %t.out -O
 // RUN: %target-run %t.out
 // REQUIRES: executable_test
+// UNSUPPORTED: nonatomic_rc
 
 import SwiftPrivate
 import StdlibUnittest
diff --git a/validation-test/stdlib/DictionaryBridging.swift b/validation-test/stdlib/DictionaryBridging.swift
index 5ca3e25..2dc33e4 100644
--- a/validation-test/stdlib/DictionaryBridging.swift
+++ b/validation-test/stdlib/DictionaryBridging.swift
@@ -8,6 +8,7 @@
 // REQUIRES: executable_test
 
 // REQUIRES: objc_interop
+// UNSUPPORTED: nonatomic_rc
 
 import StdlibUnittest
 import Foundation
diff --git a/validation-test/stdlib/ErrorProtocol.swift b/validation-test/stdlib/ErrorProtocol.swift
index 5c2b557..a62bdf1 100644
--- a/validation-test/stdlib/ErrorProtocol.swift
+++ b/validation-test/stdlib/ErrorProtocol.swift
@@ -1,6 +1,7 @@
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
 // REQUIRES: objc_interop
+// UNSUPPORTED: nonatomic_rc
 
 import SwiftPrivate
 import StdlibUnittest