Merge pull request #7870 from stephentyrone/FloatingPoint-Hashable

FloatingPoint should imply Hashable. 

 `Hashable` is related to `Equatable`, and `FloatingPoint` is `Equatable`, with enough additional constraints that `Hashable` conformance is practical.  

There's *almost* no excuse for any `Equatable` thing not to also be `Hashable`; the exception is when the underlying representation may be denormalized in some way that makes it impossible or expensive to normalize (e.g. `Set`).  Floating point numbers have denormalized forms, so this comes down to the cost of normalization.  Since we can't imagine a representation whose normalization is much more expensive than the subsequent hashing step, the conformance belongs.
diff --git a/docs/SIL.rst b/docs/SIL.rst
index 6e45602..3b8ad25 100644
--- a/docs/SIL.rst
+++ b/docs/SIL.rst
@@ -84,7 +84,7 @@
   If an arithmetic overflow occurs during the constant expression computation, a diagnostic
   is issued.
 - **Return analysis** verifies that each function returns a value on every
-  code path and doesn't "fall of the end" of its definition, which is an error.
+  code path and doesn't "fall off the end" of its definition, which is an error.
   It also issues an error when a ``noreturn`` function returns.
 - **Critical edge splitting** splits all critical edges from terminators that
   don't support arbitrary basic block arguments (all non cond_branch
diff --git a/include/swift/AST/AvailabilitySpec.h b/include/swift/AST/AvailabilitySpec.h
index 787f819..d5ebba9 100644
--- a/include/swift/AST/AvailabilitySpec.h
+++ b/include/swift/AST/AvailabilitySpec.h
@@ -31,7 +31,7 @@
     /// A platform-version constraint of the form "PlatformName X.Y.Z"
     PlatformVersionConstraint,
 
-    /// A wildcard constraint, spelled '*', that is be equivalent
+    /// A wildcard constraint, spelled '*', that is equivalent
     /// to CurrentPlatformName >= MinimumDeploymentTargetVersion
     OtherPlatform,
 
diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def
index a000471..678d17f 100644
--- a/include/swift/AST/DiagnosticsCommon.def
+++ b/include/swift/AST/DiagnosticsCommon.def
@@ -58,8 +58,6 @@
 // Generic disambiguation
 NOTE(while_parsing_as_left_angle_bracket,none,
      "while parsing this '<' as a type parameter bracket", ())
-NOTE(while_parsing_as_less_operator,none,
-     "while parsing this '<' as an operator", ())
 
 
 // FIXME: This is used both as a parse error (a literal "super" outside a
diff --git a/include/swift/AST/DiagnosticsDriver.def b/include/swift/AST/DiagnosticsDriver.def
index 65d061a..eed9c38 100644
--- a/include/swift/AST/DiagnosticsDriver.def
+++ b/include/swift/AST/DiagnosticsDriver.def
@@ -113,6 +113,10 @@
         "unable to determine when '%0' was last modified: %1",
         (StringRef, StringRef))
 
+WARNING(warn_unable_to_load_dependencies, none,
+        "unable to load dependencies file \"%0\", disabling incremental mode",
+        (StringRef))
+
 ERROR(error_input_changed_during_build,none,
       "input file '%0' was modified during the build",
       (StringRef))
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index c5e2979..0cc1062 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -448,6 +448,10 @@
       "expected constant in SIL code", ())
 ERROR(referenced_value_no_accessor,none,
       "referenced declaration has no %select{getter|setter}0", (unsigned))
+ERROR(expected_sil_value_ownership_kind,none,
+      "expected value ownership kind in SIL code", ())
+ERROR(expected_sil_colon,none,
+      "expected ':' before %0", (StringRef))
 
 // SIL Values
 ERROR(sil_value_redefinition,none,
@@ -591,6 +595,8 @@
       "sil protocol not found %0", (Identifier))
 ERROR(sil_witness_assoc_not_found,none,
       "sil associated type decl not found %0", (Identifier))
+ERROR(sil_witness_assoc_conf_not_found,none,
+      "sil associated type path for conformance not found %0", (StringRef))
 ERROR(sil_witness_protocol_conformance_not_found,none,
       "sil protocol conformance not found", ())
 
@@ -749,8 +755,6 @@
       "default arguments are not allowed in subscripts", ())
 ERROR(no_default_arg_curried,none,
       "default arguments are not allowed in curried parameter lists", ())
-WARNING(let_on_param_is_redundant, none,
-      "'let' keyword is unnecessary; function parameters are immutable by default", (unsigned))
 ERROR(var_pattern_in_var,none,
       "'%select{var|let}0' cannot appear nested inside another 'var' or "
       "'let' pattern", (unsigned))
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 42e442f..221461d 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -45,11 +45,6 @@
 NOTE(extended_type_declared_here,none,
      "extended type declared here", ())
 
-NOTE(while_converting_default_tuple_value,none,
-     "while converting default tuple value to element type %0", (Type))
-NOTE(while_converting_subscript_index,none,
-     "while converting subscript index to expected type %0", (Type))
-
 //------------------------------------------------------------------------------
 // Constraint solver diagnostics
 //------------------------------------------------------------------------------
@@ -915,8 +910,6 @@
       "%select{local function|closure}0 that captures "
       "%select{context|generic parameters|dynamic Self type}1",
       (bool, unsigned))
-NOTE(c_function_pointer_captures_here,none,
-     "%0 captured here", (Identifier))
 
 //------------------------------------------------------------------------------
 // Type Check Declarations
@@ -1508,8 +1501,6 @@
 
 ERROR(redundant_conformance,none,
       "redundant conformance of %0 to protocol %1", (Type, DeclName))
-NOTE(protocol_conformance_implied_here,none,
-     "implied protocol conformance %0 here can be made explicit", (Identifier))
 
 // "Near matches"
 WARNING(optional_req_near_match,none,
@@ -1517,9 +1508,6 @@
         (DescriptiveDeclKind, DeclName, DeclName, DeclName))
 NOTE(optional_req_nonobjc_near_match_add_objc,none,
      "add '@objc' to provide an Objective-C entrypoint", ())
-NOTE(optional_req_nonobjc_to_objc,none,
-     "rename to %0 to satisfy this requirement",
-     (DeclName))
 NOTE(optional_req_near_match_move,none,
      "move %0 to %select{an|another}1 extension to silence this warning",
      (DeclName, unsigned))
@@ -1775,8 +1763,6 @@
       "static declarations are already final", ())
 ERROR(open_decl_cannot_be_final,none,
       "%0 cannot be declared both 'final' and 'open'", (DescriptiveDeclKind))
-NOTE(decl_init_here,none,
-     "initial value is here", ())
 
 
 // Inheritance
@@ -2069,9 +2055,6 @@
 #define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'}"
 #define SELECT_APPLICATION_DELEGATE "select{'UIApplicationDelegate'|'NSApplicationDelegate'}"
 
-ERROR(attr_ApplicationMain_not_class,none,
-      "%" SELECT_APPLICATION_MAIN "0 attribute may only be used on classes",
-      (unsigned))
 ERROR(attr_ApplicationMain_not_ApplicationDelegate,none,
       "%" SELECT_APPLICATION_MAIN "0 class must conform to the %" SELECT_APPLICATION_DELEGATE "0 protocol",
       (unsigned))
@@ -2125,17 +2108,7 @@
      "found this candidate", ())
 NOTE(found_candidate_type,none,
      "found candidate with type %0", (Type))
-NOTE(first_declaration,none,
-     "first declaration", ())
-NOTE(second_declaration,none,
-     "second declaration", ())
 
-ERROR(no_IntegerLiteralType_found,none,
-      "standard library error: IntegerLiteralType not defined", ())
-ERROR(no_FloatLiteralType_found,none,
-      "standard library error: FloatLiteralType not defined", ())
-ERROR(no_StringLiteralType_found,none,
-      "standard library error: StringLiteralType not defined", ())
 ERROR(no_MaxBuiltinIntegerType_found,none,
    "standard library error: _MaxBuiltinIntegerType is not properly defined", ())
 ERROR(no_MaxBuiltinFloatType_found,none,
@@ -2241,9 +2214,6 @@
       "'" TRY_KIND_SELECT(0) "' following assignment operator does not cover "
       "everything to its right", (unsigned))
 
-NOTE(subscript_decl_here,none,
-     "subscript operator declared here", ())
-
 ERROR(broken_bool,none, "type 'Bool' is broken", ())
 
 WARNING(inject_forced_downcast,none,
@@ -3465,10 +3435,6 @@
         "%select{variable|parameter}1 %0 was written to, but never read",
         (Identifier, unsigned))
 
-WARNING(extraneous_default_args_in_call, none,
-        "call to %0 has extraneous arguments that could use defaults",
-        (DeclName))
-
 //------------------------------------------------------------------------------
 // Circular reference diagnostics
 //------------------------------------------------------------------------------
diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h
index 0db7f0f..cba8da9 100644
--- a/include/swift/AST/GenericEnvironment.h
+++ b/include/swift/AST/GenericEnvironment.h
@@ -242,6 +242,8 @@
 
   SubstitutionList getForwardingSubstitutions() const;
 
+  void dump(raw_ostream &os) const;
+
   void dump() const;
 };
   
diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h
index a859f92..54f572c 100644
--- a/include/swift/AST/GenericSignature.h
+++ b/include/swift/AST/GenericSignature.h
@@ -123,13 +123,6 @@
     return const_cast<GenericSignature *>(this)->getRequirementsBuffer();
   }
 
-  /// Check if the generic signature makes all generic parameters
-  /// concrete.
-  bool areAllParamsConcrete() const {
-    auto iter = getAllDependentTypes();
-    return iter.begin() == iter.end();
-  }
-
   /// Only allow allocation by doing a placement new.
   void *operator new(size_t Bytes, void *Mem) {
     assert(Mem);
@@ -174,11 +167,6 @@
   void getSubstitutions(const SubstitutionMap &subMap,
                         SmallVectorImpl<Substitution> &result) const;
 
-  /// Return a range that iterates through all of the types that require
-  /// substitution, which includes the generic parameter types as well as
-  /// other dependent types that require additional conformances.
-  SmallVector<Type, 4> getAllDependentTypes() const;
-
   /// Enumerate all of the dependent types in the type signature that will
   /// occur in substitution lists (in order), along with the set of
   /// conformance requirements placed on that dependent type.
@@ -191,6 +179,33 @@
   bool enumeratePairedRequirements(
          llvm::function_ref<bool(Type, ArrayRef<Requirement>)> fn) const;
 
+  /// Return a vector of all generic parameters that are not subject to
+  /// a concrete same-type constraint.
+  SmallVector<GenericTypeParamType *, 2> getSubstitutableParams() const;
+
+  /// Check if the generic signature makes all generic parameters
+  /// concrete.
+  bool areAllParamsConcrete() const {
+    return !enumeratePairedRequirements(
+      [](Type, ArrayRef<Requirement>) -> bool {
+        return true;
+      });
+  }
+
+  /// Return the size of a SubstitutionList built from this signature.
+  ///
+  /// Don't add new calls of this -- the representation of SubstitutionList
+  /// will be changing soon.
+  unsigned getSubstitutionListSize() const {
+    unsigned result = 0;
+    enumeratePairedRequirements(
+      [&](Type, ArrayRef<Requirement>) -> bool {
+        result++;
+        return false;
+      });
+    return result;
+  }
+
   /// Determines whether this GenericSignature is canonical.
   bool isCanonical() const;
   
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index ed575c4..9b2fe86 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -32,6 +32,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TrailingObjects.h"
 #include <functional>
 #include <memory>
@@ -590,6 +591,8 @@
     case Concrete:
       return 0;
     }
+
+    llvm_unreachable("Unhandled RequirementSourceKind in switch.");
   }
 
   /// Determines whether we have been provided with an acceptable storage kind
@@ -618,6 +621,8 @@
     case Concrete:
       return false;
     }
+
+    llvm_unreachable("Unhandled RequirementSourceKind in switch.");
   }
 
 public:
diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h
index 3d9f492..0dfdf5f 100644
--- a/include/swift/AST/ProtocolConformance.h
+++ b/include/swift/AST/ProtocolConformance.h
@@ -339,6 +339,10 @@
   /// the requirements of those protocols.
   InheritedConformanceMap InheritedMapping;
 
+  /// Conformances that satisfy each of conformance requirements of the
+  /// requirement signature of the protocol.
+  ArrayRef<ProtocolConformanceRef> SignatureConformances;
+
   LazyMemberLoader *Resolver = nullptr;
   uint64_t ResolverContextData;
 
@@ -440,6 +444,18 @@
                       const Substitution &substitution,
                       TypeDecl *typeDecl) const;
 
+  /// Given a dependent type expressed in terms of the self parameter,
+  /// map it into the context of this conformance.
+  Type getAssociatedType(Type assocType,
+                         LazyResolver *resolver = nullptr) const;
+
+  /// Given that the requirement signature of the protocol directly states
+  /// that the given dependent type must conform to the given protocol,
+  /// return its associated conformance.
+  ProtocolConformanceRef
+  getAssociatedConformance(Type assocType, ProtocolDecl *protocol,
+                           LazyResolver *resolver = nullptr) const;
+
   /// Retrieve the value witness corresponding to the given requirement.
   ///
   /// Note that a generic witness will only be specialized if the conformance
@@ -481,6 +497,17 @@
     InheritedMapping[proto] = conformance;
   }
 
+  /// Retrieve the protocol conformances that satisfy the requirements of the
+  /// protocol, which line up with the conformance constraints in the
+  /// protocol's requirement signature.
+  ArrayRef<ProtocolConformanceRef> getSignatureConformances() const {
+    return SignatureConformances;
+  }
+
+  /// Copy the given protocol conformances for the requirement signature into
+  /// the normal conformance.
+  void setSignatureConformances(ArrayRef<ProtocolConformanceRef> conformances);
+
   /// Determine whether the witness for the given type requirement
   /// is the default definition.
   bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
diff --git a/include/swift/AST/ProtocolConformanceRef.h b/include/swift/AST/ProtocolConformanceRef.h
index 7972750..1368cff 100644
--- a/include/swift/AST/ProtocolConformanceRef.h
+++ b/include/swift/AST/ProtocolConformanceRef.h
@@ -20,7 +20,6 @@
 #include "llvm/ADT/PointerUnion.h"
 #include "swift/AST/TypeAlignments.h"
 #include "swift/AST/Type.h"
-#include "swift/AST/ProtocolConformance.h"
 
 namespace llvm {
   class raw_ostream;
@@ -28,6 +27,8 @@
 
 namespace swift {
 
+class ProtocolConformance;
+
 /// A ProtocolConformanceRef is a handle to a protocol conformance which
 /// may be either concrete or abstract.
 ///
diff --git a/include/swift/AST/Requirement.h b/include/swift/AST/Requirement.h
index b4dfde3..650c0ef 100644
--- a/include/swift/AST/Requirement.h
+++ b/include/swift/AST/Requirement.h
@@ -19,6 +19,7 @@
 
 #include "swift/AST/Type.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/ErrorHandling.h"
 
 namespace swift {
 
@@ -109,6 +110,8 @@
     case RequirementKind::Layout:
       return Requirement(getKind(), newFirst, getLayoutConstraint());
     }
+
+    llvm_unreachable("Unhandled RequirementKind in switch.");
   }
 
   /// \brief Retrieve the layout constraint.
diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h
index 8209350..6ecc02c 100644
--- a/include/swift/AST/SubstitutionMap.h
+++ b/include/swift/AST/SubstitutionMap.h
@@ -83,12 +83,6 @@
   /// Retrieve the conformances for the given type.
   ArrayRef<ProtocolConformanceRef> getConformances(CanType type) const;
 
-  /// Look up the replacement for the given type parameter or interface type.
-  /// Note that this only finds replacements for maps that are directly
-  /// stored inside the map. In most cases, you should call Type::subst()
-  /// instead, since that will resolve member types also.
-  Type lookupSubstitution(CanSubstitutableType type) const;
-
   bool empty() const {
     return subMap.empty();
   }
@@ -149,6 +143,13 @@
 private:
   friend class GenericSignature;
   friend class GenericEnvironment;
+  friend struct QuerySubstitutionMap;
+
+  /// Look up the replacement for the given type parameter or interface type.
+  /// Note that this only finds replacements for maps that are directly
+  /// stored inside the map. In most cases, you should call Type::subst()
+  /// instead, since that will resolve member types also.
+  Type lookupSubstitution(CanSubstitutableType type) const;
 
   // You should not need to call these directly to build SubstitutionMaps;
   // instead, use GenericSignature::getSubstitutionMap() or
diff --git a/include/swift/Basic/Defer.h b/include/swift/Basic/Defer.h
index 23ba2ea..8b20dce 100644
--- a/include/swift/Basic/Defer.h
+++ b/include/swift/Basic/Defer.h
@@ -23,10 +23,10 @@
 namespace swift {
   template <typename F>
   class DoAtScopeExit {
-    F &Fn;
+    F Fn;
     void operator=(DoAtScopeExit&) = delete;
   public:
-    DoAtScopeExit(F &Fn) : Fn(Fn){}
+    DoAtScopeExit(F &&Fn) : Fn(std::move(Fn)) {}
     ~DoAtScopeExit() {
       Fn();
     }
@@ -36,7 +36,7 @@
     struct DeferTask {};
     template<typename F>
     DoAtScopeExit<typename std::decay<F>::type> operator+(DeferTask, F&& fn) {
-      return DoAtScopeExit<typename std::decay<F>::type>(fn);
+      return DoAtScopeExit<typename std::decay<F>::type>(std::move(fn));
     }
   }
 } // end namespace swift
diff --git a/include/swift/Basic/Demangle.h b/include/swift/Basic/Demangle.h
index 3635a8b..60bd414 100644
--- a/include/swift/Basic/Demangle.h
+++ b/include/swift/Basic/Demangle.h
@@ -207,6 +207,9 @@
 
   // Only to be used by the demangler parsers.
   void addChild(NodePointer Child, NodeFactory &Factory);
+
+  // Reverses the order of children.
+  void reverseChildren(size_t StartingAt = 0);
 };
 
 /// Returns true if the mangledName starts with the swift mangling prefix.
@@ -289,6 +292,20 @@
   /// or ObjC-as-swift thunks.
   bool isThunkSymbol(llvm::StringRef MangledName);
 
+  /// Returns the mangled name of the target of a thunk.
+  ///
+  /// \returns Returns the remaining name after removing the thunk mangling
+  /// characters from \p MangledName. If \p MangledName is not a thunk symbol,
+  /// an empty string is returned.
+  std::string getThunkTarget(llvm::StringRef MangledName);
+
+  /// Returns true if the \p mangledName refers to a function which conforms to
+  /// the Swift calling convention.
+  ///
+  /// The return value is unspecified if the \p MangledName does not refer to a
+  /// function symbol.
+  bool hasSwiftCallingConvention(llvm::StringRef MangledName);
+
   /// Deallocates all nodes.
   ///
   /// The memory which is used for nodes is not freed but recycled for the next
diff --git a/include/swift/Basic/Demangler.h b/include/swift/Basic/Demangler.h
index a1ca433..d30736b 100644
--- a/include/swift/Basic/Demangler.h
+++ b/include/swift/Basic/Demangler.h
@@ -35,6 +35,8 @@
 namespace swift {
 namespace Demangle {
 
+class CharVector;
+  
 /// The allocator for demangling nodes and other demangling-internal stuff.
 ///
 /// It implements a simple bump-pointer allocator.
@@ -77,15 +79,15 @@
 #endif
   }
   
-  ~NodeFactory() {
+  virtual ~NodeFactory() {
     freeSlabs(CurrentSlab);
 #ifdef NODE_FACTORY_DEBUGGING
     std::cerr << "Delete NodeFactory " << this << "\n";
 #endif
   }
   
-  void clear();
-
+  virtual void clear();
+  
   /// Allocates an object of type T or an array of objects of type T.
   template<typename T> T *Allocate(size_t NumObjects = 1) {
     size_t ObjectSize = NumObjects * sizeof(T);
@@ -173,6 +175,12 @@
   /// The \p Text string is copied.
   NodePointer createNode(Node::Kind K, llvm::StringRef Text);
 
+  /// Creates a node of kind \p K with a \p Text payload.
+  ///
+  /// The \p Text string is already allocted with the Factory and therefore
+  /// it is _not_ copied.
+  NodePointer createNode(Node::Kind K, const CharVector &Text);
+  
   /// Creates a node of kind \p K with a \p Text payload, which must be a C
   /// string literal.
   ///
@@ -180,6 +188,92 @@
   NodePointer createNode(Node::Kind K, const char *Text);
 };
 
+/// A vector with a storage managed by a NodeFactory.
+///
+/// This Vector class only provides the minimal functionality needed by the
+/// Demangler.
+template<typename T> class Vector {
+
+protected:
+  T *Elems = nullptr;
+  size_t NumElems = 0;
+  size_t Capacity = 0;
+
+public:
+  
+  typedef T *iterator;
+
+  Vector() { }
+
+  /// Construct a vector with an inital capacity.
+  explicit Vector(NodeFactory &Factory, size_t InitialCapacity) {
+    init(Factory, InitialCapacity);
+  }
+
+  /// Clears the content and re-allocates the buffer with an initial capacity.
+  void init(NodeFactory &Factory, size_t InitialCapacity) {
+    Elems = Factory.Allocate<T>(InitialCapacity);
+    NumElems = 0;
+    Capacity = InitialCapacity;
+  }
+  
+  void free() {
+    Capacity = 0;
+    Elems = 0;
+  }
+  
+  iterator begin() { return Elems; }
+  iterator end() { return Elems + NumElems; }
+  
+  T &operator[](size_t Idx) {
+    assert(Idx < NumElems);
+    return Elems[Idx];
+  }
+
+  const T &operator[](size_t Idx) const {
+    assert(Idx < NumElems);
+    return Elems[Idx];
+  }
+  
+  size_t size() const { return NumElems; }
+
+  bool empty() const { return NumElems == 0; }
+
+  T &back() { return (*this)[NumElems - 1]; }
+
+  void push_back(const T &NewElem, NodeFactory &Factory) {
+    if (NumElems >= Capacity)
+      Factory.Reallocate(Elems, Capacity, /*Growth*/ 1);
+    assert(NumElems < Capacity);
+    Elems[NumElems++] = NewElem;
+  }
+
+  T pop_back_val() {
+    if (empty())
+      return T();
+    T Val = (*this)[NumElems - 1];
+    NumElems--;
+    return Val;
+  }
+};
+
+/// A vector of chars (a string) with a storage managed by a NodeFactory.
+///
+/// This CharVector class only provides the minimal functionality needed by the
+/// Demangler.
+class CharVector : public Vector<char> {
+public:
+  // Append another string.
+  void append(StringRef Rhs, NodeFactory &Factory);
+
+  // Append an integer as readable number.
+  void append(int Number, NodeFactory &Factory);
+
+  StringRef str() const {
+    return StringRef(Elems, NumElems);
+  }
+};
+
 /// The demangler.
 ///
 /// It de-mangles a string and it also ownes the returned node-tree. This means
@@ -194,22 +288,14 @@
     size_t Pos;
   };
 
-  std::vector<NodeWithPos> NodeStack;
-  std::vector<NodePointer> Substitutions;
-  std::vector<unsigned> PendingSubstitutions;
+  Vector<NodeWithPos> NodeStack;
+  Vector<NodePointer> Substitutions;
+  Vector<unsigned> PendingSubstitutions;
 
   static const int MaxNumWords = 26;
   StringRef Words[MaxNumWords];
   int NumWords = 0;
 
-  static NodePointer pop_back_val(std::vector<NodePointer> &NodeVector) {
-    if (NodeVector.empty())
-      return nullptr;
-    NodePointer Val = NodeVector.back();
-    NodeVector.pop_back();
-    return Val;
-  }
-
   bool nextIf(StringRef str) {
     if (!Text.substr(Pos).startswith(str)) return false;
     Pos += str.size();
@@ -241,16 +327,11 @@
   }
 
   void pushNode(NodePointer Nd) {
-    NodeStack.push_back({ Nd, Pos });
+    NodeStack.push_back({ Nd, Pos }, *this);
   }
 
   NodePointer popNode() {
-    if (!NodeStack.empty()) {
-      NodePointer Val = NodeStack.back().Node;
-      NodeStack.pop_back();
-      return Val;
-    }
-    return nullptr;
+    return NodeStack.pop_back_val().Node;
   }
 
   NodePointer popNode(Node::Kind kind) {
@@ -279,7 +360,7 @@
   
   void addSubstitution(NodePointer Nd) {
     if (Nd)
-      Substitutions.push_back(Nd);
+      Substitutions.push_back(Nd, *this);
   }
 
   NodePointer addChild(NodePointer Parent, NodePointer Child);
@@ -326,7 +407,7 @@
   NodePointer popProtocol();
   NodePointer demangleBoundGenericType();
   NodePointer demangleBoundGenericArgs(NodePointer nominalType,
-                                    const std::vector<NodePointer> &TypeLists,
+                                    const Vector<NodePointer> &TypeLists,
                                     size_t TypeListIdx);
   NodePointer demangleInitializer();
   NodePointer demangleImplParamConvention();
@@ -367,6 +448,8 @@
 
 public:
   Demangler() {}
+  
+  void clear() override;
 
   /// Demangle the given symbol and return the parse tree.
   ///
diff --git a/include/swift/Basic/Version.h b/include/swift/Basic/Version.h
index 20d6ce5..9c36999 100644
--- a/include/swift/Basic/Version.h
+++ b/include/swift/Basic/Version.h
@@ -52,13 +52,16 @@
 /// a: [0 - 999]
 /// b: [0 - 999]
 class Version {
-  SmallVector<uint64_t, 5> Components;
+  SmallVector<unsigned, 5> Components;
 public:
   /// Create the empty compiler version - this always compares greater
   /// or equal to any other CompilerVersion, as in the case of building Swift
   /// from latest sources outside of a build/integration/release context.
   Version() = default;
 
+  /// Create a literal version from a list of components.
+  Version(std::initializer_list<unsigned> Values) : Components(Values) {}
+
   /// Create a version from a string in source code.
   ///
   /// Must include only groups of digits separated by a dot.
@@ -94,11 +97,15 @@
   /// away any 5th component that might be in this version.
   operator clang::VersionTuple() const;
 
-  /// Return whether this version is a valid Swift language version number
-  /// to set the compiler to using -swift-version; this is not the same as
-  /// the set of Swift versions that have ever existed, just those that we
-  /// are attempting to maintain backward-compatibility support for.
-  bool isValidEffectiveLanguageVersion() const;
+  /// Returns the concrete version to use when \e this version is provided as
+  /// an argument to -swift-version.
+  ///
+  /// This is not the same as the set of Swift versions that have ever existed,
+  /// just those that we are attempting to maintain backward-compatibility
+  /// support for. It's also common for valid versions to produce a different
+  /// result; for example "-swift-version 3" at one point instructed the
+  /// compiler to act as if it is version 3.1.
+  Optional<Version> getEffectiveLanguageVersion() const;
 
   /// Whether this version is in the Swift 3 family
   bool isVersion3() const { return !empty() && Components[0] == 3; }
@@ -141,6 +148,10 @@
 raw_ostream &operator<<(raw_ostream &os, const Version &version);
 
 /// Retrieves the numeric {major, minor} Swift version.
+///
+/// Note that this is the underlying version of the language, ignoring any
+/// -swift-version flags that may have been used in a particular invocation of
+/// the compiler.
 std::pair<unsigned, unsigned> getSwiftNumericVersion();
 
 /// Retrieves a string representing the complete Swift version, which includes
diff --git a/include/swift/Driver/Compilation.h b/include/swift/Driver/Compilation.h
index ef4db3e..ad43cbf 100644
--- a/include/swift/Driver/Compilation.h
+++ b/include/swift/Driver/Compilation.h
@@ -41,6 +41,7 @@
 namespace driver {
   class Driver;
   class ToolChain;
+  class PerformJobsState;
 
 /// An enum providing different levels of output which should be produced
 /// by a Compilation.
@@ -56,6 +57,7 @@
 };
 
 class Compilation {
+  friend class PerformJobsState;
 private:
   /// The DiagnosticEngine to which this Compilation should emit diagnostics.
   DiagnosticEngine &Diags;
@@ -136,6 +138,10 @@
   /// rebuilt.
   bool ShowIncrementalBuildDecisions = false;
 
+  /// When true, traces the lifecycle of each driver job. Provides finer
+  /// detail than ShowIncrementalBuildDecisions.
+  bool ShowJobLifecycle = false;
+
   static const Job *unwrap(const std::unique_ptr<const Job> &p) {
     return p.get();
   }
@@ -194,6 +200,10 @@
     ShowIncrementalBuildDecisions = value;
   }
 
+  void setShowJobLifecycle(bool value = true) {
+    ShowJobLifecycle = value;
+  }
+
   void setCompilationRecordPath(StringRef path) {
     assert(CompilationRecordPath.empty() && "already set");
     CompilationRecordPath = path;
diff --git a/include/swift/Driver/Job.h b/include/swift/Driver/Job.h
index 6963f2a..1839506 100644
--- a/include/swift/Driver/Job.h
+++ b/include/swift/Driver/Job.h
@@ -168,6 +168,9 @@
   /// terminating output with the given \p terminator.
   void printCommandLine(raw_ostream &Stream, StringRef Terminator = "\n") const;
 
+  /// Print a short summary of this Job to the given \p Stream.
+  void printSummary(raw_ostream &Stream) const;
+
   /// Print the command line for this Job to the given \p stream,
   /// and include any extra environment variables that will be set.
   ///
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 4570b2f..dff7665 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -91,6 +91,9 @@
 def driver_show_incremental : Flag<["-"], "driver-show-incremental">,
   InternalDebugOpt,
   HelpText<"With -v, dump information about why files are being rebuilt">;
+def driver_show_job_lifecycle : Flag<["-"], "driver-show-job-lifecycle">,
+  InternalDebugOpt,
+  HelpText<"Show every step in the lifecycle of driver jobs">;
 def driver_use_filelists : Flag<["-"], "driver-use-filelists">,
   InternalDebugOpt, HelpText<"Pass input files as filelists whenever possible">;
 
diff --git a/include/swift/Runtime/Config.h b/include/swift/Runtime/Config.h
index 2ad75a6..d8683e5 100644
--- a/include/swift/Runtime/Config.h
+++ b/include/swift/Runtime/Config.h
@@ -17,6 +17,9 @@
 #ifndef SWIFT_RUNTIME_CONFIG_H
 #define SWIFT_RUNTIME_CONFIG_H
 
+// Bring in visibility attribute macros for library visibility.
+#include "llvm/Support/Compiler.h"
+
 /// Does the current Swift platform support "unbridged" interoperation
 /// with Objective-C?  If so, the implementations of various types must
 /// implicitly handle Objective-C pointers.
@@ -185,9 +188,6 @@
 
 #endif
 
-// Bring in visibility attribute macros for library visibility.
-#include "llvm/Support/Compiler.h"
-
 // Generates a name of the runtime entry's implementation by
 // adding an underscore as a prefix and a suffix.
 #define SWIFT_RT_ENTRY_IMPL(Name) _##Name##_
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 4a8ceb0..ff984f4 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -1993,7 +1993,7 @@
       return nullptr;
 
     auto asWords = reinterpret_cast<
-      ConstTargetMetadataPointer<Runtime, TargetMetadata> const *>(this);
+      ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *>(this);
     return (asWords + Description->GenericParams.Offset);
   }
 
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index 1088268..2f83a47 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -1280,6 +1280,18 @@
         getSILDebugLocation(Loc), Operand, atomicity));
   }
 
+  EndLifetimeInst *createEndLifetime(SILLocation Loc, SILValue Operand) {
+    return insert(new (F.getModule())
+                      EndLifetimeInst(getSILDebugLocation(Loc), Operand));
+  }
+
+  UncheckedOwnershipConversionInst *
+  createUncheckedOwnershipConversion(SILLocation Loc, SILValue Operand,
+                                     ValueOwnershipKind Kind) {
+    return insert(new (F.getModule()) UncheckedOwnershipConversionInst(
+        getSILDebugLocation(Loc), Operand, Kind));
+  }
+
   FixLifetimeInst *createFixLifetime(SILLocation Loc, SILValue Operand) {
     return insert(new (F.getModule())
                       FixLifetimeInst(getSILDebugLocation(Loc), Operand));
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 9184783..f36f99a 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -1700,9 +1700,30 @@
                                    getOpValue(Inst->getOperand())));
 }
 
-template<typename ImplClass>
-void
-SILCloner<ImplClass>::visitMarkDependenceInst(MarkDependenceInst *Inst) {
+template <typename ImplClass>
+void SILCloner<ImplClass>::visitEndLifetimeInst(EndLifetimeInst *Inst) {
+  getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+  doPostProcess(Inst,
+                getBuilder().createEndLifetime(getOpLocation(Inst->getLoc()),
+                                               getOpValue(Inst->getOperand())));
+}
+
+template <typename ImplClass>
+void SILCloner<ImplClass>::visitUncheckedOwnershipConversionInst(
+    UncheckedOwnershipConversionInst *Inst) {
+  getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+  ValueOwnershipKind Kind = SILValue(Inst).getOwnershipKind();
+  if (getOpValue(Inst->getOperand()).getOwnershipKind() ==
+      ValueOwnershipKind::Trivial) {
+    Kind = ValueOwnershipKind::Trivial;
+  }
+  doPostProcess(Inst, getBuilder().createUncheckedOwnershipConversion(
+                          getOpLocation(Inst->getLoc()),
+                          getOpValue(Inst->getOperand()), Kind));
+}
+
+template <typename ImplClass>
+void SILCloner<ImplClass>::visitMarkDependenceInst(MarkDependenceInst *Inst) {
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   doPostProcess(Inst,
     getBuilder().createMarkDependence(getOpLocation(Inst->getLoc()),
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 77766a7..bfd2236 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -4337,6 +4337,48 @@
       : UnaryInstructionBase(DebugLoc, Operand) {}
 };
 
+/// EndLifetimeInst - An artificial end lifetime use of a value for the purpose
+/// of working around verification problems.
+///
+/// Specifically, the signature of destroying deinit takes self at +0 and
+/// returns self at +1. This is an issue since a deallocating deinit takes in
+/// self at +1. Previously, we could rely on the deallocating bit being set in
+/// the object header to allow SILGen to statically balance the +1 from the
+/// deallocating deinit. This is because deallocating values used to be
+/// immortal. The runtime now asserts if we release a deallocating value,
+/// meaning such an approach does not work. This instruction acts as a "fake"
+/// lifetime ending use allowing for static verification of deallocating
+/// destroyers, without an actual release being emitted (avoiding the runtime
+/// assert).
+class EndLifetimeInst
+    : public UnaryInstructionBase<ValueKind::EndLifetimeInst, SILInstruction,
+                                  /*HAS_RESULT*/ false> {
+  friend SILBuilder;
+
+  EndLifetimeInst(SILDebugLocation DebugLoc, SILValue Operand)
+      : UnaryInstructionBase(DebugLoc, Operand) {}
+};
+
+/// An unsafe conversion in between ownership kinds.
+///
+/// This is used today in destructors where due to objective-c legacy
+/// constraints, we need to be able to convert a guaranteed paramter to an owned
+/// parameter.
+class UncheckedOwnershipConversionInst
+    : public UnaryInstructionBase<ValueKind::UncheckedOwnershipConversionInst> {
+  friend SILBuilder;
+
+  ValueOwnershipKind Kind;
+
+  UncheckedOwnershipConversionInst(SILDebugLocation DebugLoc, SILValue operand,
+                                   ValueOwnershipKind Kind)
+      : UnaryInstructionBase(DebugLoc, operand, operand->getType()),
+        Kind(Kind) {}
+
+public:
+  ValueOwnershipKind getConversionOwnershipKind() const { return Kind; }
+};
+
 /// MarkDependenceInst - Marks that one value depends on another for
 /// validity in a non-obvious way.
 class MarkDependenceInst : public SILInstruction {
diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def
index 770fec1..1c9b8a9 100644
--- a/include/swift/SIL/SILNodes.def
+++ b/include/swift/SIL/SILNodes.def
@@ -164,6 +164,8 @@
   INST(UnmanagedAutoreleaseValueInst, RefCountingInst, unmanaged_autorelease_value, MayHaveSideEffects, DoesNotRelease)
   INST(CopyUnownedValueInst, SILInstruction, copy_unowned_value, MayHaveSideEffects, DoesNotRelease)
   INST(DestroyValueInst, SILInstruction, destroy_value, MayHaveSideEffects, MayRelease)
+  INST(EndLifetimeInst, SILInstruction, end_lifetime, MayHaveSideEffects, MayRelease)
+  INST(UncheckedOwnershipConversionInst, SILInstruction, unchecked_ownership_conversion, MayHaveSideEffects, MayRelease)
 
   // IsUnique does not actually write to memory but should be modeled
   // as such. Its operand is a pointer to an object reference. The
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index 4909013..f21e166 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -114,6 +114,11 @@
   ValueOwnershipKind(SILModule &M, SILType Type,
                      SILArgumentConvention Convention);
 
+  /// Parse Value into a ValueOwnershipKind.
+  ///
+  /// *NOTE* Emits an unreachable if an invalid value is passed in.
+  explicit ValueOwnershipKind(StringRef Value);
+
   operator innerty() const { return Value; }
 
   Optional<ValueOwnershipKind> merge(ValueOwnershipKind RHS) const;
diff --git a/include/swift/SIL/SILWitnessTable.h b/include/swift/SIL/SILWitnessTable.h
index 5ded6fa..284d100 100644
--- a/include/swift/SIL/SILWitnessTable.h
+++ b/include/swift/SIL/SILWitnessTable.h
@@ -62,8 +62,9 @@
   /// A witness table entry describing the witness for an associated type's
   /// protocol requirement.
   struct AssociatedTypeProtocolWitness {
-    /// The associated type required.
-    AssociatedTypeDecl *Requirement;
+    /// The associated type required.  A dependent type in the protocol's
+    /// context.
+    CanType Requirement;
     /// The protocol requirement on the type.
     ProtocolDecl *Protocol;
     /// The ProtocolConformance satisfying the requirement. Null if the
diff --git a/include/swift/SIL/SILWitnessVisitor.h b/include/swift/SIL/SILWitnessVisitor.h
index 9d8c266..5d3e9a9 100644
--- a/include/swift/SIL/SILWitnessVisitor.h
+++ b/include/swift/SIL/SILWitnessVisitor.h
@@ -49,27 +49,77 @@
 
 public:
   void visitProtocolDecl(ProtocolDecl *protocol) {
-    // Visit inherited protocols.
-    // TODO: We need to figure out all the guarantees we want here.
-    // It would be abstractly good to allow conversion to a base
-    // protocol to be trivial, but it's not clear that there's
-    // really a structural guarantee we can rely on here.
-    for (auto baseProto : protocol->getInheritedProtocols()) {
-      // ObjC protocols do not have witnesses.
-      if (!Lowering::TypeConverter::protocolRequiresWitnessTable(baseProto))
+    // Associated types get added after the inherited conformances, but
+    // before all the function requirements.
+    bool haveAddedAssociatedTypes = false;
+    auto addAssociatedTypes = [&] {
+      if (haveAddedAssociatedTypes) return;
+      haveAddedAssociatedTypes = true;
+
+      for (Decl *member : protocol->getMembers()) {
+        if (auto associatedType = dyn_cast<AssociatedTypeDecl>(member)) {
+          // TODO: only add associated types when they're new?
+          asDerived().addAssociatedType(associatedType);
+        }
+      }
+    };
+
+    for (auto &reqt : protocol->getRequirementSignature()
+                              ->getCanonicalSignature()->getRequirements()) {
+      switch (reqt.getKind()) {
+      // These requirements don't show up in the witness table.
+      case RequirementKind::Superclass:
+      case RequirementKind::SameType:
+      case RequirementKind::Layout:
         continue;
 
-      asDerived().addOutOfLineBaseProtocol(baseProto);
+      case RequirementKind::Conformance: {
+        auto type = CanType(reqt.getFirstType());
+        assert(type->isTypeParameter());
+        auto requirement =
+          cast<ProtocolType>(CanType(reqt.getSecondType()))->getDecl();
+
+        // ObjC protocols do not have witnesses.
+        if (!Lowering::TypeConverter::protocolRequiresWitnessTable(requirement))
+          continue;
+
+        // If the type parameter is 'self', consider this to be protocol
+        // inheritance.  In the canonical signature, these should all
+        // come before any protocol requirements on associated types.
+        if (auto parameter = dyn_cast<GenericTypeParamType>(type)) {
+          assert(type->isEqual(protocol->getSelfInterfaceType()));
+          assert(!haveAddedAssociatedTypes &&
+                 "unexpected ordering of conformances");
+          assert(parameter->getDepth() == 0 && parameter->getIndex() == 0 &&
+                 "non-self type parameter in protocol");
+          asDerived().addOutOfLineBaseProtocol(requirement);
+          continue;
+        }
+
+        // Add the associated types if we haven't yet.
+        addAssociatedTypes();
+
+        // Otherwise, add an associated requirement.
+        asDerived().addAssociatedConformance(type, requirement);
+        continue;
+      }
+      }
+      llvm_unreachable("bad requirement kind");
     }
 
-    /// Visit the witnesses for the direct members of a protocol.
+    // Add the associated types if we haven't yet.
+    addAssociatedTypes();
+
+    // Visit the witnesses for the direct members of a protocol.
     for (Decl *member : protocol->getMembers())
       ASTVisitor<T>::visit(member);
   }
 
   /// Fallback for unexpected protocol requirements.
   void visitDecl(Decl *d) {
+#ifndef NDEBUG
     d->print(llvm::errs());
+#endif
     llvm_unreachable("unhandled protocol requirement");
   }
 
@@ -94,11 +144,7 @@
   }
 
   void visitAssociatedTypeDecl(AssociatedTypeDecl *td) {
-    SmallVector<ProtocolDecl *, 4> protos;
-    for (auto p : td->getConformingProtocols())
-      protos.push_back(p);
-    ProtocolType::canonicalizeProtocols(protos);
-    asDerived().addAssociatedType(td, protos);
+    // We already visited these in the first pass.
   }
     
   void visitTypeAliasDecl(TypeAliasDecl *tad) {
diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h
index cf4395d..58406b6 100644
--- a/include/swift/SILOptimizer/Utils/Generics.h
+++ b/include/swift/SILOptimizer/Utils/Generics.h
@@ -115,6 +115,15 @@
                                            bool HasUnboundGenericParams);
 
   void createSubstitutedAndSpecializedTypes();
+  bool prepareAndCheck(ApplySite Apply, SILFunction *Callee,
+                       SubstitutionList ParamSubs);
+  void specializeConcreteAndGenericSubstitutions(ApplySite Apply,
+                                                 SILFunction *Callee,
+                                                 SubstitutionList ParamSubs);
+  void specializeConcreteSubstitutions(ApplySite Apply, SILFunction *Callee,
+                                       SubstitutionList ParamSubs);
+
+  ReabstractionInfo() {}
 public:
   /// Constructs the ReabstractionInfo for generic function \p Orig with
   /// substitutions \p ParamSubs.
@@ -219,6 +228,10 @@
 
   /// Returns true if it is a partial generic specialization.
   bool isPartialSpecialization() const;
+
+  /// Returns true if a given apply can be specialized.
+  static bool canBeSpecialized(ApplySite Apply, SILFunction *Callee,
+                               SubstitutionList ParamSubs);
 };
 
 /// Helper class for specializing a generic function given a list of
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index e790e71..3bf2312 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 = 321; // Last change: restrict to extension
+const uint16_t VERSION_MINOR = 325; // Last change: unchecked_ownership_conver
 
 using DeclID = PointerEmbeddedInt<unsigned, 31>;
 using DeclIDField = BCFixed<31>;
diff --git a/include/swift/SwiftDemangle/SwiftDemangle.h b/include/swift/SwiftDemangle/SwiftDemangle.h
index eb02d7e..8cf4ca5 100644
--- a/include/swift/SwiftDemangle/SwiftDemangle.h
+++ b/include/swift/SwiftDemangle/SwiftDemangle.h
@@ -53,6 +53,14 @@
                                                  char *OutputBuffer,
                                                  size_t Length);
 
+/// \brief Demangles a Swift function name and returns true if the function
+/// conforms to the Swift calling convention.
+///
+/// \returns true if the function conforms to the Swift calling convention.
+/// The return value is unspecified if the \p MangledName does not refer to a
+/// function symbol.
+int swift_demangle_hasSwiftCallingConvention(const char *MangledName);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/include/swift/Syntax/DeclSyntax.h b/include/swift/Syntax/DeclSyntax.h
index eb936fa..e5fa79e 100644
--- a/include/swift/Syntax/DeclSyntax.h
+++ b/include/swift/Syntax/DeclSyntax.h
@@ -18,10 +18,10 @@
 #ifndef SWIFT_SYNTAX_DECLSYNTAX_H
 #define SWIFT_SYNTAX_DECLSYNTAX_H
 
-#include "swift/Syntax/GenericSyntax.h"
 #include "swift/Syntax/References.h"
 #include "swift/Syntax/RawSyntax.h"
 #include "swift/Syntax/Syntax.h"
+#include "swift/Syntax/SyntaxCollection.h"
 #include "swift/Syntax/SyntaxData.h"
 #include "swift/Syntax/TokenSyntax.h"
 #include "swift/Syntax/TypeSyntax.h"
@@ -32,6 +32,148 @@
 namespace swift {
 namespace syntax {
 
+class ExprSyntax;
+class ExprSyntaxData;
+class CodeBlockStmtSyntax;
+class CodeBlockStmtSyntaxData;
+class TypeAttributesSyntax;
+class TypeAttributesSyntaxData;
+class DeclModifierListSyntax;
+class GenericWhereClauseSyntax;
+class GenericWhereClauseSyntaxData;
+class GenericParameterListSyntax;
+class GenericParameterListSyntaxData;
+
+#pragma mark declaration-modifier Data
+
+class DeclModifierSyntaxData final : public SyntaxData {
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class Syntax;
+  friend class DeclModifierSyntax;
+
+  DeclModifierSyntaxData(const RC<RawSyntax> Raw,
+                         const SyntaxData *Parent = nullptr,
+                         const CursorIndex IndexInParent = 0);
+
+  static RC<DeclModifierSyntaxData> make(const RC<RawSyntax> Raw,
+                                         const SyntaxData *Parent = nullptr,
+                                         const CursorIndex IndexInParent = 0);
+
+  static RC<DeclModifierSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *SD) {
+    return SD->getKind() == SyntaxKind::DeclModifier;
+  }
+};
+
+#pragma mark declaration-modifier API
+
+/// declaration-modifier -> access-level-modifier
+///                       | mutation-modifier
+///                       | 'class'
+///                       | 'convenience­'
+///                       | 'dynamic­'
+///                       | 'final­'
+///                       | 'infix­'
+///                       | 'lazy­'
+///                       | 'optional­'
+///                       | 'override'
+///                       | 'postfix'
+///                       | 'prefix'
+///                       | 'required'
+///                       | 'static'
+///                       | 'unowned­'
+///                       | 'unowned­(­safe­)­'
+///                       | 'unowned­(­unsafe­)­'
+///                       | 'weak­'
+/// access-level-modifier -> 'private' | 'private' '(' 'set' ')'
+///                        | 'fileprivate' | 'fileprivate' '(' 'set' ')'
+///                        | 'internal' | 'internal' '(' 'set' ')'
+///                        | 'public' | 'public' '(' 'set' ')'
+///                        | 'open' | 'open' '(' 'set' ')'
+/// mutation-modifier -> 'mutating' | 'nonmutating'
+class DeclModifierSyntax final : public Syntax {
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class DeclModifierSyntaxData;
+
+  enum class Cursor : CursorIndex {
+    Name,
+    LeftParen,
+    Argument,
+    RightParen
+  };
+
+  DeclModifierSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : Syntax(Root, Data) {}
+
+public:
+  using DataType = DeclModifierSyntaxData;
+
+  /// Return the name of the modifier.
+  RC<TokenSyntax> getName() const;
+
+  /// Return a DeclModifierSyntax with the given name.
+  DeclModifierSyntax withName(RC<TokenSyntax> NewName) const;
+
+  /// Return the left parenthesis '(' token as a part of the argument clause,
+  /// if there is one.
+  RC<TokenSyntax> getLeftParenToken() const;
+
+  /// Return a DeclModifierSyntax with the given left parenthesis '(' token.
+  DeclModifierSyntax withLeftParenToken(RC<TokenSyntax> NewLeftParen) const;
+
+  /// Get the argument to the declaration modifier.
+  ///
+  /// This is either:
+  /// - 'set' for the access modifiers such as 'private' or 'public', or
+  /// - 'safe' / 'unsafe' for the 'unowned' modifier.
+  RC<TokenSyntax> getArgument() const;
+
+  /// Return a DeclModifierSyntax with the given argument.
+  DeclModifierSyntax withArgument(RC<TokenSyntax> NewArgument) const;
+
+  /// Return the right parenthesis ')' token as a part of the argument clause,
+  /// if there is one.
+  RC<TokenSyntax> getRightParenToken() const;
+
+  /// Return a DeclModifierSyntax with the given right parenthesis ')' token.
+  DeclModifierSyntax withRightParenToken(RC<TokenSyntax> NewRightParen) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::DeclModifier;
+  }
+};
+
+#pragma mark declaration-modifiers Data
+
+using DeclModifierListSyntaxData =
+  SyntaxCollectionData<SyntaxKind::DeclModifierList, DeclModifierSyntax>;
+
+#pragma mark declaration-modifiers API
+
+class DeclModifierListSyntax final :
+  public SyntaxCollection<SyntaxKind::DeclModifierList, DeclModifierSyntax> {
+
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class FunctionDeclSyntax;
+
+  using DataType = DeclModifierListSyntaxData;
+
+  DeclModifierListSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : SyntaxCollection(Root, Data) {}
+
+public:
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::DeclModifierList;
+  }
+};
+
 #pragma mark declaration Data
 
 class DeclSyntaxData : public SyntaxData {
@@ -380,6 +522,368 @@
   TypeAliasDeclSyntax build() const;
 };
 
+#pragma mark - function-parameter Data
+
+class FunctionParameterSyntaxData final : public SyntaxData {
+
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class FunctionParameterSyntax;
+
+  RC<TypeSyntaxData> CachedTypeSyntax;
+  RC<ExprSyntaxData> CachedDefaultValue;
+
+  FunctionParameterSyntaxData(RC<RawSyntax> Raw,
+                              const SyntaxData *Parent = nullptr,
+                              CursorIndex IndexInParent = 0);
+  static RC<FunctionParameterSyntaxData>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0);
+  static RC<FunctionParameterSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *SD) {
+    return SD->getKind() == SyntaxKind::FunctionParameter;
+  }
+};
+
+#pragma mark - function-parameter API
+
+/// parameter ->
+/// external-parameter-name? local-parameter-name ':'
+///   type '...'? '='? expression? ','?
+class FunctionParameterSyntax final : public Syntax {
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class FunctionParameterSyntaxData;
+
+  enum class Cursor : CursorIndex {
+    ExternalName,
+    LocalName,
+    Colon,
+    Type,
+    Ellipsis,
+    DefaultEqual,
+    DefaultExpression,
+    TrailingComma,
+  };
+
+public:
+  using DataType = FunctionParameterSyntaxData;
+
+  FunctionParameterSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : Syntax(Root, Data) {}
+
+  /// Get the external name of the parameter, if there is one.
+  RC<TokenSyntax> getExternalName() const;
+
+  /// Return a FunctionParameterSyntax with the given external name.
+  FunctionParameterSyntax
+  withExternalName(RC<TokenSyntax> NewExternalName) const;
+
+  /// Return the local name of the parameter.
+  RC<TokenSyntax> getLocalName() const;
+
+  /// Return a FunctionParameterSyntax with the given local name.
+  FunctionParameterSyntax
+  withLocalName(RC<TokenSyntax> NewLocalName) const;
+
+  /// Return the colon ':' token between the local name and type of the
+  /// parameter.
+  RC<TokenSyntax> getColonToken() const;
+
+  /// Return a FunctionParameterSyntax with the given colon token between
+  /// the local name and type.
+  FunctionParameterSyntax
+  withColonToken(RC<TokenSyntax> NewColonToken) const;
+
+  /// Return the syntax for the type of this parameter.
+  llvm::Optional<TypeSyntax> getTypeSyntax() const;
+
+  /// Return a FunctionParameterSyntax with the given parameter type syntax.
+  FunctionParameterSyntax
+  withTypeSyntax(llvm::Optional<TypeSyntax> NewType) const;
+
+  /// Return the equal '=' token in between the parameter type and the default
+  /// value, if there is one.
+  RC<TokenSyntax> getEqualToken() const;
+
+  /// Return a FunctionParameterSyntax with the given equal '=' token in
+  /// between the parameter type and the default value.
+  FunctionParameterSyntax withEqualToken(RC<TokenSyntax> NewEqualToken) const;
+
+  /// Return the expresion for the default value of the parameter, if there
+  /// is one.
+  llvm::Optional<ExprSyntax> getDefaultValue() const;
+
+  /// Return a FunctionParameterSyntax with the given default value. To remove
+  /// the default value, pass llvm::None.
+  FunctionParameterSyntax
+  withDefaultValue(llvm::Optional<ExprSyntax> NewDefaultValue) const;
+
+  /// Return the trailing comma on the parameter, if there is one.
+  RC<TokenSyntax> getTrailingComma() const;
+
+  /// Return a FunctionParameterSyntax with the given trailing comma.
+  FunctionParameterSyntax
+  withTrailingComma(RC<TokenSyntax> NewTrailingComma) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionParameter;
+  }
+};
+
+#pragma mark - function-parameter-list Data
+
+using FunctionParameterListSyntaxData =
+  SyntaxCollectionData<SyntaxKind::FunctionParameterList,
+  FunctionParameterSyntax>;
+
+#pragma mark - function-parameter-list API
+
+/// parameter-list -> parameteter | parameter ',' parameter-list
+class FunctionParameterListSyntax final : public
+  SyntaxCollection<SyntaxKind::FunctionParameterList, FunctionParameterSyntax> {
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class FunctionSignatureSyntax;
+
+  using DataType = FunctionParameterListSyntaxData;
+
+  FunctionParameterListSyntax(const RC<SyntaxData> Root,
+                              const DataType *Data)
+    : SyntaxCollection(Root, Data) {}
+
+public:
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionParameterList;
+  }
+};
+
+#pragma mark - function-signature Data
+
+class FunctionSignatureSyntaxData final : public SyntaxData {
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class FunctionSignatureSyntax;
+
+  RC<FunctionParameterListSyntaxData> CachedParameterList;
+  RC<TypeAttributesSyntaxData> CachedReturnTypeAttributes;
+  RC<TypeSyntaxData> CachedReturnTypeSyntax;
+
+  FunctionSignatureSyntaxData(const RC<RawSyntax> Raw,
+                              const SyntaxData *Parent = nullptr,
+                              const CursorIndex IndexInParent = 0);
+
+  static RC<FunctionSignatureSyntaxData>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0);
+  static RC<FunctionSignatureSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *SD) {
+    return SD->getKind() == SyntaxKind::FunctionSignature;
+  }
+};
+
+#pragma mark - function-signature API
+
+/// function-signature ->
+///   '(' parameter-list? ')' (throws | rethrows)? '->' attributes? type
+class FunctionSignatureSyntax final : public Syntax {
+  friend struct SyntaxBuilder;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class FunctionSignatureSyntaxData;
+
+  enum class Cursor : CursorIndex {
+    LeftParen,
+    ParameterList,
+    RightParen,
+    ThrowsOrRethrows,
+    Arrow,
+    ReturnTypeAttributes,
+    ReturnType,
+  };
+
+public:
+  using DataType = FunctionSignatureSyntaxData;
+
+  FunctionSignatureSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : Syntax(Root, Data) {}
+
+  /// Return the left parenthesis '(' token enclosing the parameter list.
+  RC<TokenSyntax> getLeftParenToken() const;
+
+  /// Return a FunctionSignatureSyntax with the given left parentesis '(' token
+  /// enclosing the parameter list.
+  FunctionSignatureSyntax
+  withLeftParenToken(RC<TokenSyntax> NewLeftParen) const;
+
+  /// Return the parameter list for this signature.
+  FunctionParameterListSyntax getParameterList() const;
+
+  /// Return the parameter list for this signature.
+  FunctionSignatureSyntax
+  withParameterList(FunctionParameterListSyntax NewParameterList) const;
+
+  /// Return the right parenthesis ')' token enclosing the parameter list.
+  RC<TokenSyntax> getRightParenToken() const;
+
+  /// Return a FunctionSignatureSyntax with the given right parentesis ')' token
+  /// enclosing the parameter list.
+  FunctionSignatureSyntax
+  withRightParenToken(RC<TokenSyntax> NewRightParen) const;
+
+  /// Return the 'throws' token in this signature if it exists.
+  RC<TokenSyntax> getThrowsToken() const;
+
+  /// Return a FunctionSignatureSyntax with the given 'throws' token.
+  FunctionSignatureSyntax withThrowsToken(RC<TokenSyntax> NewThrowsToken) const;
+
+  /// Return the 'rethrows' token in this signature if it exists;
+  RC<TokenSyntax> getRethrowsToken() const;
+
+  /// Return a FunctionSignatureSyntax with the given 'rethrows' token.
+  FunctionSignatureSyntax
+  withRethrowsToken(RC<TokenSyntax> NewRethrowsToken) const;
+
+  /// Return the arrow '->' token for the signature.
+  RC<TokenSyntax> getArrowToken() const;
+
+  /// Return a FunctionSignatureSyntax with the given arrow token
+  FunctionSignatureSyntax withArrowToken(RC<TokenSyntax> NewArrowToken) const;
+
+  /// Return the return type attributes for the signature.
+  TypeAttributesSyntax getReturnTypeAttributes() const;
+
+  /// Return a FunctionSignatureSyntax with the given return type attributes.
+  FunctionSignatureSyntax
+  withReturnTypeAttributes(TypeAttributesSyntax NewReturnTypeAttributes) const;
+
+  /// Return the syntax for the return type of the signature.
+  TypeSyntax getReturnTypeSyntax() const;
+
+  /// Return a FunctionSignatureSyntax with the given return type.
+  FunctionSignatureSyntax withReturnTypeSyntax(TypeSyntax NewReturnType) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionSignature;
+  }
+};
+
+#pragma mark - function-declaration Data
+
+class FunctionDeclSyntaxData final : public SyntaxData {
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class FunctionDeclSyntax;
+
+  RC<TypeAttributesSyntaxData> CachedAttributes;
+  RC<DeclModifierListSyntaxData> CachedModifiers;
+  RC<GenericParameterClauseSyntaxData> CachedGenericParams;
+  RC<FunctionSignatureSyntaxData> CachedSignature;
+  RC<GenericWhereClauseSyntaxData> CachedGenericWhereClause;
+  RC<CodeBlockStmtSyntaxData> CachedBody;
+
+  FunctionDeclSyntaxData(const RC<RawSyntax> Raw,
+                         const SyntaxData *Parent = nullptr,
+                         const CursorIndex IndexInParent = 0);
+
+  static RC<FunctionDeclSyntaxData> make(const RC<RawSyntax> Raw,
+                                         const SyntaxData *Parent = nullptr,
+                                         const CursorIndex IndexInParent = 0);
+  static RC<FunctionDeclSyntaxData> makeBlank();
+
+public:
+  static bool classof(const SyntaxData *SD) {
+    return SD->getKind() == SyntaxKind::FunctionDecl;
+  }
+};
+
+#pragma mark - function-declaration API
+
+class FunctionDeclSyntax final : public Syntax {
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class FunctionDeclSyntaxData;
+
+  enum class Cursor : CursorIndex {
+    Attributes,
+    Modifiers,
+    FuncKeyword,
+    Identifier,
+    GenericParameterClause,
+    Signature,
+    GenericWhereClause,
+    Body
+  };
+
+  using DataType = FunctionDeclSyntaxData;
+
+  FunctionDeclSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : Syntax(Root, Data) {}
+
+public:
+  /// Get the attributes of this function declaration.
+  TypeAttributesSyntax getAttributes() const;
+
+  /// Return a FunctionDeclSyntax with the given attributes.
+  FunctionDeclSyntax withAttributes(TypeAttributesSyntax NewAttributes) const;
+
+  /// Get the modifiers of this function declaration.
+  DeclModifierListSyntax getModifiers() const;
+
+  /// Return a FunctionDeclSyntax with the given modifiers.
+  FunctionDeclSyntax withModifiers(DeclModifierListSyntax NewModifiers) const;
+
+  /// Return the 'func' keyword of tis function declaration.
+  RC<TokenSyntax> getFuncKeyword() const;
+
+  /// Return a FunctionDeclSyntax with the given 'func' keyword.
+  FunctionDeclSyntax withFuncKeyword(RC<TokenSyntax> NewFuncKeyword) const;
+
+  /// Return the identifier of the function declaration.
+  RC<TokenSyntax> getIdentifier() const;
+
+  /// Return a FunctionDeclSyntax with the given identifier.
+  FunctionDeclSyntax withIdentifier(RC<TokenSyntax> NewIdentifier) const;
+
+  /// Return the generic parameter clause of the function declaration, if
+  /// there is one. Otherwise, return llvm::None.
+  llvm::Optional<GenericParameterClauseSyntax>
+  getGenericParameterClause() const;
+
+  /// Return a FunctionDeclSyntax with the given generic parameter clause.
+  /// To remove the generic parameters, pass in llvm::None.
+  FunctionDeclSyntax withGenericParameterClause(
+    llvm::Optional<GenericParameterClauseSyntax> NewGenericParams) const;
+
+  /// Return the signature of the function declaration.
+  FunctionSignatureSyntax getSignature() const;
+
+  /// Return a FunctionDeclSyntax with the given function signature.
+  FunctionDeclSyntax withSignature(FunctionSignatureSyntax NewSignature) const;
+
+  /// Return the body of the function declaration, if there is one.
+  ///
+  /// As an example, function declarations in protocols have no body.
+  llvm::Optional<CodeBlockStmtSyntax> getBody() const;
+
+  /// Return a FunctionDeclSyntax with the given body. To remove the body,
+  /// pass in llvm::None.
+  FunctionDeclSyntax
+  withBody(llvm::Optional<CodeBlockStmtSyntax> NewBody) const;
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::FunctionDecl;
+  }
+};
+
 } // end namespace syntax
 } // end namespace swift
 
diff --git a/include/swift/Syntax/ExprSyntax.h b/include/swift/Syntax/ExprSyntax.h
index 5dbebda..1dfbf14 100644
--- a/include/swift/Syntax/ExprSyntax.h
+++ b/include/swift/Syntax/ExprSyntax.h
@@ -22,6 +22,8 @@
 #include "swift/Syntax/References.h"
 #include "swift/Syntax/Syntax.h"
 #include "swift/Syntax/SyntaxData.h"
+#include "swift/Syntax/SyntaxCollection.h"
+#include "swift/Syntax/SyntaxCollectionData.h"
 #include "swift/Syntax/TokenSyntax.h"
 #include "swift/Syntax/UnknownSyntax.h"
 
@@ -51,6 +53,7 @@
 };
 
 class ExprSyntax : public Syntax {
+  friend class FunctionParameterSyntax;
 public:
   using DataType = ExprSyntaxData;
 
@@ -248,7 +251,6 @@
 
 /// function-call-argument -> label? ':'? (expression | operator) ','?
 class FunctionCallArgumentSyntax : public Syntax {
-
   using DataType = FunctionCallArgumentSyntaxData;
 
   friend struct SyntaxFactory;
@@ -256,6 +258,10 @@
   friend class Syntax;
   friend class FunctionCallArgumentSyntaxData;
   friend class FunctionCallArgumentListSyntax;
+  friend class SyntaxCollectionData<SyntaxKind::FunctionCallArgumentList,
+                                    FunctionCallArgumentSyntax>;
+  friend class SyntaxCollection<SyntaxKind::FunctionCallArgumentList,
+                                FunctionCallArgumentSyntax>;
 
   enum class Cursor {
     Label,
@@ -305,37 +311,18 @@
 
 #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;
-  }
-};
+using FunctionCallArgumentListSyntaxData =
+  SyntaxCollectionData<SyntaxKind::FunctionCallArgumentList,
+    FunctionCallArgumentSyntax>;
 
 #pragma mark - function-call-argument-list API
 
 /// function-call-argument-list -> function-call-argument
 ///                                function-call-argument-list?
-class FunctionCallArgumentListSyntax : public Syntax {
+class FunctionCallArgumentListSyntax
+  : public SyntaxCollection<SyntaxKind::FunctionCallArgumentList,
+                            FunctionCallArgumentSyntax> {
   friend struct SyntaxFactory;
-  friend class FunctionCallArgumentListSyntaxData;
   friend class FunctionCallExprSyntax;
   friend class Syntax;
   friend class SyntaxData;
@@ -346,17 +333,6 @@
                                  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;
   }
diff --git a/include/swift/Syntax/GenericSyntax.h b/include/swift/Syntax/GenericSyntax.h
index 753018e..d8510db 100644
--- a/include/swift/Syntax/GenericSyntax.h
+++ b/include/swift/Syntax/GenericSyntax.h
@@ -19,6 +19,7 @@
 #define SWIFT_SYNTAX_GENERICSYNTAX_H
 
 #include "swift/Syntax/References.h"
+#include "swift/Syntax/SyntaxCollection.h"
 #include "swift/Syntax/SyntaxData.h"
 #include "swift/Syntax/TokenSyntax.h"
 
@@ -30,10 +31,50 @@
 class TypeIdentifierSyntax;
 class TypeIdentifierSyntaxData;
 
+#pragma mark - generic-requirement Data
+
+class GenericRequirementSyntaxData : public SyntaxData {
+  friend class GenericRequirementSyntax;
+  friend class SyntaxData;
+
+protected:
+  GenericRequirementSyntaxData(const RC<RawSyntax> Raw,
+                               const SyntaxData *Parent = nullptr,
+                               const CursorIndex IndexInParent = 0)
+  : SyntaxData(Raw, Parent, IndexInParent) {}
+
+public:
+  static bool classof(const SyntaxData *SD) {
+    return SD->getKind() == SyntaxKind::ConformanceRequirement ||
+      SD->getKind() == SyntaxKind::SameTypeRequirement;
+  }
+};
+
+#pragma mark - generic-requirement API
+
+class GenericRequirementSyntax : public Syntax {
+  friend class Syntax;
+  friend class SyntaxData;
+  friend class GenericRequirementSyntaxData;
+
+public:
+  using DataType = GenericRequirementSyntaxData;
+
+  GenericRequirementSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : Syntax(Root, Data) {}
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::ConformanceRequirement ||
+    S->getKind() == SyntaxKind::SameTypeRequirement;
+  }
+};
+
 #pragma mark - conformance-requirement Data
 
-class ConformanceRequirementSyntaxData final : public SyntaxData {
+class ConformanceRequirementSyntaxData final
+    : public GenericRequirementSyntaxData {
   friend class SyntaxData;
+
   RC<TypeIdentifierSyntaxData> CachedConformingTypeIdentifier;
   RC<TypeSyntaxData> InheritedType;
 
@@ -44,18 +85,24 @@
   make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
        CursorIndex IndexInParent = 0);
   static RC<ConformanceRequirementSyntaxData> makeBlank();
+
 public:
   static bool classof(const SyntaxData *S) {
     return S->getKind() == SyntaxKind::ConformanceRequirement;
   }
+  static bool classof(const GenericRequirementSyntaxData *SD) {
+    return SD->getKind() == SyntaxKind::ConformanceRequirement;
+  }
 };
 
 #pragma mark - conformance-requirement API
 
 /// conformance-requirement -> type-identifier : type-identifier
-class ConformanceRequirementSyntax final : public Syntax {
+class ConformanceRequirementSyntax final : public GenericRequirementSyntax {
 
   friend class ConformanceRequirementSyntaxData;
+  friend class SyntaxData;
+  friend class Syntax;
 
   enum Cursor : CursorIndex {
     LeftTypeIdentifier,
@@ -73,6 +120,8 @@
   static ConformanceRequirementSyntax makeBlank();
 
 public:
+  using DataType = ConformanceRequirementSyntaxData;
+
   /// Return the conforming "left-hand" type identifier in the
   /// conformance requirement.
   TypeIdentifierSyntax getConformingTypeIdentifier() const;
@@ -99,13 +148,18 @@
   static bool classof(const Syntax *S) {
     return S->getKind() == SyntaxKind::ConformanceRequirement;
   }
+  static bool classof(const GenericRequirementSyntax *S) {
+    return S->getKind() == SyntaxKind::ConformanceRequirement;
+  }
 };
 
 #pragma mark - same-type-requirement Data
 
-class SameTypeRequirementSyntaxData final : public SyntaxData {
+class SameTypeRequirementSyntaxData final
+    : public GenericRequirementSyntaxData {
   friend struct SyntaxFactory;
   friend class SyntaxData;
+
   RC<TypeIdentifierSyntaxData> CachedLeftTypeIdentifier;
   RC<TypeSyntaxData> CachedRightType;
 
@@ -129,8 +183,9 @@
 /// same-type-requirement -> type-identifier == type
 class SameTypeRequirementSyntax final : public Syntax {
   friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
   friend class SameTypeRequirementSyntaxData;
-
   enum Cursor : CursorIndex {
     LeftTypeIdentifier,
     EqualityToken,
@@ -141,6 +196,7 @@
                             const SameTypeRequirementSyntaxData *Data);
 
 public:
+  using DataType = SameTypeRequirementSyntaxData;
 
   /// Return the type identifier on the left side of the same-type requirement.
   TypeIdentifierSyntax getLeftTypeIdentifier() const;
@@ -277,9 +333,9 @@
 
   RC<GenericParameterListSyntaxData> CachedGenericParameterList;
 
-  GenericParameterClauseSyntaxData(RC<RawSyntax> Raw,
+  GenericParameterClauseSyntaxData(const RC<RawSyntax> Raw,
                                    const SyntaxData *Parent = nullptr,
-                                   CursorIndex IndexInParent = 0);
+                                   const CursorIndex IndexInParent = 0);
   static RC<GenericParameterClauseSyntaxData>
   make(RC<RawSyntax> Raw,
        const SyntaxData *Parent = nullptr,
@@ -299,6 +355,8 @@
   friend struct SyntaxFactory;
   friend class GenericParameterClauseSyntaxData;
   friend class GenericParameterClauseBuilder;
+  friend class FunctionDeclSyntax;
+
   enum class Cursor : CursorIndex {
     LeftAngleBracketToken,
     GenericParameterList,
@@ -478,6 +536,35 @@
   }
 };
 
+#pragma mark - generic-requirement-list Data
+
+using GenericRequirementListSyntaxData =
+  SyntaxCollectionData<SyntaxKind::GenericRequirementList,
+  GenericRequirementSyntax>;
+
+#pragma mark - generic-requirement-list API
+
+/// requirement-list -> requirement | requirement ',' requirement-list
+///
+/// requirement -> conformance-requirement | same-type-requirement
+class GenericRequirementListSyntax final
+  : public SyntaxCollection<SyntaxKind::GenericRequirementList,
+      GenericRequirementSyntax> {
+  friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
+
+  using DataType = GenericRequirementListSyntaxData;
+
+  GenericRequirementListSyntax(const RC<SyntaxData> Root,
+                               const DataType *Data)
+      : SyntaxCollection(Root, Data) {}
+public:
+  static bool classof(const Syntax *S) {
+    return S->getKind() == SyntaxKind::GenericRequirementList;
+  }
+};
+
 #pragma mark - generic-argument-clause Builder
 
 class GenericArgumentClauseBuilder {
@@ -500,47 +587,6 @@
   GenericArgumentClauseSyntax build() const;
 };
 
-#pragma mark - generic-requirement-list Data
-
-class GenericRequirementListSyntaxData final : public SyntaxData {
-  friend class SyntaxData;
-  GenericRequirementListSyntaxData(RC<RawSyntax> Raw,
-                                   const SyntaxData *Parent = nullptr,
-                                   CursorIndex IndexInParent = 0);
-  static RC<GenericRequirementListSyntaxData>
-  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
-       CursorIndex IndexInParent = 0);
-  static RC<GenericRequirementListSyntaxData> makeBlank();
-public:
-  static bool classof(const SyntaxData *S) {
-    return S->getKind() == SyntaxKind::GenericRequirementList;
-  }
-};
-
-#pragma mark - generic-requirement-list API
-
-/// requirement-list -> requirement | requirement ',' requirement-list
-///
-/// requirement -> conformance-requirement | same-type-requirement
-class GenericRequirementListSyntax final : public Syntax {
-  friend struct SyntaxFactory;
-
-  GenericRequirementListSyntax(RC<SyntaxData> Root,
-                               GenericRequirementListSyntaxData *Data);
-
-  static GenericRequirementListSyntax make(RC<RawSyntax> Raw);
-  static GenericRequirementListSyntax makeBlank();
-
-public:
-  // TODO: getRequirement(unsigned n) const;
-  // TODO: withAddedRequirement(llvm::Optional<RC<TokenSyntax>> MaybeComma,
-  //                            GenericRequirementSyntax NewRequirement) const;
-
-  static bool classof(const Syntax *S) {
-    return S->getKind() == SyntaxKind::GenericRequirementList;
-  }
-};
-
 #pragma mark - generic-where-clause Data
 
 class GenericWhereClauseSyntaxData final : public SyntaxData {
@@ -549,12 +595,12 @@
 
   RC<GenericRequirementListSyntaxData> CachedRequirementList;
 
-  GenericWhereClauseSyntaxData(RC<RawSyntax> Raw,
+  GenericWhereClauseSyntaxData(const RC<RawSyntax> Raw,
                                const SyntaxData *Parent = nullptr,
-                               CursorIndex IndexInParent = 0);
-  static RC<GenericWhereClauseSyntaxData> make(RC<RawSyntax> Raw,
-                                               const SyntaxData *Parent = nullptr,
-                                               CursorIndex IndexInParent = 0);
+                               const CursorIndex IndexInParent = 0);
+  static RC<GenericWhereClauseSyntaxData>
+  make(const RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       const CursorIndex IndexInParent = 0);
   static RC<GenericWhereClauseSyntaxData> makeBlank();
 
 public:
@@ -568,12 +614,16 @@
 /// generic-where-clause -> 'where' requirement-list
 class GenericWhereClauseSyntax final : public Syntax {
   friend struct SyntaxFactory;
+  friend class Syntax;
+  friend class SyntaxData;
   friend class GenericWhereClauseSyntaxData;
   enum class Cursor : CursorIndex {
-    WhereToken,
+    WhereKeyword,
     RequirementList,
   };
 
+  using DataType = GenericWhereClauseSyntaxData;
+
   GenericWhereClauseSyntax(RC<SyntaxData> Root,
                            const GenericWhereClauseSyntaxData *Data);
 
diff --git a/include/swift/Syntax/Rewriter.h b/include/swift/Syntax/Rewriter.h
index 224373d..ae7c208 100644
--- a/include/swift/Syntax/Rewriter.h
+++ b/include/swift/Syntax/Rewriter.h
@@ -24,6 +24,7 @@
 
 #include "swift/Syntax/References.h"
 #include "swift/Syntax/DeclSyntax.h"
+#include "swift/Syntax/GenericSyntax.h"
 #include "swift/Syntax/ExprSyntax.h"
 #include "swift/Syntax/StmtSyntax.h"
 #include "swift/Syntax/Syntax.h"
diff --git a/include/swift/Syntax/StmtSyntax.h b/include/swift/Syntax/StmtSyntax.h
index d4c93a5..f0bba83 100644
--- a/include/swift/Syntax/StmtSyntax.h
+++ b/include/swift/Syntax/StmtSyntax.h
@@ -57,9 +57,11 @@
 ///            | do-statement ';'?
 ///            | compiler-control-statement ';'?
 class StmtSyntax : public Syntax {
+  friend class Syntax;
 protected:
   StmtSyntax(const RC<SyntaxData> Root, const StmtSyntaxData *Data);
 public:
+  using DataType = StmtSyntaxData;
   static bool classof(const Syntax *S) {
     return S->isStmt();
   }
@@ -130,6 +132,7 @@
   };
   friend struct SyntaxFactory;
   friend class CodeBlockStmtSyntaxData;
+  friend class FunctionDeclSyntax;
 
   CodeBlockStmtSyntax(const RC<SyntaxData> Root, CodeBlockStmtSyntaxData *Data);
 
@@ -166,58 +169,33 @@
 #pragma mark -
 #pragma mark statements Data
 
-class StmtListSyntaxData final : public StmtSyntaxData {
-  friend class SyntaxData;
-  friend class StmtListSyntax;
-  friend class StmtListSyntaxBuilder;
-
-  StmtListSyntaxData(RC<RawSyntax> Raw,
-                     const SyntaxData *Parent = nullptr,
-                     CursorIndex IndexInParent = 0);
-  static RC<StmtListSyntaxData> make(RC<RawSyntax> Raw,
-                                     const SyntaxData *Parent = nullptr,
-                                     CursorIndex IndexInParent = 0);
-  static RC<StmtListSyntaxData> makeBlank();
-
-public:
-  static bool classof(const SyntaxData *SD) {
-    return SD->getKind() == SyntaxKind::StmtList;
-  }
-};
+using StmtListSyntaxData =
+  SyntaxCollectionData<SyntaxKind::StmtList, StmtSyntax>;
 
 #pragma mark -
 #pragma mark statements API
 
 /// statements -> statement
 ///             | statement statements
-class StmtListSyntax final : public Syntax {
+class StmtListSyntax final
+    : public SyntaxCollection<SyntaxKind::StmtList, StmtSyntax> {
   friend struct SyntaxFactory;
-  friend class StmtListSyntaxBuilder;
+  friend class Syntax;
   friend class SyntaxData;
+  friend class FunctionDeclSyntax;
 
   using DataType = StmtListSyntaxData;
 
-  StmtListSyntax(const RC<SyntaxData> Root, const StmtListSyntaxData *Data);
-public:
-  /// Returns a new statement list with an additional statement.
-  StmtListSyntax withAddedStatement(Syntax AdditionalStatement) const;
+  StmtListSyntax(const RC<SyntaxData> Root, const DataType *Data)
+    : SyntaxCollection(Root, Data) {}
 
+public:
   static bool classof(const Syntax *S) {
     return S->getKind() == SyntaxKind::StmtList;
   }
 };
 
 #pragma mark -
-#pragma mark statements Builder
-
-class StmtListSyntaxBuilder final {
-  RawSyntax::LayoutList StmtListLayout;
-public:
-  StmtListSyntaxBuilder &addStatement(Syntax Statement);
-  StmtListSyntax build() const;
-};
-
-#pragma mark -
 #pragma mark fallthrough-statement Data
 
 class FallthroughStmtSyntaxData final : public StmtSyntaxData {
diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h
index 7be6fd9..d1cc24d 100644
--- a/include/swift/Syntax/Syntax.h
+++ b/include/swift/Syntax/Syntax.h
@@ -52,7 +52,6 @@
   friend class SyntaxData;
   friend class LegacyASTTransformer;
   friend class sema::Semantics;
-  using DataType = SyntaxData;
 
 #define SYNTAX(Id, Parent) friend class Id##Syntax;
 #include "swift/Syntax/SyntaxKinds.def"
@@ -75,6 +74,8 @@
   }
 
 public:
+  using DataType = SyntaxData;
+
   Syntax(const RC<SyntaxData> Root, const SyntaxData *Data);
 
   /// Get the kind of syntax.
@@ -150,7 +151,7 @@
   /// Print a debug representation of the syntax node to standard error.
   void dump() const;
 
-  bool hasSameIdentityAs(const Syntax &Other) {
+  bool hasSameIdentityAs(const Syntax &Other) const {
     return Root == Other.Root && Data == Other.Data;
   }
 
diff --git a/include/swift/Syntax/SyntaxCollection.h b/include/swift/Syntax/SyntaxCollection.h
new file mode 100644
index 0000000..37b87c8
--- /dev/null
+++ b/include/swift/Syntax/SyntaxCollection.h
@@ -0,0 +1,183 @@
+#ifndef SWIFT_SYNTAX_SYNTAXCOLLECTION_H
+#define SWIFT_SYNTAX_SYNTAXCOLLECTION_H
+
+#include "swift/Syntax/Syntax.h"
+#include "swift/Syntax/SyntaxCollectionData.h"
+
+namespace swift {
+namespace syntax {
+
+template <SyntaxKind CollectionKind, typename Element>
+struct SyntaxCollectionIterator {
+  const SyntaxCollection<CollectionKind, Element> &Collection;
+  size_t Index;
+
+  Element operator*() {
+    return Collection[Index];
+  }
+
+  SyntaxCollectionIterator<CollectionKind, Element> &operator++() {
+    ++Index;
+    return *this;
+  }
+
+  bool
+  operator==(const SyntaxCollectionIterator<CollectionKind, Element> &Other) {
+    return Collection.hasSameIdentityAs(Other.Collection) &&
+    Index == Other.Index;
+  }
+
+  bool
+  operator!=(const SyntaxCollectionIterator<CollectionKind, Element> &Other) {
+    return !operator==(Other);
+
+  }
+};
+
+/// A generic unbounded collection of syntax nodes
+template <SyntaxKind CollectionKind, typename Element>
+class SyntaxCollection : public Syntax {
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class Syntax;
+  using DataType = SyntaxCollectionData<CollectionKind, Element>;
+
+protected:
+  SyntaxCollection(const RC<SyntaxData> Root, const DataType *Data)
+    : Syntax(Root, Data) {}
+
+public:
+
+  /// Returns true if the collection is empty.
+  bool empty() const {
+    return size() == 0;
+  }
+
+  /// Returns the number of elements in the collection.
+  size_t size() const {
+    return getRaw()->Layout.size();
+  }
+
+  SyntaxCollectionIterator<CollectionKind, Element> begin() const {
+    return SyntaxCollectionIterator<CollectionKind, Element> {
+      *this,
+      0,
+    };
+  }
+
+  SyntaxCollectionIterator<CollectionKind, Element> end() const {
+    return SyntaxCollectionIterator<CollectionKind, Element> {
+      *this,
+      getRaw()->Layout.size(),
+    };
+  }
+
+  /// Return the element at the given Index.
+  ///
+  /// Precondition: Index < size()
+  /// Precondition: !empty()
+  Element operator[](const size_t Index) const {
+    assert(Index < size());
+    assert(!empty());
+
+    auto RawElement = getRaw()->Layout[Index];
+    auto *MyData = getUnsafeData<SyntaxCollection<CollectionKind, Element>>();
+
+    if (auto Data = MyData->CachedElements[Index].get()) {
+      return Element { Root, Data };
+    }
+
+    auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+      MyData->CachedElements.data() + Index);
+
+    SyntaxData::realizeSyntaxNode<Element>(ChildPtr, RawElement, MyData, Index);
+
+    return Element {
+      Root,
+      MyData->CachedElements[Index].get()
+    };
+  }
+
+  /// Return a new collection with the given element added to the end.
+  SyntaxCollection<CollectionKind, Element>
+  appending(Element E) const {
+    auto NewLayout = getRaw()->Layout;
+    NewLayout.push_back(E.getRaw());
+    auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  /// Return a new collection with an element removed from the end.
+  ///
+  /// Precondition: !empty()
+  SyntaxCollection<CollectionKind, Element> removingLast() const {
+    assert(!empty());
+    auto NewLayout = getRaw()->Layout;
+    NewLayout.pop_back();
+    auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  /// Return a new collection with the given element appended to the front.
+  SyntaxCollection<CollectionKind, Element>
+  prepending(Element E) const {
+    RawSyntax::LayoutList NewLayout = { E.getRaw() };
+    std::copy(getRaw()->Layout.begin(),
+              getRaw()->Layout.end(),
+              std::back_inserter(NewLayout));
+    auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  /// Return a new collection with an element removed from the end.
+  ///
+  /// Precondition: !empty()
+  SyntaxCollection<CollectionKind, Element> removingFirst() const {
+    assert(!empty());
+    RawSyntax::LayoutList NewLayout;
+    std::copy(getRaw()->Layout.begin() + 1,
+              getRaw()->Layout.end(),
+              std::back_inserter(NewLayout));
+    auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  /// Return a new collection with the Element inserted at index i.
+  ///
+  /// Precondition: i <= size()
+  SyntaxCollection<CollectionKind, Element>
+  inserting(size_t i, Element E) const {
+    assert(i <= size());
+    RawSyntax::LayoutList NewLayout;
+    std::copy(getRaw()->Layout.begin(), getRaw()->Layout.begin() + i,
+              std::back_inserter(NewLayout));
+    NewLayout.push_back(E.getRaw());
+    std::copy(getRaw()->Layout.begin() + i, getRaw()->Layout.end(),
+              std::back_inserter(NewLayout));
+    auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  /// Return a new collection with the element removed at index i.
+  SyntaxCollection<CollectionKind, Element> removing(size_t i) const {
+    auto NewLayout = getRaw()->Layout;
+    NewLayout.erase(NewLayout.begin() + i);
+    auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  /// Return an empty syntax collection of this type.
+  SyntaxCollection<CollectionKind, Element> cleared() const {
+    auto Raw = RawSyntax::make(CollectionKind, {}, getRaw()->Presence);
+    return Data->replaceSelf<SyntaxCollection<CollectionKind, Element>>(Raw);
+  }
+
+  static bool classof(const Syntax *S) {
+    return S->getKind() == CollectionKind;
+  }
+};
+
+} // end namespace syntax
+} // end namespace swift
+
+#endif // SWIFT_SYNTAX_SYNTAXCOLLECTION_H
diff --git a/include/swift/Syntax/SyntaxCollectionData.h b/include/swift/Syntax/SyntaxCollectionData.h
new file mode 100644
index 0000000..1970f3b
--- /dev/null
+++ b/include/swift/Syntax/SyntaxCollectionData.h
@@ -0,0 +1,53 @@
+#ifndef SWIFT_SYNTAX_SYNTAXCOLLECTIONDATA_H
+#define SWIFT_SYNTAX_SYNTAXCOLLECTIONDATA_H
+
+#include "swift/Syntax/SyntaxData.h"
+
+namespace swift {
+namespace syntax {
+
+template <SyntaxKind CollectionKind, typename ElementType>
+class SyntaxCollection;
+
+template <SyntaxKind CollectionKind, typename ElementType>
+class SyntaxCollectionData : public SyntaxData {
+  friend class SyntaxCollection<CollectionKind, ElementType>;
+  std::vector<RC<typename ElementType::DataType>> CachedElements;
+
+  friend struct SyntaxFactory;
+  friend class SyntaxData;
+  friend class FunctionCallExprSyntaxBuilder;
+
+  SyntaxCollectionData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+                       CursorIndex IndexInParent = 0)
+      : SyntaxData(Raw, Parent, IndexInParent),
+        CachedElements(Raw->Layout.size(), nullptr) {
+    assert(Raw->Kind == CollectionKind);
+  }
+
+  static RC<SyntaxCollectionData<CollectionKind, ElementType>>
+  make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
+       CursorIndex IndexInParent = 0) {
+
+    return RC<SyntaxCollectionData<CollectionKind, ElementType>> {
+      new SyntaxCollectionData<CollectionKind, ElementType> {
+        Raw, Parent, IndexInParent
+      }
+    };
+  }
+
+  static RC<SyntaxCollectionData<CollectionKind, ElementType>> makeBlank() {
+    auto Raw = RawSyntax::make(CollectionKind, {}, SourcePresence::Present);
+    return make(Raw);
+  }
+
+public:
+  static bool classof(const SyntaxData *SD) {
+    return SD->getKind() == CollectionKind;
+  }
+};
+
+} // end namespace syntax
+} // end namespace swift
+
+#endif
diff --git a/include/swift/Syntax/SyntaxData.h b/include/swift/Syntax/SyntaxData.h
index f27e59e..8fcd79b 100644
--- a/include/swift/Syntax/SyntaxData.h
+++ b/include/swift/Syntax/SyntaxData.h
@@ -77,7 +77,7 @@
   ///
   /// If there is no parent, this is 0.
   const CursorIndex IndexInParent;
-protected:
+
   SyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
              CursorIndex IndexInParent = 0)
     : Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) {}
diff --git a/include/swift/Syntax/SyntaxFactory.h b/include/swift/Syntax/SyntaxFactory.h
index d1d74c8..c99c8d3 100644
--- a/include/swift/Syntax/SyntaxFactory.h
+++ b/include/swift/Syntax/SyntaxFactory.h
@@ -51,6 +51,26 @@
   makeUnknownSyntax(llvm::ArrayRef<RC<TokenSyntax>> Tokens);
 
 #pragma mark - Declarations
+
+#pragma mark - declaration-modifier
+
+  /// Make a declaration modifier with the specified elements.
+  static DeclModifierSyntax
+  makeDeclModifier(RC<TokenSyntax> Name, RC<TokenSyntax> LeftParen,
+                   RC<TokenSyntax> Argument, RC<TokenSyntax> RightParen);
+
+  /// Make a declaration modifier with all missing elements.
+  static DeclModifierSyntax makeBlankDeclModifier();
+
+  /// Make a declaration modifier list with the specified modifiers.
+  static DeclModifierListSyntax
+  makeDeclModifierList(const std::vector<DeclModifierSyntax> &Modifiers);
+
+  /// Make an empty declaration modifier list.
+  static DeclModifierListSyntax makeBlankDeclModifierList();
+
+#pragma mark - struct-declaration
+
   /// Make a struct declaration with the specified elements.
   static StructDeclSyntax
   makeStructDecl(RC<TokenSyntax> StructToken, RC<TokenSyntax> Identifier,
@@ -73,6 +93,65 @@
   /// Make an empty list of declaration members.
   static DeclMembersSyntax makeBlankDeclMembers();
 
+  /// Make a function declaration with the specified elements.
+  static FunctionDeclSyntax
+  makeFunctionDecl(TypeAttributesSyntax Attributes,
+                   DeclModifierListSyntax Modifiers,
+                   RC<TokenSyntax> FuncKeyword,
+                   RC<TokenSyntax> Identifier,
+                   llvm::Optional<GenericParameterClauseSyntax> GenericParams,
+                   FunctionSignatureSyntax Signature,
+                   llvm::Optional<GenericWhereClauseSyntax> GenericWhereClause,
+                   llvm::Optional<CodeBlockStmtSyntax> Body);
+
+  /// Make a function declaration with all missing elements.
+  static FunctionDeclSyntax makeBlankFunctionDecl();
+
+#pragma mark - function-parameter
+
+  /// Make a function parameter with the given elements.
+  static FunctionParameterSyntax
+  makeFunctionParameter(RC<TokenSyntax> ExternalName, RC<TokenSyntax> LocalName,
+                        RC<TokenSyntax> Colon,
+                        llvm::Optional<TypeSyntax> ParameterTypeSyntax,
+                        RC<TokenSyntax> Ellipsis,
+                        RC<TokenSyntax> Equal,
+                        llvm::Optional<ExprSyntax> DefaultValue,
+                        RC<TokenSyntax> TrailingComma);
+
+  /// Make a function parameter with all elements marked as missing.
+  static FunctionParameterSyntax makeBlankFunctionParameter();
+
+#pragma mark - function-parameter-list
+
+  /// Make a function parameter list with the given parameters.
+  static FunctionParameterListSyntax makeFunctionParameterList(
+    const std::vector<FunctionParameterSyntax> &Parameters);
+
+  /// Make an empty function parameter list.
+  static FunctionParameterListSyntax makeBlankFunctionParameterList();
+
+#pragma mark - function-signature
+
+  /// Make a function signature with the given elements.
+  static FunctionSignatureSyntax
+  makeFunctionSignature(RC<TokenSyntax> LeftParen,
+                        FunctionParameterListSyntax ParameterList,
+                        RC<TokenSyntax> RightParen,
+                        RC<TokenSyntax> ThrowsOrRethrows,
+                        RC<TokenSyntax> Arrow,
+                        TypeAttributesSyntax ReturnTypeAttributes,
+                        TypeSyntax ReturnTypeSyntax);
+
+  /// Make a blank function signature.
+  static FunctionSignatureSyntax makeBlankFunctionSignature();
+
+  //-/ Make a function declaration with the given elements.
+  // TODO
+
+  //-/ Make a blank function declaration.
+  // TODO
+
 #pragma mark - Statements
 
   /// Make a code block with the specified elements.
@@ -119,6 +198,12 @@
   /// marked as missing.
   static ReturnStmtSyntax makeBlankReturnStmt();
 
+  /// Make a statement list from a loosely connected list of statements.
+  static StmtListSyntax makeStmtList(const std::vector<StmtSyntax> &Statements);
+
+  /// Make an empty statement list.
+  static StmtListSyntax makeBlankStmtList();
+
 #pragma mark - Expressions
 
   /// Make an integer literal with the given '+'/'-' sign and string of digits.
@@ -168,6 +253,19 @@
 
 #pragma mark - Tokens
 
+  /// Make a 'static' keyword with the specified leading and trailing trivia.
+  static RC<TokenSyntax> makeStaticKeyword(const Trivia &LeadingTrivia,
+                                           const Trivia &TrailingTrivia);
+
+
+  /// Make a 'public' keyword with the specified leading and trailing trivia.
+  static RC<TokenSyntax> makePublicKeyword(const Trivia &LeadingTrivia,
+                                           const Trivia &TrailingTrivia);
+
+  /// Make a 'func' keyword with the specified leading and trailing trivia.
+  static RC<TokenSyntax> makeFuncKeyword(const Trivia &LeadingTrivia,
+                                         const Trivia &TrailingTrivia);
+
   /// Make a 'fallthrough' keyword with the specified leading and
   /// trailing trivia.
   static RC<TokenSyntax> makeFallthroughKeyword(const Trivia &LeadingTrivia,
@@ -213,6 +311,17 @@
   static RC<TokenSyntax> makeRightParenToken(const Trivia &LeadingTrivia,
                                             const Trivia &TrailingTrivia);
 
+  /// Make a left brace '{' token with the specified leading and
+  /// trailing trivia.
+  static RC<TokenSyntax> makeLeftBraceToken(const Trivia &LeadingTrivia,
+                                            const Trivia &TrailingTrivia);
+
+  /// Make a right brace '}' token with the specified leading and
+  /// trailing trivia.
+  static RC<TokenSyntax> makeRightBraceToken(const Trivia &LeadingTrivia,
+                                             const Trivia &TrailingTrivia);
+
+
   /// Make a left square bracket '[' token with the specified leading and
   /// trailing trivia.
   static RC<TokenSyntax>
@@ -333,6 +442,8 @@
   /// Make a set of type attributes with all elements marked as missing.
   static TypeAttributesSyntax makeBlankTypeAttributes();
 
+#pragma mark - balanced-tokens
+
   /// Make a list of balanced tokens.
   static BalancedTokensSyntax
   makeBalancedTokens(RawSyntax::LayoutList Tokens);
@@ -340,6 +451,8 @@
   /// Make an empty list of balanced tokens.
   static BalancedTokensSyntax makeBlankBalancedTokens();
 
+#pragma mark - type-identifier
+
   /// Make a non-generic type identifier with some name.
   static TypeIdentifierSyntax
   makeTypeIdentifier(OwnedString Name, const Trivia &LeadingTrivia,
@@ -356,6 +469,8 @@
   /// Make a bare "Self" type.
   static TypeIdentifierSyntax makeSelfTypeIdentifier();
 
+#pragma mark - tuple-type
+
   /// Make a bare "()" void tuple type
   static TupleTypeSyntax makeVoidTupleType();
 
@@ -366,6 +481,8 @@
   /// Make a tuple type element without a label.
   static TupleTypeElementSyntax makeTupleTypeElement(TypeSyntax ElementType);
 
+#pragma mark - optional-type
+
   /// Make an optional type, such as `Int?`
   static OptionalTypeSyntax
   makeOptionalType(TypeSyntax BaseType, const Trivia &TrailingTrivia);
@@ -373,6 +490,8 @@
   /// Make an optional type with all elements marked as missing.
   static OptionalTypeSyntax makeBlankOptionalType();
 
+#pragma mark - implicitly-unwrapped-optional-type
+
   /// Make an implicitly unwrapped optional type, such as `Int!`
   static ImplicitlyUnwrappedOptionalTypeSyntax
   makeImplicitlyUnwrappedOptionalType(TypeSyntax BaseType,
@@ -381,6 +500,8 @@
   static ImplicitlyUnwrappedOptionalTypeSyntax
   makeBlankImplicitlyUnwrappedOptionalType();
 
+#pragma mark - metatype-type
+
   /// Make a metatype type, as in `T.Type`
   /// `Type` is a terminal token here, not a placeholder for something else.
   static MetatypeTypeSyntax makeMetatypeType(TypeSyntax BaseType,
@@ -390,6 +511,8 @@
   /// Make a metatype type with all elements marked as missing.
   static MetatypeTypeSyntax makeBlankMetatypeType();
 
+#pragma mark - array-type
+
   /// Make a sugared Array type, as in `[MyType]`.
   static ArrayTypeSyntax makeArrayType(RC<TokenSyntax> LeftSquareBracket,
                                        TypeSyntax ElementType,
@@ -398,6 +521,8 @@
   /// Make an array type with all elements marked as missing.
   static ArrayTypeSyntax makeBlankArrayType();
 
+#pragma mark - dictionary-type
+
   /// Make a Dictionary type, as in `[Key : Value]`.
   static DictionaryTypeSyntax
   makeDictionaryType(RC<TokenSyntax> LeftSquareBracket, TypeSyntax KeyType,
@@ -407,6 +532,8 @@
   /// Make an a dictionary type with all elements marked as missing.
   static DictionaryTypeSyntax makeBlankDictionaryType();
 
+#pragma mark - function-type-argument
+
   /// Make a function argument type syntax with the specified elements.
   static FunctionTypeArgumentSyntax
   makeFunctionTypeArgument(RC<TokenSyntax> ExternalParameterName,
@@ -431,6 +558,8 @@
   /// Make a function argument type syntax with all elements marked as missing.
   static FunctionTypeArgumentSyntax makeBlankFunctionArgumentType();
 
+#pragma mark - function-type
+
   /// Make a function type, for example, `(Int, Int) throws -> Int`
   static FunctionTypeSyntax
   makeFunctionType(TypeAttributesSyntax TypeAttributes,
@@ -442,6 +571,8 @@
   /// Make a function type with all elements marked as missing.
   static FunctionTypeSyntax makeBlankFunctionType();
 
+#pragma mark - type-argument-list
+
   /// Make a list of type arguments with all elements marked as missing.
   static TypeArgumentListSyntax makeBlankTypeArgumentList();
 
@@ -464,6 +595,14 @@
   makeSameTypeRequirement(TypeIdentifierSyntax LeftTypeIdentifier,
                           RC<TokenSyntax> EqualityToken, TypeSyntax RightType);
 
+  /// Make a list of generic requirements with the given loosely collected
+  /// requirements/
+  static GenericRequirementListSyntax makeGenericRequirementList(
+    std::vector<GenericRequirementSyntax> &Requirements);
+
+  /// Make an empty list of generic requirements.
+  static GenericRequirementListSyntax makeBlankGenericRequirementList();
+
   /// Make a same-type requirement with all elements marked as missing.
   static SameTypeRequirementSyntax makeBlankSameTypeRequirement();
 
diff --git a/include/swift/Syntax/SyntaxKinds.def b/include/swift/Syntax/SyntaxKinds.def
index 941d50d..2c0fa59 100644
--- a/include/swift/Syntax/SyntaxKinds.def
+++ b/include/swift/Syntax/SyntaxKinds.def
@@ -40,8 +40,9 @@
   SYNTAX(UnknownDecl, DeclSyntax)
   SYNTAX(StructDecl, DeclSyntax)
   SYNTAX(TypeAliasDecl, DeclSyntax)
+  SYNTAX(FunctionDecl, DeclSyntax)
 
-SYNTAX_RANGE(Decl, MissingDecl, TypeAliasDecl)
+SYNTAX_RANGE(Decl, MissingDecl, FunctionDecl)
 
 SYNTAX(DeclMembers, Syntax)
 SYNTAX(GenericParameter, Syntax)
@@ -52,8 +53,9 @@
 SYNTAX(GenericRequirementList, Syntax)
 SYNTAX(GenericArgumentClause, Syntax)
 SYNTAX(GenericArgumentList, Syntax)
-SYNTAX(ConformanceRequirement, Syntax)
-SYNTAX(SameTypeRequirement, Syntax)
+ABSTRACT_SYNTAX(GenericRequirementSyntax, Syntax)
+  SYNTAX(ConformanceRequirement, GenericRequirementSyntax)
+  SYNTAX(SameTypeRequirement, GenericRequirementSyntax)
 SYNTAX(TypeArgumentList, Syntax)
 
 // Types
@@ -98,6 +100,11 @@
 SYNTAX(FunctionTypeArgument, Syntax)
 SYNTAX(FunctionCallArgumentList, Syntax)
 SYNTAX(FunctionCallArgument, Syntax)
+SYNTAX(FunctionSignature, Syntax)
+SYNTAX(FunctionParameterList, Syntax)
+SYNTAX(FunctionParameter, Syntax)
+SYNTAX(DeclModifier, Syntax)
+SYNTAX(DeclModifierList, Syntax)
 
 #undef ABSTRACT_SYNTAX
 #undef DECL
diff --git a/include/swift/Syntax/TypeSyntax.h b/include/swift/Syntax/TypeSyntax.h
index 07bf362..d8bee68 100644
--- a/include/swift/Syntax/TypeSyntax.h
+++ b/include/swift/Syntax/TypeSyntax.h
@@ -186,13 +186,16 @@
   friend struct SyntaxFactory;
   friend class TypeAttributesSyntaxData;
   friend class SyntaxData;
+  friend class FunctionSignatureSyntax;
+  friend class FunctionDeclSyntax;
 
   using DataType = TypeAttributesSyntaxData;
 
   TypeAttributesSyntax(RC<SyntaxData> Root,
                        const TypeAttributesSyntaxData *Data);
 public:
-  // TODO: TODO: TypeAttributesSyntax::getAttribute
+  // TODO: Convert to SyntaxCollection
+  // 
 
   TypeAttributesSyntax
   addTypeAttribute(TypeAttributeSyntax NewTypeAttribute) const;
@@ -235,6 +238,8 @@
 class TypeSyntax : public Syntax {
   using DataType = TypeSyntaxData;
   friend class SyntaxData;
+  friend class FunctionParameterSyntax;
+  friend class FunctionSignatureSyntax;
 protected:
   TypeSyntax(const RC<SyntaxData> Root, const TypeSyntaxData *Data);
 public:
diff --git a/include/swift/Syntax/UnknownSyntax.h b/include/swift/Syntax/UnknownSyntax.h
index 7158e03..39d265b 100644
--- a/include/swift/Syntax/UnknownSyntax.h
+++ b/include/swift/Syntax/UnknownSyntax.h
@@ -1,4 +1,4 @@
-//===--- UnknownSyntax.h - Swift Unknown Syntax Interface -----------------===//
+//===--- UnknownSyntax.h - Swift Unknown Syntax Interface -------*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 70f5135..1045062 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -28,6 +28,7 @@
 #include "swift/AST/LazyResolver.h"
 #include "swift/AST/ModuleLoader.h"
 #include "swift/AST/NameLookup.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/RawComment.h"
 #include "swift/AST/SILLayout.h"
 #include "swift/AST/TypeCheckerDebugConsumer.h"
@@ -3606,6 +3607,36 @@
   return nullptr;
 }
 
+bool ForeignRepresentationInfo::isRepresentableAsOptional() const {
+  switch (getKind()) {
+  case ForeignRepresentableKind::None:
+    llvm_unreachable("this type is not representable");
+
+  case ForeignRepresentableKind::Trivial:
+    return Storage.getPointer() != 0;
+
+  case ForeignRepresentableKind::Bridged: {
+    auto KPK_ObjectiveCBridgeable = KnownProtocolKind::ObjectiveCBridgeable;
+    ProtocolDecl *proto = getConformance()->getProtocol();
+    assert(proto->isSpecificProtocol(KPK_ObjectiveCBridgeable) &&
+           "unknown protocol; does it support optional?");
+    (void)proto;
+    (void)KPK_ObjectiveCBridgeable;
+
+    return true;
+  }
+
+  case ForeignRepresentableKind::BridgedError:
+    return true;
+
+  case ForeignRepresentableKind::Object:
+  case ForeignRepresentableKind::StaticBridged:
+    llvm_unreachable("unexpected kind in ForeignRepresentableCacheEntry");
+  }
+
+  llvm_unreachable("Unhandled ForeignRepresentableKind in switch.");
+}
+
 ForeignRepresentationInfo
 ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
                                          ForeignLanguage language,
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 7be8ea7..9d35f66 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -29,6 +29,7 @@
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/Support/raw_ostream.h"
@@ -207,6 +208,8 @@
   case SILFunctionType::Representation::WitnessMethod: return "witness_method";
   case SILFunctionType::Representation::Closure: return "closure";
   }
+
+  llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
 }
 static StringRef
 getAbstractStorageDeclKindString(AbstractStorageDecl::StorageKindTy value) {
@@ -230,6 +233,8 @@
   case AbstractStorageDecl::Computed:
     return "computed";
   }
+
+  llvm_unreachable("Unhandled AbstractStorageDecl in switch.");
 }
 static StringRef getImportKindString(ImportKind value) {
   switch (value) {
@@ -242,6 +247,8 @@
   case ImportKind::Var: return "var";
   case ImportKind::Func: return "func";
   }
+  
+  llvm_unreachable("Unhandled ImportKind in switch.");
 }
 static StringRef getAccessibilityString(Accessibility value) {
   switch (value) {
@@ -251,6 +258,8 @@
   case Accessibility::Public: return "public";
   case Accessibility::Open: return "open";
   }
+
+  llvm_unreachable("Unhandled Accessibility in switch.");
 }
 static StringRef
 getForeignErrorConventionKindString(ForeignErrorConvention::Kind value) {
@@ -261,6 +270,8 @@
   case ForeignErrorConvention::NilResult: return "NilResult";
   case ForeignErrorConvention::NonNilError: return "NonNilError";
   }
+
+  llvm_unreachable("Unhandled ForeignErrorConvention in switch.");
 }
 static StringRef getDefaultArgumentKindString(DefaultArgumentKind value) {
   switch (value) {
@@ -276,6 +287,8 @@
     case DefaultArgumentKind::EmptyDictionary: return "[:]";
     case DefaultArgumentKind::Normal: return "normal";
   }
+
+  llvm_unreachable("Unhandled DefaultArgumentKind in switch.");
 }
 static StringRef getAccessorKindString(AccessorKind value) {
   switch (value) {
@@ -288,6 +301,8 @@
     case AccessorKind::IsAddressor: return "addressor";
     case AccessorKind::IsMutableAddressor: return "mutableAddressor";
   }
+
+  llvm_unreachable("Unhandled AccessorKind in switch.");
 }
 static StringRef getAccessKindString(AccessKind value) {
   switch (value) {
@@ -295,6 +310,8 @@
     case AccessKind::Write: return "write";
     case AccessKind::ReadWrite: return "readwrite";
   }
+
+  llvm_unreachable("Unhandled AccessKind in switch.");
 }
 static StringRef
 getMagicIdentifierLiteralExprKindString(MagicIdentifierLiteralExpr::Kind value) {
@@ -305,6 +322,8 @@
     case MagicIdentifierLiteralExpr::Column: return "#column";
     case MagicIdentifierLiteralExpr::DSOHandle: return "#dsohandle";
   }
+
+  llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
 }
 static StringRef
 getObjCSelectorExprKindString(ObjCSelectorExpr::ObjCSelectorKind value) {
@@ -313,6 +332,8 @@
     case ObjCSelectorExpr::Getter: return "getter";
     case ObjCSelectorExpr::Setter: return "setter";
   }
+
+  llvm_unreachable("Unhandled ObjCSelectorExpr in switch.");
 }
 static StringRef getAccessSemanticsString(AccessSemantics value) {
   switch (value) {
@@ -321,6 +342,8 @@
     case AccessSemantics::DirectToAccessor: return "direct_to_accessor";
     case AccessSemantics::BehaviorInitialization: return "behavior_init";
   }
+
+  llvm_unreachable("Unhandled AccessSemantics in switch.");
 }
 static StringRef getMetatypeRepresentationString(MetatypeRepresentation value) {
   switch (value) {
@@ -328,6 +351,8 @@
     case MetatypeRepresentation::Thick: return "thick";
     case MetatypeRepresentation::ObjC: return "@objc";
   }
+
+  llvm_unreachable("Unhandled MetatypeRepresentation in switch.");
 }
 static StringRef
 getStringLiteralExprEncodingString(StringLiteralExpr::Encoding value) {
@@ -336,6 +361,8 @@
     case StringLiteralExpr::UTF16: return "utf16";
     case StringLiteralExpr::OneUnicodeScalar: return "unicodeScalar";
   }
+
+  llvm_unreachable("Unhandled StringLiteral in switch.");
 }
 static StringRef getCtorInitializerKindString(CtorInitializerKind value) {
   switch (value) {
@@ -344,6 +371,8 @@
     case CtorInitializerKind::ConvenienceFactory: return "convenience_factory";
     case CtorInitializerKind::Factory: return "factory";
   }
+
+  llvm_unreachable("Unhandled CtorInitializerKind in switch.");
 }
 static StringRef getOptionalTypeKindString(OptionalTypeKind value) {
   switch (value) {
@@ -351,6 +380,8 @@
     case OTK_Optional: return "Optional";
     case OTK_ImplicitlyUnwrappedOptional: return "ImplicitlyUnwrappedOptional";
   }
+
+  llvm_unreachable("Unhandled OptionalTypeKind in switch.");
 }
 static StringRef getAssociativityString(Associativity value) {
   switch (value) {
@@ -358,6 +389,8 @@
     case Associativity::Left: return "left";
     case Associativity::Right: return "right";
   }
+
+  llvm_unreachable("Unhandled Associativity in switch.");
 }
 
 //===----------------------------------------------------------------------===//
@@ -2615,10 +2648,18 @@
   };
 
   switch (getKind()) {
-  case ProtocolConformanceKind::Normal:
+  case ProtocolConformanceKind::Normal: {
+    auto normal = cast<NormalProtocolConformance>(this);
+
     printCommon("normal");
     // Maybe print information about the conforming context?
+
+    for (auto conformance : normal->getSignatureConformances()) {
+      out << '\n';
+      conformance.dump(out, indent + 2);
+    }
     break;
+  }
 
   case ProtocolConformanceKind::Inherited: {
     auto conf = cast<InheritedProtocolConformance>(this);
@@ -3109,13 +3150,17 @@
   Type(const_cast<TypeBase *>(this)).dump(os, indent);
 }
 
-void GenericEnvironment::dump() const {
-  llvm::errs() << "Generic environment:\n";
+void GenericEnvironment::dump(raw_ostream &os) const {
+  os << "Generic environment:\n";
   for (auto gp : getGenericParams()) {
-    gp->dump();
-    mapTypeIntoContext(gp)->dump();
+    gp->dump(os);
+    mapTypeIntoContext(gp)->dump(os);
   }
-  llvm::errs() << "Generic parameters:\n";
+  os << "Generic parameters:\n";
   for (auto paramTy : getGenericParams())
-    paramTy->dump();
+    paramTy->dump(os);
+}
+
+void GenericEnvironment::dump() const {
+  dump(llvm::errs());
 }
diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
index e70cdfb..03cb39b 100644
--- a/lib/AST/ASTVerifier.cpp
+++ b/lib/AST/ASTVerifier.cpp
@@ -1997,7 +1997,8 @@
 
         if (auto req = dyn_cast<ValueDecl>(member)) {
           if (!normal->hasWitness(req)) {
-            if (req->getAttrs().isUnavailable(Ctx) &&
+            if ((req->getAttrs().isUnavailable(Ctx) ||
+                 req->getAttrs().hasAttribute<OptionalAttr>()) &&
                 proto->isObjC()) {
               continue;
             }
@@ -2025,6 +2026,40 @@
           continue;
         }
       }
+
+      // Make sure we have the right signature conformances.
+      if (!normal->isInvalid()){
+        auto conformances = normal->getSignatureConformances();
+        unsigned idx = 0;
+        for (auto req : proto->getRequirementSignature()->getRequirements()) {
+          if (req.getKind() != RequirementKind::Conformance)
+            continue;
+
+          if (idx >= conformances.size()) {
+            Out << "error: not enough conformances for requirement signature\n";
+            normal->dump(Out);
+            abort();
+          }
+
+          auto reqProto =
+            req.getSecondType()->castTo<ProtocolType>()->getDecl();
+          if (reqProto != conformances[idx].getRequirement()) {
+            Out << "error: wrong protocol in signature conformances: have "
+              << conformances[idx].getRequirement()->getName().str()
+              << ", expected " << reqProto->getName().str()<< "\n";
+            normal->dump(Out);
+            abort();
+          }
+
+          ++idx;
+        }
+
+        if (idx != conformances.size()) {
+          Out << "error: too many conformances for requirement signature\n";
+          normal->dump(Out);
+          abort();
+        }
+      }
     }
 
     void verifyGenericEnvironment(Decl *D,
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index 3bdcbe3..e790ae4 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -197,6 +197,10 @@
   }
 
   bool visitAbstractTypeParamDecl(AbstractTypeParamDecl *TPD) {
+    for (auto Inherit: TPD->getInherited()) {
+      if (doIt(Inherit))
+        return true;
+    }
     return false;
   }
 
@@ -207,10 +211,6 @@
       for (auto GP : NTD->getGenericParams()->getParams()) {
         if (doIt(GP))
           return true;
-        for(auto Inherit: GP->getInherited()) {
-          if (doIt(Inherit))
-            return true;
-        }
       }
       // Visit param conformance
       for (auto &Req : NTD->getGenericParams()->getRequirements()) {
@@ -266,10 +266,6 @@
       for (auto &P : AFD->getGenericParams()->getParams()) {
         if (doIt(P))
           return true;
-        for (auto Inherit : P->getInherited()) {
-          if (doIt(Inherit))
-            return true;
-        }
       }
 
       // Visit param conformance
diff --git a/lib/AST/ForeignRepresentationInfo.h b/lib/AST/ForeignRepresentationInfo.h
index 7dd0629..05fdb94 100644
--- a/lib/AST/ForeignRepresentationInfo.h
+++ b/lib/AST/ForeignRepresentationInfo.h
@@ -13,7 +13,6 @@
 #ifndef SWIFT_FOREIGNREPRESENTATIONINFO_H
 #define SWIFT_FOREIGNREPRESENTATIONINFO_H
 
-#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/Type.h"
 #include "swift/Basic/LLVM.h"
 #include "llvm/ADT/PointerEmbeddedInt.h"
@@ -21,6 +20,8 @@
 
 namespace swift {
 
+class ProtocolConformance;
+
 class ForeignRepresentationInfo {
   using PayloadTy =
     llvm::PointerEmbeddedInt<uintptr_t, sizeof(uintptr_t) * CHAR_BIT - 3>;
@@ -112,35 +113,7 @@
   }
 
   /// Returns true if the optional version of this type is also representable.
-  bool isRepresentableAsOptional() const {
-    switch (getKind()) {
-    case ForeignRepresentableKind::None:
-      llvm_unreachable("this type is not representable");
-
-    case ForeignRepresentableKind::Trivial:
-      return Storage.getPointer() != 0;
-
-    case ForeignRepresentableKind::Bridged: {
-      auto KPK_ObjectiveCBridgeable = KnownProtocolKind::ObjectiveCBridgeable;
-      ProtocolDecl *proto = getConformance()->getProtocol();
-      assert(proto->isSpecificProtocol(KPK_ObjectiveCBridgeable) &&
-             "unknown protocol; does it support optional?");
-      (void)proto;
-      (void)KPK_ObjectiveCBridgeable;
-
-      return true;
-    }
-
-    case ForeignRepresentableKind::BridgedError:
-      return true;
-
-    case ForeignRepresentableKind::Object:
-    case ForeignRepresentableKind::StaticBridged:
-      llvm_unreachable("unexpected kind in ForeignRepresentableCacheEntry");
-    }
-
-    llvm_unreachable("Unhandled ForeignRepresentableKind in switch.");
-  }
+  bool isRepresentableAsOptional() const;
 };
 
 } // end namespace swift
diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp
index a1f739b..e2e805a 100644
--- a/lib/AST/GenericEnvironment.cpp
+++ b/lib/AST/GenericEnvironment.cpp
@@ -395,25 +395,27 @@
 getSubstitutionMap(SubstitutionList subs) const {
   SubstitutionMap result;
 
-  for (auto depTy : getGenericSignature()->getAllDependentTypes()) {
+  getGenericSignature()->enumeratePairedRequirements(
+    [&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
+      // Map the interface type to a context type.
+      auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this),
+                                   MakeAbstractConformanceForGenericType());
 
-    // Map the interface type to a context type.
-    auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this),
-                                 MakeAbstractConformanceForGenericType());
+      auto sub = subs.front();
+      subs = subs.slice(1);
 
-    auto sub = subs.front();
-    subs = subs.slice(1);
+      // Record the replacement type and its conformances.
+      if (auto *archetype = contextTy->getAs<ArchetypeType>()) {
+        result.addSubstitution(CanArchetypeType(archetype), sub.getReplacement());
+        assert(reqts.size() == sub.getConformances().size());
+        for (auto conformance : sub.getConformances())
+          result.addConformance(CanType(archetype), conformance);
+        return false;
+      }
 
-    // Record the replacement type and its conformances.
-    if (auto *archetype = contextTy->getAs<ArchetypeType>()) {
-      result.addSubstitution(CanArchetypeType(archetype), sub.getReplacement());
-      for (auto conformance : sub.getConformances())
-        result.addConformance(CanType(archetype), conformance);
-      continue;
-    }
-
-    assert(contextTy->hasError());
-  }
+      assert(contextTy->hasError());
+      return false;
+    });
 
   assert(subs.empty() && "did not use all substitutions?!");
 
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 56747a6..d4c5b3b 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -78,6 +78,20 @@
   return params;
 }
 
+
+SmallVector<GenericTypeParamType *, 2>
+GenericSignature::getSubstitutableParams() const {
+  SmallVector<GenericTypeParamType *, 2> result;
+
+  enumeratePairedRequirements([&](Type depTy, ArrayRef<Requirement>) -> bool {
+    if (auto *paramTy = depTy->getAs<GenericTypeParamType>())
+      result.push_back(paramTy);
+    return false;
+  });
+
+  return result;
+}
+
 std::string GenericSignature::gatherGenericParamBindingsText(
     ArrayRef<Type> types, TypeSubstitutionFn substitutions) const {
   llvm::SmallPtrSet<GenericTypeParamType *, 2> knownGenericParams;
@@ -375,21 +389,21 @@
 GenericSignature::getSubstitutionMap(SubstitutionList subs) const {
   SubstitutionMap result;
 
-  // An empty parameter list gives an empty map.
-  if (subs.empty())
-    assert(getGenericParams().empty() || areAllParamsConcrete());
+  enumeratePairedRequirements(
+    [&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
+      auto sub = subs.front();
+      subs = subs.slice(1);
 
-  for (auto depTy : getAllDependentTypes()) {
-    auto sub = subs.front();
-    subs = subs.slice(1);
+      auto canTy = depTy->getCanonicalType();
+      if (isa<SubstitutableType>(canTy))
+        result.addSubstitution(cast<SubstitutableType>(canTy),
+                               sub.getReplacement());
+      assert(reqts.size() == sub.getConformances().size());
+      for (auto conformance : sub.getConformances())
+        result.addConformance(canTy, conformance);
 
-    auto canTy = depTy->getCanonicalType();
-    if (isa<SubstitutableType>(canTy))
-      result.addSubstitution(cast<SubstitutableType>(canTy),
-                             sub.getReplacement());
-    for (auto conformance : sub.getConformances())
-      result.addConformance(canTy, conformance);
-  }
+      return false;
+    });
 
   assert(subs.empty() && "did not use all substitutions?!");
   populateParentMap(result);
@@ -430,16 +444,6 @@
   return subMap;
 }
 
-SmallVector<Type, 4> GenericSignature::getAllDependentTypes() const {
-  SmallVector<Type, 4> result;
-  enumeratePairedRequirements([&](Type type, ArrayRef<Requirement>) {
-    result.push_back(type);
-    return false;
-  });
-
-  return result;
-}
-
 void GenericSignature::
 getSubstitutions(const TypeSubstitutionMap &subs,
                  GenericSignature::LookupConformanceFn lookupConformance,
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index b3f69c4..71dc8b2 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -160,6 +160,8 @@
       return false;
     }
   }
+
+  llvm_unreachable("Unhandled RequirementSourceKind in switch.");
 }
 
 const void *RequirementSource::getOpaqueStorage() const {
@@ -182,6 +184,8 @@
   case StorageKind::AssociatedTypeDecl:
     return storage.assocType;
   }
+
+  llvm_unreachable("Unhandled StorageKind in switch.");
 }
 
 const void *RequirementSource::getExtraOpaqueStorage() const {
@@ -210,6 +214,8 @@
     // need to keep them for the requirement signature.
     return parent->kind != RequirementSignatureSelf;
   }
+
+  llvm_unreachable("Unhandled RequirementSourceKind in switch.");
 }
 
 bool RequirementSource::isDerivedViaConcreteConformance() const {
@@ -418,6 +424,8 @@
   case StorageKind::AssociatedTypeDecl:
     return storage.assocType->getProtocol();
   }
+
+  llvm_unreachable("Unhandled StorageKind in switch.");
 }
 
 SourceLoc RequirementSource::getLoc() const {
@@ -569,6 +577,8 @@
   case Inferred:
     return RequirementSource::forInferred(pa, storage.get<const TypeRepr *>());
   }
+
+  llvm_unreachable("Unhandled FloatingPointRequirementSourceKind in switch.");
 }
 
 SourceLoc FloatingRequirementSource::getLoc() const {
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index 52e5a4e..aeb4904 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -252,6 +252,25 @@
   return getRootNormalConformance()->getBehaviorDecl();
 }
 
+void NormalProtocolConformance::setSignatureConformances(
+                               ArrayRef<ProtocolConformanceRef> conformances) {
+  auto &ctx = getProtocol()->getASTContext();
+  SignatureConformances = ctx.AllocateCopy(conformances);
+
+#if !NDEBUG
+  unsigned idx = 0;
+  for (auto req : getProtocol()->getRequirementSignature()->getRequirements()) {
+    if (req.getKind() == RequirementKind::Conformance) {
+      assert(idx < conformances.size());
+      assert(conformances[idx].getRequirement() ==
+               req.getSecondType()->castTo<ProtocolType>()->getDecl());
+      ++idx;
+    }
+  }
+  assert(idx == conformances.size() && "Too many conformances");
+#endif
+}
+
 void NormalProtocolConformance::resolveLazyInfo() const {
   assert(Resolver);
   assert(isComplete());
@@ -317,6 +336,103 @@
   TypeWitnesses[assocType] = std::make_pair(substitution, typeDecl);
 }
 
+/// TypeWitnesses is keyed by the protocol's own declarations, but
+/// DependentMemberTypes will sometimes store a base protocol's declaration.
+/// Map to the derived declaration if possible.
+static AssociatedTypeDecl *getOwnAssociatedTypeDecl(ProtocolDecl *protocol,
+                                                    AssociatedTypeDecl *assoc) {
+  // Fast path.
+  if (assoc->getProtocol() == protocol) return assoc;
+
+  // Search the protocol.
+  for (auto member : protocol->getMembers()) {
+    if (auto memberAssoc = dyn_cast<AssociatedTypeDecl>(member)) {
+      if (memberAssoc->getName() == assoc->getName()) {
+        return memberAssoc;
+      }
+    }
+  }
+
+  // Just assume this is fine.
+  return assoc;
+}
+
+Type NormalProtocolConformance::getAssociatedType(Type assocType,
+                                                LazyResolver *resolver) const {
+  assert(assocType->isTypeParameter() &&
+         "associated type must be a type parameter");
+
+  // Fast path.
+  auto type = assocType->getCanonicalType();
+  if (isa<GenericTypeParamType>(type)) {
+    assert(type->isEqual(getProtocol()->getSelfInterfaceType()) &&
+           "type parameter in protocol was not Self");
+    return getType();
+  }
+
+  auto memberType = cast<DependentMemberType>(type);
+
+  // TODO: make this handle multiple levels of dependent member type.
+  assert(memberType.getBase()->isEqual(getProtocol()->getSelfInterfaceType()) &&
+         "dependent member in protocol was not rooted in Self");
+
+  auto assocTypeDecl =
+    getOwnAssociatedTypeDecl(getProtocol(), memberType->getAssocType());
+  auto &subst = getTypeWitnessSubstAndDecl(assocTypeDecl, resolver).first;
+  return subst.getReplacement();
+}
+
+ProtocolConformanceRef
+NormalProtocolConformance::getAssociatedConformance(Type assocType,
+                                                    ProtocolDecl *protocol,
+                                                LazyResolver *resolver) const {
+  assert(assocType->isTypeParameter() &&
+         "associated type must be a type parameter");
+
+#ifndef NDEBUG
+  bool foundInRequirements = false;
+  for (auto &reqt :
+         getProtocol()->getRequirementSignature()->getRequirements()) {
+    if (reqt.getKind() == RequirementKind::Conformance &&
+        reqt.getFirstType()->isEqual(assocType) &&
+        reqt.getSecondType()->castTo<ProtocolType>()->getDecl() == protocol) {
+      foundInRequirements = true;
+      break;
+    }
+  }
+  assert(foundInRequirements &&
+         "requested conformance was not a direct requirement of the protocol");
+#endif
+
+  auto type = assocType->getCanonicalType();
+
+  if (isa<GenericTypeParamType>(type)) {
+    assert(type->isEqual(getProtocol()->getSelfInterfaceType()) &&
+           "type parameter in protocol was not Self");
+    auto conf = getInheritedConformance(protocol);
+    assert(conf && "inherited conformances cannot be abstract");
+    return ProtocolConformanceRef(conf);
+  }
+
+  auto memberType = cast<DependentMemberType>(type);
+
+  // For now, NormalProtocolConformance does not store indirect associations.
+  assert(memberType.getBase()->isEqual(getProtocol()->getSelfInterfaceType()) &&
+         "dependent member in protocol was not rooted in Self");
+
+  auto assocTypeDecl =
+    getOwnAssociatedTypeDecl(getProtocol(), memberType->getAssocType());
+  auto &subst = getTypeWitnessSubstAndDecl(assocTypeDecl, resolver).first;
+
+  // Scan the conformances for the exact conformance.
+  // TODO: should we allow indirect conformances for convenience of use?
+  for (auto &conf : subst.getConformances()) {
+    if (conf.getRequirement() == protocol)
+      return conf;
+  }
+  llvm_unreachable("missing conformance to protocol");
+}
+
   /// Retrieve the value witness corresponding to the given requirement.
 Witness NormalProtocolConformance::getWitness(ValueDecl *requirement,
                                               LazyResolver *resolver) const {
@@ -347,7 +463,11 @@
   assert(getProtocol() == cast<ProtocolDecl>(requirement->getDeclContext()) &&
          "requirement in wrong protocol");
   assert(Mapping.count(requirement) == 0 && "Witness already known");
-  assert((!isComplete() || isInvalid()) && "Conformance already complete?");
+  assert((!isComplete() || isInvalid() ||
+          requirement->getAttrs().hasAttribute<OptionalAttr>() ||
+          requirement->getAttrs().isUnavailable(
+                                        requirement->getASTContext())) &&
+				 "Conformance already complete?");
   Mapping[requirement] = witness;
 }
 
diff --git a/lib/AST/SourceEntityWalker.cpp b/lib/AST/SourceEntityWalker.cpp
index d6a28c3..5aa4cbf 100644
--- a/lib/AST/SourceEntityWalker.cpp
+++ b/lib/AST/SourceEntityWalker.cpp
@@ -335,6 +335,9 @@
 }
 
 std::pair<bool, Pattern *> SemaAnnotator::walkToPatternPre(Pattern *P) {
+  if (P->isImplicit())
+    return { true, P };
+
   if (auto *EP = dyn_cast<EnumElementPattern>(P)) {
     auto *Element = EP->getElementDecl();
     if (!Element)
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 659ad44..e801028 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -23,6 +23,7 @@
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/LazyResolver.h"
 #include "swift/AST/Module.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/SubstitutionMap.h"
 #include "swift/AST/TypeLoc.h"
 #include "llvm/ADT/APFloat.h"
diff --git a/lib/Basic/Demangle.cpp b/lib/Basic/Demangle.cpp
index 281883f..af9bb55 100644
--- a/lib/Basic/Demangle.cpp
+++ b/lib/Basic/Demangle.cpp
@@ -2331,7 +2331,9 @@
 bool
 swift::Demangle::isSwiftSymbol(const char *mangledName) {
   // The old mangling.
-  if (mangledName[0] == '_' && mangledName[1] == 'T')
+  if (mangledName[0] == '_'
+      // Also accept the future mangling prefix.
+      && (mangledName[1] == 'T' || mangledName[1] == 'S'))
     return true;
 
   // The new mangling.
diff --git a/lib/Basic/Demangler.cpp b/lib/Basic/Demangler.cpp
index 70ded11..0856944 100644
--- a/lib/Basic/Demangler.cpp
+++ b/lib/Basic/Demangler.cpp
@@ -137,7 +137,10 @@
 
 NodePointer Context::demangleSymbolAsNode(llvm::StringRef MangledName) {
 #ifndef NO_NEW_DEMANGLING
-  if (MangledName.startswith(MANGLING_PREFIX_STR)) {
+  if (MangledName.startswith(MANGLING_PREFIX_STR)
+      // Also accept the future mangling prefix.
+      // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S".
+      || MangledName.startswith("_S")) {
     return D->demangleSymbol(MangledName);
   }
 #endif
@@ -171,7 +174,10 @@
 }
 
 bool Context::isThunkSymbol(llvm::StringRef MangledName) {
-  if (MangledName.startswith(MANGLING_PREFIX_STR)) {
+  if (MangledName.startswith(MANGLING_PREFIX_STR)
+      // Also accept the future mangling prefix.
+      // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S".
+      || MangledName.startswith("_S")) {
     // First do a quick check
     if (MangledName.endswith("TA") ||  // partial application forwarder
         MangledName.endswith("Ta") ||  // ObjC partial application forwarder
@@ -202,13 +208,60 @@
     StringRef Remaining = MangledName.substr(2);
     if (Remaining.startswith("To") ||   // swift-as-ObjC thunk
         Remaining.startswith("TO") ||   // ObjC-as-swift thunk
-        Remaining.startswith("PA")) {  // (ObjC) partial application forwarder
+        Remaining.startswith("PA_") ||  // partial application forwarder
+        Remaining.startswith("PAo_")) { // ObjC partial application forwarder
       return true;
     }
   }
   return false;
 }
-  
+
+std::string Context::getThunkTarget(llvm::StringRef MangledName) {
+  if (!isThunkSymbol(MangledName))
+    return std::string();
+
+  if (MangledName.startswith(MANGLING_PREFIX_STR)
+      // Also accept the future mangling prefix.
+      // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S".
+      || MangledName.startswith("_S")) {
+
+    return MangledName.substr(0, MangledName.size() - 2).str();
+  }
+  // Old mangling.
+  assert(MangledName.startswith("_T"));
+  StringRef Remaining = MangledName.substr(2);
+  if (Remaining.startswith("PA_"))
+    return Remaining.substr(3).str();
+  if (Remaining.startswith("PAo_"))
+    return Remaining.substr(4).str();
+  assert(Remaining.startswith("To") || Remaining.startswith("TO"));
+  return std::string("_T") + Remaining.substr(2).str();
+}
+
+bool Context::hasSwiftCallingConvention(llvm::StringRef MangledName) {
+  Node *Global = demangleSymbolAsNode(MangledName);
+  if (!Global || Global->getKind() != Node::Kind::Global ||
+      Global->getNumChildren() == 0)
+    return false;
+
+  Node *TopLevel = Global->getFirstChild();
+  switch (TopLevel->getKind()) {
+    // Functions, which don't have the swift calling conventions:
+    case Node::Kind::TypeMetadataAccessFunction:
+    case Node::Kind::ValueWitness:
+    case Node::Kind::ProtocolWitnessTableAccessor:
+    case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
+    case Node::Kind::LazyProtocolWitnessTableAccessor:
+    case Node::Kind::AssociatedTypeMetadataAccessor:
+    case Node::Kind::AssociatedTypeWitnessTableAccessor:
+    case Node::Kind::ObjCAttribute:
+      return false;
+    default:
+      break;
+  }
+  return true;
+}
+
 NodePointer Context::createNode(Node::Kind K) {
   return D->createNode(K);
 }
@@ -257,6 +310,11 @@
   addChild(Child, *Ctx.D);
 }
 
+void Node::reverseChildren(size_t StartingAt) {
+  assert(StartingAt <= NumChildren);
+  std::reverse(Children + StartingAt, Children + NumChildren);
+}
+
 //////////////////////////////////
 // NodeFactory member functions //
 //////////////////////////////////
@@ -297,18 +355,49 @@
 NodePointer NodeFactory::createNode(Node::Kind K, llvm::StringRef Text) {
   return new (Allocate<Node>()) Node(K, Text.copy(*this));
 }
+NodePointer NodeFactory::createNode(Node::Kind K, const CharVector &Text) {
+  return new (Allocate<Node>()) Node(K, Text.str());
+}
 NodePointer NodeFactory::createNode(Node::Kind K, const char *Text) {
   return new (Allocate<Node>()) Node(K, llvm::StringRef(Text));
 }
 
 //////////////////////////////////
+// CharVector member functions  //
+//////////////////////////////////
+
+void CharVector::append(StringRef Rhs, NodeFactory &Factory) {
+  if (NumElems + Rhs.size() > Capacity)
+    Factory.Reallocate(Elems, Capacity, /*Growth*/ Rhs.size());
+  memcpy(Elems + NumElems, Rhs.data(), Rhs.size());
+  NumElems += Rhs.size();
+  assert(NumElems <= Capacity);
+}
+
+void CharVector::append(int Number, NodeFactory &Factory) {
+  const int MaxIntPrintSize = 8;
+  if (NumElems + MaxIntPrintSize > Capacity)
+    Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxIntPrintSize);
+  int Length = snprintf(Elems + NumElems, MaxIntPrintSize, "%d", Number);
+  assert(Length > 0 && Length < MaxIntPrintSize);
+  NumElems += Length;
+}
+
+//////////////////////////////////
 // Demangler member functions   //
 //////////////////////////////////
 
+void Demangler::clear() {
+  NodeStack.free();
+  Substitutions.free();
+  PendingSubstitutions.free();
+  NodeFactory::clear();
+}
+
 void Demangler::init(StringRef MangledName) {
-  NodeStack.clear();
-  Substitutions.clear();
-  PendingSubstitutions.clear();
+  NodeStack.init(*this, 16);
+  Substitutions.init(*this, 16);
+  PendingSubstitutions.init(*this, 4);
   NumWords = 0;
   Text = MangledName;
   Pos = 0;
@@ -317,7 +406,10 @@
 NodePointer Demangler::demangleSymbol(StringRef MangledName) {
   init(MangledName);
 
-  if (!nextIf(MANGLING_PREFIX_STR))
+  if (!nextIf(MANGLING_PREFIX_STR)
+      // Also accept the future mangling prefix.
+      // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S".
+      && !nextIf("_S"))
     return nullptr;
 
   NodePointer topLevel = createNode(Node::Kind::Global);
@@ -625,7 +717,7 @@
       hasWordSubsts = true;
     }
   }
-  std::string Identifier;
+  CharVector Identifier;
   do {
     while (hasWordSubsts && isLetter(peekChar())) {
       char c = nextChar();
@@ -641,7 +733,7 @@
         return nullptr;
       assert(WordIdx < MaxNumWords);
       StringRef Slice = Words[WordIdx];
-      Identifier.append(Slice.data(), Slice.size());
+      Identifier.append(Slice, *this);
     }
     if (nextIf('0'))
       break;
@@ -654,10 +746,12 @@
       return nullptr;
     StringRef Slice = StringRef(Text.data() + Pos, numChars);
     if (isPunycoded) {
-      if (!Punycode::decodePunycodeUTF8(Slice, Identifier))
+      std::string PunycodedString;
+      if (!Punycode::decodePunycodeUTF8(Slice, PunycodedString))
         return nullptr;
+      Identifier.append(StringRef(PunycodedString), *this);
     } else {
-      Identifier.append(Slice.data(), Slice.size());
+      Identifier.append(Slice, *this);
       int wordStartPos = -1;
       for (int Idx = 0, End = (int)Slice.size(); Idx <= End; ++Idx) {
         char c = (Idx < End ? Slice[Idx] : 0);
@@ -688,12 +782,11 @@
 
   static const char op_char_table[] = "& @/= >    <*!|+?%-~   ^ .";
 
-  std::string OpStr;
-  OpStr.reserve(Ident->getText().size());
+  CharVector OpStr;
   for (signed char c : Ident->getText()) {
     if (c < 0) {
       // Pass through Unicode characters.
-      OpStr.push_back(c);
+      OpStr.push_back(c, *this);
       continue;
     }
     if (!isLowerLetter(c))
@@ -701,7 +794,7 @@
     char o = op_char_table[c - 'a'];
     if (o == ' ')
       return nullptr;
-    OpStr.push_back(o);
+    OpStr.push_back(o, *this);
   }
   switch (nextChar()) {
     case 'i': return createNode(Node::Kind::InfixOperator, OpStr);
@@ -772,16 +865,20 @@
       int size = demangleIndex() - 1;
       if (size <= 0)
         return nullptr;
-      Ty = createNode(Node::Kind::BuiltinTypeName,
-               std::move(DemanglerPrinter() << "Builtin.Float" << size).str());
+      CharVector name;
+      name.append("Builtin.Float", *this);
+      name.append(size, *this);
+      Ty = createNode(Node::Kind::BuiltinTypeName, name);
       break;
     }
     case 'i': {
       int size = demangleIndex() - 1;
       if (size <= 0)
         return nullptr;
-      Ty = createNode(Node::Kind::BuiltinTypeName,
-                          (DemanglerPrinter() << "Builtin.Int" << size).str());
+      CharVector name;
+      name.append("Builtin.Int", *this);
+      name.append(size, *this);
+      Ty = createNode(Node::Kind::BuiltinTypeName, name);
       break;
     }
     case 'v': {
@@ -792,9 +889,12 @@
       if (!EltType || EltType->getKind() != Node::Kind::BuiltinTypeName ||
           !EltType->getText().startswith("Builtin."))
         return nullptr;
-      Ty = createNode(Node::Kind::BuiltinTypeName,
-                      (DemanglerPrinter() << "Builtin.Vec" << elts << "x" <<
-                      EltType->getText().substr(sizeof("Builtin.") - 1)).str());
+      CharVector name;
+      name.append("Builtin.Vec", *this);
+      name.append(elts, *this);
+      name.push_back('x', *this);
+      name.append(EltType->getText().substr(sizeof("Builtin.") - 1), *this);
+      Ty = createNode(Node::Kind::BuiltinTypeName, name);
       break;
     }
     case 'O':
@@ -880,7 +980,6 @@
                                          Node::Kind::NonVariadicTuple);
 
   if (!popNode(Node::Kind::EmptyList)) {
-    std::vector<NodePointer> Nodes;
     bool firstElem = false;
     do {
       firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
@@ -893,12 +992,10 @@
       if (!Ty)
         return nullptr;
       TupleElmt->addChild(Ty, *this);
-      Nodes.push_back(TupleElmt);
+      Root->addChild(TupleElmt, *this);
     } while (!firstElem);
 
-    while (NodePointer TupleElmt = pop_back_val(Nodes)) {
-      Root->addChild(TupleElmt, *this);
-    }
+    Root->reverseChildren();
   }
   return createType(Root);
 }
@@ -907,18 +1004,16 @@
   NodePointer Root = createNode(Node::Kind::TypeList);
 
   if (!popNode(Node::Kind::EmptyList)) {
-    std::vector<NodePointer> Nodes;
     bool firstElem = false;
     do {
       firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
       NodePointer Ty = popNode(Node::Kind::Type);
       if (!Ty)
         return nullptr;
-      Nodes.push_back(Ty);
-    } while (!firstElem);
-    while (NodePointer Ty = pop_back_val(Nodes)) {
       Root->addChild(Ty, *this);
-    }
+    } while (!firstElem);
+    
+    Root->reverseChildren();
   }
   return Root;
 }
@@ -931,17 +1026,15 @@
 }
 
 NodePointer Demangler::demangleBoundGenericType() {
-  std::vector<NodePointer> TypeListList;
-  std::vector<NodePointer> Types;
+  Vector<NodePointer> TypeListList(*this, 4);
   for (;;) {
     NodePointer TList = createNode(Node::Kind::TypeList);
-    TypeListList.push_back(TList);
+    TypeListList.push_back(TList, *this);
     while (NodePointer Ty = popNode(Node::Kind::Type)) {
-      Types.push_back(Ty);
-    }
-    while (NodePointer Ty = pop_back_val(Types)) {
       TList->addChild(Ty, *this);
     }
+    TList->reverseChildren();
+
     if (popNode(Node::Kind::EmptyList))
       break;
     if (!popNode(Node::Kind::FirstElementMarker))
@@ -952,7 +1045,7 @@
 }
 
 NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal,
-                                    const std::vector<NodePointer> &TypeLists,
+                                    const Vector<NodePointer> &TypeLists,
                                     size_t TypeListIdx) {
   if (!Nominal || Nominal->getNumChildren() < 2)
     return nullptr;
@@ -1001,7 +1094,7 @@
 }
 
 NodePointer Demangler::demangleImplParamConvention() {
-  StringRef attr;
+  const char *attr = nullptr;
   switch (nextChar()) {
     case 'i': attr = "@in"; break;
     case 'l': attr = "@inout"; break;
@@ -1020,7 +1113,7 @@
 }
 
 NodePointer Demangler::demangleImplResultConvention(Node::Kind ConvKind) {
-  StringRef attr;
+  const char *attr = nullptr;
   switch (nextChar()) {
     case 'r': attr = "@out"; break;
     case 'o': attr = "@owned"; break;
@@ -1136,19 +1229,6 @@
   }
 }
 
-static std::string getArchetypeName(Node::IndexType index,
-                                    Node::IndexType depth) {
-  DemanglerPrinter name;
-  do {
-    name << (char)('A' + (index % 26));
-    index /= 26;
-  } while (index);
-  if (depth != 0)
-    name << depth;
-  return std::move(name).str();
-}
-
-
 NodePointer Demangler::demangleArchetype() {
   switch (nextChar()) {
     case 'a': {
@@ -1201,19 +1281,19 @@
 
 NodePointer Demangler::demangleAssociatedTypeCompound(
                                                   NodePointer GenericParamIdx) {
-  std::vector<NodePointer> AssocTyNames;
+  Vector<NodePointer> AssocTyNames(*this, 4);
   bool firstElem = false;
   do {
     firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
     NodePointer AssocTyName = popAssocTypeName();
     if (!AssocTyName)
       return nullptr;
-    AssocTyNames.push_back(AssocTyName);
+    AssocTyNames.push_back(AssocTyName, *this);
   } while (!firstElem);
 
   NodePointer Base = GenericParamIdx;
 
-  while (NodePointer AssocTy = pop_back_val(AssocTyNames)) {
+  while (NodePointer AssocTy = AssocTyNames.pop_back_val()) {
     NodePointer depTy = createNode(Node::Kind::DependentMemberType);
     depTy = addChild(depTy, createType(Base));
     Base = addChild(depTy, AssocTy);
@@ -1235,11 +1315,17 @@
 NodePointer Demangler::getDependentGenericParamType(int depth, int index) {
   if (depth < 0 || index < 0)
     return nullptr;
-  DemanglerPrinter PrintName;
-  PrintName << getArchetypeName(index, depth);
-  
-  auto paramTy = createNode(Node::Kind::DependentGenericParamType,
-                                     std::move(PrintName).str());
+
+  CharVector name;
+  int idxChar = index;
+  do {
+    name.push_back((char)('A' + (idxChar % 26)), *this);
+    idxChar /= 26;
+  } while (idxChar);
+  if (depth != 0)
+    name.append(depth, *this);
+
+  auto paramTy = createNode(Node::Kind::DependentGenericParamType, name);
   paramTy->addChild(createNode(Node::Kind::Index, depth), *this);
   paramTy->addChild(createNode(Node::Kind::Index, index), *this);
   return paramTy;
@@ -1372,10 +1458,10 @@
       case FunctionSigSpecializationParamKind::ConstantPropGlobal:
       case FunctionSigSpecializationParamKind::ConstantPropString:
       case FunctionSigSpecializationParamKind::ClosureProp: {
-        std::vector<NodePointer> Types;
+        size_t FixedChildren = Param->getNumChildren();
         while (NodePointer Ty = popNode(Node::Kind::Type)) {
           assert(ParamKind == FunctionSigSpecializationParamKind::ClosureProp);
-          Types.push_back(Ty);
+          Param = addChild(Param, Ty);
         }
         NodePointer Name = popNode(Node::Kind::Identifier);
         if (!Name)
@@ -1389,9 +1475,7 @@
         }
         addChild(Param, createNode(
           Node::Kind::FunctionSignatureSpecializationParamPayload, Text));
-        while (NodePointer Ty = pop_back_val(Types)) {
-          Param = addChild(Param, Ty);
-        }
+        Param->reverseChildren(FixedChildren);
         break;
       }
       default:
@@ -1499,9 +1583,9 @@
   Param->addChild(createNode(
         Node::Kind::FunctionSignatureSpecializationParamKind, unsigned(Kind)),
         *this);
-  std::string Str;
+  CharVector Str;
   while (isDigit(peekChar())) {
-    Str += nextChar();
+    Str.push_back(nextChar(), *this);
   }
   if (Str.empty())
     return nullptr;
@@ -1801,28 +1885,21 @@
   NodePointer TypeList = createNode(Node::Kind::TypeList);
   NodePointer ProtoList = createWithChild(Node::Kind::ProtocolList, TypeList);
   if (!popNode(Node::Kind::EmptyList)) {
-    std::vector<NodePointer> ProtoNames;
     bool firstElem = false;
     do {
       firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
       NodePointer Proto = popProtocol();
       if (!Proto)
         return nullptr;
-      ProtoNames.push_back(Proto);
+      TypeList->addChild(Proto, *this);
     } while (!firstElem);
 
-    while (NodePointer Proto = pop_back_val(ProtoNames)) {
-      TypeList->addChild(Proto, *this);
-    }
+    TypeList->reverseChildren();
   }
   return createType(ProtoList);
 }
 
 NodePointer Demangler::demangleGenericSignature(bool hasParamCounts) {
-  std::vector<NodePointer> Requirements;
-  while (NodePointer Req = popNode(isRequirement)) {
-    Requirements.push_back(Req);
-  }
   NodePointer Sig = createNode(Node::Kind::DependentGenericSignature);
   if (hasParamCounts) {
     while (!nextIf('l')) {
@@ -1840,9 +1917,11 @@
   }
   if (Sig->getNumChildren() == 0)
     return nullptr;
-  while (NodePointer Req = pop_back_val(Requirements)) {
+  size_t NumCounts = Sig->getNumChildren();
+  while (NodePointer Req = popNode(isRequirement)) {
     Sig->addChild(Req, *this);
   }
+  Sig->reverseChildren(NumCounts);
   return Sig;
 }
 
@@ -1905,7 +1984,7 @@
     auto c = nextChar();
     NodePointer size = nullptr;
     NodePointer alignment = nullptr;
-    StringRef name;
+    const char *name = nullptr;
     if (c == 'U') {
       name = "U";
     } else if (c == 'R') {
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index f38da00..220f1e2 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -242,16 +242,11 @@
 }
 
 Version Version::getCurrentLanguageVersion() {
-#ifndef SWIFT_VERSION_STRING
-#error Swift language version is not set!
+#if SWIFT_VERSION_PATCHLEVEL
+  return {SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR, SWIFT_VERSION_PATCHLEVEL};
+#else
+  return {SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR};
 #endif
-  auto currentVersion = Version::parseVersionString(
-    SWIFT_VERSION_STRING, SourceLoc(), nullptr);
-  assert(currentVersion.hasValue() &&
-         "Embedded Swift language version couldn't be parsed: '"
-         SWIFT_VERSION_STRING
-         "'");
-  return currentVersion.getValue();
 }
 
 raw_ostream &operator<<(raw_ostream &os, const Version &version) {
@@ -304,18 +299,35 @@
   }
 }
 
-bool Version::isValidEffectiveLanguageVersion() const {
-  for (auto verStr : getValidEffectiveVersions()) {
-    auto v = parseVersionString(verStr, SourceLoc(), nullptr);
-    assert(v.hasValue());
-    // In this case, use logical-equality _and_ precision-equality. We do not
-    // want to permit users requesting effective language versions more precise
-    // than our whitelist (eg. we permit 3 but not 3.0 or 3.0.0), since
-    // accepting such an argument promises more than we're able to deliver.
-    if (v == *this && v.getValue().size() == size())
-      return true;
+Optional<Version> Version::getEffectiveLanguageVersion() const {
+  switch (size()) {
+  case 0:
+    return None;
+  case 1:
+    break;
+  default:
+    // We do not want to permit users requesting more precise effective language
+    // versions since accepting such an argument promises more than we're able
+    // to deliver.
+    return None;
   }
-  return false;
+
+  // FIXME: When we switch to Swift 4 by default, the "3" case should return
+  // a version newer than any released 3.x compiler (probably "3.2"), and the
+  // "4" case should start returning getCurrentLanguageVersion. We should
+  // also check for the presence of SWIFT_VERSION_PATCHLEVEL, and if that's
+  // set apply it to the "3" case, so that Swift 4.0.1 will automatically
+  // have a compatibility mode of 3.2.1.
+  switch (Components[0]) {
+  case 3:
+    static_assert(SWIFT_VERSION_MAJOR == 3,
+                  "getCurrentLanguageVersion is no longer correct here");
+    return Version::getCurrentLanguageVersion();
+  case 4:
+    return Version{4, 0};
+  default:
+    return None;
+  }
 }
 
 Version Version::asMajorVersion() const {
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 6fcdebc..8028752 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -6952,6 +6952,7 @@
     };
     return getDeclName(*left).compare(getDeclName(*right));
   });
+
   // Schedule any that aren't complete.
   for (auto *inherited : inheritedProtos) {
     ModuleDecl *M = conformance->getDeclContext()->getParentModule();
@@ -6964,6 +6965,24 @@
                                          inheritedConformance->getConcrete());
   }
 
+  // Collect conformances for the requirement signature.
+  SmallVector<ProtocolConformanceRef, 4> reqConformances;
+  for (auto req : proto->getRequirementSignature()->getRequirements()) {
+    if (req.getKind() != RequirementKind::Conformance)
+      continue;
+
+    assert(req.getFirstType()->isEqual(proto->getSelfInterfaceType()));
+    auto reqProto = req.getSecondType()->castTo<ProtocolType>()->getDecl();
+
+    ModuleDecl *M = conformance->getDeclContext()->getParentModule();
+    auto reqConformance = M->lookupConformance(conformance->getType(),
+                                               reqProto, /*resolver=*/nullptr);
+    assert(reqConformance && reqConformance->isConcrete() &&
+           "required conformance not found");
+    reqConformances.push_back(*reqConformance);
+  }
+  conformance->setSignatureConformances(reqConformances);
+
   conformance->setState(ProtocolConformanceState::Complete);
 }
 
diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp
index b00f41f..e330bfc 100644
--- a/lib/ClangImporter/ImportName.cpp
+++ b/lib/ClangImporter/ImportName.cpp
@@ -37,6 +37,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Sema.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <algorithm>
 #include <memory>
 
@@ -79,6 +80,8 @@
   case ImportNameVersion::Swift4:
     return 4;
   }
+
+  llvm_unreachable("Unhandled ImportNameVersion in switch.");
 }
 
 
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index e6f2ca0..7ae5be6 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -44,6 +44,45 @@
 using namespace swift::driver;
 using namespace llvm::opt;
 
+struct LogJob {
+  const Job *j;
+  LogJob(const Job *j) : j(j) {}
+};
+
+struct LogJobArray {
+  const ArrayRef<const Job *> js;
+  LogJobArray(const ArrayRef<const Job *> js) : js(js) {}
+};
+
+struct LogJobSet {
+  const SmallPtrSetImpl<const Job*> &js;
+  LogJobSet(const SmallPtrSetImpl<const Job*> &js) : js(js) {}
+};
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const LogJob &lj) {
+  lj.j->printSummary(os);
+  return os;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const LogJobArray &ljs) {
+  os << "[";
+  interleave(ljs.js,
+             [&](Job const *j) { os << LogJob(j); },
+             [&]() { os << ' '; });
+  os << "]";
+  return os;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const LogJobSet &ljs) {
+  os << "{";
+  interleave(ljs.js,
+             [&](Job const *j) { os << LogJob(j); },
+             [&]() { os << ' '; });
+  os << "}";
+  return os;
+}
+
+
 Compilation::Compilation(DiagnosticEngine &Diags, OutputLevel Level,
                          std::unique_ptr<InputArgList> InputArgs,
                          std::unique_ptr<DerivedArgList> TranslatedArgs,
@@ -65,10 +104,21 @@
     ShowDriverTimeCompilation(ShowDriverTimeCompilation) {
 };
 
+static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags);
+
 using CommandSet = llvm::SmallPtrSet<const Job *, 16>;
 
-namespace {
-  struct PerformJobsState {
+
+using InputInfoMap = llvm::SmallMapVector<const llvm::opt::Arg *,
+                                          CompileJobAction::InputInfo, 16>;
+
+namespace swift {
+namespace driver {
+  class PerformJobsState {
+
+    /// The containing Compilation object.
+    Compilation &Comp;
+
     /// All jobs which have been scheduled for execution (whether or not
     /// they've finished execution), or which have been determined that they
     /// don't need to run.
@@ -89,8 +139,548 @@
     ///
     /// Only intended for source files.
     llvm::SmallDenseMap<const Job *, bool, 16> UnfinishedCommands;
+
+    /// Jobs that incremental-mode has decided it can skip.
+    CommandSet DeferredCommands;
+
+    /// Jobs in the initial set with Condition::Always, or lacking existing
+    /// .swiftdeps files.
+    SmallVector<const Job *, 16> InitialOutOfDateCommands;
+
+    /// Dependency graph for deciding which jobs are dirty (need running)
+    /// or clean (can be skipped).
+    using DependencyGraph = DependencyGraph<const Job *>;
+    DependencyGraph DepGraph;
+
+    /// Helper for tracing the propagation of marks in the graph.
+    DependencyGraph::MarkTracer ActualIncrementalTracer;
+    DependencyGraph::MarkTracer *IncrementalTracer = nullptr;
+
+    /// TaskQueue for execution.
+    std::unique_ptr<TaskQueue> TQ;
+
+    /// Cumulative result of PerformJobs(), accumulated from subprocesses.
+    int Result = EXIT_SUCCESS;
+
+    /// Timers for monitoring execution time of subprocesses.
+    llvm::TimerGroup DriverTimerGroup {"driver", "Driver Compilation Time"};
+    llvm::SmallDenseMap<const Job *, std::unique_ptr<llvm::Timer>, 16>
+    DriverTimers;
+
+    void noteBuilding(const Job *cmd, StringRef reason) {
+      if (!Comp.ShowIncrementalBuildDecisions)
+        return;
+      if (ScheduledCommands.count(cmd))
+        return;
+      llvm::outs() << "Queuing " << reason << ": " << LogJob(cmd) << "\n";
+      IncrementalTracer->printPath(
+        llvm::outs(), cmd, [](raw_ostream &out, const Job *base) {
+          out << llvm::sys::path::filename(base->getOutput().getBaseInput(0));
+        });
+    }
+
+    const Job *findUnfinishedJob(ArrayRef<const Job *> JL) {
+      for (const Job *Cmd : JL) {
+        if (!FinishedCommands.count(Cmd))
+          return Cmd;
+      }
+      return nullptr;
+    }
+
+    /// Schedule the given Job if it has not been scheduled and if all of
+    /// its inputs are in FinishedCommands.
+    void scheduleCommandIfNecessaryAndPossible(const Job *Cmd) {
+      if (ScheduledCommands.count(Cmd)) {
+        if (Comp.ShowJobLifecycle) {
+          llvm::outs() << "Already scheduled: " << LogJob(Cmd) << "\n";
+        }
+        return;
+      }
+
+      if (auto Blocking = findUnfinishedJob(Cmd->getInputs())) {
+        BlockingCommands[Blocking].push_back(Cmd);
+        if (Comp.ShowJobLifecycle) {
+          llvm::outs() << "Blocked by: " << LogJob(Blocking)
+                       << ", now blocking jobs: "
+                       << LogJobArray(BlockingCommands[Blocking]) << "\n";
+        }
+        return;
+      }
+
+      // FIXME: Failing here should not take down the whole process.
+      bool success = writeFilelistIfNecessary(Cmd, Comp.Diags);
+      assert(success && "failed to write filelist");
+      (void)success;
+
+      assert(Cmd->getExtraEnvironment().empty() &&
+             "not implemented for compilations with multiple jobs");
+      ScheduledCommands.insert(Cmd);
+      if (Comp.ShowJobLifecycle)
+        llvm::outs() << "Added to TaskQueue: " << LogJob(Cmd) << "\n";
+      TQ->addTask(Cmd->getExecutable(), Cmd->getArguments(), llvm::None,
+                  (void *)Cmd);
+    }
+
+    /// When a task finishes, check other Jobs that may be blocked.
+    void markFinished(const Job *Cmd, bool Skipped=false) {
+      if (Comp.ShowJobLifecycle) {
+        llvm::outs() << "Job "
+                     << (Skipped ? "skipped" : "finished")
+                     << ": " << LogJob(Cmd) << "\n";
+      }
+      FinishedCommands.insert(Cmd);
+
+      auto BlockedIter = BlockingCommands.find(Cmd);
+      if (BlockedIter != BlockingCommands.end()) {
+        auto AllBlocked = std::move(BlockedIter->second);
+        if (Comp.ShowJobLifecycle) {
+          llvm::outs() << "Scheduling maybe-unblocked jobs: "
+                       << LogJobArray(AllBlocked) << "\n";
+        }
+        BlockingCommands.erase(BlockedIter);
+        for (auto *Blocked : AllBlocked)
+          scheduleCommandIfNecessaryAndPossible(Blocked);
+      }
+    }
+
+    /// Callback which will be called immediately after a task has started. This
+    /// callback may be used to provide output indicating that the task began.
+    void taskBegan(ProcessId Pid, void *Context) {
+      // TODO: properly handle task began.
+      const Job *BeganCmd = (const Job *)Context;
+
+      if (Comp.ShowDriverTimeCompilation) {
+        llvm::SmallString<128> TimerName;
+        llvm::raw_svector_ostream OS(TimerName);
+        OS << LogJob(BeganCmd);
+        DriverTimers.insert({
+            BeganCmd,
+              std::unique_ptr<llvm::Timer>(
+                new llvm::Timer("task", OS.str(), DriverTimerGroup))
+              });
+        DriverTimers[BeganCmd]->startTimer();
+      }
+
+      // For verbose output, print out each command as it begins execution.
+      if (Comp.Level == OutputLevel::Verbose)
+        BeganCmd->printCommandLine(llvm::errs());
+      else if (Comp.Level == OutputLevel::Parseable)
+        parseable_output::emitBeganMessage(llvm::errs(), *BeganCmd, Pid);
+    }
+
+    void
+    dependencyLoadFailed(StringRef DependenciesFile, bool Warn=true) {
+      if (Warn && Comp.ShowIncrementalBuildDecisions)
+        Comp.Diags.diagnose(SourceLoc(),
+                            diag::warn_unable_to_load_dependencies,
+                            DependenciesFile);
+      Comp.disableIncrementalBuild();
+      for (const Job *Cmd : DeferredCommands)
+        scheduleCommandIfNecessaryAndPossible(Cmd);
+      DeferredCommands.clear();
+    }
+
+    /// Helper that reloads a job's .swiftdeps file after the job exits, and
+    /// re-runs transitive marking to ensure everything is properly invalidated
+    /// by any new dependency edges introduced by it.
+    template <unsigned N>
+    void reloadAndRemarkDeps(const Job *FinishedCmd,
+                             int ReturnCode,
+                             SmallVector<const Job *, N> &Dependents) {
+      const CommandOutput &Output = FinishedCmd->getOutput();
+      StringRef DependenciesFile =
+        Output.getAdditionalOutputForType(types::TY_SwiftDeps);
+
+      if (DependenciesFile.empty()) {
+        // If this job doesn't track dependencies, it must always be run.
+        // Note: In theory CheckDependencies makes sense as well (for a leaf
+        // node in the dependency graph), and maybe even NewlyAdded (for very
+        // coarse dependencies that always affect downstream nodes), but we're
+        // not using either of those right now, and this logic should probably
+        // be revisited when we are.
+        assert(FinishedCmd->getCondition() == Job::Condition::Always);
+      } else {
+        // If we have a dependency file /and/ the frontend task exited normally,
+        // we can be discerning about what downstream files to rebuild.
+        if (ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE) {
+          bool wasCascading = DepGraph.isMarked(FinishedCmd);
+
+          switch (DepGraph.loadFromPath(FinishedCmd, DependenciesFile)) {
+          case DependencyGraphImpl::LoadResult::HadError:
+            if (ReturnCode == EXIT_SUCCESS) {
+              dependencyLoadFailed(DependenciesFile);
+              Dependents.clear();
+            } // else, let the next build handle it.
+            break;
+          case DependencyGraphImpl::LoadResult::UpToDate:
+            if (!wasCascading)
+              break;
+            LLVM_FALLTHROUGH;
+          case DependencyGraphImpl::LoadResult::AffectsDownstream:
+            DepGraph.markTransitive(Dependents, FinishedCmd,
+                                    IncrementalTracer);
+            break;
+          }
+        } else {
+          // If there's an abnormal exit (a crash), assume the worst.
+          switch (FinishedCmd->getCondition()) {
+          case Job::Condition::NewlyAdded:
+            // The job won't be treated as newly added next time. Conservatively
+            // mark it as affecting other jobs, because some of them may have
+            // completed already.
+            DepGraph.markTransitive(Dependents, FinishedCmd,
+                                    IncrementalTracer);
+            break;
+          case Job::Condition::Always:
+            // Any incremental task that shows up here has already been marked;
+            // we didn't need to wait for it to finish to start downstream
+            // tasks.
+            assert(DepGraph.isMarked(FinishedCmd));
+            break;
+          case Job::Condition::RunWithoutCascading:
+            // If this file changed, it might have been a non-cascading change
+            // and it might not. Unfortunately, the interface hash has been
+            // updated or compromised, so we don't actually know anymore; we
+            // have to conservatively assume the changes could affect other
+            // files.
+            DepGraph.markTransitive(Dependents, FinishedCmd,
+                                    IncrementalTracer);
+            break;
+          case Job::Condition::CheckDependencies:
+            // If the only reason we're running this is because something else
+            // changed, then we can trust the dependency graph as to whether
+            // it's a cascading or non-cascading change. That is, if whatever
+            // /caused/ the error isn't supposed to affect other files, and
+            // whatever /fixes/ the error isn't supposed to affect other files,
+            // then there's no need to recompile any other inputs. If either of
+            // those are false, we /do/ need to recompile other inputs.
+            break;
+          }
+        }
+      }
+    }
+
+    /// Callback which will be called immediately after a task has finished
+    /// execution. Determines if execution should continue, and also schedule
+    /// any additional Jobs which we now know we need to run.
+    TaskFinishedResponse
+    taskFinished(ProcessId Pid, int ReturnCode, StringRef Output,
+                 StringRef Errors, void *Context) {
+      const Job *FinishedCmd = (const Job *)Context;
+
+      if (Comp.ShowDriverTimeCompilation) {
+        DriverTimers[FinishedCmd]->stopTimer();
+      }
+
+      if (Comp.Level == OutputLevel::Parseable) {
+        // Parseable output was requested.
+        parseable_output::emitFinishedMessage(llvm::errs(), *FinishedCmd, Pid,
+                                              ReturnCode, Output);
+      } else {
+        // Otherwise, send the buffered output to stderr, though only if we
+        // support getting buffered output.
+        if (TaskQueue::supportsBufferingOutput())
+          llvm::errs() << Output;
+      }
+
+      // In order to handle both old dependencies that have disappeared and new
+      // dependencies that have arisen, we need to reload the dependency file.
+      // Do this whether or not the build succeeded.
+      SmallVector<const Job *, 16> Dependents;
+      if (Comp.getIncrementalBuildEnabled()) {
+        reloadAndRemarkDeps(FinishedCmd, ReturnCode, Dependents);
+      }
+
+      if (ReturnCode != EXIT_SUCCESS) {
+        // The task failed, so return true without performing any further
+        // dependency analysis.
+
+        // Store this task's ReturnCode as our Result if we haven't stored
+        // anything yet.
+        if (Result == EXIT_SUCCESS)
+          Result = ReturnCode;
+
+        if (!isa<CompileJobAction>(FinishedCmd->getSource()) ||
+            ReturnCode != EXIT_FAILURE) {
+          Comp.Diags.diagnose(SourceLoc(), diag::error_command_failed,
+                              FinishedCmd->getSource().getClassName(),
+                              ReturnCode);
+        }
+
+        return Comp.ContinueBuildingAfterErrors ?
+          TaskFinishedResponse::ContinueExecution :
+          TaskFinishedResponse::StopExecution;
+      }
+
+      // When a task finishes, we need to reevaluate the other commands that
+      // might have been blocked.
+      markFinished(FinishedCmd);
+
+      for (const Job *Cmd : Dependents) {
+        DeferredCommands.erase(Cmd);
+        noteBuilding(Cmd, "because of dependencies discovered later");
+        scheduleCommandIfNecessaryAndPossible(Cmd);
+      }
+
+      return TaskFinishedResponse::ContinueExecution;
+    }
+
+    TaskFinishedResponse
+    taskSignalled(ProcessId Pid, StringRef ErrorMsg, StringRef Output,
+                  StringRef Errors, void *Context, Optional<int> Signal) {
+      const Job *SignalledCmd = (const Job *)Context;
+
+      if (Comp.ShowDriverTimeCompilation) {
+        DriverTimers[SignalledCmd]->stopTimer();
+      }
+
+      if (Comp.Level == OutputLevel::Parseable) {
+        // Parseable output was requested.
+        parseable_output::emitSignalledMessage(llvm::errs(), *SignalledCmd,
+                                               Pid, ErrorMsg, Output, Signal);
+      } else {
+        // Otherwise, send the buffered output to stderr, though only if we
+        // support getting buffered output.
+        if (TaskQueue::supportsBufferingOutput())
+          llvm::errs() << Output;
+      }
+
+      if (!ErrorMsg.empty())
+        Comp.Diags.diagnose(SourceLoc(), diag::error_unable_to_execute_command,
+                            ErrorMsg);
+
+      if (Signal.hasValue()) {
+        Comp.Diags.diagnose(SourceLoc(), diag::error_command_signalled,
+                            SignalledCmd->getSource().getClassName(),
+                            Signal.getValue());
+      } else {
+        Comp.Diags.diagnose(SourceLoc(),
+                            diag::error_command_signalled_without_signal_number,
+                            SignalledCmd->getSource().getClassName());
+      }
+
+      // Since the task signalled, unconditionally set result to -2.
+      Result = -2;
+
+      return TaskFinishedResponse::StopExecution;
+    }
+
+  public:
+    PerformJobsState(Compilation &Comp) : Comp(Comp) {
+      if (Comp.SkipTaskExecution)
+        TQ.reset(new DummyTaskQueue(Comp.NumberOfParallelCommands));
+      else
+        TQ.reset(new TaskQueue(Comp.NumberOfParallelCommands));
+      if (Comp.ShowIncrementalBuildDecisions)
+        IncrementalTracer = &ActualIncrementalTracer;
+    }
+
+    /// Schedule all jobs we can from the initial list provided by Compilation.
+    void scheduleInitialJobs() {
+      for (const Job *Cmd : Comp.getJobs()) {
+        if (!Comp.getIncrementalBuildEnabled()) {
+          scheduleCommandIfNecessaryAndPossible(Cmd);
+          continue;
+        }
+
+        // Try to load the dependencies file for this job. If there isn't one, we
+        // always have to run the job, but it doesn't affect any other jobs. If
+        // there should be one but it's not present or can't be loaded, we have to
+        // run all the jobs.
+        // FIXME: We can probably do better here!
+        Job::Condition Condition = Job::Condition::Always;
+        StringRef DependenciesFile =
+          Cmd->getOutput().getAdditionalOutputForType(types::TY_SwiftDeps);
+        if (!DependenciesFile.empty()) {
+          if (Cmd->getCondition() == Job::Condition::NewlyAdded) {
+            DepGraph.addIndependentNode(Cmd);
+          } else {
+            switch (DepGraph.loadFromPath(Cmd, DependenciesFile)) {
+            case DependencyGraphImpl::LoadResult::HadError:
+              dependencyLoadFailed(DependenciesFile, /*Warn=*/false);
+              break;
+            case DependencyGraphImpl::LoadResult::UpToDate:
+              Condition = Cmd->getCondition();
+              break;
+            case DependencyGraphImpl::LoadResult::AffectsDownstream:
+              llvm_unreachable("we haven't marked anything in this graph yet");
+            }
+          }
+        }
+
+        switch (Condition) {
+        case Job::Condition::Always:
+          if (Comp.getIncrementalBuildEnabled() && !DependenciesFile.empty()) {
+            InitialOutOfDateCommands.push_back(Cmd);
+            DepGraph.markIntransitive(Cmd);
+          }
+          LLVM_FALLTHROUGH;
+        case Job::Condition::RunWithoutCascading:
+          noteBuilding(Cmd, "(initial)");
+          scheduleCommandIfNecessaryAndPossible(Cmd);
+          break;
+        case Job::Condition::CheckDependencies:
+          DeferredCommands.insert(Cmd);
+          break;
+        case Job::Condition::NewlyAdded:
+          llvm_unreachable("handled above");
+        }
+      }
+    }
+
+    /// Schedule transitive closure of initial jobs, and external jobs.
+    void scheduleAdditionalJobs() {
+      if (Comp.getIncrementalBuildEnabled()) {
+        SmallVector<const Job *, 16> AdditionalOutOfDateCommands;
+
+        // We scheduled all of the files that have actually changed. Now add the
+        // files that haven't changed, so that they'll get built in parallel if
+        // possible and after the first set of files if it's not.
+        for (auto *Cmd : InitialOutOfDateCommands) {
+          DepGraph.markTransitive(AdditionalOutOfDateCommands, Cmd,
+                                  IncrementalTracer);
+        }
+
+        for (auto *transitiveCmd : AdditionalOutOfDateCommands)
+          noteBuilding(transitiveCmd, "because of the initial set");
+        size_t firstSize = AdditionalOutOfDateCommands.size();
+
+        // Check all cross-module dependencies as well.
+        for (StringRef dependency : DepGraph.getExternalDependencies()) {
+          llvm::sys::fs::file_status depStatus;
+          if (!llvm::sys::fs::status(dependency, depStatus))
+            if (depStatus.getLastModificationTime() < Comp.LastBuildTime)
+              continue;
+
+          // If the dependency has been modified since the oldest built file,
+          // or if we can't stat it for some reason (perhaps it's been deleted?),
+          // trigger rebuilds through the dependency graph.
+          DepGraph.markExternal(AdditionalOutOfDateCommands, dependency);
+        }
+
+        for (auto *externalCmd :
+               llvm::makeArrayRef(AdditionalOutOfDateCommands).slice(firstSize)) {
+          noteBuilding(externalCmd, "because of external dependencies");
+        }
+
+        for (auto *AdditionalCmd : AdditionalOutOfDateCommands) {
+          if (!DeferredCommands.count(AdditionalCmd))
+            continue;
+          scheduleCommandIfNecessaryAndPossible(AdditionalCmd);
+          DeferredCommands.erase(AdditionalCmd);
+        }
+      }
+    }
+
+    void runTaskQueueToCompletion() {
+      do {
+        using namespace std::placeholders;
+        // Ask the TaskQueue to execute.
+        TQ->execute(std::bind(&PerformJobsState::taskBegan, this,
+                              _1, _2),
+                    std::bind(&PerformJobsState::taskFinished, this,
+                              _1, _2, _3, _4, _5),
+                    std::bind(&PerformJobsState::taskSignalled, this,
+                              _1, _2, _3, _4, _5, _6));
+
+        // Mark all remaining deferred commands as skipped.
+        for (const Job *Cmd : DeferredCommands) {
+          if (Comp.Level == OutputLevel::Parseable) {
+            // Provide output indicating this command was skipped if parseable output
+            // was requested.
+            parseable_output::emitSkippedMessage(llvm::errs(), *Cmd);
+          }
+
+          ScheduledCommands.insert(Cmd);
+          markFinished(Cmd, /*Skipped=*/true);
+        }
+        DeferredCommands.clear();
+
+        // ...which may allow us to go on and do later tasks.
+      } while (Result == 0 && TQ->hasRemainingTasks());
+    }
+
+    void checkUnfinishedJobs() {
+      if (Result == 0) {
+        assert(BlockingCommands.empty() &&
+               "some blocking commands never finished properly");
+      } else {
+        // Make sure we record any files that still need to be rebuilt.
+        for (const Job *Cmd : Comp.getJobs()) {
+          // Skip files that don't use dependency analysis.
+          StringRef DependenciesFile =
+            Cmd->getOutput().getAdditionalOutputForType(types::TY_SwiftDeps);
+          if (DependenciesFile.empty())
+            continue;
+
+          // Don't worry about commands that finished or weren't going to run.
+          if (FinishedCommands.count(Cmd))
+            continue;
+          if (!ScheduledCommands.count(Cmd))
+            continue;
+
+          bool isCascading = true;
+          if (Comp.getIncrementalBuildEnabled())
+            isCascading = DepGraph.isMarked(Cmd);
+          UnfinishedCommands.insert({Cmd, isCascading});
+        }
+      }
+    }
+
+    void populateInputInfoMap(InputInfoMap &inputs) const {
+      for (auto &entry : UnfinishedCommands) {
+        for (auto *action : entry.first->getSource().getInputs()) {
+          auto inputFile = dyn_cast<InputAction>(action);
+          if (!inputFile)
+            continue;
+
+          CompileJobAction::InputInfo info;
+          info.previousModTime = entry.first->getInputModTime();
+          info.status = entry.second ?
+            CompileJobAction::InputInfo::NeedsCascadingBuild :
+            CompileJobAction::InputInfo::NeedsNonCascadingBuild;
+          inputs[&inputFile->getInputArg()] = info;
+        }
+      }
+
+      for (const Job *entry : FinishedCommands) {
+        const auto *compileAction = dyn_cast<CompileJobAction>(&entry->getSource());
+        if (!compileAction)
+          continue;
+
+        for (auto *action : compileAction->getInputs()) {
+          auto inputFile = dyn_cast<InputAction>(action);
+          if (!inputFile)
+            continue;
+
+          CompileJobAction::InputInfo info;
+          info.previousModTime = entry->getInputModTime();
+          info.status = CompileJobAction::InputInfo::UpToDate;
+          inputs[&inputFile->getInputArg()] = info;
+        }
+      }
+
+      // Sort the entries by input order.
+      static_assert(IsTriviallyCopyable<CompileJobAction::InputInfo>::value,
+                    "llvm::array_pod_sort relies on trivially-copyable data");
+      using InputInfoEntry = std::decay<decltype(inputs.front())>::type;
+      llvm::array_pod_sort(inputs.begin(), inputs.end(),
+                           [](const InputInfoEntry *lhs,
+                              const InputInfoEntry *rhs) -> int {
+                             auto lhsIndex = lhs->first->getIndex();
+                             auto rhsIndex = rhs->first->getIndex();
+                             return (lhsIndex < rhsIndex) ? -1 : (lhsIndex > rhsIndex) ? 1 : 0;
+                           });
+    }
+
+    int getResult() {
+      if (Result == 0)
+        Result = Comp.Diags.hadAnyError();
+      return Result;
+    }
   };
-} // end anonymous namespace
+} // driver
+} // swift
 
 Compilation::~Compilation() = default;
 
@@ -100,64 +690,6 @@
   return result;
 }
 
-static const Job *findUnfinishedJob(ArrayRef<const Job *> JL,
-                                    const CommandSet &FinishedCommands) {
-  for (const Job *Cmd : JL) {
-    if (!FinishedCommands.count(Cmd))
-      return Cmd;
-  }
-  return nullptr;
-}
-
-using InputInfoMap =
-  llvm::SmallMapVector<const llvm::opt::Arg *, CompileJobAction::InputInfo, 16>;
-
-static void populateInputInfoMap(InputInfoMap &inputs,
-                                 const PerformJobsState &endState) {
-  for (auto &entry : endState.UnfinishedCommands) {
-    for (auto *action : entry.first->getSource().getInputs()) {
-      auto inputFile = dyn_cast<InputAction>(action);
-      if (!inputFile)
-        continue;
-
-      CompileJobAction::InputInfo info;
-      info.previousModTime = entry.first->getInputModTime();
-      info.status = entry.second ?
-          CompileJobAction::InputInfo::NeedsCascadingBuild :
-          CompileJobAction::InputInfo::NeedsNonCascadingBuild;
-      inputs[&inputFile->getInputArg()] = info;
-    }
-  }
-
-  for (const Job *entry : endState.FinishedCommands) {
-    const auto *compileAction = dyn_cast<CompileJobAction>(&entry->getSource());
-    if (!compileAction)
-      continue;
-
-    for (auto *action : compileAction->getInputs()) {
-      auto inputFile = dyn_cast<InputAction>(action);
-      if (!inputFile)
-        continue;
-
-      CompileJobAction::InputInfo info;
-      info.previousModTime = entry->getInputModTime();
-      info.status = CompileJobAction::InputInfo::UpToDate;
-      inputs[&inputFile->getInputArg()] = info;
-    }
-  }
-
-  // Sort the entries by input order.
-  static_assert(IsTriviallyCopyable<CompileJobAction::InputInfo>::value,
-                "llvm::array_pod_sort relies on trivially-copyable data");
-  using InputInfoEntry = std::decay<decltype(inputs.front())>::type;
-  llvm::array_pod_sort(inputs.begin(), inputs.end(),
-                       [](const InputInfoEntry *lhs,
-                          const InputInfoEntry *rhs) -> int {
-    auto lhsIndex = lhs->first->getIndex();
-    auto rhsIndex = rhs->first->getIndex();
-    return (lhsIndex < rhsIndex) ? -1 : (lhsIndex > rhsIndex) ? 1 : 0;
-  });
-}
 
 static void checkForOutOfDateInputs(DiagnosticEngine &diags,
                                     const InputInfoMap &inputs) {
@@ -274,448 +806,23 @@
 }
 
 int Compilation::performJobsImpl() {
-  // Create a TaskQueue for execution.
-  std::unique_ptr<TaskQueue> TQ;
-  if (SkipTaskExecution)
-    TQ.reset(new DummyTaskQueue(NumberOfParallelCommands));
-  else
-    TQ.reset(new TaskQueue(NumberOfParallelCommands));
 
-  PerformJobsState State;
+  PerformJobsState State(*this);
 
-  using DependencyGraph = DependencyGraph<const Job *>;
-  DependencyGraph DepGraph;
-  SmallPtrSet<const Job *, 16> DeferredCommands;
-  SmallVector<const Job *, 16> InitialOutOfDateCommands;
-
-  DependencyGraph::MarkTracer ActualIncrementalTracer;
-  DependencyGraph::MarkTracer *IncrementalTracer = nullptr;
-  if (ShowIncrementalBuildDecisions)
-    IncrementalTracer = &ActualIncrementalTracer;
-
-  auto noteBuilding = [&] (const Job *cmd, StringRef reason) {
-    if (!ShowIncrementalBuildDecisions)
-      return;
-    if (State.ScheduledCommands.count(cmd))
-      return;
-    llvm::outs() << "Queuing "
-                 << llvm::sys::path::filename(cmd->getOutput().getBaseInput(0))
-                 << " " << reason << "\n";
-    IncrementalTracer->printPath(llvm::outs(), cmd,
-                                 [](raw_ostream &out, const Job *base) {
-      out << llvm::sys::path::filename(base->getOutput().getBaseInput(0));
-    });
-  };
-
-  // Set up scheduleCommandIfNecessaryAndPossible.
-  // This will only schedule the given command if it has not been scheduled
-  // and if all of its inputs are in FinishedCommands.
-  auto scheduleCommandIfNecessaryAndPossible = [&] (const Job *Cmd) {
-    if (State.ScheduledCommands.count(Cmd))
-      return;
-
-    if (auto Blocking = findUnfinishedJob(Cmd->getInputs(),
-                                          State.FinishedCommands)) {
-      State.BlockingCommands[Blocking].push_back(Cmd);
-      return;
-    }
-
-    // FIXME: Failing here should not take down the whole process.
-    bool success = writeFilelistIfNecessary(Cmd, Diags);
-    assert(success && "failed to write filelist");
-    (void)success;
-
-    assert(Cmd->getExtraEnvironment().empty() &&
-           "not implemented for compilations with multiple jobs");
-    State.ScheduledCommands.insert(Cmd);
-    TQ->addTask(Cmd->getExecutable(), Cmd->getArguments(), llvm::None,
-                (void *)Cmd);
-  };
-
-  // When a task finishes, we need to reevaluate the other commands that
-  // might have been blocked.
-  auto markFinished = [&] (const Job *Cmd) {
-    State.FinishedCommands.insert(Cmd);
-
-    auto BlockedIter = State.BlockingCommands.find(Cmd);
-    if (BlockedIter != State.BlockingCommands.end()) {
-      auto AllBlocked = std::move(BlockedIter->second);
-      State.BlockingCommands.erase(BlockedIter);
-      for (auto *Blocked : AllBlocked)
-        scheduleCommandIfNecessaryAndPossible(Blocked);
-    }
-  };
-
-  // Schedule all jobs we can.
-  for (const Job *Cmd : getJobs()) {
-    if (!getIncrementalBuildEnabled()) {
-      scheduleCommandIfNecessaryAndPossible(Cmd);
-      continue;
-    }
-
-    // Try to load the dependencies file for this job. If there isn't one, we
-    // always have to run the job, but it doesn't affect any other jobs. If
-    // there should be one but it's not present or can't be loaded, we have to
-    // run all the jobs.
-    // FIXME: We can probably do better here!
-    Job::Condition Condition = Job::Condition::Always;
-    StringRef DependenciesFile =
-      Cmd->getOutput().getAdditionalOutputForType(types::TY_SwiftDeps);
-    if (!DependenciesFile.empty()) {
-      if (Cmd->getCondition() == Job::Condition::NewlyAdded) {
-        DepGraph.addIndependentNode(Cmd);
-      } else {
-        switch (DepGraph.loadFromPath(Cmd, DependenciesFile)) {
-        case DependencyGraphImpl::LoadResult::HadError:
-          disableIncrementalBuild();
-          for (const Job *Cmd : DeferredCommands)
-            scheduleCommandIfNecessaryAndPossible(Cmd);
-          DeferredCommands.clear();
-          break;
-        case DependencyGraphImpl::LoadResult::UpToDate:
-          Condition = Cmd->getCondition();
-          break;
-        case DependencyGraphImpl::LoadResult::AffectsDownstream:
-          llvm_unreachable("we haven't marked anything in this graph yet");
-        }
-      }
-    }
-
-    switch (Condition) {
-    case Job::Condition::Always:
-      if (getIncrementalBuildEnabled() && !DependenciesFile.empty()) {
-        InitialOutOfDateCommands.push_back(Cmd);
-        DepGraph.markIntransitive(Cmd);
-      }
-      LLVM_FALLTHROUGH;
-    case Job::Condition::RunWithoutCascading:
-      noteBuilding(Cmd, "(initial)");
-      scheduleCommandIfNecessaryAndPossible(Cmd);
-      break;
-    case Job::Condition::CheckDependencies:
-      DeferredCommands.insert(Cmd);
-      break;
-    case Job::Condition::NewlyAdded:
-      llvm_unreachable("handled above");
-    }
-  }
-
-  if (getIncrementalBuildEnabled()) {
-    SmallVector<const Job *, 16> AdditionalOutOfDateCommands;
-
-    // We scheduled all of the files that have actually changed. Now add the
-    // files that haven't changed, so that they'll get built in parallel if
-    // possible and after the first set of files if it's not.
-    for (auto *Cmd : InitialOutOfDateCommands) {
-      DepGraph.markTransitive(AdditionalOutOfDateCommands, Cmd,
-                              IncrementalTracer);
-    }
-
-    for (auto *transitiveCmd : AdditionalOutOfDateCommands)
-      noteBuilding(transitiveCmd, "because of the initial set:");
-    size_t firstSize = AdditionalOutOfDateCommands.size();
-
-    // Check all cross-module dependencies as well.
-    for (StringRef dependency : DepGraph.getExternalDependencies()) {
-      llvm::sys::fs::file_status depStatus;
-      if (!llvm::sys::fs::status(dependency, depStatus))
-        if (depStatus.getLastModificationTime() < LastBuildTime)
-          continue;
-
-      // If the dependency has been modified since the oldest built file,
-      // or if we can't stat it for some reason (perhaps it's been deleted?),
-      // trigger rebuilds through the dependency graph.
-      DepGraph.markExternal(AdditionalOutOfDateCommands, dependency);
-    }
-
-    for (auto *externalCmd :
-            llvm::makeArrayRef(AdditionalOutOfDateCommands).slice(firstSize)) {
-      noteBuilding(externalCmd, "because of external dependencies");
-    }
-
-    for (auto *AdditionalCmd : AdditionalOutOfDateCommands) {
-      if (!DeferredCommands.count(AdditionalCmd))
-        continue;
-      scheduleCommandIfNecessaryAndPossible(AdditionalCmd);
-      DeferredCommands.erase(AdditionalCmd);
-    }
-  }
-
-  int Result = EXIT_SUCCESS;
-  llvm::TimerGroup DriverTimerGroup("driver", "Driver Compilation Time");
-  llvm::SmallDenseMap<const Job *, std::unique_ptr<llvm::Timer>, 16>
-    DriverTimers;
-
-  // Set up a callback which will be called immediately after a task has
-  // started. This callback may be used to provide output indicating that the
-  // task began.
-  auto taskBegan = [&] (ProcessId Pid, void *Context) {
-    // TODO: properly handle task began.
-    const Job *BeganCmd = (const Job *)Context;
-
-    if (ShowDriverTimeCompilation) {
-      llvm::SmallString<128> TimerName;
-      llvm::raw_svector_ostream OS(TimerName);
-
-      OS << BeganCmd->getSource().getClassName();
-      for (auto A : BeganCmd->getSource().getInputs()) {
-        if (const InputAction *IA = dyn_cast<InputAction>(A)) {
-          OS << " " << IA->getInputArg().getValue();
-        }
-      }
-      for (auto J : BeganCmd->getInputs()) {
-        for (auto A : J->getSource().getInputs()) {
-          if (const InputAction *IA = dyn_cast<InputAction>(A)) {
-            OS << " " << IA->getInputArg().getValue();
-          }
-        }
-      }
-
-      DriverTimers.insert({
-        BeganCmd,
-        std::unique_ptr<llvm::Timer>(
-          new llvm::Timer("task", OS.str(), DriverTimerGroup))
-      });
-      DriverTimers[BeganCmd]->startTimer();
-    }
-
-    // For verbose output, print out each command as it begins execution.
-    if (Level == OutputLevel::Verbose)
-      BeganCmd->printCommandLine(llvm::errs());
-    else if (Level == OutputLevel::Parseable)
-      parseable_output::emitBeganMessage(llvm::errs(), *BeganCmd, Pid);
-  };
-
-  // Set up a callback which will be called immediately after a task has
-  // finished execution. This callback should determine if execution should
-  // continue (if execution should stop, this callback should return true), and
-  // it should also schedule any additional commands which we now know need
-  // to run.
-  auto taskFinished = [&](ProcessId Pid, int ReturnCode, StringRef Output,
-                          StringRef Errors,
-                          void *Context) -> TaskFinishedResponse {
-    const Job *FinishedCmd = (const Job *)Context;
-
-    if (ShowDriverTimeCompilation) {
-      DriverTimers[FinishedCmd]->stopTimer();
-    }
-
-    if (Level == OutputLevel::Parseable) {
-      // Parseable output was requested.
-      parseable_output::emitFinishedMessage(llvm::errs(), *FinishedCmd, Pid,
-                                            ReturnCode, Output);
-    } else {
-      // Otherwise, send the buffered output to stderr, though only if we
-      // support getting buffered output.
-      if (TaskQueue::supportsBufferingOutput())
-        llvm::errs() << Output;
-    }
-
-    // In order to handle both old dependencies that have disappeared and new
-    // dependencies that have arisen, we need to reload the dependency file.
-    // Do this whether or not the build succeeded.
-    SmallVector<const Job *, 16> Dependents;
-    if (getIncrementalBuildEnabled()) {
-      const CommandOutput &Output = FinishedCmd->getOutput();
-      StringRef DependenciesFile =
-        Output.getAdditionalOutputForType(types::TY_SwiftDeps);
-
-      if (DependenciesFile.empty()) {
-        // If this job doesn't track dependencies, it must always be run.
-        // Note: In theory CheckDependencies makes sense as well (for a leaf
-        // node in the dependency graph), and maybe even NewlyAdded (for very
-        // coarse dependencies that always affect downstream nodes), but we're
-        // not using either of those right now, and this logic should probably
-        // be revisited when we are.
-        assert(FinishedCmd->getCondition() == Job::Condition::Always);
-      } else {
-        // If we have a dependency file /and/ the frontend task exited normally,
-        // we can be discerning about what downstream files to rebuild.
-        if (ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE) {
-          bool wasCascading = DepGraph.isMarked(FinishedCmd);
-
-          switch (DepGraph.loadFromPath(FinishedCmd, DependenciesFile)) {
-          case DependencyGraphImpl::LoadResult::HadError:
-            if (ReturnCode == EXIT_SUCCESS) {
-              disableIncrementalBuild();
-              for (const Job *Cmd : DeferredCommands)
-                scheduleCommandIfNecessaryAndPossible(Cmd);
-              DeferredCommands.clear();
-              Dependents.clear();
-            } // else, let the next build handle it.
-            break;
-          case DependencyGraphImpl::LoadResult::UpToDate:
-            if (!wasCascading)
-              break;
-            LLVM_FALLTHROUGH;
-          case DependencyGraphImpl::LoadResult::AffectsDownstream:
-            DepGraph.markTransitive(Dependents, FinishedCmd);
-            break;
-          }
-        } else {
-          // If there's an abnormal exit (a crash), assume the worst.
-          switch (FinishedCmd->getCondition()) {
-          case Job::Condition::NewlyAdded:
-            // The job won't be treated as newly added next time. Conservatively
-            // mark it as affecting other jobs, because some of them may have
-            // completed already.
-            DepGraph.markTransitive(Dependents, FinishedCmd);
-            break;
-          case Job::Condition::Always:
-            // Any incremental task that shows up here has already been marked;
-            // we didn't need to wait for it to finish to start downstream
-            // tasks.
-            assert(DepGraph.isMarked(FinishedCmd));
-            break;
-          case Job::Condition::RunWithoutCascading:
-            // If this file changed, it might have been a non-cascading change
-            // and it might not. Unfortunately, the interface hash has been
-            // updated or compromised, so we don't actually know anymore; we
-            // have to conservatively assume the changes could affect other
-            // files.
-            DepGraph.markTransitive(Dependents, FinishedCmd);
-            break;
-          case Job::Condition::CheckDependencies:
-            // If the only reason we're running this is because something else
-            // changed, then we can trust the dependency graph as to whether
-            // it's a cascading or non-cascading change. That is, if whatever
-            // /caused/ the error isn't supposed to affect other files, and
-            // whatever /fixes/ the error isn't supposed to affect other files,
-            // then there's no need to recompile any other inputs. If either of
-            // those are false, we /do/ need to recompile other inputs.
-            break;
-          }
-        }
-      }
-    }
-
-    if (ReturnCode != EXIT_SUCCESS) {
-      // The task failed, so return true without performing any further
-      // dependency analysis.
-
-      // Store this task's ReturnCode as our Result if we haven't stored
-      // anything yet.
-      if (Result == EXIT_SUCCESS)
-        Result = ReturnCode;
-
-      if (!isa<CompileJobAction>(FinishedCmd->getSource()) ||
-          ReturnCode != EXIT_FAILURE) {
-        Diags.diagnose(SourceLoc(), diag::error_command_failed,
-                       FinishedCmd->getSource().getClassName(),
-                       ReturnCode);
-      }
-
-      return ContinueBuildingAfterErrors ?
-          TaskFinishedResponse::ContinueExecution :
-          TaskFinishedResponse::StopExecution;
-    }
-
-    // When a task finishes, we need to reevaluate the other commands that
-    // might have been blocked.
-    markFinished(FinishedCmd);
-
-    for (const Job *Cmd : Dependents) {
-      DeferredCommands.erase(Cmd);
-      noteBuilding(Cmd, "because of dependencies discovered later");
-      scheduleCommandIfNecessaryAndPossible(Cmd);
-    }
-
-    return TaskFinishedResponse::ContinueExecution;
-  };
-
-  auto taskSignalled = [&](ProcessId Pid, StringRef ErrorMsg, StringRef Output,
-                           StringRef Errors,
-                           void *Context, Optional<int> Signal) -> TaskFinishedResponse {
-    const Job *SignalledCmd = (const Job *)Context;
-
-    if (ShowDriverTimeCompilation) {
-      DriverTimers[SignalledCmd]->stopTimer();
-    }
-
-    if (Level == OutputLevel::Parseable) {
-      // Parseable output was requested.
-      parseable_output::emitSignalledMessage(llvm::errs(), *SignalledCmd, Pid,
-                                             ErrorMsg, Output, Signal);
-    } else {
-      // Otherwise, send the buffered output to stderr, though only if we
-      // support getting buffered output.
-      if (TaskQueue::supportsBufferingOutput())
-        llvm::errs() << Output;
-    }
-
-    if (!ErrorMsg.empty())
-      Diags.diagnose(SourceLoc(), diag::error_unable_to_execute_command,
-                     ErrorMsg);
-    
-    if (Signal.hasValue()) {
-      Diags.diagnose(SourceLoc(), diag::error_command_signalled,
-                     SignalledCmd->getSource().getClassName(), Signal.getValue());
-    } else {
-      Diags.diagnose(SourceLoc(), diag::error_command_signalled_without_signal_number,
-                     SignalledCmd->getSource().getClassName());
-    }
-
-    // Since the task signalled, unconditionally set result to -2.
-    Result = -2;
-
-    return TaskFinishedResponse::StopExecution;
-  };
-
-  do {
-    // Ask the TaskQueue to execute.
-    TQ->execute(taskBegan, taskFinished, taskSignalled);
-
-    // Mark all remaining deferred commands as skipped.
-    for (const Job *Cmd : DeferredCommands) {
-      if (Level == OutputLevel::Parseable) {
-        // Provide output indicating this command was skipped if parseable output
-        // was requested.
-        parseable_output::emitSkippedMessage(llvm::errs(), *Cmd);
-      }
-
-      State.ScheduledCommands.insert(Cmd);
-      markFinished(Cmd);
-    }
-
-    // ...which may allow us to go on and do later tasks.
-  } while (Result == 0 && TQ->hasRemainingTasks());
-
-  if (Result == 0) {
-    assert(State.BlockingCommands.empty() &&
-           "some blocking commands never finished properly");
-  } else {
-    // Make sure we record any files that still need to be rebuilt.
-    for (const Job *Cmd : getJobs()) {
-      // Skip files that don't use dependency analysis.
-      StringRef DependenciesFile =
-          Cmd->getOutput().getAdditionalOutputForType(types::TY_SwiftDeps);
-      if (DependenciesFile.empty())
-        continue;
-
-      // Don't worry about commands that finished or weren't going to run.
-      if (State.FinishedCommands.count(Cmd))
-        continue;
-      if (!State.ScheduledCommands.count(Cmd))
-        continue;
-
-      bool isCascading = true;
-      if (getIncrementalBuildEnabled())
-        isCascading = DepGraph.isMarked(Cmd);
-      State.UnfinishedCommands.insert({Cmd, isCascading});
-    }
-  }
+  State.scheduleInitialJobs();
+  State.scheduleAdditionalJobs();
+  State.runTaskQueueToCompletion();
+  State.checkUnfinishedJobs();
 
   if (!CompilationRecordPath.empty() && !SkipTaskExecution) {
     InputInfoMap InputInfo;
-    populateInputInfoMap(InputInfo, State);
+    State.populateInputInfoMap(InputInfo);
     checkForOutOfDateInputs(Diags, InputInfo);
     writeCompilationRecord(CompilationRecordPath, ArgsHash, BuildStartTime,
                            InputInfo);
   }
 
-  if (Result == 0)
-    Result = Diags.hadAnyError();
-  return Result;
+  return State.getResult();
 }
 
 int Compilation::performSingleCommand(const Job *Cmd) {
diff --git a/lib/Driver/DependencyGraph.cpp b/lib/Driver/DependencyGraph.cpp
index 1b321eb..6db9006 100644
--- a/lib/Driver/DependencyGraph.cpp
+++ b/lib/Driver/DependencyGraph.cpp
@@ -425,10 +425,15 @@
       }
       StringRef memberPart = name.str().substr(splitPoint+1);
 
-      out << " provides member '" << memberPart << "' of type '"
-          << swift::Demangle::demangleTypeAsString(typePart)
-          << "'\n";
-
+      if (memberPart.empty()) {
+        out << " provides non-private members of type '"
+            << swift::Demangle::demangleTypeAsString(typePart)
+            << "'\n";
+      } else {
+        out << " provides member '" << memberPart << "' of type '"
+            << swift::Demangle::demangleTypeAsString(typePart)
+            << "'\n";
+      }
     } else if (entry.KindMask.contains(DependencyKind::DynamicLookupName)) {
       out << " provides AnyObject member '" << entry.Name << "'\n";
 
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 3990de9..525b511 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -470,6 +470,8 @@
     ArgList->hasArg(options::OPT_driver_skip_execution);
   bool ShowIncrementalBuildDecisions =
     ArgList->hasArg(options::OPT_driver_show_incremental);
+  bool ShowJobLifecycle =
+    ArgList->hasArg(options::OPT_driver_show_job_lifecycle);
 
   bool Incremental = ArgList->hasArg(options::OPT_incremental);
   if (ArgList->hasArg(options::OPT_whole_module_optimization)) {
@@ -642,9 +644,12 @@
       ContinueBuildingAfterErrors)
     C->setContinueBuildingAfterErrors();
 
-  if (ShowIncrementalBuildDecisions)
+  if (ShowIncrementalBuildDecisions || ShowJobLifecycle)
     C->setShowsIncrementalBuildDecisions();
 
+  if (ShowJobLifecycle)
+    C->setShowJobLifecycle();
+
   // This has to happen after building jobs, because otherwise we won't even
   // emit .swiftdeps files for the next build.
   if (rebuildEverything)
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 10733cf..d4a8beb 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -13,7 +13,9 @@
 #include "swift/Basic/STLExtras.h"
 #include "swift/Driver/Job.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Option/Arg.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -106,3 +108,42 @@
   printArguments(os, Arguments);
   os << Terminator;
 }
+
+void Job::printSummary(raw_ostream &os) const {
+  // Deciding how to describe our inputs is a bit subtle; if we are a Job built
+  // from a JobAction that itself has InputActions sources, then we collect
+  // those up. Otherwise it's more correct to talk about our inputs as the
+  // outputs of our input-jobs.
+  SmallVector<std::string, 4> Inputs;
+
+  for (const Action *A : getSource().getInputs())
+    if (const InputAction *IA = dyn_cast<InputAction>(A))
+      Inputs.push_back(IA->getInputArg().getValue());
+
+  for (const Job *J : getInputs())
+    for (const std::string &f : J->getOutput().getPrimaryOutputFilenames())
+      Inputs.push_back(f);
+
+  size_t limit = 3;
+  size_t actual = Inputs.size();
+  if (actual > limit) {
+    Inputs.erase(Inputs.begin() + limit, Inputs.end());
+  }
+
+  os << "{" << getSource().getClassName() << ": ";
+  interleave(getOutput().getPrimaryOutputFilenames(),
+             [&](const std::string &Arg) {
+               os << llvm::sys::path::filename(Arg);
+             },
+             [&] { os << ' '; });
+  os << " <= ";
+  interleave(Inputs,
+             [&](const std::string &Arg) {
+               os << llvm::sys::path::filename(Arg);
+             },
+             [&] { os << ' '; });
+  if (actual > limit) {
+    os << " ... " << (actual-limit) << " more";
+  }
+  os << "}";
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 6fbb2a2..49c09b0 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -802,7 +802,7 @@
 
   // Check for an unneeded minor version, otherwise just list valid versions
   if (vers.hasValue() && !vers.getValue().empty() &&
-      vers.getValue().asMajorVersion().isValidEffectiveLanguageVersion()) {
+      vers.getValue().asMajorVersion().getEffectiveLanguageVersion()) {
     diags.diagnose(SourceLoc(), diag::note_swift_version_major,
                    vers.getValue()[0]);
   } else {
@@ -822,12 +822,15 @@
   if (auto A = Args.getLastArg(OPT_swift_version)) {
     auto vers = version::Version::parseVersionString(
       A->getValue(), SourceLoc(), &Diags);
-    if (vers.hasValue() &&
-        vers.getValue().isValidEffectiveLanguageVersion()) {
-      Opts.EffectiveLanguageVersion = vers.getValue();
-    } else {
-      diagnoseSwiftVersion(vers, A, Args, Diags);
+    bool isValid = false;
+    if (vers.hasValue()) {
+      if (auto effectiveVers = vers.getValue().getEffectiveLanguageVersion()) {
+        Opts.EffectiveLanguageVersion = effectiveVers.getValue();
+        isValid = true;
+      }
     }
+    if (!isValid)
+      diagnoseSwiftVersion(vers, A, Args, Diags);
   }
 
   Opts.AttachCommentsToDecls |= Args.hasArg(OPT_dump_api_path);
diff --git a/lib/IRGen/DebugTypeInfo.cpp b/lib/IRGen/DebugTypeInfo.cpp
index 551ea82..98f1546 100644
--- a/lib/IRGen/DebugTypeInfo.cpp
+++ b/lib/IRGen/DebugTypeInfo.cpp
@@ -50,16 +50,15 @@
                        Info.getBestKnownAlignment());
 }
 
-DebugTypeInfo DebugTypeInfo::getLocalVariable(DeclContext *DeclCtx,
+DebugTypeInfo DebugTypeInfo::getLocalVariable(DeclContext *DC,
                                               VarDecl *Decl, swift::Type Ty,
                                               const TypeInfo &Info,
                                               bool Unwrap) {
 
-  auto DeclType = Ty;
-  if (DeclCtx)
-    DeclType = (Decl->hasType()
-                    ? Decl->getType()
-                    : DeclCtx->mapTypeIntoContext(Decl->getInterfaceType()));
+  auto DeclType = (Decl->hasType()
+                   ? Decl->getType()
+                   : Decl->getDeclContext()->mapTypeIntoContext(
+                     Decl->getInterfaceType()));
   auto RealType = Ty;
   if (Unwrap) {
     DeclType = DeclType->getInOutObjectType();
@@ -75,7 +74,7 @@
   // the type hasn't been mucked with by an optimization pass.
   auto *Type = DeclSelfType->isEqual(RealType) ? DeclType.getPointer()
                                                : RealType.getPointer();
-  return getFromTypeInfo(DeclCtx, Type, Info);
+  return getFromTypeInfo(DC, Type, Info);
 }
 
 DebugTypeInfo DebugTypeInfo::getMetadata(swift::Type Ty, llvm::Type *StorageTy,
diff --git a/lib/IRGen/DebugTypeInfo.h b/lib/IRGen/DebugTypeInfo.h
index 87d389e..dc398e8 100644
--- a/lib/IRGen/DebugTypeInfo.h
+++ b/lib/IRGen/DebugTypeInfo.h
@@ -37,7 +37,8 @@
 /// for a type.
 class DebugTypeInfo {
 public:
-  /// The DeclContext if this is has an Archetype.
+  /// The DeclContext of the function. This might not be the DeclContext of
+  /// the variable if inlining took place.
   DeclContext *DeclCtx;
   /// The type we need to emit may be different from the type
   /// mentioned in the Decl, for example, stripped of qualifiers.
diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp
index 8fc2a0c..88aa338 100644
--- a/lib/IRGen/GenArchetype.cpp
+++ b/lib/IRGen/GenArchetype.cpp
@@ -74,49 +74,70 @@
   return metadata;
 }
 
-static bool declaresDirectConformance(AssociatedTypeDecl *associatedType,
-                                      ProtocolDecl *target) {
-  for (auto protocol : associatedType->getConformingProtocols()) {
-    if (protocol == target)
-      return true;
-  }
-  return false;
+namespace {
+  struct ConformancePath {
+    CanArchetypeType ParentArchetype;
+    ProtocolDecl *ParentProtocol;
+    CanType Path;
+  };
 }
 
-static AssociatedTypeDecl *
-findConformanceDeclaration(ArrayRef<ProtocolDecl*> conformsTo,
-                           AssociatedTypeDecl *associatedType,
-                           ProtocolDecl *target) {
-  // Fast path: this associated type declaration declares the
-  // desired conformance.
-  if (declaresDirectConformance(associatedType, target))
-    return associatedType;
-
-  // Otherwise, look at the conformance list.
-  for (auto source : conformsTo) {
-    // Do a lookup in this protocol.
-    auto results = source->lookupDirect(associatedType->getFullName());
-    for (auto lookupResult: results) {
-      if (auto sourceAssociatedType =
-            dyn_cast<AssociatedTypeDecl>(lookupResult)) {
-        if (declaresDirectConformance(sourceAssociatedType, target))
-          return sourceAssociatedType;
+static Optional<ConformancePath>
+declaresDirectConformance(ProtocolDecl *source,
+                          AssociatedTypeDecl *associatedType,
+                          ProtocolDecl *target) {
+  for (auto &reqt : source->getRequirementSignature()->getRequirements()) {
+    if (reqt.getKind() != RequirementKind::Conformance)
+      continue;
+    if (reqt.getSecondType()->castTo<ProtocolType>()->getDecl() != target)
+      continue;
+    auto path = reqt.getFirstType()->getCanonicalType();
+    if (auto memberType = dyn_cast<DependentMemberType>(path)) {
+      if (isa<GenericTypeParamType>(memberType.getBase())) {
+        assert(memberType.getBase()->isEqual(source->getSelfInterfaceType()));
+        if (memberType->getName() == associatedType->getName())
+          return ConformancePath{ CanArchetypeType(), source, path };
       }
     }
+  }
+  return None;
+}
+
+static Optional<ConformancePath>
+findConformanceRecursive(ArrayRef<ProtocolDecl*> conformsTo,
+                         AssociatedTypeDecl *associatedType,
+                         ProtocolDecl *target) {
+  for (auto source : conformsTo) {
+    // Check the protocol directly.
+    if (source != associatedType->getProtocol())
+      if (auto result = declaresDirectConformance(source, associatedType,
+                                                  target))
+        return result;
 
     // Recurse into implied protocols.
-    if (auto result =
-          findConformanceDeclaration(source->getInheritedProtocols(),
-                                     associatedType, target)) {
+    if (auto result = findConformanceRecursive(source->getInheritedProtocols(),
+                                               associatedType, target))
       return result;
-    }
   }
 
   // Give up.
-  return nullptr;
+  return None;
 }
 
-static IRGenFunction::ArchetypeAccessPath
+static Optional<ConformancePath>
+findConformanceDeclaration(ArrayRef<ProtocolDecl*> conformsTo,
+                           AssociatedTypeDecl *associatedType,
+                           ProtocolDecl *target) {
+  // Fast path: if the protocol that made this associated type
+  // declaration declared the desired conformance, we can use it directly.
+  if (auto result = declaresDirectConformance(associatedType->getProtocol(),
+                                              associatedType, target))
+    return result;
+
+  return findConformanceRecursive(conformsTo, associatedType, target);
+}
+
+static ConformancePath
 findAccessPathDeclaringConformance(IRGenFunction &IGF,
                                    CanArchetypeType archetype,
                                    ProtocolDecl *protocol) {
@@ -128,14 +149,20 @@
     auto association =
       findConformanceDeclaration(parent->getConformsTo(),
                                  archetype->getAssocType(), protocol);
-    if (association) return { parent, association };
+    if (association) {
+      association->ParentArchetype = parent;
+      return *association;
+    }
   }
 
   for (auto accessPath : IGF.getArchetypeAccessPaths(archetype)) {
     auto association =
       findConformanceDeclaration(accessPath.BaseType->getConformsTo(),
                                  accessPath.Association, protocol);
-    if (association) return { accessPath.BaseType, association };
+    if (association) {
+      association->ParentArchetype = accessPath.BaseType;
+      return *association;
+    }
   }
 
   llvm_unreachable("no relation found that declares conformance to target");
@@ -197,16 +224,30 @@
 
     // If that's not present, this conformance must be implied by some
     // associated-type relationship.
+
+    // First, find the right access path.
     auto accessPath =
       findAccessPathDeclaringConformance(IGF, archetype, protocol);
 
-    // To do this, we need the metadata for the associated type.
-    auto associatedMetadata = emitArchetypeTypeMetadataRef(IGF, archetype);
+    // Get the metadata for the parent.
+    llvm::Value *parentMetadata =
+      emitArchetypeTypeMetadataRef(IGF, accessPath.ParentArchetype);
 
-    CanArchetypeType parent = accessPath.BaseType;
-    AssociatedTypeDecl *association = accessPath.Association;
-    wtable = emitAssociatedTypeWitnessTableRef(IGF, parent, association,
-                                               associatedMetadata,
+    // Get the conformance of the parent to the protocol which declares
+    // the associated conformance.
+    llvm::Value *parentWTable =
+      emitArchetypeWitnessTableRef(IGF, accessPath.ParentArchetype,
+                                   accessPath.ParentProtocol);
+
+    // Get the metadata for the associated type, i.e. this type.
+    auto archetypeMetadata = emitArchetypeTypeMetadataRef(IGF, archetype);
+
+    // Call the accessor.
+    wtable = emitAssociatedTypeWitnessTableRef(IGF, parentMetadata,
+                                               parentWTable,
+                                               accessPath.ParentProtocol,
+                                               accessPath.Path,
+                                               archetypeMetadata,
                                                protocol);
 
     setProtocolWitnessTableName(IGF.IGM, wtable, archetype, protocol);
@@ -361,34 +402,6 @@
   return emitAssociatedTypeMetadataRef(IGF, originMetadata, wtable, associate);
 }
 
-llvm::Value *
-irgen::emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
-                                         CanArchetypeType origin,
-                                         AssociatedTypeDecl *associate,
-                                         llvm::Value *associateMetadata,
-                                         ProtocolDecl *associateProtocol) {
-  // We might really be asking for information associated with a more refined
-  // associated type declaration.
-  associate = findConformanceDeclaration(origin->getConformsTo(),
-                                         associate,
-                                         associateProtocol);
-  assert(associate &&
-         "didn't find any associatedtype declaration declaring "
-         "direct conformance to target protocol");
-
-  // Find the conformance of the origin to the associated type's protocol.
-  llvm::Value *wtable = emitArchetypeWitnessTableRef(IGF, origin,
-                                                     associate->getProtocol());
-
-  // Find the origin's type metadata.
-  llvm::Value *originMetadata = emitArchetypeTypeMetadataRef(IGF, origin);
-
-  // FIXME: will this ever be an indirect requirement?
-  return emitAssociatedTypeWitnessTableRef(IGF, originMetadata, wtable,
-                                           associate, associateMetadata,
-                                           associateProtocol);
-}
-
 const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
   assert(isExemplarArchetype(archetype) && "lowering non-exemplary archetype");
 
diff --git a/lib/IRGen/GenArchetype.h b/lib/IRGen/GenArchetype.h
index c6e495a..6baa977 100644
--- a/lib/IRGen/GenArchetype.h
+++ b/lib/IRGen/GenArchetype.h
@@ -53,14 +53,6 @@
                                              CanArchetypeType origin,
                                              AssociatedTypeDecl *associate);
 
-  /// Emit a witness table reference for a specific conformance of an
-  /// associated type of an archetype.
-  llvm::Value *emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
-                                                 CanArchetypeType origin,
-                                                 AssociatedTypeDecl *associate,
-                                                 llvm::Value *associateMetadata,
-                                               ProtocolDecl *associateProtocol);
-
   /// Emit a dynamic metatype lookup for the given archetype.
   llvm::Value *emitDynamicTypeOfOpaqueArchetype(IRGenFunction &IGF,
                                                 Address archetypeAddr,
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index ac932a7..46c949d 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -3303,16 +3303,15 @@
 llvm::Function *
 IRGenModule::getAddrOfAssociatedTypeWitnessTableAccessFunction(
                                   const NormalProtocolConformance *conformance,
-                                  AssociatedTypeDecl *associate,
-                                  ProtocolDecl *associateProtocol) {
+                                  CanType associatedType,
+                                  ProtocolDecl *associatedProtocol) {
   checkEligibleConf(conformance);
   auto forDefinition = ForDefinition;
 
-  assert(conformance->getProtocol() == associate->getProtocol());
   LinkEntity entity =
     LinkEntity::forAssociatedTypeWitnessTableAccessFunction(conformance,
-                                                            associate,
-                                                            associateProtocol);
+                                                            associatedType,
+                                                            associatedProtocol);
   llvm::Function *&entry = GlobalFuncs[entity];
   if (entry) {
     if (forDefinition) updateLinkageForDefinition(*this, entry, entity);
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 1102627..b7a5862 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -639,40 +639,31 @@
 
   /// A class which lays out a witness table in the abstract.
   class WitnessTableLayout : public SILWitnessVisitor<WitnessTableLayout> {
-    unsigned NumWitnesses = 0;
     SmallVector<WitnessTableEntry, 16> Entries;
 
-    WitnessIndex getNextIndex() {
-      return WitnessIndex(NumWitnesses++, /*isPrefix=*/false);
-    }
-
   public:
     /// The next witness is an out-of-line base protocol.
     void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) {
-      Entries.push_back(
-             WitnessTableEntry::forOutOfLineBase(baseProto, getNextIndex()));
+      Entries.push_back(WitnessTableEntry::forOutOfLineBase(baseProto));
     }
 
     void addMethod(FuncDecl *func) {
-      Entries.push_back(WitnessTableEntry::forFunction(func, getNextIndex()));
+      Entries.push_back(WitnessTableEntry::forFunction(func));
     }
 
     void addConstructor(ConstructorDecl *ctor) {
-      Entries.push_back(WitnessTableEntry::forFunction(ctor, getNextIndex()));
+      Entries.push_back(WitnessTableEntry::forFunction(ctor));
     }
 
-    void addAssociatedType(AssociatedTypeDecl *ty,
-                           ArrayRef<ProtocolDecl *> protos) {
-      // An associated type takes up a spot for the type metadata and for the
-      // witnesses to all its conformances.
+    void addAssociatedType(AssociatedTypeDecl *ty) {
+      Entries.push_back(WitnessTableEntry::forAssociatedType(ty));
+    }
+
+    void addAssociatedConformance(CanType path, ProtocolDecl *protocol) {
       Entries.push_back(
-                      WitnessTableEntry::forAssociatedType(ty, getNextIndex()));
-      for (auto *proto : protos)
-        if (Lowering::TypeConverter::protocolRequiresWitnessTable(proto))
-          ++NumWitnesses;
+                   WitnessTableEntry::forAssociatedConformance(path, protocol));
     }
 
-    unsigned getNumWitnesses() const { return NumWitnesses; }
     ArrayRef<WitnessTableEntry> getEntries() const { return Entries; }
   };
 
@@ -769,12 +760,11 @@
         if (!Lowering::TypeConverter::protocolRequiresWitnessTable(base))
           continue;
 
-        auto &baseEntry = protoInfo.getWitnessEntry(base);
-        assert(baseEntry.isBase());
+        auto baseIndex = protoInfo.getBaseIndex(base);
 
         // Compute the length down to this base.
         unsigned lengthToBase = lengthSoFar;
-        if (baseEntry.isOutOfLineBase()) {
+        if (!baseIndex.isPrefix()) {
           lengthToBase++;
 
           // Don't consider this path if we reach a length that can't
@@ -803,8 +793,8 @@
         foundBetter = true;
 
         // Add the link from proto to base if necessary.
-        if (baseEntry.isOutOfLineBase()) {
-          ReversePath.push_back(baseEntry.getOutOfLineBaseIndex());
+        if (!baseIndex.isPrefix()) {
+          ReversePath.push_back(baseIndex);
 
         // If it isn't necessary, then we might be able to
         // short-circuit considering the bases of this protocol.
@@ -1048,8 +1038,8 @@
              && "sil witness table does not match protocol");
       assert(entry.getBaseProtocolWitness().Requirement == baseProto
              && "sil witness table does not match protocol");
-      auto piEntry = PI.getWitnessEntry(baseProto);
-      assert(piEntry.getOutOfLineBaseIndex().getValue() == Table.size()
+      auto piIndex = PI.getBaseIndex(baseProto);
+      assert(piIndex.getValue() == Table.size()
              && "offset doesn't match ProtocolInfo layout");
 #endif
       
@@ -1092,8 +1082,8 @@
              && "sil witness table does not match protocol");
       assert(entry.getMethodWitness().Requirement.getDecl() == requirement
              && "sil witness table does not match protocol");
-      auto piEntry = PI.getWitnessEntry(requirement);
-      assert(piEntry.getFunctionIndex().getValue() == Table.size()
+      auto piIndex = PI.getFunctionIndex(requirement);
+      assert(piIndex.getValue() == Table.size()
              && "offset doesn't match ProtocolInfo layout");
 #endif
 
@@ -1118,16 +1108,15 @@
       return addMethodFromSILWitnessTable(requirement);
     }
 
-    void addAssociatedType(AssociatedTypeDecl *requirement,
-                           ArrayRef<ProtocolDecl *> protos) {
+    void addAssociatedType(AssociatedTypeDecl *requirement) {
 #ifndef NDEBUG
       auto &entry = SILEntries.front();
       assert(entry.getKind() == SILWitnessTable::AssociatedType
              && "sil witness table does not match protocol");
       assert(entry.getAssociatedTypeWitness().Requirement == requirement
              && "sil witness table does not match protocol");
-      auto piEntry = PI.getWitnessEntry(requirement);
-      assert(piEntry.getAssociatedTypeIndex().getValue() == Table.size()
+      auto piIndex = PI.getAssociatedTypeIndex(requirement);
+      assert(piIndex.getValue() == Table.size()
              && "offset doesn't match ProtocolInfo layout");
 #endif
 
@@ -1135,7 +1124,6 @@
 
       const Substitution &sub =
         Conformance.getTypeWitness(requirement, nullptr);
-      assert(protos.size() == sub.getConformances().size());
 
       // This type will be expressed in terms of the archetypes
       // of the conforming context.
@@ -1145,34 +1133,41 @@
       llvm::Constant *metadataAccessFunction =
         getAssociatedTypeMetadataAccessFunction(requirement, associate);
       Table.push_back(metadataAccessFunction);
+    }
 
+    void addAssociatedConformance(Type associatedType, ProtocolDecl *protocol) {
       // FIXME: Add static witness tables for type conformances.
-      for (auto index : indices(protos)) {
-        ProtocolDecl *protocol = protos[index];
-        auto associatedConformance = sub.getConformances()[index];
 
-        if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
-          continue;
+      CanType associate = Conformance.getAssociatedType(associatedType)
+                                    ->getCanonicalType();
+      assert(!associate->hasTypeParameter());
+
+      ProtocolConformanceRef associatedConformance =
+        Conformance.getAssociatedConformance(associatedType, protocol);
 
 #ifndef NDEBUG
-        auto &entry = SILEntries.front();
-        (void)entry;
-        assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol
-               && "sil witness table does not match protocol");
-        auto associatedWitness = entry.getAssociatedTypeProtocolWitness();
-        assert(associatedWitness.Requirement == requirement
-               && "sil witness table does not match protocol");
-        assert(associatedWitness.Protocol == protocol
-               && "sil witness table does not match protocol");
+      auto &entry = SILEntries.front();
+      (void)entry;
+      assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol
+             && "sil witness table does not match protocol");
+      auto associatedWitness = entry.getAssociatedTypeProtocolWitness();
+      assert(associatedWitness.Requirement->isEqual(associatedType)
+             && "sil witness table does not match protocol");
+      assert(associatedWitness.Protocol == protocol
+             && "sil witness table does not match protocol");
+      auto piIndex =
+        PI.getAssociatedConformanceIndex(associatedType->getCanonicalType(),
+                                         protocol);
+      assert(piIndex.getValue() == Table.size()
+             && "offset doesn't match ProtocolInfo layout");
 #endif
 
-        SILEntries = SILEntries.slice(1);
+      SILEntries = SILEntries.slice(1);
 
-        llvm::Constant *wtableAccessFunction = 
-          getAssociatedTypeWitnessTableAccessFunction(requirement, associate,
-                                            protocol, associatedConformance);
-        Table.push_back(wtableAccessFunction);
-      }
+      llvm::Constant *wtableAccessFunction = 
+        getAssociatedTypeWitnessTableAccessFunction(CanType(associatedType),
+                                 associate, protocol, associatedConformance);
+      Table.push_back(wtableAccessFunction);
     }
 
   private:
@@ -1183,7 +1178,7 @@
                                             CanType associatedType);
 
     llvm::Constant *
-    getAssociatedTypeWitnessTableAccessFunction(AssociatedTypeDecl *requirement,
+    getAssociatedTypeWitnessTableAccessFunction(CanType depAssociatedType,
                                                 CanType associatedType,
                                                 ProtocolDecl *protocol,
                                         ProtocolConformanceRef conformance);
@@ -1344,8 +1339,19 @@
   }
 }
 
+static void buildAssociatedTypeValueName(CanType depAssociatedType,
+                                         SmallString<128> &name) {
+  if (auto memberType = dyn_cast<DependentMemberType>(depAssociatedType)) {
+    buildAssociatedTypeValueName(memberType.getBase(), name);
+    name += '.';
+    name += memberType->getName().str();
+  } else {
+    assert(isa<GenericTypeParamType>(depAssociatedType)); // Self
+  }
+}
+
 llvm::Constant *WitnessTableBuilder::
-getAssociatedTypeWitnessTableAccessFunction(AssociatedTypeDecl *requirement,
+getAssociatedTypeWitnessTableAccessFunction(CanType depAssociatedType,
                                             CanType associatedType,
                                             ProtocolDecl *associatedProtocol,
                                 ProtocolConformanceRef associatedConformance) {
@@ -1359,7 +1365,7 @@
   // Otherwise, emit an access function.
   llvm::Function *accessor =
     IGM.getAddrOfAssociatedTypeWitnessTableAccessFunction(&Conformance,
-                                                          requirement,
+                                                          depAssociatedType,
                                                           associatedProtocol);
 
   IRGenFunction IGF(IGM, accessor);
@@ -1372,16 +1378,19 @@
 
   // We use a non-standard name for the type that states the association
   // requirement rather than the concrete type.
-  if (IGM.EnableValueNames)
-    associatedTypeMetadata->setName(Twine(ConcreteType->getString())
-                                      + "." + requirement->getNameStr());
+  if (IGM.EnableValueNames) {
+    SmallString<128> name;
+    name += ConcreteType->getString();
+    buildAssociatedTypeValueName(depAssociatedType, name);
+    associatedTypeMetadata->setName(name);
+  }
 
   llvm::Value *self = parameters.claimNext();
   setTypeMetadataName(IGM, self, ConcreteType);
 
   Address destTable(parameters.claimNext(), IGM.getPointerAlignment());
   setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType,
-                              requirement->getProtocol());
+                              Conformance.getProtocol());
 
   const ConformanceInfo *conformanceI = nullptr;
   if (associatedConformance.isConcrete()) {
@@ -1642,8 +1651,7 @@
     layout.visitProtocolDecl(protocol);
 
   // Create a ProtocolInfo object from the layout.
-  ProtocolInfo *info = ProtocolInfo::create(layout.getNumWitnesses(),
-                                            layout.getEntries());
+  ProtocolInfo *info = ProtocolInfo::create(layout.getEntries());
   info->NextConverted = FirstProtocol;
   FirstProtocol = info;
 
@@ -1655,11 +1663,10 @@
 }
 
 /// Allocate a new ProtocolInfo.
-ProtocolInfo *ProtocolInfo::create(unsigned numWitnesses,
-                                   ArrayRef<WitnessTableEntry> table) {
+ProtocolInfo *ProtocolInfo::create(ArrayRef<WitnessTableEntry> table) {
   size_t bufferSize = totalSizeToAlloc<WitnessTableEntry>(table.size());
   void *buffer = ::operator new(bufferSize);
-  return new(buffer) ProtocolInfo(numWitnesses, table);
+  return new(buffer) ProtocolInfo(table);
 }
 
 ProtocolInfo::~ProtocolInfo() {
@@ -2069,13 +2076,13 @@
 
     if (source) {
       auto &pi = IGF.IGM.getProtocolInfo(protocol);
-      auto &entry = pi.getWitnessEntry(inheritedProtocol);
-      assert(entry.isOutOfLineBase());
-      source = emitInvariantLoadOfOpaqueWitness(IGF, source,
-                                                entry.getOutOfLineBaseIndex());
-      source = IGF.Builder.CreateBitCast(source, IGF.IGM.WitnessTablePtrTy);
-      setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type,
-                                  inheritedProtocol);
+      auto index = pi.getBaseIndex(inheritedProtocol);
+      if (!index.isPrefix()) {
+        source = emitInvariantLoadOfOpaqueWitness(IGF, source, index);
+        source = IGF.Builder.CreateBitCast(source, IGF.IGM.WitnessTablePtrTy);
+        setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type,
+                                    inheritedProtocol);
+      }
     }
     return source;
   }
@@ -2752,7 +2759,7 @@
 
   // Find the witness we're interested in.
   auto &fnProtoInfo = IGF.IGM.getProtocolInfo(conformance.getRequirement());
-  auto index = fnProtoInfo.getWitnessEntry(fn).getFunctionIndex();
+  auto index = fnProtoInfo.getFunctionIndex(fn);
   llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
   
   // Cast the witness pointer to i8*.
@@ -2779,7 +2786,7 @@
                                                   llvm::Value *wtable,
                                           AssociatedTypeDecl *associatedType) {
   auto &pi = IGF.IGM.getProtocolInfo(associatedType->getProtocol());
-  auto index = pi.getWitnessEntry(associatedType).getAssociatedTypeIndex();
+  auto index = pi.getAssociatedTypeIndex(associatedType);
   llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
 
   // Cast the witness to the appropriate function type.
@@ -2818,12 +2825,13 @@
 irgen::emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
                                          llvm::Value *parentMetadata,
                                          llvm::Value *wtable,
-                                         AssociatedTypeDecl *associatedType,
+                                         ProtocolDecl *parentProtocol,
+                                         CanType associatedType,
                                          llvm::Value *associatedTypeMetadata,
                                          ProtocolDecl *associatedProtocol) {
-  auto &pi = IGF.IGM.getProtocolInfo(associatedType->getProtocol());
-  auto index = pi.getWitnessEntry(associatedType)
-                 .getAssociatedTypeWitnessTableIndex(associatedProtocol);
+  auto &pi = IGF.IGM.getProtocolInfo(parentProtocol);
+  auto index =
+    pi.getAssociatedConformanceIndex(associatedType, associatedProtocol);
   llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
 
   // Cast the witness to the appropriate function type.
diff --git a/lib/IRGen/GenProto.h b/lib/IRGen/GenProto.h
index f924346..48b67a6 100644
--- a/lib/IRGen/GenProto.h
+++ b/lib/IRGen/GenProto.h
@@ -71,21 +71,23 @@
                                              llvm::Value *wtable,
                                            AssociatedTypeDecl *associatedType);
 
-  /// Given a type T and an associated type X of a protocol PT to which
+  /// Given a type T and an associated type path X.Y of a protocol PT to which
   /// T conforms, where X is required to implement some protocol PX, return
-  /// the witness table witnessing the conformance of T.X to PX.
+  /// the witness table witnessing the conformance of T.X.Y to PX.
   ///
-  /// PX must be a direct requirement of X.
+  /// PX must be a direct requirement of PT.
   ///
   /// \param parentMetadata - the type metadata for T
   /// \param wtable - the witness table witnessing the conformance of T to PT
-  /// \param associatedType - the declaration of X; a member of PT
-  /// \param associatedTypeMetadata - the type metadata for T.X
+  /// \param parentProtocol - PT
+  /// \param associatedType - the path X.Y, a dependent type within PT
+  /// \param associatedTypeMetadata - the type metadata for T.X.Y
   /// \param associatedProtocol - the declaration of PX
   llvm::Value *emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
                                                  llvm::Value *parentMetadata,
                                                  llvm::Value *wtable,
-                                          AssociatedTypeDecl *associatedType,
+                                          ProtocolDecl *parentProtocol,
+                                          CanType associatedType,
                                           llvm::Value *associatedTypeMetadata,
                                           ProtocolDecl *associatedProtocol);
 
diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h
index 33c5245..026d0a0 100644
--- a/lib/IRGen/IRGenMangler.h
+++ b/lib/IRGen/IRGenMangler.h
@@ -120,16 +120,25 @@
 
   std::string mangleAssociatedTypeWitnessTableAccessFunction(
                                       const ProtocolConformance *Conformance,
-                                      StringRef AssocTyName,
+                                      CanType AssociatedType,
                                       const ProtocolDecl *Proto) {
     beginMangling();
     appendProtocolConformance(Conformance);
-    appendIdentifier(AssocTyName);
+    appendAssociatedTypePath(AssociatedType);
     appendNominalType(Proto);
     appendOperator("WT");
     return finalize();
   }
 
+  void appendAssociatedTypePath(CanType associatedType) {
+    if (auto memberType = dyn_cast<DependentMemberType>(associatedType)) {
+      appendAssociatedTypePath(memberType.getBase());
+      appendIdentifier(memberType->getName().str());
+    } else {
+      assert(isa<GenericTypeParamType>(associatedType));
+    }
+  }
+
   std::string mangleReflectionBuiltinDescriptor(Type type) {
     return mangleTypeSymbol(type, "MB");
   }
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index e5282b1..ede0aae 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -968,7 +968,7 @@
                                            AssociatedTypeDecl *associatedType);
   llvm::Function *getAddrOfAssociatedTypeWitnessTableAccessFunction(
                                            const NormalProtocolConformance *C,
-                                           AssociatedTypeDecl *associatedType,
+                                           CanType depAssociatedType,
                                            ProtocolDecl *requiredProtocol);
 
   Address getAddrOfObjCISAMask();
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index 97e61fb..73408ac 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -898,6 +898,13 @@
   void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *i);
   
   void visitFixLifetimeInst(FixLifetimeInst *i);
+  void visitEndLifetimeInst(EndLifetimeInst *i) {
+    llvm_unreachable("unimplemented");
+  }
+  void
+  visitUncheckedOwnershipConversionInst(UncheckedOwnershipConversionInst *i) {
+    llvm_unreachable("unimplemented");
+  }
   void visitBeginBorrowInst(BeginBorrowInst *i) {
     llvm_unreachable("unimplemented");
   }
diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp
index 0fdcbfc..5ecd6c5 100644
--- a/lib/IRGen/Linking.cpp
+++ b/lib/IRGen/Linking.cpp
@@ -80,6 +80,15 @@
   buffer.write(Result.data(), Result.size());
 }
 
+static void mangleAssociatedTypePath(Mangler &mangler, CanType assocType) {
+  if (auto memberType = dyn_cast<DependentMemberType>(assocType)) {
+    mangleAssociatedTypePath(mangler, memberType.getBase());
+    mangler.mangleIdentifier(memberType->getName().str());
+  } else {
+    assert(isa<GenericTypeParamType>(assocType));
+  }
+}
+
 /// Mangle this entity into the given stream.
 std::string LinkEntity::mangleOld() const {
   // Almost everything below gets the common prefix:
@@ -209,13 +218,15 @@
     mangler.mangleIdentifier(getAssociatedType()->getNameStr());
     return mangler.finalize();
 
-  //   global ::= 'WT' protocol-conformance identifier nominal-type
-  case Kind::AssociatedTypeWitnessTableAccessFunction:
+  //   global ::= 'WT' protocol-conformance identifier+ nominal-type
+  case Kind::AssociatedTypeWitnessTableAccessFunction: {
     mangler.append("_TWT");
     mangler.mangleProtocolConformance(getProtocolConformance());
-    mangler.mangleIdentifier(getAssociatedType()->getNameStr());
-    mangler.mangleProtocolDecl(getAssociatedProtocol());
+    auto assocConf = getAssociatedConformance();
+    mangleAssociatedTypePath(mangler, assocConf.first);
+    mangler.mangleProtocolDecl(assocConf.second);
     return mangler.finalize();
+  }
 
   // For all the following, this rule was imposed above:
   //   global ::= local-marker? entity            // some identifiable thing
@@ -412,11 +423,12 @@
       return mangler.mangleAssociatedTypeMetadataAccessFunction(
                   getProtocolConformance(), getAssociatedType()->getNameStr());
 
-      //   global ::= 'WT' protocol-conformance identifier nominal-type
-    case Kind::AssociatedTypeWitnessTableAccessFunction:
+      //   global ::= protocol-conformance identifier+ nominal-type 'WT'
+    case Kind::AssociatedTypeWitnessTableAccessFunction: {
+      auto assocConf = getAssociatedConformance();
       return mangler.mangleAssociatedTypeWitnessTableAccessFunction(
-                  getProtocolConformance(), getAssociatedType()->getNameStr(),
-                  getAssociatedProtocol());
+                  getProtocolConformance(), assocConf.first, assocConf.second);
+    }
 
       // For all the following, this rule was imposed above:
       //   global ::= local-marker? entity            // some identifiable thing
diff --git a/lib/IRGen/Linking.h b/lib/IRGen/Linking.h
index fce2224..37c30f9 100644
--- a/lib/IRGen/Linking.h
+++ b/lib/IRGen/Linking.h
@@ -83,8 +83,12 @@
     MetadataAddressShift = 8, MetadataAddressMask = 0x0300,
     IsPatternShift = 10, IsPatternMask = 0x0400,
 
-    // This field appears in associated type access function kinds.
+    // This field appears in associated type access functions.
     AssociatedTypeIndexShift = 8, AssociatedTypeIndexMask = ~KindMask,
+
+    // This field appears in associated conformance access functions.
+    AssociatedConformanceIndexShift = 8,
+    AssociatedConformanceIndexMask = ~KindMask,
   };
 #define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
 #define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
@@ -160,8 +164,8 @@
 
     /// A function which returns the witness table for a protocol-constrained
     /// associated type of a protocol.  The secondary pointer is a
-    /// ProtocolConformance*.  The primary pointer is a ProtocolDecl*.
-    /// The index of the associated type declaration is stored in the data.
+    /// ProtocolConformance*.  The index of the associated conformance
+    /// requirement is stored in the data.
     AssociatedTypeWitnessTableAccessFunction,
 
     /// A reflection metadata descriptor for the associated type witnesses of a
@@ -264,16 +268,28 @@
 
   void setForProtocolConformanceAndAssociatedType(Kind kind,
                                                   const ProtocolConformance *c,
-                                                  AssociatedTypeDecl *associate,
-                                   ProtocolDecl *associatedProtocol = nullptr) {
+                                                  AssociatedTypeDecl *associate) {
     assert(isProtocolConformanceKind(kind));
-    Pointer = associatedProtocol;
+    Pointer = nullptr;
     SecondaryPointer = const_cast<void*>(static_cast<const void*>(c));
     Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) |
            LINKENTITY_SET_FIELD(AssociatedTypeIndex,
                                 getAssociatedTypeIndex(c, associate));
   }
 
+  void setForProtocolConformanceAndAssociatedConformance(Kind kind,
+                                                  const ProtocolConformance *c,
+                                                  CanType associatedType,
+                                            ProtocolDecl *associatedProtocol) {
+    assert(isProtocolConformanceKind(kind));
+    Pointer = associatedProtocol;
+    SecondaryPointer = const_cast<void*>(static_cast<const void*>(c));
+    Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) |
+           LINKENTITY_SET_FIELD(AssociatedConformanceIndex,
+                                getAssociatedConformanceIndex(c, associatedType,
+                                                          associatedProtocol));
+  }
+
   // We store associated types using their index in their parent protocol
   // in order to avoid bloating LinkEntity out to three key pointers.
   static unsigned getAssociatedTypeIndex(const ProtocolConformance *conformance,
@@ -299,6 +315,37 @@
     llvm_unreachable("didn't find associated type in protocol?");
   }
 
+  // We store associated conformances using their index in the requirement
+  // list of the requirement signature of the conformance's protocol.
+  static unsigned getAssociatedConformanceIndex(
+                                      const ProtocolConformance *conformance,
+                                                CanType associatedType,
+                                                ProtocolDecl *requirement) {
+    unsigned index = 0;
+    for (auto &reqt : conformance->getProtocol()->getRequirementSignature()
+                                                ->getRequirements()) {
+      if (reqt.getKind() == RequirementKind::Conformance &&
+          reqt.getFirstType()->getCanonicalType() == associatedType &&
+          reqt.getSecondType()->castTo<ProtocolType>()->getDecl() ==
+                                                                requirement) {
+        return index;
+      }
+      ++index;
+    }
+    llvm_unreachable("requirement not found in protocol");
+  }
+
+  static std::pair<CanType, ProtocolDecl*>
+  getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
+                                  unsigned index) {
+    auto &reqt =
+      conformance->getProtocol()->getRequirementSignature()
+                                ->getRequirements()[index];
+    assert(reqt.getKind() == RequirementKind::Conformance);
+    return { reqt.getFirstType()->getCanonicalType(),
+             reqt.getSecondType()->castTo<ProtocolType>()->getDecl() };
+  }
+
   void setForType(Kind kind, CanType type) {
     assert(isTypeKind(kind));
     Pointer = type.getPointer();
@@ -493,12 +540,12 @@
 
   static LinkEntity
   forAssociatedTypeWitnessTableAccessFunction(const ProtocolConformance *C,
-                                              AssociatedTypeDecl *associate,
-                                              ProtocolDecl *associateProtocol) {
+                                              CanType associatedType,
+                                              ProtocolDecl *associatedProtocol){
     LinkEntity entity;
-    entity.setForProtocolConformanceAndAssociatedType(
-                Kind::AssociatedTypeWitnessTableAccessFunction, C, associate,
-                                                      associateProtocol);
+    entity.setForProtocolConformanceAndAssociatedConformance(
+                     Kind::AssociatedTypeWitnessTableAccessFunction, C,
+                     associatedType, associatedProtocol);
     return entity;
   }
 
@@ -576,12 +623,17 @@
   }
 
   AssociatedTypeDecl *getAssociatedType() const {
-    assert(getKind() == Kind::AssociatedTypeMetadataAccessFunction ||
-           getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
+    assert(getKind() == Kind::AssociatedTypeMetadataAccessFunction);
     return getAssociatedTypeByIndex(getProtocolConformance(),
                               LINKENTITY_GET_FIELD(Data, AssociatedTypeIndex));
   }
 
+  std::pair<CanType, ProtocolDecl *> getAssociatedConformance() const {
+    assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
+    return getAssociatedConformanceByIndex(getProtocolConformance(),
+                       LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
+  }
+
   ProtocolDecl *getAssociatedProtocol() const {
     assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
     return reinterpret_cast<ProtocolDecl*>(Pointer);
diff --git a/lib/IRGen/ProtocolInfo.h b/lib/IRGen/ProtocolInfo.h
index d197b1c..ed7af13 100644
--- a/lib/IRGen/ProtocolInfo.h
+++ b/lib/IRGen/ProtocolInfo.h
@@ -52,92 +52,110 @@
 };
 
 /// A witness to a specific element of a protocol.  Every
-/// ProtocolTypeInfo stores one of these for each declaration in the
-/// protocol.
-/// 
-/// The structure of a witness varies by the type of declaration:
-///   - a function requires a single witness, the function;
-///   - a variable requires two witnesses, a getter and a setter;
-///   - a subscript requires two witnesses, a getter and a setter;
-///   - a type requires a pointer to the metadata for that type and
-///     to witness tables for each of the protocols it obeys.
+/// ProtocolTypeInfo stores one of these for each requirement
+/// introduced by the protocol.
 class WitnessTableEntry {
-  Decl *Member;
-  WitnessIndex BeginIndex;
+public:
+  void *MemberOrAssociatedType;
+  ProtocolDecl *Protocol;
 
- WitnessTableEntry(Decl *member, WitnessIndex begin)
-   : Member(member), BeginIndex(begin) {}
+  WitnessTableEntry(void *member, ProtocolDecl *protocol)
+    : MemberOrAssociatedType(member), Protocol(protocol) {}
 
 public:
   WitnessTableEntry() = default;
 
-  Decl *getMember() const {
-    return Member;
-  }
-
-  static WitnessTableEntry forPrefixBase(ProtocolDecl *proto) {
-    return WitnessTableEntry(proto, WitnessIndex(0, /*isPrefix=*/ true));
-  }
-
-  static WitnessTableEntry forOutOfLineBase(ProtocolDecl *proto,
-                                            WitnessIndex index) {
-    return WitnessTableEntry(proto, index);
+  static WitnessTableEntry forOutOfLineBase(ProtocolDecl *proto) {
+    assert(proto != nullptr);
+    return WitnessTableEntry(nullptr, proto);
   }
 
   /// Is this a base-protocol entry?
-  bool isBase() const { return isa<ProtocolDecl>(Member); }
+  bool isBase() const { return MemberOrAssociatedType == nullptr; }
 
-  /// Is the table for this base-protocol entry "out of line",
-  /// i.e. there is a witness which indirectly points to it, or is
-  /// it a prefix of the layout of this protocol?
+  bool matchesBase(ProtocolDecl *proto) const {
+    assert(proto != nullptr);
+    return MemberOrAssociatedType == nullptr && Protocol == proto;
+  }
+
+  /// Given that this is a base-protocol entry, is the table
+  /// "out of line"?
   bool isOutOfLineBase() const {
     assert(isBase());
-    return !BeginIndex.isPrefix();
+    return true;
   }
 
-  /// Return the index at which to find the table for this
-  /// base-protocol entry.
-  WitnessIndex getOutOfLineBaseIndex() const {
-    assert(isOutOfLineBase());
-    return BeginIndex;
+  ProtocolDecl *getBase() const {
+    assert(isBase());
+    return Protocol;
   }
 
-  static WitnessTableEntry forFunction(AbstractFunctionDecl *func,
-                                       WitnessIndex index) {
-    return WitnessTableEntry(func, index);
+  static WitnessTableEntry forFunction(AbstractFunctionDecl *func) {
+    assert(func != nullptr);
+    return WitnessTableEntry(func, nullptr);
   }
   
-  bool isFunction() const { return isa<AbstractFunctionDecl>(Member); }
+  bool isFunction() const {
+    return Protocol == nullptr &&
+           isa<AbstractFunctionDecl>(
+             static_cast<Decl*>(MemberOrAssociatedType));
+  }
 
-  WitnessIndex getFunctionIndex() const {
+  bool matchesFunction(AbstractFunctionDecl *func) const {
+    assert(func != nullptr);
+    return MemberOrAssociatedType == func && Protocol == nullptr;
+  }
+
+  AbstractFunctionDecl *getFunction() const {
     assert(isFunction());
-    return BeginIndex;
-  }
-  
-  static WitnessTableEntry forAssociatedType(AssociatedTypeDecl *ty,
-                                             WitnessIndex index) {
-    return WitnessTableEntry(ty, index);
-  }
-  
-  bool isAssociatedType() const { return isa<AssociatedTypeDecl>(Member); }
-  
-  WitnessIndex getAssociatedTypeIndex() const {
-    assert(isAssociatedType());
-    return BeginIndex;
+    return static_cast<AbstractFunctionDecl*>(MemberOrAssociatedType);
   }
 
-  WitnessIndex
-  getAssociatedTypeWitnessTableIndex(ProtocolDecl *target) const {
-    assert(!BeginIndex.isPrefix());
-    auto index = BeginIndex.getValue() + 1;
-    for (auto protocol :
-           cast<AssociatedTypeDecl>(Member)->getConformingProtocols()) {
-      if (protocol == target) {
-        return WitnessIndex(index, false);
-      }
-      index++;
-    }
-    llvm_unreachable("protocol not in direct conformance list?");
+  static WitnessTableEntry forAssociatedType(AssociatedTypeDecl *ty) {
+    return WitnessTableEntry(ty, nullptr);
+  }
+  
+  bool isAssociatedType() const {
+    return Protocol == nullptr &&
+           isa<AssociatedTypeDecl>(
+             static_cast<Decl*>(MemberOrAssociatedType));
+  }
+
+  bool matchesAssociatedType(AssociatedTypeDecl *assocType) const {
+    assert(assocType != nullptr);
+    return MemberOrAssociatedType == assocType && Protocol == nullptr;
+  }
+
+  AssociatedTypeDecl *getAssociatedType() const {
+    assert(isAssociatedType());
+    return static_cast<AssociatedTypeDecl*>(MemberOrAssociatedType);
+  }
+
+  static WitnessTableEntry forAssociatedConformance(CanType path,
+                                                    ProtocolDecl *requirement) {
+    assert(path && requirement != nullptr);
+    return WitnessTableEntry(path.getPointer(), requirement);
+  }
+
+  bool isAssociatedConformance() const {
+    return Protocol != nullptr && MemberOrAssociatedType != nullptr;
+  }
+
+  bool matchesAssociatedConformance(CanType path,
+                                    ProtocolDecl *requirement) const {
+    assert(path && requirement != nullptr);
+    return MemberOrAssociatedType == path.getPointer() &&
+           Protocol == requirement;
+  }
+
+  CanType getAssociatedConformancePath() const {
+    assert(isAssociatedConformance());
+    return CanType(static_cast<TypeBase *>(MemberOrAssociatedType));
+  }
+
+  ProtocolDecl *getAssociatedConformanceRequirement() const {
+    assert(isAssociatedConformance());
+    return Protocol;
   }
 };
 
@@ -150,9 +168,6 @@
   const ProtocolInfo *NextConverted;
   friend class TypeConverter;
 
-  /// The number of witnesses in the protocol.
-  unsigned NumWitnesses;
-
   /// The number of table entries in this protocol layout.
   unsigned NumTableEntries;
 
@@ -161,14 +176,13 @@
   mutable llvm::SmallDenseMap<const ProtocolConformance*, ConformanceInfo*, 2>
     Conformances;
 
-  ProtocolInfo(unsigned numWitnesses, ArrayRef<WitnessTableEntry> table)
-    : NumWitnesses(numWitnesses), NumTableEntries(table.size()) {
+  ProtocolInfo(ArrayRef<WitnessTableEntry> table)
+      : NumTableEntries(table.size()) {
     std::uninitialized_copy(table.begin(), table.end(),
                             getTrailingObjects<WitnessTableEntry>());
   }
 
-  static ProtocolInfo *create(unsigned numWitnesses,
-                              ArrayRef<WitnessTableEntry> table);
+  static ProtocolInfo *create(ArrayRef<WitnessTableEntry> table);
 
 public:
   const ConformanceInfo &getConformance(IRGenModule &IGM,
@@ -178,20 +192,53 @@
   /// The number of witness slots in a conformance to this protocol;
   /// in other words, the size of the table in words.
   unsigned getNumWitnesses() const {
-    return NumWitnesses;
+    return NumTableEntries;
   }
 
   ArrayRef<WitnessTableEntry> getWitnessEntries() const {
     return {getTrailingObjects<WitnessTableEntry>(), NumTableEntries};
   }
 
-  const WitnessTableEntry &getWitnessEntry(Decl *member) const {
-    // FIXME: do a binary search if the number of witnesses is large
-    // enough.
-    for (auto &witness : getWitnessEntries())
-      if (witness.getMember() == member)
-        return witness;
-    llvm_unreachable("didn't find entry for member!");
+  WitnessIndex getBaseIndex(ProtocolDecl *protocol) const {
+    auto entries = getWitnessEntries();
+    for (auto &witness : entries) {
+      if (witness.matchesBase(protocol)) {
+        if (witness.isOutOfLineBase()) {
+          return WitnessIndex(&witness - entries.begin(), false);
+        } else {
+          return WitnessIndex(0, true);
+        }
+      }
+    }
+    llvm_unreachable("didn't find entry for base");
+  }
+
+  WitnessIndex getFunctionIndex(AbstractFunctionDecl *function) const {
+    auto entries = getWitnessEntries();
+    for (auto &witness : entries) {
+      if (witness.matchesFunction(function))
+        return WitnessIndex(&witness - entries.begin(), false);
+    }
+    llvm_unreachable("didn't find entry for function");
+  }
+
+  WitnessIndex getAssociatedTypeIndex(AssociatedTypeDecl *assocType) const {
+    auto entries = getWitnessEntries();
+    for (auto &witness : entries) {
+      if (witness.matchesAssociatedType(assocType))
+        return WitnessIndex(&witness - entries.begin(), false);
+    }
+    llvm_unreachable("didn't find entry for associated type");
+  }
+
+  WitnessIndex getAssociatedConformanceIndex(CanType path,
+                                             ProtocolDecl *requirement) const {
+    auto entries = getWitnessEntries();
+    for (auto &witness : entries) {
+      if (witness.matchesAssociatedConformance(path, requirement))
+        return WitnessIndex(&witness - entries.begin(), false);
+    }
+    llvm_unreachable("didn't find entry for associated conformance");
   }
 
   ~ProtocolInfo();
diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp
index 52bf53c..dc07a83 100644
--- a/lib/Index/Index.cpp
+++ b/lib/Index/Index.cpp
@@ -355,7 +355,7 @@
   bool startEntity(Decl *D, IndexSymbol &Info);
   bool startEntityDecl(ValueDecl *D);
 
-  bool reportRelatedRef(ValueDecl *D, SourceLoc Loc, SymbolRoleSet Relations, Decl *Related);
+  bool reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isImplicit, SymbolRoleSet Relations, Decl *Related);
   bool reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet Relations, Decl *Related);
   bool reportInheritedTypeRefs(ArrayRef<TypeLoc> Inherited, Decl *Inheritee);
   NominalTypeDecl *getTypeLocAsNominalTypeDecl(const TypeLoc &Ty);
@@ -624,13 +624,16 @@
   return startEntity(D, Info);
 }
 
-bool IndexSwiftASTWalker::reportRelatedRef(ValueDecl *D, SourceLoc Loc, SymbolRoleSet Relations, Decl *Related) {
+bool IndexSwiftASTWalker::reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isImplicit,
+                                           SymbolRoleSet Relations, Decl *Related) {
   if (!shouldIndex(D))
     return true;
 
   IndexSymbol Info;
   if (addRelation(Info, Relations, Related))
     return true;
+  if (isImplicit)
+    Info.roles |= (unsigned)SymbolRole::Implicit;
 
   // don't report this ref again when visitDeclReference reports it
   repressRefAtLoc(Loc);
@@ -655,9 +658,24 @@
 
   if (IdentTypeRepr *T = dyn_cast_or_null<IdentTypeRepr>(Ty.getTypeRepr())) {
     auto Comps = T->getComponentRange();
-    if (auto NTD =
-            dyn_cast_or_null<NominalTypeDecl>(Comps.back()->getBoundDecl())) {
-      if (!reportRelatedRef(NTD, Comps.back()->getIdLoc(), Relations, Related))
+    SourceLoc IdLoc = Comps.back()->getIdLoc();
+    NominalTypeDecl *NTD = nullptr;
+    bool isImplicit = false;
+    if (auto *VD = Comps.back()->getBoundDecl()) {
+      if (auto *TAD = dyn_cast<TypeAliasDecl>(VD)) {
+        IndexSymbol Info;
+        if (!reportRef(TAD, IdLoc, Info))
+          return false;
+        if (auto Ty = TAD->getUnderlyingTypeLoc().getType()) {
+          NTD = Ty->getAnyNominal();
+          isImplicit = true;
+        }
+      } else {
+        NTD = dyn_cast<NominalTypeDecl>(VD);
+      }
+    }
+    if (NTD) {
+      if (!reportRelatedRef(NTD, IdLoc, isImplicit, Relations, Related))
         return false;
     }
     return true;
@@ -665,7 +683,7 @@
 
   if (Ty.getType()) {
     if (auto nominal = Ty.getType()->getAnyNominal())
-      if (!reportRelatedRef(nominal, Ty.getLoc(), Relations, Related))
+      if (!reportRelatedRef(nominal, Ty.getLoc(), /*isImplicit=*/false, Relations, Related))
         return false;
   }
   return true;
@@ -752,8 +770,8 @@
   if (!startEntity(D, Info))
     return false;
 
-  if (!reportRelatedRef(NTD, Loc, (SymbolRoleSet)SymbolRole::RelationExtendedBy,
-                        D))
+  if (!reportRelatedRef(NTD, Loc, /*isImplicit=*/false,
+                        (SymbolRoleSet)SymbolRole::RelationExtendedBy, D))
       return false;
   if (!reportInheritedTypeRefs(D->getInherited(), D))
       return false;
diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp
index f6c064d..378b897 100644
--- a/lib/Parse/ParseIfConfig.cpp
+++ b/lib/Parse/ParseIfConfig.cpp
@@ -1,4 +1,4 @@
-//===--- ParseDecl.cpp - Swift Language Parser for #if directives -- ------===//
+//===--- ParseIfConfig.cpp - Swift Language Parser for #if directives -----===//
 //
 // This source file is part of the Swift.org open source project
 //
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index dedf8c8..0ce7d6c 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -200,6 +200,25 @@
       return parseSILIdentifier(Result, L, Diagnostic(ID, Args...));
     }
 
+    template <typename T, typename... DiagArgTypes, typename... ArgTypes>
+    bool parseSILIdentifierSwitch(T &Result, ArrayRef<StringRef> Strings,
+                                  Diag<DiagArgTypes...> ID, ArgTypes... Args) {
+      Identifier TmpResult;
+      SourceLoc L;
+      if (parseSILIdentifier(TmpResult, L, Diagnostic(ID, Args...))) {
+        return true;
+      }
+
+      auto Iter = std::find(Strings.begin(), Strings.end(), TmpResult.str());
+      if (Iter == Strings.end()) {
+        P.diagnose(P.Tok, Diagnostic(ID, Args...));
+        return true;
+      }
+
+      Result = ValueOwnershipKind(*Iter);
+      return false;
+    }
+
     template<typename ...DiagArgTypes, typename ...ArgTypes>
     bool parseSILIdentifier(Identifier &Result, SourceLoc &L,
                             Diag<DiagArgTypes...> ID, ArgTypes... Args) {
@@ -226,31 +245,17 @@
       TypeLoc = P.Tok.getLoc();
       return parseASTType(result);
     }
-    bool parseSILOwnership(Optional<ValueOwnershipKind> &OwnershipKind) {
-      // We pare here @ <identifier>.
-      if (P.consumeIf(tok::at_sign) && P.Tok.isNot(tok::identifier)) {
+    bool parseSILOwnership(ValueOwnershipKind &OwnershipKind) {
+      // We parse here @ <identifier>.
+      if (!P.consumeIf(tok::at_sign)) {
         // Add error here.
         return true;
       }
 
-      OwnershipKind =
-          llvm::StringSwitch<Optional<ValueOwnershipKind>>(P.Tok.getText())
-              .Case("trivial",
-                    Optional<ValueOwnershipKind>(ValueOwnershipKind::Trivial))
-              .Case("unowned",
-                    Optional<ValueOwnershipKind>(ValueOwnershipKind::Unowned))
-              .Case("owned",
-                    Optional<ValueOwnershipKind>(ValueOwnershipKind::Owned))
-              .Case("guaranteed", Optional<ValueOwnershipKind>(
-                                      ValueOwnershipKind::Guaranteed))
-              .Default(None);
-
-      if (OwnershipKind.hasValue()) {
-        P.consumeToken();
-        return false;
-      }
-
-      return true;
+      StringRef AllOwnershipKinds[4] = {"trivial", "unowned", "owned",
+                                        "guaranteed"};
+      return parseSILIdentifierSwitch(OwnershipKind, AllOwnershipKinds,
+                                      diag::expected_sil_value_ownership_kind);
     }
     bool parseSILType(SILType &Result,
                       GenericEnvironment *&genericEnv,
@@ -1443,41 +1448,41 @@
 
   auto loc = parses[0].loc;
 
-  // Collect conformance requirements in a convenient form.
-  llvm::DenseMap<TypeBase *, SmallVector<ProtocolDecl *, 2>> conformsTo;
-  for (auto reqt : env->getGenericSignature()->getRequirements()) {
-    if (reqt.getKind() == RequirementKind::Conformance) {
-      auto canTy = reqt.getFirstType()->getCanonicalType();
-      auto nominal = reqt.getSecondType()->getAnyNominal();
-      conformsTo[canTy.getPointer()].push_back(cast<ProtocolDecl>(nominal));
-    }
-  }
-
   // The replacement is for the corresponding dependent type by ordering.
-  for (auto depTy : env->getGenericSignature()->getAllDependentTypes()) {
+  auto result = env->getGenericSignature()->enumeratePairedRequirements(
+    [&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
+      if (parses.empty()) {
+        SP.P.diagnose(loc, diag::sil_missing_substitutions);
+        return true;
+      }
+      auto parsed = parses.front();
+      parses = parses.slice(1);
 
-    auto canTy = depTy->getCanonicalType().getPointer();
+      SmallVector<ProtocolConformanceRef, 2> conformances;
+      SmallVector<ProtocolDecl *, 2> protocols;
+      for (auto reqt : reqts) {
+        protocols.push_back(reqt.getSecondType()
+                            ->castTo<ProtocolType>()->getDecl());
+      }
 
-    if (parses.empty()) {
-      SP.P.diagnose(loc, diag::sil_missing_substitutions);
-      return true;
-    }
-    auto parsed = parses.front();
-    parses = parses.slice(1);
+      if (getConformancesForSubstitution(SP.P, protocols,
+                                         parsed.replacement,
+                                         parsed.loc, conformances))
+        return true;
 
-    SmallVector<ProtocolConformanceRef, 2> conformances;
-    if (getConformancesForSubstitution(SP.P, conformsTo[canTy],
-                                       parsed.replacement,
-                                       parsed.loc, conformances))
-      return true;
+      subs.push_back({parsed.replacement,
+                      SP.P.Context.AllocateCopy(conformances)});
+      return false;
+    });
 
-    subs.push_back({parsed.replacement,
-                    SP.P.Context.AllocateCopy(conformances)});
-  }
+  if (result)
+    return true;
+
   if (!parses.empty()) {
     SP.P.diagnose(loc, diag::sil_too_many_substitutions);
     return true;
   }
+
   return false;
 }
 
@@ -2124,6 +2129,7 @@
   } break;
 
     UNARY_INSTRUCTION(FixLifetime)
+    UNARY_INSTRUCTION(EndLifetime)
     UNARY_INSTRUCTION(CopyBlock)
     UNARY_INSTRUCTION(IsUnique)
     UNARY_INSTRUCTION(IsUniqueOrPinned)
@@ -2164,6 +2170,29 @@
    break;
  }
 
+ // unchecked_ownership_conversion <reg> : <type>, <ownership> to <ownership>
+ case ValueKind::UncheckedOwnershipConversionInst: {
+   ValueOwnershipKind LHSKind = ValueOwnershipKind::Any;
+   ValueOwnershipKind RHSKind = ValueOwnershipKind::Any;
+   SourceLoc Loc;
+
+   if (parseTypedValueRef(Val, Loc, B) ||
+       P.parseToken(tok::comma, diag::expected_sil_colon,
+                    "unchecked_ownership_conversion value ownership kind "
+                    "conversion specification") ||
+       parseSILOwnership(LHSKind) || parseVerbatim("to") ||
+       parseSILOwnership(RHSKind) || parseSILDebugLocation(InstLoc, B)) {
+     return true;
+   }
+
+   if (Val.getOwnershipKind() != LHSKind) {
+     return true;
+   }
+
+   ResultVal = B.createUncheckedOwnershipConversion(InstLoc, Val, RHSKind);
+   break;
+ }
+
  case ValueKind::LoadInst: {
    LoadOwnershipQualifier Qualifier;
    SourceLoc AddrLoc;
@@ -4166,7 +4195,7 @@
     if (P.consumeIf(tok::l_paren)) {
       do {
         SILType Ty;
-        Optional<ValueOwnershipKind> OwnershipKind;
+        ValueOwnershipKind OwnershipKind = ValueOwnershipKind::Any;
         SourceLoc NameLoc;
         StringRef Name = P.Tok.getText();
         if (P.parseToken(tok::sil_local_name, NameLoc,
@@ -4190,9 +4219,7 @@
         if (IsEntry) {
           Arg = BB->createFunctionArgument(Ty);
         } else {
-          Arg = BB->createPHIArgument(
-              Ty, OwnershipKind.getValueOr(
-                      ValueOwnershipKind(ValueOwnershipKind::Any)));
+          Arg = BB->createPHIArgument(Ty, OwnershipKind);
         }
         setLocalValue(Arg, Name, NameLoc);
       } while (P.consumeIf(tok::comma));
@@ -4566,7 +4593,7 @@
 }
 
 static AssociatedTypeDecl *parseAssociatedTypeDecl(Parser &P, SILParser &SP,
-           ProtocolDecl *proto) {
+                                                   ProtocolDecl *proto) {
   Identifier DeclName;
   SourceLoc DeclLoc;
   if (SP.parseSILIdentifier(DeclName, DeclLoc, diag::expected_sil_value_name))
@@ -4584,6 +4611,59 @@
   return dyn_cast<AssociatedTypeDecl>(VD);
 }
 
+static bool parseAssociatedTypePath(SILParser &SP,
+                                    SmallVectorImpl<Identifier> &path) {
+  do {
+    Identifier name;
+    SourceLoc loc;
+    if (SP.parseSILIdentifier(name, loc, diag::expected_sil_value_name))
+      return false;
+    path.push_back(name);
+  } while (SP.P.consumeIf(tok::period));
+
+  return true;
+}
+
+static bool matchesAssociatedTypePath(CanType assocType,
+                                      ArrayRef<Identifier> path) {
+  if (auto memberType = dyn_cast<DependentMemberType>(assocType)) {
+    return (!path.empty() &&
+            memberType->getName() == path.back() &&
+            matchesAssociatedTypePath(memberType.getBase(), path.drop_back()));
+  } else {
+    assert(isa<GenericTypeParamType>(assocType));
+    return path.empty();
+  }
+}
+
+static CanType parseAssociatedTypePath(Parser &P, SILParser &SP,
+                                       ProtocolDecl *proto) {
+  SourceLoc loc = SP.P.Tok.getLoc();
+  SmallVector<Identifier, 4> path;
+  if (!parseAssociatedTypePath(SP, path))
+    return CanType();
+
+  // This is only used for parsing associated conformances, so we can
+  // go ahead and just search the requirement signature for something that
+  // matches the path.
+  for (auto &reqt : proto->getRequirementSignature()->getRequirements()) {
+    if (reqt.getKind() != RequirementKind::Conformance)
+      continue;
+    CanType assocType = reqt.getFirstType()->getCanonicalType();
+    if (matchesAssociatedTypePath(assocType, path))
+      return assocType;
+  }
+
+  SmallString<128> name;
+  name += path[0].str();
+  for (auto elt : makeArrayRef(path).slice(1)) {
+    name += '.';
+    name += elt.str();
+  }
+  P.diagnose(loc, diag::sil_witness_assoc_conf_not_found, name);
+  return CanType();
+}
+
 static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
            SILParser &SP, Type ConformingTy, ProtocolDecl *&proto) {
   Identifier ModuleKeyword, ModuleName;
@@ -4827,8 +4907,7 @@
       if (EntryKeyword.str() == "associated_type_protocol") {
         if (parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
           return true;
-        AssociatedTypeDecl *assoc = parseAssociatedTypeDecl(*this,
-                                        WitnessState, proto);
+        CanType assoc = parseAssociatedTypePath(*this, WitnessState, proto);
         if (!assoc)
           return true;
         if (parseToken(tok::colon, diag::expected_sil_witness_colon))
@@ -4851,7 +4930,7 @@
         }
 
         witnessEntries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{
-          assoc, proto, ProtocolConformanceRef(conformance)
+          assoc, proto, conformance
         });
         continue;
       }
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a00630c..cbdd9b7 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -620,7 +620,6 @@
   return false;
 }
 
-
 /// parseAnyIdentifier - Consume an identifier or operator if present and return
 /// its name in Result.  Otherwise, emit an error and return true.
 bool Parser::parseAnyIdentifier(Identifier &Result, SourceLoc &Loc,
diff --git a/lib/SIL/Mangle.cpp b/lib/SIL/Mangle.cpp
index 9e3b8e2..25a1a25 100644
--- a/lib/SIL/Mangle.cpp
+++ b/lib/SIL/Mangle.cpp
@@ -21,6 +21,7 @@
 #include "swift/AST/Mangle.h"
 #include "swift/AST/Module.h"
 #include "swift/AST/ProtocolConformance.h"
+#include "swift/AST/SubstitutionMap.h"
 #include "swift/Basic/Punycode.h"
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/SILType.h"
@@ -44,33 +45,21 @@
 //                           Generic Specialization
 //===----------------------------------------------------------------------===//
 
-static void mangleSubstitution(Mangler &M, Substitution Sub) {
-  M.mangleType(Sub.getReplacement()->getCanonicalType(), 0);
-  for (auto C : Sub.getConformances()) {
-    if (C.isAbstract())
-      return;
-    M.mangleProtocolConformance(C.getConcrete());
-  }
-}
-
 void GenericSpecializationMangler::mangleSpecialization() {
   Mangler &M = getMangler();
   // This is a full specialization.
   SILFunctionType *FTy = Function->getLoweredFunctionType();
   CanGenericSignature Sig = FTy->getGenericSignature();
-
-  unsigned idx = 0;
-  for (Type DepType : Sig->getAllDependentTypes()) {
-    // It is sufficient to only mangle the substitutions of the "primary"
-    // dependent types. As all other dependent types are just derived from the
-    // primary types, this will give us unique symbol names.
-    if (DepType->is<GenericTypeParamType>()) {
-      mangleSubstitution(M, Subs[idx]);
-      M.append('_');
+  auto SubMap = Sig->getSubstitutionMap(Subs);
+  for (Type DepType : Sig->getSubstitutableParams()) {
+    M.mangleType(DepType.subst(SubMap)->getCanonicalType(), 0);
+    for (auto C : SubMap.getConformances(DepType->getCanonicalType())) {
+      if (C.isAbstract())
+        return;
+      M.mangleProtocolConformance(C.getConcrete());
     }
-    ++idx;
+    M.append('_');
   }
-  assert(idx == Subs.size() && "subs not parallel to dependent types");
 }
 
 void PartialSpecializationMangler::mangleSpecialization() {
diff --git a/lib/SIL/PrettyStackTrace.cpp b/lib/SIL/PrettyStackTrace.cpp
index 633ef3c..e7230ed 100644
--- a/lib/SIL/PrettyStackTrace.cpp
+++ b/lib/SIL/PrettyStackTrace.cpp
@@ -18,6 +18,7 @@
 #include "swift/SIL/PrettyStackTrace.h"
 #include "swift/SIL/SILFunction.h"
 #include "swift/SIL/SILModule.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace swift;
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index 70da549..c8e7eea 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -383,6 +383,7 @@
 CONSTANT_OWNERSHIP_INST(Owned, true, UnownedRelease)
 CONSTANT_OWNERSHIP_INST(Owned, true, InitExistentialRef)
 CONSTANT_OWNERSHIP_INST(Owned, true, OpenExistentialOpaque)
+CONSTANT_OWNERSHIP_INST(Owned, true, EndLifetime)
 CONSTANT_OWNERSHIP_INST(Trivial, false, AddressToPointer)
 CONSTANT_OWNERSHIP_INST(Trivial, false, BindMemory)
 CONSTANT_OWNERSHIP_INST(Trivial, false, CheckedCastAddrBranch)
@@ -476,6 +477,7 @@
 ACCEPTS_ANY_OWNERSHIP_INST(UncheckedTrivialBitCast)
 ACCEPTS_ANY_OWNERSHIP_INST(ExistentialMetatype)
 ACCEPTS_ANY_OWNERSHIP_INST(ValueMetatype)
+ACCEPTS_ANY_OWNERSHIP_INST(UncheckedOwnershipConversion)
 #undef ACCEPTS_ANY_OWNERSHIP_INST
 
 // Trivial if trivial typed, otherwise must accept owned?
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 654a13a..0dc077b 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1234,6 +1234,13 @@
     *this << getIDAndType(operand) << " to " << CI->getType();
   }
 
+  void visitUncheckedOwnershipConversionInst(
+      UncheckedOwnershipConversionInst *UOCI) {
+    *this << getIDAndType(UOCI->getOperand()) << ", "
+          << "@" << UOCI->getOperand().getOwnershipKind() << " to "
+          << "@" << UOCI->getConversionOwnershipKind();
+  }
+
   void visitConvertFunctionInst(ConvertFunctionInst *CI) {
     printUncheckedConversionInst(CI, CI->getOperand());
   }
@@ -1549,6 +1556,11 @@
   void visitFixLifetimeInst(FixLifetimeInst *RI) {
     *this << getIDAndType(RI->getOperand());
   }
+
+  void visitEndLifetimeInst(EndLifetimeInst *ELI) {
+    *this << getIDAndType(ELI->getOperand());
+  }
+
   void visitMarkDependenceInst(MarkDependenceInst *MDI) {
     *this << getIDAndType(MDI->getValue()) << " on "
           << getIDAndType(MDI->getBase());
@@ -2246,6 +2258,19 @@
   print(llvm::errs());
 }
 
+/// Returns true if anything was printed.
+static bool printAssociatedTypePath(llvm::raw_ostream &OS, CanType path) {
+  if (auto memberType = dyn_cast<DependentMemberType>(path)) {
+    if (printAssociatedTypePath(OS, memberType.getBase()))
+      OS << '.';
+    OS << memberType->getName().str();
+    return true;
+  } else {
+    assert(isa<GenericTypeParamType>(path));
+    return false;
+  }
+}
+
 void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const {
   PrintOptions Options = PrintOptions::printSIL();
   PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType();
@@ -2301,9 +2326,9 @@
     case AssociatedTypeProtocol: {
       // associated_type_protocol (AssociatedTypeName: Protocol): <conformance>
       auto &assocProtoWitness = witness.getAssociatedTypeProtocolWitness();
-      OS << "associated_type_protocol ("
-         << assocProtoWitness.Requirement->getName() << ": "
-         << assocProtoWitness.Protocol->getName() << "): ";
+      OS << "associated_type_protocol (";
+      (void) printAssociatedTypePath(OS, assocProtoWitness.Requirement);
+      OS << ": " << assocProtoWitness.Protocol->getName() << "): ";
       if (assocProtoWitness.Witness.isConcrete())
         assocProtoWitness.Witness.getConcrete()->printName(OS, Options);
       else
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index 1a154c7..1cb2a04 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -376,7 +376,6 @@
   assert(MetatypeType->is<AnyMetatypeType>() &&
          "This method should only be called on SILTypes with an underlying "
          "metatype type.");
-  assert(isObject() && "Should only be called on object types.");
   Type instanceType =
     MetatypeType->castTo<AnyMetatypeType>()->getInstanceType();
 
diff --git a/lib/SIL/SILValue.cpp b/lib/SIL/SILValue.cpp
index f9bf589..9c069b5 100644
--- a/lib/SIL/SILValue.cpp
+++ b/lib/SIL/SILValue.cpp
@@ -16,6 +16,7 @@
 #include "swift/SIL/SILInstruction.h"
 #include "swift/SIL/SILModule.h"
 #include "swift/SIL/SILVisitor.h"
+#include "llvm/ADT/StringSwitch.h"
 
 using namespace swift;
 
@@ -143,6 +144,19 @@
   return (LHSVal == RHSVal) ? Optional<ValueOwnershipKind>(*this) : None;
 }
 
+ValueOwnershipKind::ValueOwnershipKind(StringRef S) {
+  auto Result = llvm::StringSwitch<Optional<ValueOwnershipKind::innerty>>(S)
+                    .Case("trivial", ValueOwnershipKind::Trivial)
+                    .Case("unowned", ValueOwnershipKind::Unowned)
+                    .Case("owned", ValueOwnershipKind::Owned)
+                    .Case("guaranteed", ValueOwnershipKind::Guaranteed)
+                    .Case("any", ValueOwnershipKind::Any)
+                    .Default(None);
+  if (!Result.hasValue())
+    llvm_unreachable("Invalid string representation of ValueOwnershipKind");
+  Value = Result.getValue();
+}
+
 //===----------------------------------------------------------------------===//
 //                 Instruction ValueOwnershipKind Computation
 //===----------------------------------------------------------------------===//
@@ -333,6 +347,7 @@
 NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
 NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque)
 NO_RESULT_OWNERSHIP_INST(CondFail)
+NO_RESULT_OWNERSHIP_INST(EndLifetime)
 
 // Terminators. These do not produce SILValue, so they do not have a
 // ValueOwnershipKind. They do have ownership implications in terms of the
@@ -459,6 +474,12 @@
   return visitForwardingInst(UBCI);
 }
 
+ValueOwnershipKind
+ValueOwnershipKindVisitor::visitUncheckedOwnershipConversionInst(
+    UncheckedOwnershipConversionInst *I) {
+  return I->getConversionOwnershipKind();
+}
+
 // An enum without payload is trivial. One with non-trivial payload is
 // forwarding.
 ValueOwnershipKind
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 541709a..49d7170 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -1649,14 +1649,8 @@
   }
 
   // Is a SIL type a potential lowering of a formal type?
-  static bool isLoweringOf(SILType loweredType,
-                           CanType formalType) {
-    
-    
-    // Dynamic self has the same lowering as its contained type.
-    if (auto dynamicSelf = dyn_cast<DynamicSelfType>(formalType))
-      formalType = CanType(dynamicSelf->getSelfType());
-
+  bool isLoweringOf(SILType loweredType,
+                    CanType formalType) {
     // Optional lowers its contained type. The difference between Optional
     // and IUO is lowered away.
     SILType loweredObjectType = loweredType
@@ -1670,9 +1664,10 @@
     }
 
     // Metatypes preserve their instance type through lowering.
-    if (auto loweredMT = loweredType.getAs<MetatypeType>()) {
+    if (loweredType.is<MetatypeType>()) {
       if (auto formalMT = dyn_cast<MetatypeType>(formalType)) {
-        return loweredMT.getInstanceType() == formalMT.getInstanceType();
+        return isLoweringOf(loweredType.getMetatypeInstanceType(F.getModule()),
+                            formalMT.getInstanceType());
       }
     }
     if (auto loweredEMT = loweredType.getAs<ExistentialMetatypeType>()) {
@@ -1701,7 +1696,11 @@
         }
         return true;
       }
-    
+
+    // Dynamic self has the same lowering as its contained type.
+    if (auto dynamicSelf = dyn_cast<DynamicSelfType>(formalType))
+      formalType = dynamicSelf.getSelfType();
+
     // Other types are preserved through lowering.
     return loweredType.getSwiftRValueType() == formalType;
   }
@@ -3011,7 +3010,7 @@
   void checkSwitchValueInst(SwitchValueInst *SVI) {
     // TODO: Type should be either integer or function
     auto Ty = SVI->getOperand()->getType();
-    require(Ty.getAs<BuiltinIntegerType>() || Ty.getAs<SILFunctionType>(),
+    require(Ty.is<BuiltinIntegerType>() || Ty.is<SILFunctionType>(),
             "switch_value operand should be either of an integer "
             "or function type");
 
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index dbc9b5d..fefc5ec 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -32,12 +32,10 @@
 using namespace Lowering;
 
 /// Retrieve the type to use for a method found via dynamic lookup.
-static CanAnyFunctionType getDynamicMethodFormalType(SILGenModule &SGM,
-                                                     SILValue proto,
+static CanAnyFunctionType getDynamicMethodFormalType(SILValue proto,
                                                      ValueDecl *member,
-                                                     SILDeclRef methodName,
                                                      Type memberType) {
-  auto &ctx = SGM.getASTContext();
+  auto &ctx = member->getASTContext();
   CanType selfTy;
   if (member->isInstanceMember()) {
     selfTy = ctx.TheUnknownObjectType;
@@ -189,9 +187,6 @@
   SILValue SelfValue;
   SubstitutionList Substitutions;
   CanAnyFunctionType OrigFormalInterfaceType;
-  CanFunctionType SubstFormalType;
-  Optional<SILLocation> SpecializeLoc;
-  bool HasSubstitutions = false;
   Optional<SmallVector<ManagedValue, 2>> Captures;
 
   // The pointer back to the AST node that produced the callee.
@@ -201,28 +196,24 @@
 
   Callee(ManagedValue indirectValue,
          CanAnyFunctionType origFormalType,
-         CanFunctionType substFormalType,
          SILLocation L)
     : kind(Kind::IndirectValue),
       IndirectValue(indirectValue),
       OrigFormalInterfaceType(origFormalType),
-      SubstFormalType(substFormalType),
       Loc(L)
   {}
 
   static CanAnyFunctionType getConstantFormalInterfaceType(SILGenFunction &gen,
-                                                  SILDeclRef fn) {
+                                                           SILDeclRef fn) {
     return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0))
              .FormalInterfaceType;
   }
 
   Callee(SILGenFunction &gen, SILDeclRef standaloneFunction,
-         CanFunctionType substFormalType,
          SILLocation l)
     : kind(Kind::StandaloneFunction), Constant(standaloneFunction),
       OrigFormalInterfaceType(getConstantFormalInterfaceType(gen,
                                                            standaloneFunction)),
-      SubstFormalType(substFormalType),
       Loc(l)
   {
   }
@@ -231,170 +222,86 @@
          SILGenFunction &gen,
          SILValue selfValue,
          SILDeclRef methodName,
-         CanFunctionType substFormalType,
          SILLocation l)
     : kind(methodKind), Constant(methodName), SelfValue(selfValue),
       OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, methodName)),
-      SubstFormalType(substFormalType),
       Loc(l)
   {
   }
 
-  /// Build a clause that looks like 'origParamType' but uses 'selfType'
-  /// in place of the underlying archetype.
-  static CanType buildSubstSelfType(CanType origParamType, CanType selfType,
-                                    ASTContext &ctx) {
-    assert(!isa<LValueType>(origParamType) && "Self can't be @lvalue");
-    if (auto lv = dyn_cast<InOutType>(origParamType)) {
-      selfType = buildSubstSelfType(lv.getObjectType(), selfType, ctx);
-      return CanInOutType::get(selfType);
-    }
-
-    if (auto tuple = dyn_cast<TupleType>(origParamType)) {
-      assert(tuple->getNumElements() == 1);
-      selfType = buildSubstSelfType(tuple.getElementType(0), selfType, ctx);
-
-      auto field = tuple->getElement(0).getWithType(selfType);
-      return CanType(TupleType::get(field, ctx));
-    }
-
-    assert(isa<MetatypeType>(origParamType) == isa<MetatypeType>(selfType));
-    assert(origParamType->getRValueInstanceType()->isTypeParameter());
-    assert(selfType->getRValueInstanceType()->is<ArchetypeType>());
-
-    return selfType;
-  }
-
   CanArchetypeType getWitnessMethodSelfType() const {
-    return cast<ArchetypeType>(SubstFormalType.getInput()
+    return cast<ArchetypeType>(getSubstFormalType().getInput()
         ->getRValueInstanceType()
         ->getCanonicalType());
   }
 
   CanSILFunctionType getSubstFunctionType(SILGenModule &SGM,
                                           CanSILFunctionType origFnType) const {
-    if (!HasSubstitutions) return origFnType;
-    
     return origFnType->substGenericArgs(SGM.M, Substitutions);
   }
 
-  /// Add the 'self' clause back to the substituted formal type of
-  /// this protocol method.
-  void addProtocolSelfToFormalType(SILGenModule &SGM, SILDeclRef name,
-                                   CanType protocolSelfType) {
-    // The result types of the expressions yielding protocol values
-    // (reflected in SubstFormalType) reflect an implicit level of
-    // function application, including some extra polymorphic
-    // substitution.
-    HasSubstitutions = true;
-
-    auto &ctx = SGM.getASTContext();
-
-    // Add the 'self' parameter back.  We want it to look like a
-    // substitution of the appropriate clause from the original type.
-    auto selfType = OrigFormalInterfaceType.getInput();
-    auto substSelfType =
-      buildSubstSelfType(selfType, protocolSelfType, ctx);
-
-    auto extInfo = FunctionType::ExtInfo(FunctionType::Representation::Thin,
-                                         /*throws*/ OrigFormalInterfaceType->throws());
-
-    SubstFormalType = CanFunctionType::get(substSelfType, SubstFormalType,
-                                           extInfo);
-  }
-
   /// Add the 'self' type to the substituted function type of this
   /// dynamic callee.
-  void addDynamicCalleeSelfToFormalType(SILGenModule &SGM,
-                                        CanAnyFunctionType substFormalType) {
+  void addDynamicCalleeSelfToFormalType(Type substFormalType) {
     assert(kind == Kind::DynamicMethod);
 
-    // Add the dynamic self type to the substituted type. Even if the dynamic
-    // callee came from a generic ObjC class, when we find it on AnyObject the
-    // parameters should be substituted with their upper bound types.
     OrigFormalInterfaceType
-      = getDynamicMethodFormalType(SGM, SelfValue,
+      = getDynamicMethodFormalType(SelfValue,
                                    Constant.getDecl(),
-                                   Constant, substFormalType);
+                                   substFormalType);
     assert(!OrigFormalInterfaceType->hasTypeParameter());
-
-    // Add a self clause to the substituted type.
-    auto selfType = OrigFormalInterfaceType.getInput();
-    SubstFormalType
-      = CanFunctionType::get(selfType, SubstFormalType,
-                             OrigFormalInterfaceType->getExtInfo());
   }
 
 public:
 
   static Callee forIndirect(ManagedValue indirectValue,
                             CanAnyFunctionType origFormalType,
-                            CanFunctionType substFormalType,
                             SILLocation l) {
-    return Callee(indirectValue,
-                  origFormalType,
-                  substFormalType,
-                  l);
+    return Callee(indirectValue, origFormalType, l);
   }
   static Callee forDirect(SILGenFunction &gen, SILDeclRef c,
-                          CanFunctionType substFormalType,
                           SILLocation l) {
-    return Callee(gen, c, substFormalType, l);
+    return Callee(gen, c, l);
   }
   static Callee forEnumElement(SILGenFunction &gen, SILDeclRef c,
-                               CanFunctionType substFormalType,
                                SILLocation l) {
     assert(isa<EnumElementDecl>(c.getDecl()));
-    return Callee(Kind::EnumElement, gen, SILValue(),
-                  c, substFormalType, l);
+    return Callee(Kind::EnumElement, gen, SILValue(), c, l);
   }
   static Callee forClassMethod(SILGenFunction &gen, SILValue selfValue,
                                SILDeclRef name,
-                               CanFunctionType substFormalType,
                                SILLocation l) {
-    return Callee(Kind::ClassMethod, gen, selfValue, name,
-                  substFormalType, l);
+    return Callee(Kind::ClassMethod, gen, selfValue, name, l);
   }
   static Callee forSuperMethod(SILGenFunction &gen, SILValue selfValue,
                                SILDeclRef name,
-                               CanFunctionType substFormalType,
                                SILLocation l) {
     while (auto *UI = dyn_cast<UpcastInst>(selfValue))
       selfValue = UI->getOperand();
 
-    return Callee(Kind::SuperMethod, gen, selfValue, name,
-                  substFormalType, l);
+    return Callee(Kind::SuperMethod, gen, selfValue, name, l);
   }
   static Callee forArchetype(SILGenFunction &gen,
                              SILValue optOpeningInstruction,
                              CanType protocolSelfType,
                              SILDeclRef name,
-                             CanFunctionType substFormalType,
                              SILLocation l) {
-    Callee callee(Kind::WitnessMethod, gen, optOpeningInstruction, name,
-                  substFormalType, l);
-    callee.addProtocolSelfToFormalType(gen.SGM, name, protocolSelfType);
+    Callee callee(Kind::WitnessMethod, gen, optOpeningInstruction, name, l);
     return callee;
   }
   static Callee forDynamic(SILGenFunction &gen, SILValue proto,
-                           SILDeclRef name, CanFunctionType substFormalType,
+                           SILDeclRef name, Type substFormalType,
                            SILLocation l) {
-    Callee callee(Kind::DynamicMethod, gen, proto, name,
-                  substFormalType, l);
-    callee.addDynamicCalleeSelfToFormalType(gen.SGM, substFormalType);
+    Callee callee(Kind::DynamicMethod, gen, proto, name, l);
+    callee.addDynamicCalleeSelfToFormalType(substFormalType);
     return callee;
   }
   Callee(Callee &&) = default;
   Callee &operator=(Callee &&) = default;
 
-  void setSubstitutions(SILGenFunction &gen,
-                        SILLocation loc,
-                        SubstitutionList newSubs) {
+  void setSubstitutions(SubstitutionList newSubs) {
     assert(Substitutions.empty() && "Already have substitutions?");
     Substitutions = newSubs;
-
-    SpecializeLoc = loc;
-    HasSubstitutions = true;
   }
   
   void setCaptures(SmallVectorImpl<ManagedValue> &&captures) {
@@ -416,7 +323,13 @@
   }
 
   CanFunctionType getSubstFormalType() const {
-    return SubstFormalType;
+    if (auto *gft = OrigFormalInterfaceType->getAs<GenericFunctionType>()) {
+      return cast<FunctionType>(
+        gft->substGenericArgs(getSubstitutions())
+          ->getCanonicalType());
+    }
+
+    return cast<FunctionType>(OrigFormalInterfaceType);
   }
 
   unsigned getNaturalUncurryLevel() const {
@@ -452,7 +365,7 @@
     case Kind::IndirectValue:
       assert(level == 0 && "can't curry indirect function");
       mv = IndirectValue;
-      assert(!HasSubstitutions);
+      assert(Substitutions.empty());
       break;
 
     case Kind::StandaloneFunction: {
@@ -566,8 +479,9 @@
       constant = Constant.atUncurryLevel(level);
       // Lower the substituted type from the AST, which should have any generic
       // parameters in the original signature erased to their upper bounds.
-      auto objcFormalType = SubstFormalType.withExtInfo(
-         SubstFormalType->getExtInfo()
+      auto substFormalType = getSubstFormalType();
+      auto objcFormalType = substFormalType.withExtInfo(
+         substFormalType->getExtInfo()
            .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod));
       auto fnType = gen.SGM.M.Types
         .getUncachedSILFunctionTypeForConstant(*constant, objcFormalType);
@@ -655,7 +569,6 @@
   SILGenFunction &gen;
   SILLocation loc;
   ArgumentSource &selfValue;
-  CanFunctionType substFnType;
   SILParameterInfo selfParam;
   AbstractFunctionDecl *fd;
   ProtocolDecl *protocol;
@@ -663,9 +576,8 @@
 
 public:
   ArchetypeCalleeBuilder(SILGenFunction &gen, SILLocation loc,
-                         SILDeclRef inputConstant, ArgumentSource &selfValue,
-                         CanFunctionType substFnType)
-      : gen(gen), loc(loc), selfValue(selfValue), substFnType(substFnType),
+                         SILDeclRef inputConstant, ArgumentSource &selfValue)
+      : gen(gen), loc(loc), selfValue(selfValue),
         selfParam(), fd(cast<AbstractFunctionDecl>(inputConstant.getDecl())),
         protocol(cast<ProtocolDecl>(fd->getDeclContext())),
         constant(inputConstant.asForeign(protocol->isObjC())) {}
@@ -687,11 +599,7 @@
       setSelfValueToAddress(selfLoc, address);
     }
 
-    // The protocol self is implicitly decurried.
-    substFnType = cast<FunctionType>(substFnType.getResult());
-
-    return Callee::forArchetype(gen, openingSite, getSelfType(), constant,
-                                substFnType, loc);
+    return Callee::forArchetype(gen, openingSite, getSelfType(), constant, loc);
   }
 
 private:
@@ -773,10 +681,9 @@
 static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc,
                                      SILDeclRef constant,
                                      ArgumentSource &selfValue,
-                                     CanFunctionType substFnType,
                                      SubstitutionList &substitutions) {
   // Construct an archetype call.
-  ArchetypeCalleeBuilder Builder{gen, loc, constant, selfValue, substFnType};
+  ArchetypeCalleeBuilder Builder{gen, loc, constant, selfValue};
   return Builder.build();
 }
 
@@ -863,70 +770,18 @@
     visit(e);
   }
 
-  /// Get the type of the function for substitution purposes.
-  ///
-  /// \param otherCtorRefUsesAllocating If true, the OtherConstructorDeclRef
-  /// refers to the initializing
-  CanFunctionType getSubstFnType(bool otherCtorRefUsesAllocating = false) {
-    // TODO: optimize this if there are no specializes in play
-    auto getSiteType = [&](ApplyExpr *site, bool otherCtorRefUsesAllocating) {
-      if (otherCtorRefUsesAllocating) {
-        // We have a reference to an initializing constructor, but we will
-        // actually be using the allocating constructor. Update the type
-        // appropriately.
-        // FIXME: Re-derive the type from the declaration + substitutions?
-        auto ctorRef = cast<OtherConstructorDeclRefExpr>(site->getSemanticFn());
-        auto fnType = ctorRef->getType()->castTo<FunctionType>();
-        auto selfTy = MetatypeType::get(
-                        fnType->getInput()->getInOutObjectType());
-        return CanFunctionType::get(selfTy->getCanonicalType(),
-                                    fnType->getResult()->getCanonicalType(),
-                                    fnType->getExtInfo());
-      }
-
-      return cast<FunctionType>(site->getFn()->getType()->getCanonicalType());
-    };
-
-    CanFunctionType fnType;
-
-    auto addSite = [&](ApplyExpr *site, bool otherCtorRefUsesAllocating) {
-      auto siteType = getSiteType(site, otherCtorRefUsesAllocating);
-
-      // If this is the first call site, use its formal type directly.
-      if (!fnType) {
-        fnType = siteType;
-        return;
-      }
-
-      fnType = CanFunctionType::get(siteType.getInput(), fnType,
-                                    siteType->getExtInfo());
-    };
-
-    for (auto callSite : CallSites) {
-      addSite(callSite, false);
-    }
-
-    // The self application might be a DynamicMemberRefExpr.
-    if (auto selfApply = dyn_cast_or_null<ApplyExpr>(SelfApplyExpr)) {
-      addSite(selfApply, otherCtorRefUsesAllocating);
-    }
-
-    assert(fnType && "found no call sites?");
-    return fnType;
-  }
-
   /// Fall back to an unknown, indirect callee.
   void visitExpr(Expr *e) {
     ManagedValue fn = SGF.emitRValueAsSingleValue(e);
     auto origType = cast<AnyFunctionType>(e->getType()->getCanonicalType());
-    setCallee(Callee::forIndirect(fn, origType, getSubstFnType(), e));
+    setCallee(Callee::forIndirect(fn, origType, e));
   }
 
   void visitLoadExpr(LoadExpr *e) {
     // TODO: preserve the function pointer at its original abstraction level
     ManagedValue fn = SGF.emitRValueAsSingleValue(e);
     auto origType = cast<AnyFunctionType>(e->getType()->getCanonicalType());
-    setCallee(Callee::forIndirect(fn, origType, getSubstFnType(), e));
+    setCallee(Callee::forIndirect(fn, origType, e));
   }
 
   /// Add a call site to the curry.
@@ -1005,7 +860,6 @@
         // to the +0 value in memory.  We just pass in the address since
         // archetypes are address-only.
 
-        auto substFnType = getSubstFnType();
         assert(!CallSites.empty());
         ApplyExpr *thisCallSite = CallSites.back();
         CallSites.pop_back();
@@ -1039,7 +893,7 @@
 
         // Prepare the callee.  This can modify both selfValue and subs.
         Callee theCallee = prepareArchetypeCallee(SGF, e, constant, selfValue,
-                                                  substFnType, subs);
+                                                  subs);
         AssumedPlusZeroSelf = selfValue.isRValue()
           && selfValue.forceAndPeekRValue(SGF).peekIsPlusZeroRValueOrTrivial();
 
@@ -1048,7 +902,7 @@
 
         // If there are substitutions, add them now.
         if (!subs.empty())
-          ApplyCallee->setSubstitutions(SGF, e, subs);
+          ApplyCallee->setSubstitutions(subs);
 
         return;
       }
@@ -1127,13 +981,11 @@
                             SILDeclRef::ConstructAtNaturalUncurryLevel,
                             requiresForeignEntryPoint(afd));
 
-        setCallee(Callee::forClassMethod(SGF, selfValue,
-                                         constant, getSubstFnType(), e));
+        setCallee(Callee::forClassMethod(SGF, selfValue, constant, e));
 
         // If there are substitutions, add them.
         if (e->getDeclRef().isSpecialized()) {
-          ApplyCallee->setSubstitutions(SGF, e,
-                                        e->getDeclRef().getSubstitutions());
+          ApplyCallee->setSubstitutions(e->getDeclRef().getSubstitutions());
         }
 
         return;
@@ -1154,29 +1006,18 @@
                           && requiresForeignEntryPoint(e->getDecl()));
 
     // Otherwise, we have a statically-dispatched call.
-    CanFunctionType substFnType = getSubstFnType();
-
-    auto afd = dyn_cast<AbstractFunctionDecl>(e->getDecl());
-    if (afd) {
-      // If there are captures, put the placeholder curry level in the formal
-      // type.
-      // TODO: Eliminate the need for this.
-      if (SGF.SGM.M.Types.hasLoweredLocalCaptures(afd))
-        substFnType = CanFunctionType::get(
-          SGF.getASTContext().TheEmptyTupleType, substFnType);
-    }
-
     SubstitutionList subs;
     if (e->getDeclRef().isSpecialized())
       subs = e->getDeclRef().getSubstitutions();
 
     // Enum case constructor references are open-coded.
     if (isa<EnumElementDecl>(e->getDecl()))
-      setCallee(Callee::forEnumElement(SGF, constant, substFnType, e));
+      setCallee(Callee::forEnumElement(SGF, constant, e));
     else
-      setCallee(Callee::forDirect(SGF, constant, substFnType, e));
+      setCallee(Callee::forDirect(SGF, constant, e));
     
     // If the decl ref requires captures, emit the capture params.
+    auto afd = dyn_cast<AbstractFunctionDecl>(e->getDecl());
     if (afd) {
       // FIXME: We should be checking hasLocalCaptures() on the lowered
       // captures in the constant info too, to generate more efficient
@@ -1195,7 +1036,7 @@
         (!afd ||
          !afd->getDeclContext()->isLocalContext() ||
          afd->getCaptureInfo().hasGenericParamCaptures()))
-      ApplyCallee->setSubstitutions(SGF, e, subs);
+      ApplyCallee->setSubstitutions(subs);
   }
   
   void visitAbstractClosureExpr(AbstractClosureExpr *e) {
@@ -1217,24 +1058,10 @@
     if (e->getCaptureInfo().hasGenericParamCaptures())
       subs = SGF.getForwardingSubstitutions();
 
-    CanFunctionType substFnType = getSubstFnType();
-    
-    // FIXME: We should be checking hasLocalCaptures() on the lowered
-    // captures in the constant info above, to generate more efficient
-    // code for mutually recursive local functions which otherwise
-    // capture no state.
-
-    // If there are captures, put the placeholder curry level in the formal
-    // type.
-    // TODO: Eliminate the need for this.
-    bool hasCaptures = SGF.SGM.M.Types.hasLoweredLocalCaptures(e);
-    if (hasCaptures)
-      substFnType = CanFunctionType::get(
-                         SGF.getASTContext().TheEmptyTupleType, substFnType);
-
-    setCallee(Callee::forDirect(SGF, constant, substFnType, e));
+    setCallee(Callee::forDirect(SGF, constant, e));
     
     // If the closure requires captures, emit them.
+    bool hasCaptures = SGF.SGM.M.Types.hasLoweredLocalCaptures(e);
     if (hasCaptures) {
       SmallVector<ManagedValue, 4> captures;
       SGF.emitCaptures(e, e, CaptureEmission::ImmediateApplication,
@@ -1243,7 +1070,7 @@
     }
     // If there are substitutions, add them.
     if (!subs.empty())
-      ApplyCallee->setSubstitutions(SGF, e, subs);
+      ApplyCallee->setSubstitutions(subs);
   }
   
   void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) {
@@ -1251,12 +1078,11 @@
     // constructors imported from Clang (which won't have a direct entry point)
     // or to delegate to a designated initializer.
     setCallee(Callee::forDirect(SGF,
-                SILDeclRef(e->getDecl(), SILDeclRef::Kind::Initializer),
-                                getSubstFnType(), e));
+                SILDeclRef(e->getDecl(), SILDeclRef::Kind::Initializer), e));
 
     // If there are substitutions, add them.
     if (e->getDeclRef().isSpecialized())
-      ApplyCallee->setSubstitutions(SGF, e, e->getDeclRef().getSubstitutions());
+      ApplyCallee->setSubstitutions(e->getDeclRef().getSubstitutions());
   }
   void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) {
     setSideEffect(e->getLHS());
@@ -1338,16 +1164,15 @@
 
     if (!canUseStaticDispatch(SGF, constant)) {
       // ObjC super calls require dynamic dispatch.
-      setCallee(Callee::forSuperMethod(SGF, super.getValue(), constant,
-                                       getSubstFnType(), fn));
+      setCallee(Callee::forSuperMethod(SGF, super.getValue(), constant, fn));
     } else {
       // Native Swift super calls to final methods are direct.
-      setCallee(Callee::forDirect(SGF, constant, getSubstFnType(), fn));
+      setCallee(Callee::forDirect(SGF, constant, fn));
     }
 
     // If there are any substitutions for the callee, apply them now.
     if (!substitutions.empty())
-      ApplyCallee->setSubstitutions(SGF, fn, substitutions);
+      ApplyCallee->setSubstitutions(substitutions);
   }
 
   /// Walk the given \c selfArg expression that produces the appropriate
@@ -1508,9 +1333,7 @@
                              SILDeclRef::ConstructAtNaturalUncurryLevel,
                              requiresForeignEntryPoint(ctorRef->getDecl()));
       setCallee(Callee::forArchetype(SGF, SILValue(),
-                     self.getType().getSwiftRValueType(), constant,
-                     cast<FunctionType>(expr->getType()->getCanonicalType()),
-                     expr));
+                     self.getType().getSwiftRValueType(), constant, expr));
     } else if (getMethodDispatch(ctorRef->getDecl())
                  == MethodDispatch::Class) {
       // Dynamic dispatch to the initializer.
@@ -1524,7 +1347,7 @@
                              SILDeclRef::ConstructAtBestResilienceExpansion,
                              SILDeclRef::ConstructAtNaturalUncurryLevel,
                              requiresForeignEntryPoint(ctorRef->getDecl())),
-                  getSubstFnType(), fn));
+                  fn));
     } else {
       // Directly call the peer constructor.
       setCallee(
@@ -1537,13 +1360,12 @@
                      SILDeclRef::ConstructAtBestResilienceExpansion,
                      SILDeclRef::ConstructAtNaturalUncurryLevel,
                      requiresForeignEntryPoint(ctorRef->getDecl())),
-            getSubstFnType(useAllocatingCtor), fn));
+            fn));
     }
 
     // Set up the substitutions, if we have any.
     if (ctorRef->getDeclRef().isSpecialized())
-      ApplyCallee->setSubstitutions(SGF, fn,
-                                    ctorRef->getDeclRef().getSubstitutions());
+      ApplyCallee->setSubstitutions(ctorRef->getDeclRef().getSubstitutions());
 
     return true;
   }
@@ -1634,8 +1456,10 @@
                         SILDeclRef::ConstructAtNaturalUncurryLevel,
                         /*isObjC=*/true);
 
+      auto substFormalType = dynamicMemberRef->getType()
+          ->getAnyOptionalObjectType();
       setCallee(Callee::forDynamic(SGF, base.getValue(), member,
-                                   getSubstFnType(), e));
+                                   substFormalType, e));
     };
 
     // When we have an open existential, open it and then emit the
@@ -4712,19 +4536,12 @@
                                             SubstitutionList subs,
                                             ArrayRef<ManagedValue> args,
                                             SGFContext ctx) {
+  auto callee = Callee::forDirect(*this, SILDeclRef(fn), loc);
+  callee.setSubstitutions(subs);
+
   auto origFormalType =
     cast<AnyFunctionType>(fn->getInterfaceType()->getCanonicalType());
-  CanFunctionType substFormalType;
-  if (!subs.empty()) {
-    auto genericFnType = cast<GenericFunctionType>(origFormalType);
-    auto applied = genericFnType->substGenericArgs(subs);
-    substFormalType = cast<FunctionType>(applied->getCanonicalType());
-  } else {
-    substFormalType = cast<FunctionType>(origFormalType);
-  }
-
-  auto callee = Callee::forDirect(*this, SILDeclRef(fn), substFormalType, loc);
-  callee.setSubstitutions(*this, loc, subs);
+  auto substFormalType = callee.getSubstFormalType();
 
   ManagedValue mv;
   CanSILFunctionType substFnType;
@@ -4771,37 +4588,12 @@
                      SILDeclRef::ConstructAtBestResilienceExpansion,
                      SILDeclRef::ConstructAtNaturalUncurryLevel,
                      requiresForeignEntryPoint(ctor));
-  SILConstantInfo initConstant = SGF.getConstantInfo(initRef);
+  auto initConstant = SGF.getConstantInfo(initRef);
+  auto subs = init.getSubstitutions();
 
   // Scope any further writeback just within this operation.
   FormalEvaluationScope writebackScope(SGF);
 
-  // Determine the formal and substituted types.
-  CanFunctionType substFormalType;
-  auto subs = init.getSubstitutions();
-  if (!subs.empty()) {
-    auto genericFnType = cast<GenericFunctionType>(
-        initConstant.FormalInterfaceType);
-    auto applied = genericFnType->substGenericArgs(subs);
-    substFormalType = cast<FunctionType>(applied->getCanonicalType());
-  } else {
-    substFormalType = cast<FunctionType>(initConstant.FormalInterfaceType);
-  }
-
-  // For an inheritable initializer, determine whether we'll need to adjust the
-  // result type.
-  bool requiresDowncast = false;
-  if (ctor->isInheritable() && overriddenSelfType) {
-    CanType substResultType = substFormalType;
-    for (unsigned i : range(ctor->getNumParameterLists())) {
-      (void)i;
-      substResultType = cast<FunctionType>(substResultType).getResult();
-    }
-
-    if (!substResultType->isEqual(overriddenSelfType))
-      requiresDowncast = true;
-  }
-
   // Form the metatype argument.
   ManagedValue selfMetaVal;
   SILType selfMetaTy;
@@ -4841,13 +4633,28 @@
                               RValue(SGF, loc,
                                      selfMetaVal.getType().getSwiftRValueType(),
                                      selfMetaVal));
-    callee.emplace(prepareArchetypeCallee(SGF, loc, initRef, selfSource,
-                                          substFormalType, subs));
+    callee.emplace(prepareArchetypeCallee(SGF, loc, initRef, selfSource, subs));
   } else {
-    callee.emplace(Callee::forDirect(SGF, initRef, substFormalType, loc));
+    callee.emplace(Callee::forDirect(SGF, initRef, loc));
   }
   if (!subs.empty())
-    callee->setSubstitutions(SGF, loc, subs);
+    callee->setSubstitutions(subs);
+
+  auto substFormalType = callee->getSubstFormalType();
+
+  // For an inheritable initializer, determine whether we'll need to adjust the
+  // result type.
+  bool requiresDowncast = false;
+  if (ctor->isInheritable() && overriddenSelfType) {
+    CanType substResultType = substFormalType;
+    for (unsigned i : range(ctor->getNumParameterLists())) {
+      (void)i;
+      substResultType = cast<FunctionType>(substResultType).getResult();
+    }
+
+    if (!substResultType->isEqual(overriddenSelfType))
+      requiresDowncast = true;
+  }
 
   // Form the call emission.
   CallEmission emission(SGF, std::move(*callee), std::move(writebackScope));
@@ -5045,7 +4852,6 @@
                                          ArgumentSource &selfValue,
                                          bool isSuper,
                                          bool isDirectUse,
-                                         CanFunctionType substAccessorType,
                                          SubstitutionList &substitutions){
   auto *decl = cast<AbstractFunctionDecl>(constant.getDecl());
 
@@ -5055,7 +4861,7 @@
     assert(!isSuper && "super call to protocol method?");
 
     return prepareArchetypeCallee(gen, loc, constant, selfValue,
-                                  substAccessorType, substitutions);
+                                  substitutions);
   }
 
   bool isClassDispatch = false;
@@ -5072,20 +4878,20 @@
 
   // Dispatch in a struct/enum or to a final method is always direct.
   if (!isClassDispatch || decl->isFinal())
-    return Callee::forDirect(gen, constant, substAccessorType, loc);
+    return Callee::forDirect(gen, constant, loc);
 
   // Otherwise, if we have a non-final class dispatch to a normal method,
   // perform a dynamic dispatch.
   auto self = selfValue.forceAndPeekRValue(gen).peekScalarValue();
   if (!isSuper)
-    return Callee::forClassMethod(gen, self, constant, substAccessorType, loc);
+    return Callee::forClassMethod(gen, self, constant, loc);
 
   // If this is a "super." dispatch, we do a dynamic dispatch for objc methods
   // or non-final native Swift methods.
   if (!canUseStaticDispatch(gen, constant))
-    return Callee::forSuperMethod(gen, self, constant, substAccessorType, loc);
+    return Callee::forSuperMethod(gen, self, constant, loc);
 
-  return Callee::forDirect(gen, constant, substAccessorType, loc);
+  return Callee::forDirect(gen, constant, loc);
 }
 
 static Callee
@@ -5097,23 +4903,11 @@
                                    bool isSuper,
                                    bool isDirectUse)
 {
-  SILConstantInfo constantInfo = gen.getConstantInfo(constant);
-
-  // Apply substitutions to the callee type.
-  CanFunctionType substAccessorType;
-  if (!substitutions.empty()) {
-    auto genericFn = cast<GenericFunctionType>(constantInfo.FormalInterfaceType);
-    auto substFn = genericFn->substGenericArgs(substitutions);
-    substAccessorType = cast<FunctionType>(substFn->getCanonicalType());
-  } else {
-    substAccessorType = cast<FunctionType>(constantInfo.FormalInterfaceType);
-  }
-
   // Get the accessor function. The type will be a polymorphic function if
   // the Self type is generic.
   Callee callee = getBaseAccessorFunctionRef(gen, loc, constant, selfValue,
                                              isSuper, isDirectUse,
-                                             substAccessorType, substitutions);
+                                             substitutions);
   
   // Collect captures if the accessor has them.
   auto accessorFn = cast<AbstractFunctionDecl>(constant.getDecl());
@@ -5126,10 +4920,8 @@
   }
 
   // If there are substitutions, specialize the generic accessor.
-  // FIXME: Generic subscript operator could add another layer of
-  // substitutions.
   if (!substitutions.empty()) {
-    callee.setSubstitutions(gen, loc, substitutions);
+    callee.setSubstitutions(substitutions);
   }
   return callee;
 }
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index b791ed3..954aafa 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -511,3 +511,26 @@
   SILBuilder::createCheckedCastBranch(loc, isExact, operand.forward(gen), type,
                                       trueBlock, falseBlock);
 }
+
+ManagedValue SILGenBuilder::createUpcast(SILLocation Loc, ManagedValue Original,
+                                         SILType Type) {
+  bool hadCleanup = Original.hasCleanup();
+  bool isLValue = Original.isLValue();
+
+  SILValue convertedValue =
+      SILBuilder::createUpcast(Loc, Original.forward(gen), Type);
+
+  if (isLValue) {
+    return ManagedValue::forLValue(convertedValue);
+  }
+
+  if (!hadCleanup) {
+    return ManagedValue::forUnmanaged(convertedValue);
+  }
+
+  if (Type.isAddress()) {
+    return gen.emitManagedBufferWithCleanup(convertedValue);
+  }
+
+  return gen.emitManagedRValueWithCleanup(convertedValue);
+}
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index 3e4701c..db837d2 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -226,6 +226,10 @@
                                ManagedValue operand, SILType type,
                                SILBasicBlock *trueBlock,
                                SILBasicBlock *falseBlock);
+
+  using SILBuilder::createUpcast;
+  ManagedValue createUpcast(SILLocation Loc, ManagedValue Original,
+                            SILType Type);
 };
 
 } // namespace Lowering
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index c160037..77c8103 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -726,8 +726,7 @@
   
   // Convert to an object reference.
   value = B.createObjCMetatypeToObject(loc, value, resultTy);
-
-  return ManagedValue::forUnmanaged(value);
+  return emitManagedRValueWithCleanup(value);
 }
 
 ManagedValue SILGenFunction::emitExistentialMetatypeToObject(SILLocation loc,
@@ -746,7 +745,7 @@
   // Convert to an object reference.
   value = B.createObjCExistentialMetatypeToObject(loc, value, resultTy);
   
-  return ManagedValue::forUnmanaged(value);
+  return emitManagedRValueWithCleanup(value);
 }
 
 ManagedValue SILGenFunction::emitProtocolMetatypeToObject(SILLocation loc,
@@ -763,7 +762,7 @@
   // deallocate itself. It doesn't matter if we ever actually clean up that
   // retain though.
   value = B.createCopyValue(loc, value);
-  return ManagedValue::forUnmanaged(value);
+  return emitManagedRValueWithCleanup(value);
 }
 
 SILGenFunction::OpaqueValueState
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index cbe0448..8805540 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -1725,56 +1725,23 @@
                     SILWitnessTable::MethodWitness{requirementRef, witnessFn});
   }
 
-  void addAssociatedType(AssociatedTypeDecl *td,
-                         ArrayRef<ProtocolDecl *> protos) {
+  void addAssociatedType(AssociatedTypeDecl *td) {
     // Find the substitution info for the witness type.
     const auto &witness = Conformance->getTypeWitness(td, /*resolver=*/nullptr);
 
     // Emit the record for the type itself.
     Entries.push_back(SILWitnessTable::AssociatedTypeWitness{td,
-                                witness.getReplacement()->getCanonicalType()});
+                                witness.getReplacement()->getCanonicalType()});    
+  }
 
-    // Emit records for the protocol requirements on the type.
-    assert(protos.size() == witness.getConformances().size()
-           && "number of conformances in assoc type substitution do not match "
-              "number of requirements on assoc type");
-    // The conformances should be all abstract or all concrete.
-    assert(witness.getConformances().empty()
-           || (witness.getConformances()[0].isConcrete()
-                 ? std::all_of(witness.getConformances().begin(),
-                               witness.getConformances().end(),
-                               [&](const ProtocolConformanceRef C) -> bool {
-                                 return C.isConcrete();
-                               })
-                 : std::all_of(witness.getConformances().begin(),
-                               witness.getConformances().end(),
-                               [&](const ProtocolConformanceRef C) -> bool {
-                                 return C.isAbstract();
-                               })));
+  void addAssociatedConformance(CanType dependentType, ProtocolDecl *protocol) {
+    auto assocConformance =
+      Conformance->getAssociatedConformance(dependentType, protocol);
 
-    for (auto *protocol : protos) {
-      // Only reference the witness if the protocol requires it.
-      if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
-        continue;
+    SGM.useConformance(assocConformance);
 
-      ProtocolConformanceRef conformance(protocol);
-      // If the associated type requirement is satisfied by an associated type,
-      // these will all be abstract conformances.
-      if (witness.getConformances()[0].isConcrete()) {
-        auto foundConformance = std::find_if(witness.getConformances().begin(),
-                                        witness.getConformances().end(),
-                                        [&](ProtocolConformanceRef c) {
-                                          return c.getRequirement() == protocol;
-                                        });
-        assert(foundConformance != witness.getConformances().end());
-        conformance = *foundConformance;
-      }
-      SGM.useConformance(conformance);
-
-      Entries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{
-        td, protocol, conformance
-      });
-    }
+    Entries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{
+        dependentType, protocol, assocConformance});
   }
 
   void visitAbstractStorageDecl(AbstractStorageDecl *d) {
@@ -2098,18 +2065,13 @@
     DefaultWitnesses.push_back(entry);
   }
 
-  void addAssociatedType(AssociatedTypeDecl *ty,
-                         ArrayRef<ProtocolDecl *> protos) {
-    // Add a dummy entry for the metatype itself, and then for each conformance.
+  void addAssociatedType(AssociatedTypeDecl *ty) {
+    // Add a dummy entry for the metatype itself.
     addMissingDefault();
+  }
 
-    for (auto *protocol : protos) {
-      // Only reference the witness if the protocol requires it.
-      if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
-        continue;
-
-      addMissingDefault();
-    }
+  void addAssociatedConformance(CanType type, ProtocolDecl *requirement) {
+    addMissingDefault();
   }
 
   void visitAbstractStorageDecl(AbstractStorageDecl *d) {
diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp
index e6c897e..0d373a1 100644
--- a/lib/SILGen/SILGenDestructor.cpp
+++ b/lib/SILGen/SILGenDestructor.cpp
@@ -12,6 +12,7 @@
 
 #include "SILGenFunction.h"
 #include "RValue.h"
+#include "Scope.h"
 #include "swift/AST/AST.h"
 #include "swift/SIL/TypeLowering.h"
 
@@ -49,6 +50,7 @@
   // If we have a superclass, invoke its destructor.
   SILValue resultSelfValue;
   SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext());
+  SILType classTy = selfValue->getType();
   if (cd->hasSuperclass()) {
     Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass());
     ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass();
@@ -66,13 +68,33 @@
     resultSelfValue = B.createApply(cleanupLoc, dtorValue.forward(*this),
                                     dtorTy, objectPtrTy, subs, baseSelf);
   } else {
-    resultSelfValue = B.createUncheckedRefCast(cleanupLoc, selfValue,
-                                                 objectPtrTy);
+    resultSelfValue = selfValue;
   }
 
-  // Release our members.
-  emitClassMemberDestruction(selfValue, cd, cleanupLoc);
+  {
+    Scope S(Cleanups, cleanupLoc);
+    ManagedValue borrowedResultSelfValue =
+        emitManagedBeginBorrow(cleanupLoc, resultSelfValue);
+    SILValue borrowedValue = borrowedResultSelfValue.getUnmanagedValue();
+    if (classTy != borrowedValue->getType()) {
+      borrowedValue =
+          B.createUncheckedRefCast(cleanupLoc, borrowedValue, classTy);
+    }
 
+    // Release our members.
+    emitClassMemberDestruction(borrowedValue, cd, cleanupLoc);
+  }
+
+  if (resultSelfValue->getType() != objectPtrTy) {
+    resultSelfValue =
+        B.createUncheckedRefCast(cleanupLoc, resultSelfValue, objectPtrTy);
+  }
+  if (resultSelfValue.getOwnershipKind() != ValueOwnershipKind::Owned) {
+    assert(resultSelfValue.getOwnershipKind() ==
+           ValueOwnershipKind::Guaranteed);
+    resultSelfValue = B.createUncheckedOwnershipConversion(
+        cleanupLoc, resultSelfValue, ValueOwnershipKind::Owned);
+  }
   B.createReturn(returnLoc, resultSelfValue);
 }
 
@@ -84,25 +106,45 @@
   loc.markAutoGenerated();
 
   // Emit the prolog.
-  SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl());
+  SILValue initialSelfValue = emitSelfDecl(dd->getImplicitSelfDecl());
 
   // Form a reference to the destroying destructor.
   SILDeclRef dtorConstant(dd, SILDeclRef::Kind::Destroyer);
-  auto classTy = selfValue->getType();
+  auto classTy = initialSelfValue->getType();
   ManagedValue dtorValue;
   SILType dtorTy;
   SubstitutionList subs = classTy.gatherAllSubstitutions(SGM.M);
   std::tie(dtorValue, dtorTy, subs)
-    = emitSiblingMethodRef(loc, selfValue, dtorConstant, subs);
+    = emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subs);
 
   // Call the destroying destructor.
-  SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext());
-  selfValue = B.createApply(loc, dtorValue.forward(*this),
-                            dtorTy, objectPtrTy, subs, selfValue);
+  SILValue selfForDealloc;
+  {
+    FullExpr CleanupScope(Cleanups, CleanupLocation::get(loc));
+    ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, initialSelfValue);
+    SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext());
+    selfForDealloc = B.createApply(loc, dtorValue.forward(*this),
+                                   dtorTy, objectPtrTy, subs, borrowedSelf.getUnmanagedValue());
+  }
+
+  // Balance out the +1 from the self argument using end_lifetime.
+  //
+  // The issue here is that:
+  //
+  // 1. Self is passed into deallocating deinits at +1.
+  // 2. Destroying deinits take in self as a +0 value that is then returned at
+  // +1.
+  //
+  // This means that the lifetime of self can not be modeled statically in a
+  // deallocating deinit without analyzing the body of the destroying deinit
+  // (something that violates semantic sil). Thus we add an artifical destroy of
+  // self before the actual destroy of self so that the verifier can understand
+  // that self is being properly balanced.
+  B.createEndLifetime(loc, initialSelfValue);
 
   // Deallocate the object.
-  selfValue = B.createUncheckedRefCast(loc, selfValue, classTy);
-  B.createDeallocRef(loc, selfValue, false);
+  selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy);
+  B.createDeallocRef(loc, selfForDealloc, false);
 
   // Return.
   B.createReturn(loc, emitEmptyTuple(loc));
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 7407c7a..ea697f5 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3619,15 +3619,18 @@
   
   RValue get(SILGenFunction &gen, SILLocation loc,
              ManagedValue base, SGFContext c) && override {
+    FullExpr TightBorrowScope(gen.Cleanups, CleanupLocation::get(loc));
+
     // Load the value at +0.
-    SILValue owned = gen.B.createLoadBorrow(loc, base.getUnmanagedValue());
+    ManagedValue loadedBase = gen.B.createLoadBorrow(loc, base);
 
     // Convert it to unowned.
-    auto refType = owned->getType().getSwiftRValueType();
+    auto refType = loadedBase.getType().getSwiftRValueType();
     auto unownedType = SILType::getPrimitiveObjectType(
                                         CanUnmanagedStorageType::get(refType));
-    SILValue unowned = gen.B.createRefToUnmanaged(loc, owned, unownedType);
-    
+    SILValue unowned = gen.B.createRefToUnmanaged(
+        loc, loadedBase.getUnmanagedValue(), unownedType);
+
     // A reference type should never be exploded.
     return RValue::withPreExplodedElements(ManagedValue::forUnmanaged(unowned),
                                            refType);
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index 53326de..e03e999 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -456,21 +456,17 @@
 
     // Eagerly loading here could cause an unnecessary
     // load+materialize in some cases, but it's not really important.
-    SILValue selfValue = self.getValue();
-    if (selfValue->getType().isAddress()) {
-      // SEMANTIC ARC TODO: We are returning self as a borrowed value. Is this
-      // correct?
-      selfValue = gen.B.createLoadBorrow(loc, selfValue);
+    if (self.getType().isAddress()) {
+      self = gen.B.createLoadBorrow(loc, self);
     }
 
     // Do a derived-to-base conversion if necessary.
     if (witnessSelfType != SubstSelfType) {
       auto selfSILType = gen.getLoweredType(witnessSelfType);
-      selfValue = gen.B.createUpcast(loc, selfValue, selfSILType);
+      self = gen.B.createUpcast(loc, self, selfSILType);
     }
 
     // Recreate as a borrowed value.
-    self = ManagedValue::forUnmanaged(selfValue);
     return LValue::forValue(self, witnessSelfType);
   }
 
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index c53f642..7da97fb 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -1792,8 +1792,11 @@
       if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) {
         SILValue boxedValue = SGF.B.createProjectBox(loc, origCMV.getValue(), 0);
         eltTL = &SGF.getTypeLowering(boxedValue->getType());
-        if (eltTL->isLoadable())
-          boxedValue = SGF.B.createLoadBorrow(loc, boxedValue);
+        if (eltTL->isLoadable()) {
+          ManagedValue newLoadedBoxValue = SGF.B.createLoadBorrow(
+              loc, ManagedValue::forUnmanaged(boxedValue));
+          boxedValue = newLoadedBoxValue.getUnmanagedValue();
+        }
 
         // The boxed value may be shared, so we always have to copy it.
         eltCMV = getManagedSubobject(SGF, boxedValue, *eltTL,
diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp
index b5c39b8..0a857f9 100644
--- a/lib/SILOptimizer/IPO/CapturePropagation.cpp
+++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp
@@ -248,7 +248,7 @@
                                  SILFunctionType::Representation::Thin);
   SILFunction *NewF = OrigF->getModule().createFunction(
       SILLinkage::Shared, Name, NewFTy,
-      /*contextGenericParams*/ nullptr, OrigF->getLocation(), OrigF->isBare(),
+      OrigF->getGenericEnvironment(), OrigF->getLocation(), OrigF->isBare(),
       OrigF->isTransparent(), Fragile, OrigF->isThunk(),
       OrigF->getClassVisibility(), OrigF->getInlineStrategy(),
       OrigF->getEffectsKind(),
diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
index 3edb44d..bbba5d6 100644
--- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
+++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
@@ -22,6 +22,7 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 using namespace swift;
 
diff --git a/lib/SILOptimizer/IPO/EagerSpecializer.cpp b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
index c84965c..40fce0f 100644
--- a/lib/SILOptimizer/IPO/EagerSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
@@ -337,41 +337,30 @@
   // SubstitutableTypes, skipping DependentTypes.
   auto GenericSig =
     GenericFunc->getLoweredFunctionType()->getGenericSignature();
-  auto SubIt = ReInfo.getClonerParamSubstitutions().begin();
-  auto SubEnd = ReInfo.getClonerParamSubstitutions().end();
-  auto DepTypes = GenericSig->getAllDependentTypes();
-  for (auto DepTy : DepTypes) {
-    assert(SubIt != SubEnd && "Not enough substitutions.");
-    if (auto ParamTy = DepTy->getAs<SubstitutableType>()) {
-      auto Replacement = SubIt->getReplacement();
-      auto GenericEnv = ReInfo.getSpecializedGenericEnvironment();
-      if (!Replacement->hasArchetype()) {
-        if (GenericEnv)
-          Replacement = GenericEnv->mapTypeIntoContext(Replacement);
-        assert(!Replacement->hasTypeParameter());
-        // Dispatch on concrete type.
-        emitTypeCheck(FailedTypeCheckBB, ParamTy, Replacement);
-      } else {
-        // If Replacement has a layout constraint, then dispatch based
-        // on its size and the fact that it is trivial.
-        auto LayoutInfo = Replacement->getLayoutConstraint();
-        if (LayoutInfo && LayoutInfo->isTrivial()) {
-          // Emit a check that it is a trivial type of a certain size.
-          emitTrivialAndSizeCheck(FailedTypeCheckBB, ParamTy,
-                                  GenericEnv->mapTypeIntoContext(Replacement),
-                                  LayoutInfo);
-        } else if (LayoutInfo && LayoutInfo->isRefCountedObject()) {
-          // Emit a check that it is an object of a reference counted type.
-          emitRefCountedObjectCheck(FailedTypeCheckBB, ParamTy,
-                                    GenericEnv->mapTypeIntoContext(Replacement),
-                                    LayoutInfo);
-        }
+  auto SubMap = GenericSig->getSubstitutionMap(
+    ReInfo.getClonerParamSubstitutions());
+  for (auto ParamTy : GenericSig->getSubstitutableParams()) {
+    auto Replacement = Type(ParamTy).subst(SubMap);
+    assert(!Replacement->hasTypeParameter());
+
+    if (!Replacement->hasArchetype()) {
+      // Dispatch on concrete type.
+      emitTypeCheck(FailedTypeCheckBB, ParamTy, Replacement);
+    } else {
+      // If Replacement has a layout constraint, then dispatch based
+      // on its size and the fact that it is trivial.
+      auto LayoutInfo = Replacement->getLayoutConstraint();
+      if (LayoutInfo && LayoutInfo->isTrivial()) {
+        // Emit a check that it is a trivial type of a certain size.
+        emitTrivialAndSizeCheck(FailedTypeCheckBB, ParamTy,
+                                Replacement, LayoutInfo);
+      } else if (LayoutInfo && LayoutInfo->isRefCountedObject()) {
+        // Emit a check that it is an object of a reference counted type.
+        emitRefCountedObjectCheck(FailedTypeCheckBB, ParamTy,
+                                  Replacement, LayoutInfo);
       }
     }
-    ++SubIt;
   }
-  assert(SubIt == SubEnd && "Too many substitutions.");
-  (void) SubEnd;
   static_cast<void>(FailedTypeCheckBB);
 
   if (OldReturnBB == &EntryBB) {
@@ -709,13 +698,9 @@
   DEBUG(auto FT = GenericFunc->getLoweredFunctionType();
         dbgs() << "  Generic Sig:";
         dbgs().indent(2); FT->getGenericSignature()->print(dbgs());
-        dbgs() << "\n  Substituting: <";
-        auto depTypes = FT->getGenericSignature()->getAllDependentTypes();
-        interleave(depTypes.begin(), depTypes.end(),
-                   [&](Type t){
-                     GenericFunc->mapTypeIntoContext(t).print(dbgs()); },
-                   []{ dbgs() << ", "; });
-        dbgs() << "> with ";
+        dbgs() << "  Generic Env:";
+        dbgs().indent(2); GenericFunc->getGenericEnvironment()->dump(dbgs());
+        dbgs() << "  Specialize Attr:";
         SA.print(dbgs()); dbgs() << "\n");
 
   GenericFuncSpecializer
diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp
index 21ce0d6..413bc8c 100644
--- a/lib/SILOptimizer/IPO/GlobalOpt.cpp
+++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp
@@ -240,7 +240,8 @@
   auto LoweredType = SILFunctionType::get(nullptr, EInfo,
       ParameterConvention::Direct_Owned, { }, Results, None,
       Store->getModule().getASTContext());
-  auto *GetterF = Store->getModule().getOrCreateFunction(Store->getLoc(),
+  auto *GetterF = Store->getModule().getOrCreateFunction(
+      Store->getLoc(),
       getterName, SILLinkage::Private, LoweredType,
       IsBare_t::IsBare, IsTransparent_t::IsNotTransparent,
       IsFragile_t::IsFragile);
@@ -493,8 +494,9 @@
   auto LoweredType = SILFunctionType::get(nullptr, EInfo,
       ParameterConvention::Direct_Owned, { }, Results, None,
       InitF->getASTContext());
-  auto *GetterF = InitF->getModule().getOrCreateFunction(InitF->getLocation(),
-     getterName, SILLinkage::Private, LoweredType,
+  auto *GetterF = InitF->getModule().getOrCreateFunction(
+      InitF->getLocation(),
+      getterName, SILLinkage::Private, LoweredType,
       IsBare_t::IsBare, IsTransparent_t::IsNotTransparent,
       IsFragile_t::IsFragile);
   if (InitF->hasUnqualifiedOwnership())
diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
index 4731fe0..fe648ff 100644
--- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp
+++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
@@ -92,20 +92,6 @@
 
     return valueVector.back().second;
   }
-
-  // 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");
-    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
 
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
index 3d8f05c..54b99d4 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
@@ -692,39 +692,26 @@
   // replaced by a concrete type.
   SmallVector<Substitution, 8> Substitutions;
   for (auto Subst : AI.getSubstitutions()) {
-    auto *A = Subst.getReplacement()->getAs<ArchetypeType>();
-    if (A && A == OpenedArchetype) {
-      auto Conformances = AI.getModule().getASTContext()
-                            .AllocateUninitialized<ProtocolConformanceRef>(1);
-      Conformances[0] = Conformance;
-      Substitution NewSubst(ConcreteType, Conformances);
-      Substitutions.push_back(NewSubst);
-    } else
-      Substitutions.push_back(Subst);
+    auto NewSubst = Subst.subst(
+      AI.getModule().getSwiftModule(),
+      [&](SubstitutableType *type) -> Type {
+        if (type == OpenedArchetype)
+          return ConcreteType;
+        return type;
+      },
+      [&](Type origTy, Type substTy, ProtocolType *protoType)
+        -> Optional<ProtocolConformanceRef> {
+        assert(origTy->isEqual(OpenedArchetype));
+        return Conformance;
+      });
+    Substitutions.push_back(NewSubst);
   }
 
-  SILType SubstCalleeType = AI.getSubstCalleeSILType();
-
-  SILType NewSubstCalleeType;
-
   auto FnTy = AI.getCallee()->getType().castTo<SILFunctionType>();
-  if (FnTy->isPolymorphic()) {
-    // Handle polymorphic functions by properly substituting
-    // their parameter types.
-    CanSILFunctionType SFT = FnTy->substGenericArgs(
-                                        AI.getModule(),
-                                        Substitutions);
-    NewSubstCalleeType = SILType::getPrimitiveObjectType(SFT);
-  } else {
-    NewSubstCalleeType =
-      SubstCalleeType.subst(AI.getModule(),
-                            [&](SubstitutableType *type) -> Type {
-                              if (type == OpenedArchetype)
-                                return ConcreteType;
-                              return type;
-                            },
-                            MakeAbstractConformanceForGenericType());
-  }
+  assert(FnTy->isPolymorphic());
+
+  auto SFT = FnTy->substGenericArgs(AI.getModule(), Substitutions);
+  auto NewSubstCalleeType = SILType::getPrimitiveObjectType(SFT);
 
   FullApplySite NewAI;
   Builder.setCurrentDebugScope(AI.getDebugScope());
@@ -732,14 +719,14 @@
 
   if (auto *TAI = dyn_cast<TryApplyInst>(AI))
     NewAI = Builder.createTryApply(AI.getLoc(), AI.getCallee(),
-                                    NewSubstCalleeType,
-                                    Substitutions, Args,
-                                    TAI->getNormalBB(), TAI->getErrorBB());
+                                   NewSubstCalleeType,
+                                   Substitutions, Args,
+                                   TAI->getNormalBB(), TAI->getErrorBB());
   else
     NewAI = Builder.createApply(AI.getLoc(), AI.getCallee(),
-                                 NewSubstCalleeType,
-                                 AI.getType(), Substitutions, Args,
-                                 cast<ApplyInst>(AI)->isNonThrowing());
+                                NewSubstCalleeType,
+                                AI.getType(), Substitutions, Args,
+                                cast<ApplyInst>(AI)->isNonThrowing());
 
   if (isa<ApplyInst>(NewAI))
     replaceInstUsesWith(*AI.getInstruction(), NewAI.getInstruction());
@@ -886,21 +873,6 @@
   if (WMI->getConformance().isConcrete())
     return nullptr;
 
-  // Don't specialize Apply instructions that return the Self type.
-  // Notice that it is sufficient to compare the return type to the
-  // substituted type because types that depend on the Self type are
-  // not allowed (for example [Self] is not allowed).
-  if (AI.getType().getSwiftRValueType() == WMI->getLookupType())
-    return nullptr;
-
-  // We need to handle the Self return type.
-  // 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().getSwiftRValueType() == WMI->getLookupType())
-      return nullptr;
-  }
-
   // The lookup type is not an opened existential type,
   // thus it cannot be made more concrete.
   if (!WMI->getLookupType()->isOpenedExistential())
@@ -916,10 +888,10 @@
     // Keep around the dependence on the open instruction unless we've
     // actually eliminated the use.
     auto *NewWMI = Builder.createWitnessMethod(WMI->getLoc(),
-                                                ConcreteType,
-                                                Conformance, WMI->getMember(),
-                                                WMI->getType(),
-                                                WMI->isVolatile());
+                                               ConcreteType,
+                                               Conformance, WMI->getMember(),
+                                               WMI->getType(),
+                                               WMI->isVolatile());
     // Replace only uses of the witness_method in the apply that is going to
     // be changed.
     MutableArrayRef<Operand> Operands = AI.getInstruction()->getAllOperands();
@@ -957,15 +929,6 @@
   if (!Self)
     return nullptr;
 
-  // We need to handle the Self return type.
-  // 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().getSwiftRValueType() ==
-        AI.getArguments().back()->getType().getSwiftRValueType())
-      return nullptr;
-  }
-
   // Obtain the protocol whose which should be used by the conformance.
   auto *AFD = dyn_cast<AbstractFunctionDecl>(Callee->getDeclContext());
   if (!AFD)
diff --git a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
index ce6a1d1..73d41fb 100644
--- a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
+++ b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
@@ -488,10 +488,11 @@
   DEBUG(llvm::dbgs() << "  -> create specialized function " << Name << "\n");
 
   NewF = M.createFunction(linkage, Name, createOptimizedSILFunctionType(),
-                          nullptr, F->getLocation(), F->isBare(),
-                          F->isTransparent(), F->isFragile(), F->isThunk(),
-                          F->getClassVisibility(), F->getInlineStrategy(),
-                          F->getEffectsKind(), nullptr, F->getDebugScope());
+                          F->getGenericEnvironment(), F->getLocation(),
+                          F->isBare(), F->isTransparent(), F->isFragile(),
+                          F->isThunk(), F->getClassVisibility(),
+                          F->getInlineStrategy(), F->getEffectsKind(), nullptr,
+                          F->getDebugScope());
   if (F->hasUnqualifiedOwnership()) {
     NewF->setUnqualifiedOwnership();
   }
diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
index 0ec3d33..db045e7 100644
--- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
+++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
@@ -64,6 +64,16 @@
     EBI->eraseFromParent();
     return true;
   }
+  bool visitEndLifetimeInst(EndLifetimeInst *ELI) {
+    ELI->eraseFromParent();
+    return true;
+  }
+  bool visitUncheckedOwnershipConversionInst(
+      UncheckedOwnershipConversionInst *UOCI) {
+    UOCI->replaceAllUsesWith(UOCI->getOperand());
+    UOCI->eraseFromParent();
+    return true;
+  }
   bool visitUnmanagedRetainValueInst(UnmanagedRetainValueInst *URVI);
   bool visitUnmanagedReleaseValueInst(UnmanagedReleaseValueInst *URVI);
   bool visitUnmanagedAutoreleaseValueInst(UnmanagedAutoreleaseValueInst *UAVI);
diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
index fb14a28..6966f78 100644
--- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
+++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
@@ -316,8 +316,7 @@
 // specialization for a given call.
 static bool canSpecializeGeneric(ApplySite AI, SILFunction *F,
                                  SubstitutionList Subs) {
-  ReabstractionInfo ReInfo(AI, F, Subs);
-  return ReInfo.canBeSpecialized();
+  return ReabstractionInfo::canBeSpecialized(AI, F, Subs);
 }
 
 bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index 2adfd48..13e8a6f 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -22,6 +22,18 @@
 
 using namespace swift;
 
+/// Set to true to enable the support for partial specialization.
+llvm::cl::opt<bool> EnablePartialSpecialization(
+    "sil-partial-specialization", llvm::cl::init(false),
+    llvm::cl::desc("Enable partial specialization of generics"));
+
+/// If set, then generic specialization tries to specialize using
+/// all substitutions, even if they the replacement types are generic.
+llvm::cl::opt<bool> SpecializeGenericSubstitutions(
+    "sil-partial-specialization-with-generic-substitutions",
+    llvm::cl::init(false),
+    llvm::cl::desc("Enable partial specialization with generic substitutions"));
+
 // Max depth of a bound generic which can be processed by the generic
 // specializer.
 // E.g. the depth of Array<Array<Array<T>>> is 3.
@@ -49,40 +61,54 @@
 // ReabstractionInfo
 // =============================================================================
 
-// Initialize SpecializedType iff the specialization is allowed.
-ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *OrigF,
-                                     SubstitutionList ParamSubs) {
-  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;
+static bool shouldNotSpecializeCallee(SILFunction *Callee) {
+  if (!Callee->shouldOptimize()) {
+    DEBUG(llvm::dbgs() << "    Cannot specialize function " << Callee->getName()
+          << " marked to be excluded from optimizations.\n");
+    return true;
   }
 
-  OriginalF = OrigF;
-  OriginalParamSubs = ParamSubs;
-  ClonerParamSubs = ParamSubs;
-  CallerParamSubs = ParamSubs;
-  SpecializedGenericSig = nullptr;
+  if (Callee->hasSemanticsAttr("optimize.sil.specialize.generic.never"))
+    return true;
+
+  return false;
+}
+
+/// Prepares the ReabstractionInfo object for further processing and checks
+/// if the current function can be specialized at all.
+/// Returns false, if the current function cannot be specialized.
+/// Returns true otherwise.
+bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
+                                        SubstitutionList ParamSubs) {
+  if (shouldNotSpecializeCallee(Callee))
+    return false;
+
   SpecializedGenericEnv = nullptr;
+  SpecializedGenericSig = nullptr;
+  OriginalParamSubs = ParamSubs;
+  auto CalleeGenericSig = Callee->getLoweredFunctionType()->getGenericSignature();
+  auto CalleeGenericEnv = Callee->getGenericEnvironment();
+
+  OriginalF = Callee;
+  this->Apply = Apply;
 
   SubstitutionMap InterfaceSubs;
-  if (OrigF->getLoweredFunctionType()->getGenericSignature())
-    InterfaceSubs = OrigF->getLoweredFunctionType()->getGenericSignature()
-      ->getSubstitutionMap(ParamSubs);
+
+  // Get the original substitution map.
+  if (CalleeGenericSig)
+    InterfaceSubs = CalleeGenericSig->getSubstitutionMap(ParamSubs);
 
   // We do not support partial specialization.
-  if (InterfaceSubs.hasArchetypes()) {
-    DEBUG(llvm::dbgs() <<
-          "    Cannot specialize with unbound interface substitutions.\n");
-    DEBUG(for (auto Sub : ParamSubs) {
-            Sub.dump();
-          });
-    return;
+  if (!EnablePartialSpecialization && InterfaceSubs.hasArchetypes()) {
+    DEBUG(llvm::dbgs() << "    Partial specialization is not supported.\n");
+    DEBUG(for (auto Sub : ParamSubs) { Sub.dump(); });
+    return false;
   }
+
+  // Perform some checks to see if we need to bail.
   if (InterfaceSubs.hasDynamicSelf()) {
     DEBUG(llvm::dbgs() << "    Cannot specialize with dynamic self.\n");
-    return;
+    return false;
   }
 
   // Check if the substitution contains any generic types that are too deep.
@@ -93,46 +119,175 @@
     if (Replacement.findIf([](Type ty) -> bool {
           return getBoundGenericDepth(ty) >= BoundGenericDepthThreshold;
         })) {
-      return;
+      DEBUG(llvm::dbgs()
+            << "    Cannot specialize because the generic type is too deep.\n");
+      return false;
     }
   }
 
-  SILModule &M = OrigF->getModule();
-  SubstitutedType = OrigF->getLoweredFunctionType()->substGenericArgs(
-    M, InterfaceSubs);
+  // Check if we have substitutions which replace generic type parameters with
+  // concrete types or unbound generic types.
+  bool HasConcreteGenericParams = false;
+  bool HasNonArchetypeGenericParams = false;
+  HasUnboundGenericParams = false;
+  for (auto DT : CalleeGenericSig->getGenericParams()) {
+    // Check only the substitutions for the generic parameters.
+    // Ignore any dependent types, etc.
+    auto Replacement = Type(DT).subst(InterfaceSubs);
+    if (!Replacement->is<ArchetypeType>())
+      HasNonArchetypeGenericParams = true;
 
-  NumFormalIndirectResults = SubstitutedType->getNumIndirectFormalResults();
-  Conversions.resize(NumFormalIndirectResults
-                     + SubstitutedType->getParameters().size());
-  if (SubstitutedType->getNumDirectFormalResults() == 0) {
-    // The original function has no direct result yet. Try to convert the first
-    // indirect result to a direct result.
-    // TODO: We could also convert multiple indirect results by returning a
-    // tuple type and created tuple_extract instructions at the call site.
-    SILFunctionConventions substConv(SubstitutedType, M);
-    unsigned IdxForResult = 0;
-    for (SILResultInfo RI : SubstitutedType->getIndirectFormalResults()) {
-      assert(RI.isFormalIndirect());
-      if (substConv.getSILType(RI).isLoadable(M) && !RI.getType()->isVoid()) {
-        Conversions.set(IdxForResult);
-        break;
+    if (Replacement->hasArchetype()) {
+      HasUnboundGenericParams = true;
+      // Check if the replacement is an archetype which is more specific
+      // than the corresponding archetype in the original generic signature.
+      // If this is the case, then specialization makes sense, because
+      // it would produce something more specific.
+      if (CalleeGenericEnv) {
+        if (auto Archetype = Replacement->getAs<ArchetypeType>()) {
+          auto OrigArchetype =
+              CalleeGenericEnv->mapTypeIntoContext(DT)->castTo<ArchetypeType>();
+          if (Archetype->requiresClass() && !OrigArchetype->requiresClass())
+            HasNonArchetypeGenericParams = true;
+          if (Archetype->getLayoutConstraint() &&
+              !OrigArchetype->getLayoutConstraint())
+            HasNonArchetypeGenericParams = true;
+        }
       }
-      ++IdxForResult;
+      continue;
+    }
+
+    HasConcreteGenericParams = true;
+  }
+
+  if (HasUnboundGenericParams) {
+    if (!HasNonArchetypeGenericParams && !HasConcreteGenericParams) {
+      DEBUG(llvm::dbgs() << "    Partial specialization is not supported if "
+                            "all substitutions are archetypes.\n");
+      DEBUG(for (auto Sub : ParamSubs) {
+          Sub.dump();
+        });
+      return false;
+    }
+
+    // We need a generic environment for the partial specialization.
+    if (!CalleeGenericEnv)
+      return false;
+  }
+
+  return true;
+}
+
+bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee,
+                                         SubstitutionList ParamSubs) {
+  ReabstractionInfo ReInfo;
+  return ReInfo.prepareAndCheck(Apply, Callee, ParamSubs);
+}
+
+ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
+                                     ArrayRef<Substitution> ParamSubs) {
+  if (!prepareAndCheck(Apply, Callee, ParamSubs))
+    return;
+
+  if (SpecializeGenericSubstitutions) {
+    specializeConcreteAndGenericSubstitutions(Apply, Callee, ParamSubs);
+  } else {
+    specializeConcreteSubstitutions(Apply, Callee, ParamSubs);
+  }
+
+  if (SpecializedGenericSig) {
+    DEBUG(llvm::dbgs() << "\n\nPartially specialized types for function: "
+                       << Callee->getName() << "\n\n";
+          llvm::dbgs() << "Original generic function type:\n"
+                       << Callee->getLoweredFunctionType() << "\n"
+                       << "Partially specialized generic function type:\n"
+                       << SpecializedType << "\n\n");
+  }
+
+  // Some sanity checks.
+  auto SpecializedFnTy = getSpecializedType();
+  auto SpecializedSubstFnTy = SpecializedFnTy;
+
+  if (SpecializedFnTy->isPolymorphic() &&
+      !getCallerParamSubstitutions().empty()) {
+    auto CalleeFnTy = Callee->getLoweredFunctionType();
+    assert(CalleeFnTy->isPolymorphic());
+    auto CalleeSubstFnTy = CalleeFnTy->substGenericArgs(
+        Callee->getModule(), getOriginalParamSubstitutions());
+    assert(!CalleeSubstFnTy->isPolymorphic() &&
+           "Substituted callee type should not be polymorphic");
+    assert(!CalleeSubstFnTy->hasTypeParameter() &&
+           "Substituted callee type should not have type parameters");
+
+    SpecializedSubstFnTy = SpecializedFnTy->substGenericArgs(
+        Callee->getModule(), getCallerParamSubstitutions());
+
+    assert(!SpecializedSubstFnTy->isPolymorphic() &&
+           "Substituted callee type should not be polymorphic");
+    assert(!SpecializedSubstFnTy->hasTypeParameter() &&
+           "Substituted callee type should not have type parameters");
+
+    auto SpecializedCalleeSubstFnTy =
+        createSpecializedType(CalleeSubstFnTy, Callee->getModule());
+
+    if (SpecializedSubstFnTy != SpecializedCalleeSubstFnTy) {
+      llvm::dbgs() << "SpecializedFnTy:\n" << SpecializedFnTy << "\n";
+      llvm::dbgs() << "SpecializedSubstFnTy:\n" << SpecializedSubstFnTy << "\n";
+      for (auto Sub : getCallerParamSubstitutions()) {
+        llvm::dbgs() << "Sub:\n";
+        Sub.dump();
+      }
+      llvm::dbgs() << "\n\n";
+
+      llvm::dbgs() << "CalleeFnTy:\n" << CalleeFnTy << "\n";
+      llvm::dbgs() << "SpecializedCalleeSubstFnTy:\n" << SpecializedCalleeSubstFnTy << "\n";
+      for (auto Sub : ParamSubs) {
+        llvm::dbgs() << "Sub:\n";
+        Sub.dump();
+      }
+      llvm::dbgs() << "\n\n";
+      assert(SpecializedSubstFnTy == SpecializedCalleeSubstFnTy &&
+             "Substituted function types should be the same");
     }
   }
-  // Try to convert indirect incoming parameters to direct parameters.
-  // The Conversions index domain is
-  // [0..<NumFormalIndirectResults + NumParameters]. This is *not* the same as
-  // a SubstitutedType's SIL argument index.
-  unsigned IdxForParam = NumFormalIndirectResults;
-  for (SILParameterInfo PI : SubstitutedType->getParameters()) {
-    if (PI.getSILStorageType().isLoadable(M)
-        && PI.getConvention() == ParameterConvention::Indirect_In) {
-      Conversions.set(IdxForParam);
-    }
-    ++IdxForParam;
+
+  // If the new type is the same, there is nothing to do and
+  // no specialization should be performed.
+  if (getSubstitutedType() == Callee->getLoweredFunctionType()) {
+    DEBUG(llvm::dbgs() << "The new specialized type is the same as "
+                          "the original "
+                          "type. Don't specialize!\n";
+          llvm::dbgs() << "The type is: " << getSubstitutedType() << "\n");
+    SpecializedType = CanSILFunctionType();
+    SubstitutedType = CanSILFunctionType();
+    SpecializedGenericSig = nullptr;
+    return;
   }
-  SpecializedType = createSpecializedType(SubstitutedType, M);
+
+  if (SpecializedGenericSig) {
+    // It is a partial specializaiton.
+    DEBUG(llvm::dbgs() << "Specializing the call:\n";
+          Apply.getInstruction()->dumpInContext();
+          llvm::dbgs() << "\n\nPartially specialized types for function: "
+                       << Callee->getName() << "\n\n";
+          llvm::dbgs() << "Original generic function type:\n"
+                       << Callee->getLoweredFunctionType() << "\n\n";
+          llvm::dbgs() << "\nOriginal call substitution:\n";
+          for (auto Sub : getOriginalParamSubstitutions()) {
+            llvm::dbgs() << "Sub:\n";
+            Sub.dump();
+            llvm::dbgs() << "\n";
+          }
+
+          llvm::dbgs() << "Partially specialized generic function type:\n"
+                       << getSpecializedType() << "\n\n";
+          llvm::dbgs() << "\nSpecialization call substitution:\n";
+          for (auto Sub : getCallerParamSubstitutions()) {
+            llvm::dbgs() << "Sub:\n";
+            Sub.dump();
+            llvm::dbgs() << "\n";
+          });
+  }
 }
 
 bool ReabstractionInfo::canBeSpecialized() const {
@@ -210,11 +365,6 @@
                                          const SubstitutionMap &SubstMap,
                                          bool HasUnboundGenericParams) {
   auto &M = OrigF->getModule();
-  auto OrigFnTy = OrigF->getLoweredFunctionType();
-
-  // First substitute concrete types into the existing function type.
-  auto FnTy = OrigFnTy->substGenericArgs(M, SubstMap);
-
   if ((SpecializedGenericSig &&
        SpecializedGenericSig->areAllParamsConcrete()) ||
       !HasUnboundGenericParams) {
@@ -222,11 +372,24 @@
     SpecializedGenericEnv = nullptr;
   }
 
+  CanGenericSignature CanSpecializedGenericSig;
+  if (SpecializedGenericSig)
+    CanSpecializedGenericSig = SpecializedGenericSig->getCanonicalSignature();
+
+  // First substitute concrete types into the existing function type.
+  CanSILFunctionType FnTy;
+  {
+    Lowering::GenericContextScope GenericScope(M.Types,
+                                               CanSpecializedGenericSig);
+    FnTy = OrigF->getLoweredFunctionType()->substGenericArgs(M, SubstMap);
+  }
+  assert(FnTy);
+
   // Use the new specialized generic signature.
   auto NewFnTy = SILFunctionType::get(
-      SpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCalleeConvention(),
-      FnTy->getParameters(), FnTy->getResults(),
-      FnTy->getOptionalErrorResult(), M.getASTContext());
+      CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCalleeConvention(),
+      FnTy->getParameters(), FnTy->getResults(), FnTy->getOptionalErrorResult(),
+      M.getASTContext());
 
   // This is an interface type. It should not have any archetypes.
   assert(!NewFnTy->hasArchetype());
@@ -280,6 +443,25 @@
                          M.getASTContext());
 }
 
+static std::pair<GenericEnvironment *, GenericSignature *>
+getGenericEnvironmentAndSignature(GenericSignatureBuilder &Builder,
+                                  SILModule &M) {
+  auto *GenericSig =
+      Builder.getGenericSignature()->getCanonicalSignature().getPointer();
+  auto *GenericEnv = GenericSig->createGenericEnvironment(*M.getSwiftModule());
+
+  // FIXME: This is a workaround for the signature minimization bug.
+  GenericSignatureBuilder TmpBuilder(
+      M.getASTContext(), LookUpConformanceInModule(M.getSwiftModule()));
+  TmpBuilder.addGenericSignature(GenericSig);
+  TmpBuilder.finalize(SourceLoc(), GenericSig->getGenericParams());
+  GenericSig =
+      TmpBuilder.getGenericSignature()->getCanonicalSignature().getPointer();
+  GenericEnv = GenericSig->createGenericEnvironment(*M.getSwiftModule());
+
+  return std::make_pair(GenericEnv, GenericSig);
+}
+
 std::pair<GenericEnvironment *, GenericSignature *>
 getSignatureWithRequirements(GenericSignature *OrigGenSig,
                              GenericEnvironment *OrigGenericEnv,
@@ -301,11 +483,7 @@
   }
 
   Builder.finalize(SourceLoc(), OrigGenSig->getGenericParams());
-  auto *GenericSig = Builder.getGenericSignature();
-  // Remember the new generic environment.
-  auto *GenericEnv = GenericSig->createGenericEnvironment(*M.getSwiftModule());
-
-  return std::make_pair(GenericEnv, GenericSig);
+  return getGenericEnvironmentAndSignature(Builder, M);
 }
 
 /// Perform some sanity checks for the requirements
@@ -340,11 +518,8 @@
 
 ReabstractionInfo::ReabstractionInfo(SILFunction *OrigF,
                                      ArrayRef<Requirement> Requirements) {
-  if (!OrigF->shouldOptimize()) {
-    DEBUG(llvm::dbgs() << "    Cannot specialize function " << OrigF->getName()
-                       << " marked to be excluded from optimizations.\n");
+  if (shouldNotSpecializeCallee(OrigF))
     return;
-  }
 
   // Perform some sanity checks for the requirements
   checkSpecializationRequirements(Requirements);
@@ -399,6 +574,138 @@
   createSubstitutedAndSpecializedTypes();
 }
 
+static void verifySubstitutionList(SubstitutionList Subs) {
+  for (auto Sub : Subs) {
+    assert(!Sub.getReplacement()->hasError() &&
+           "There should be no error types in substitutions");
+  }
+}
+
+// Builds a new signature based on the old one and adds same type
+// requirements for those generic type parameters that are concrete
+// according to the partial substitution. This way, the signature
+// has exactly the same generic parameter types, just with more
+// requirements.
+// Current issues:
+// - If Sig2 = GenericSignatureBuilder(Sig2 + Req), then GenericSignatureBuilder(Sig2) != Sig2
+// - The set of requirements is not really minimized.
+// - Some requirements are lost, when you add a same type parameter to the builder.
+
+// Initialize SpecializedType if and only if the specialization is allowed.
+void ReabstractionInfo::specializeConcreteSubstitutions(
+    ApplySite Apply, SILFunction *Callee, ArrayRef<Substitution> ParamSubs) {
+
+  SILModule &M = Callee->getModule();
+  auto &Ctx = M.getASTContext();
+
+  OriginalF = Callee;
+
+  auto OrigGenericSig = Callee->getLoweredFunctionType()->getGenericSignature();
+  auto OrigGenericEnv = Callee->getGenericEnvironment();
+
+  SubstitutionMap InterfaceSubs;
+  // Get the original substitution map.
+  if (Callee->getLoweredFunctionType()->getGenericSignature())
+    InterfaceSubs = Callee->getLoweredFunctionType()->getGenericSignature()
+      ->getSubstitutionMap(ParamSubs);
+
+  // This is a workaround for the rdar://30610428
+  if (!EnablePartialSpecialization) {
+    SubstitutedType =
+        Callee->getLoweredFunctionType()->substGenericArgs(M, InterfaceSubs);
+    ClonerParamSubs = OriginalParamSubs;
+    CallerParamSubs = {};
+    createSubstitutedAndSpecializedTypes();
+    return;
+  }
+
+  // Build a set of requirements.
+  SmallVector<Requirement, 4> Requirements;
+
+  for (auto DP : OrigGenericSig->getGenericParams()) {
+    auto Replacement = Type(DP).subst(InterfaceSubs);
+    if (Replacement->hasArchetype())
+      continue;
+    // Replacemengt is concrete. Add a same type requirement.
+    Requirement Req(RequirementKind::SameType, DP, Replacement);
+    Requirements.push_back(Req);
+  }
+
+  std::tie(SpecializedGenericEnv, SpecializedGenericSig) =
+      getSignatureWithRequirements(OrigGenericSig, OrigGenericEnv,
+                                   Requirements, M);
+  HasUnboundGenericParams = !SpecializedGenericSig->areAllParamsConcrete();
+
+  // No partial specializations!
+  //if (HasUnboundGenericParams)
+  //  return;
+
+  {
+    SmallVector<Substitution, 4> List;
+
+    OrigGenericSig->getSubstitutions(
+      [&](SubstitutableType *type) -> Type {
+        return SpecializedGenericEnv->mapTypeIntoContext(type);
+      },
+      LookUpConformanceInSignature(*SpecializedGenericSig),
+      List);
+    ClonerParamSubs = Ctx.AllocateCopy(List);
+    verifySubstitutionList(ClonerParamSubs);
+  }
+
+  {
+    SmallVector<Substitution, 4> List;
+    SpecializedGenericSig->getSubstitutions(InterfaceSubs, List);
+    CallerParamSubs = Ctx.AllocateCopy(List);
+    verifySubstitutionList(CallerParamSubs);
+  }
+
+  {
+    CallerInterfaceSubs = OrigGenericSig->getSubstitutionMap(
+      [&](SubstitutableType *type) -> Type {
+        return SpecializedGenericEnv->mapTypeOutOfContext(
+          SpecializedGenericEnv->mapTypeIntoContext(type));
+      },
+        //LookUpConformanceInSignature(*SpecializedGenericSig));
+      LookUpConformanceInSignature(*OrigGenericSig));
+  }
+
+  HasUnboundGenericParams = !SpecializedGenericSig->areAllParamsConcrete();
+  createSubstitutedAndSpecializedTypes();
+}
+
+// Builds a new generic and function signatures for a partial specialization.
+// Allows for partial specializations even if substitututions contain
+// type parameters.
+//
+// The new generic signature has the following generic parameters:
+// - For each substitution with a concrete type CT as a replacement for a generic
+// type T, it introduces a generic parameter T' and a requirement T' == CT
+// - For all other substitutions that are considered for partial specialization,
+// it collects first the archetypes used in the replacements. Then for each such
+// archetype A a new generic parameter T' introduced.
+// - If there is a substitution for type T and this substitution is execluded from
+// partial specialization (e.g. because it is impossible or would result in a less
+// efficient code), then a new generic parameter T' is introduced, which does not
+// get any additional, more specific requirements based on the substitutions.
+//
+// After all generic parameters are added accoriding to the rules above,
+// the requirements of the callee's signature are re-mapped by re-formulating them
+// in terms of the newly introduced generic parameters. In case a remapped
+// requirement does not contain any generic types, it can be omitted, because
+// it is fulfilled already.
+
+// Current issues:
+// - If Sig2 = GenericSignatureBuilder(Sig2 + Req), then
+// GenericSignatureBuilder(Sig2) != Sig2
+// - The set of requirements is not really minimized.
+// - Some requirements are lost, when you add a same type parameter to the
+// builder.
+void ReabstractionInfo::specializeConcreteAndGenericSubstitutions(
+    ApplySite Apply, SILFunction *Callee, ArrayRef<Substitution> ParamSubs) {
+  llvm_unreachable("Not implemented yet");
+}
+
 // =============================================================================
 // GenericFuncSpecializer
 // =============================================================================
@@ -505,16 +812,13 @@
   VoidVal->replaceAllUsesWith(NewVoidVal);
 }
 
-// Create a new apply based on an old one, but with a different
-// function being applied.
-static ApplySite replaceWithSpecializedCallee(ApplySite AI,
-                                              SILValue Callee,
-                                              SILBuilder &Builder,
-                                              const ReabstractionInfo &ReInfo) {
-  SILLocation Loc = AI.getLoc();
-  SmallVector<SILValue, 4> Arguments;
-  SILValue StoreResultTo;
+// Prepare call arguments. Perform re-abstraction if required.
+static void prepareCallArguments(ApplySite AI, SILBuilder &Builder,
+                                 const ReabstractionInfo &ReInfo,
+                                 SmallVectorImpl<SILValue> &Arguments,
+                                 SILValue &StoreResultTo) {
   /// SIL function conventions for the original apply site with substitutions.
+  SILLocation Loc = AI.getLoc();
   auto substConv = AI.getSubstCalleeConv();
   unsigned ArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg();
   for (auto &Op : AI.getArgumentOperands()) {
@@ -553,13 +857,58 @@
 
     ++ArgIdx;
   }
+}
+
+/// Return a substituted callee function type.
+static CanSILFunctionType
+getCalleeSubstFunctionType(SILValue Callee, const ReabstractionInfo &ReInfo) {
+  // Create a substituted callee type.
+  auto CanFnTy =
+      dyn_cast<SILFunctionType>(Callee->getType().getSwiftRValueType());
+  auto CalleeSubstFnTy = CanFnTy;
+
+  if (ReInfo.getSpecializedType()->isPolymorphic() &&
+      !ReInfo.getCallerParamSubstitutions().empty()) {
+    CalleeSubstFnTy = CanFnTy->substGenericArgs(
+        ReInfo.getNonSpecializedFunction()->getModule(),
+        ReInfo.getCallerParamSubstitutions());
+    assert(!CalleeSubstFnTy->isPolymorphic() &&
+           "Substituted callee type should not be polymorphic");
+    assert(!CalleeSubstFnTy->hasTypeParameter() &&
+           "Substituted callee type should not have type parameters");
+  }
+
+  return CalleeSubstFnTy;
+}
+
+// Create a new apply based on an old one, but with a different
+// function being applied.
+static ApplySite replaceWithSpecializedCallee(ApplySite AI,
+                                              SILValue Callee,
+                                              SILBuilder &Builder,
+                                              const ReabstractionInfo &ReInfo) {
+  SILLocation Loc = AI.getLoc();
+  SmallVector<SILValue, 4> Arguments;
+  SILValue StoreResultTo;
+
+  prepareCallArguments(AI, Builder, ReInfo, Arguments, StoreResultTo);
+
+  // Create a substituted callee type.
+  ArrayRef<Substitution> Subs;
+  if (ReInfo.getSpecializedType()->isPolymorphic()) {
+    Subs = ReInfo.getCallerParamSubstitutions();
+  }
+
+  auto CalleeSubstFnTy = getCalleeSubstFunctionType(Callee, ReInfo);
+  auto CalleeSILSubstFnTy = SILType::getPrimitiveObjectType(CalleeSubstFnTy);
+  SILFunctionConventions substConv(CalleeSubstFnTy, Builder.getModule());
 
   if (auto *TAI = dyn_cast<TryApplyInst>(AI)) {
     SILBasicBlock *ResultBB = TAI->getNormalBB();
     assert(ResultBB->getSinglePredecessorBlock() == TAI->getParent());
     auto *NewTAI =
-      Builder.createTryApply(Loc, Callee, Callee->getType(), {},
-                             Arguments, ResultBB, TAI->getErrorBB());
+        Builder.createTryApply(Loc, Callee, CalleeSILSubstFnTy, Subs, Arguments,
+                               ResultBB, TAI->getErrorBB());
     if (StoreResultTo) {
       assert(substConv.useLoweredAddresses());
       // The original normal result of the try_apply is an empty tuple.
@@ -577,7 +926,9 @@
     return NewTAI;
   }
   if (auto *A = dyn_cast<ApplyInst>(AI)) {
-    auto *NewAI = Builder.createApply(Loc, Callee, Arguments, A->isNonThrowing());
+    auto *NewAI = Builder.createApply(Loc, Callee, CalleeSILSubstFnTy,
+                                      substConv.getSILResultType(), Subs,
+                                      Arguments, A->isNonThrowing());
     if (StoreResultTo) {
       assert(substConv.useLoweredAddresses());
       // Store the direct result to the original result address.
@@ -589,12 +940,14 @@
     return NewAI;
   }
   if (auto *PAI = dyn_cast<PartialApplyInst>(AI)) {
-    CanSILFunctionType NewPAType =
-      ReInfo.createSpecializedType(PAI->getFunctionType(), Builder.getModule());
-    SILType PTy = SILType::getPrimitiveObjectType(ReInfo.getSpecializedType());
+    CanSILFunctionType NewPAType = ReInfo.createSpecializedType(
+        PAI->getFunctionType(), Builder.getModule());
+    // SILType PTy =
+    // SILType::getPrimitiveObjectType(ReInfo.getSpecializedType());
+    SILType PTy = CalleeSILSubstFnTy;
     auto *NewPAI =
-      Builder.createPartialApply(Loc, Callee, PTy, {}, Arguments,
-                                 SILType::getPrimitiveObjectType(NewPAType));
+        Builder.createPartialApply(Loc, Callee, PTy, Subs, Arguments,
+                                   SILType::getPrimitiveObjectType(NewPAType));
     PAI->replaceAllUsesWith(NewPAI);
     return NewPAI;
   }
@@ -835,6 +1188,9 @@
   if (F->isFragile() && !RefF->hasValidLinkageForFragileInline())
       return;
 
+  if (shouldNotSpecializeCallee(RefF))
+    return;
+
   // If the caller and callee are both fragile, preserve the fragility when
   // cloning the callee. Otherwise, strip it off so that we can optimize
   // the body more.
@@ -851,6 +1207,12 @@
   bool needAdaptUsers = false;
   bool replacePartialApplyWithoutReabstraction = false;
   auto *PAI = dyn_cast<PartialApplyInst>(Apply);
+
+  // TODO: Partial specializations of partial applies are
+  // not supported yet.
+  if (PAI && ReInfo.getSpecializedType()->isPolymorphic())
+    return;
+
   if (PAI && ReInfo.hasConversions()) {
     // If we have a partial_apply and we converted some results/parameters from
     // indirect to direct there are 3 cases:
diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp
index a01756c..6d4a293 100644
--- a/lib/SILOptimizer/Utils/SILInliner.cpp
+++ b/lib/SILOptimizer/Utils/SILInliner.cpp
@@ -233,6 +233,8 @@
     case ValueKind::FunctionRefInst:
     case ValueKind::AllocGlobalInst:
     case ValueKind::GlobalAddrInst:
+    case ValueKind::EndLifetimeInst:
+    case ValueKind::UncheckedOwnershipConversionInst:
       return InlineCost::Free;
 
     // Typed GEPs are free.
diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
index 76d4be7..00ef34d 100644
--- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp
+++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
@@ -12,6 +12,7 @@
 
 #include "swift/SILOptimizer/Utils/SpecializationMangler.h"
 #include "swift/SIL/SILGlobalVariable.h"
+#include "swift/AST/SubstitutionMap.h"
 #include "swift/Basic/Demangler.h"
 #include "swift/Basic/ManglingMacros.h"
 
@@ -60,19 +61,12 @@
   SILFunctionType *FTy = Function->getLoweredFunctionType();
   CanGenericSignature Sig = FTy->getGenericSignature();
 
-  unsigned idx = 0;
+  auto SubMap = Sig->getSubstitutionMap(Subs);
   bool First = true;
-  for (Type DepType : Sig->getAllDependentTypes()) {
-    // It is sufficient to only mangle the substitutions of the "primary"
-    // dependent types. As all other dependent types are just derived from the
-    // primary types, this will give us unique symbol names.
-    if (DepType->is<GenericTypeParamType>()) {
-      appendType(Subs[idx].getReplacement()->getCanonicalType());
-      appendListSeparator(First);
-    }
-    ++idx;
+  for (auto ParamType : Sig->getSubstitutableParams()) {
+    appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
+    appendListSeparator(First);
   }
-  assert(idx == Subs.size() && "subs not parallel to dependent types");
   assert(!First && "no generic substitutions");
   
   appendSpecializationOperator(isReAbstracted ? "Tg" : "TG");
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 4f27b76..58a9796 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -19,6 +19,7 @@
 #include "ConstraintSystem.h"
 #include "swift/AST/ASTVisitor.h"
 #include "swift/AST/ASTWalker.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/SubstitutionMap.h"
 #include "swift/Basic/StringExtras.h"
 #include "llvm/ADT/APFloat.h"
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index f84b7dd..b78d05c 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -2507,8 +2507,13 @@
       if (!selfDecl->hasType())
         return ErrorType::get(tc.Context);
 
-      Type declaredType = selfDecl->getType()->getRValueInstanceType();
-      Type superclassTy = declaredType->getSuperclass(&tc);
+      // If the method returns 'Self', the type of 'self' is a
+      // DynamicSelfType. Unwrap it before getting the superclass.
+      auto selfTy = selfDecl->getType()->getRValueInstanceType();
+      if (auto *dynamicSelfTy = selfTy->getAs<DynamicSelfType>())
+        selfTy = dynamicSelfTy->getSelfType();
+
+      auto superclassTy = selfTy->getSuperclass(&tc);
 
       if (selfDecl->getType()->is<MetatypeType>())
         superclassTy = MetatypeType::get(superclassTy);
@@ -3367,9 +3372,11 @@
                     llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap) {
   Type BaseTy = PD->getDeclaredInterfaceType();
   DeclContext *DC = PD->getDeclContext();
+  std::unique_ptr<TypeChecker> CreatedTC;
   auto *TC = static_cast<TypeChecker*>(DC->getASTContext().getLazyResolver());
   if (!TC) {
-    TC = new TypeChecker(DC->getASTContext());
+    CreatedTC.reset(new TypeChecker(DC->getASTContext()));
+    TC = CreatedTC.get();
   }
   for (Decl *D : PD->getMembers()) {
     ValueDecl *VD = dyn_cast<ValueDecl>(D);
diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp
index 02cc31d..d437e0e 100644
--- a/lib/Sema/CSRanking.cpp
+++ b/lib/Sema/CSRanking.cpp
@@ -15,6 +15,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "ConstraintSystem.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Support/Compiler.h"
 
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index d337194..11bae88 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -3351,9 +3351,10 @@
                                              Type type2,
                                              TypeMatchOptions flags,
                                              ConstraintLocatorBuilder locator) {
-  // There's no bridging without ObjC interop.
-  if (!TC.Context.LangOpts.EnableObjCInterop)
-    return SolutionKind::Error;
+  // There's no bridging without ObjC interop, so we shouldn't have set up
+  // bridging constraints without it.
+  assert(TC.Context.LangOpts.EnableObjCInterop
+         && "bridging constraint w/o ObjC interop?!");
   
   TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
 
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 2756738..dc02e5e 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -23,6 +23,7 @@
 #include "swift/AST/Expr.h"
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/ParameterList.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "swift/Basic/Defer.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp
index 6dec1cd..23245d9 100644
--- a/lib/Sema/Constraint.cpp
+++ b/lib/Sema/Constraint.cpp
@@ -527,6 +527,10 @@
           kind != ConstraintKind::LiteralConformsTo &&
           kind != ConstraintKind::SelfObjectOfProtocol) ||
          second->is<ProtocolType>());
+  
+  // Bridging constraints require bridging to be enabled.
+  assert(kind != ConstraintKind::BridgingConversion
+         || cs.TC.Context.LangOpts.EnableObjCInterop);
 
   // Create the constraint.
   unsigned size = totalSizeToAlloc<TypeVariableType*>(typeVars.size());
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index ef5f386..ee4c66c 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -29,7 +29,6 @@
 #include "swift/AST/ASTVisitor.h"
 #include "swift/AST/ASTWalker.h"
 #include "swift/AST/NameLookup.h"
-#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/Types.h"
 #include "swift/AST/TypeCheckerDebugConsumer.h"
 #include "llvm/ADT/ilist.h"
@@ -1047,8 +1046,10 @@
     /// \param scope The scope to associate with current solver state.
     void registerScope(SolverScope *scope) {
       CS.incrementScopeCounter();
-      scopes.insert({ scope, std::make_pair(retiredConstraints.begin(),
-                                            generatedConstraints.size()) });
+      auto scopeInfo =
+        std::make_tuple(scope, retiredConstraints.begin(),
+                        generatedConstraints.size());
+      scopes.push_back(scopeInfo);
     }
 
     /// \brief Check whether there are any retired constraints present.
@@ -1086,22 +1087,15 @@
     ///
     /// \param constraint The constraint to erase.
     void removeGeneratedConstraint(Constraint *constraint) {
-      size_t index = 0;
-      for (auto generated : generatedConstraints) {
+      for (auto *&generated : generatedConstraints) {
+        // When we find the constraint we're erasing, overwrite its
+        // value with the last element in the generated constraints
+        // vector and then pop that element from the vector.
         if (generated == constraint) {
-          unsigned last = generatedConstraints.size() - 1;
-          auto lastConstraint = generatedConstraints[last];
-          if (lastConstraint == generated) {
-            generatedConstraints.pop_back();
-            break;
-          } else {
-            generatedConstraints[index] = lastConstraint;
-            generatedConstraints[last] = constraint;
-            generatedConstraints.pop_back();
-            break;
-          }
+          generated = generatedConstraints.back();
+          generatedConstraints.pop_back();
+          return;
         }
-        index++;
       }
     }
 
@@ -1113,18 +1107,16 @@
     ///
     /// \param scope The solver scope to rollback.
     void rollback(SolverScope *scope) {
-      auto entry = scopes.find(scope);
-      assert(entry != scopes.end() && "Unknown solver scope");
-
-      // Remove given scope from the circulation.
-      scopes.erase(scope);
-
+      SolverScope *savedScope;
       // The position of last retired constraint before given scope.
       ConstraintList::iterator lastRetiredPos;
       // The original number of generated constraints before given scope.
       unsigned numGenerated;
 
-      std::tie(lastRetiredPos, numGenerated) = entry->getSecond();
+      std::tie(savedScope, lastRetiredPos, numGenerated) =
+        scopes.pop_back_val();
+
+      assert(savedScope == scope && "Scope rollback not in LIFO order!");
 
       // Restore all of the retired constraints.
       CS.InactiveConstraints.splice(CS.InactiveConstraints.end(),
@@ -1155,9 +1147,8 @@
     /// constraints generated before registration of given scope,
     /// this helps to rollback all of the constraints retired/generated
     /// each of the registered scopes correct (LIFO) order.
-    llvm::SmallDenseMap<SolverScope *,
-                        std::pair<ConstraintList::iterator, unsigned>>
-        scopes;
+    llvm::SmallVector<
+      std::tuple<SolverScope *, ConstraintList::iterator, unsigned>, 4> scopes;
   };
 
   class CacheExprTypes : public ASTWalker {
diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp
index acc5e42..10a8190 100644
--- a/lib/Sema/TypeCheckAvailability.cpp
+++ b/lib/Sema/TypeCheckAvailability.cpp
@@ -1186,7 +1186,7 @@
         << OriginalIndent;
   }
 
-  TC.diagnose(ReferenceRange.Start, diag::availability_add_attribute,
+  TC.diagnose(D, diag::availability_add_attribute,
               KindForDiagnostic)
       .fixItInsert(InsertLoc, AttrText);
 }
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 11fa677..30e1853 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -1388,6 +1388,11 @@
   return true;
 }
 
+void GenericRequirementsCheckListener::satisfiedConformance(
+                                          Type depTy, Type replacementTy,
+                                          ProtocolConformanceRef conformance) {
+}
+
 bool TypeChecker::
 solveForExpression(Expr *&expr, DeclContext *dc, Type convertType,
                    FreeTypeVariableBinding allowFreeTypeVariables,
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index d324496..643db8d 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -30,6 +30,7 @@
 #include "swift/AST/GenericSignatureBuilder.h"
 #include "swift/AST/NameLookup.h"
 #include "swift/AST/PrettyStackTrace.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/ReferencedNameTracker.h"
 #include "swift/AST/TypeWalker.h"
 #include "swift/Basic/Statistic.h"
@@ -4047,7 +4048,7 @@
 
       TC.validateDecl(ED);
 
-      TC.ValidatedTypes.remove(ED);
+      TC.TypesToFinalize.remove(ED);
 
       {
         // Check for circular inheritance of the raw type.
@@ -4103,7 +4104,7 @@
       checkUnsupportedNestedType(SD);
 
       TC.validateDecl(SD);
-      TC.ValidatedTypes.remove(SD);
+      TC.TypesToFinalize.remove(SD);
       TC.addImplicitConstructors(SD);
     }
 
@@ -4235,7 +4236,7 @@
       if (!CD->hasValidSignature())
         return;
 
-      TC.ValidatedTypes.remove(CD);
+      TC.TypesToFinalize.remove(CD);
 
       {
         // Check for circular inheritance.
@@ -7090,7 +7091,7 @@
         checkEnumRawValues(*this, ED);
     }
 
-    ValidatedTypes.insert(nominal);
+    TypesToFinalize.insert(nominal);
     break;
   }
 
@@ -7130,7 +7131,7 @@
       markAsObjC(*this, proto, isObjC);
     }
 
-    ValidatedTypes.insert(proto);
+    TypesToFinalize.insert(proto);
     break;
   }
 
@@ -7301,6 +7302,9 @@
         validateDeclForNameLookup(ATD);
       }
     }
+
+    // Make sure the protocol is fully validated by the end of Sema.
+    TypesToFinalize.insert(proto);
     break;
   }
   case DeclKind::AssociatedType: {
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index a0dc719..3ad9369 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -20,6 +20,7 @@
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/Types.h"
 #include "swift/Basic/Defer.h"
+#include "llvm/Support/ErrorHandling.h"
 
 using namespace swift;
 
@@ -399,6 +400,8 @@
     return false;
   }
   }
+
+  llvm_unreachable("Unhandled RequirementKind in switch.");
 }
 
 void
@@ -1124,10 +1127,13 @@
     UnsatisfiedDependency *unsatisfiedDependency,
     ConformanceCheckOptions conformanceOptions,
     GenericRequirementsCheckListener *listener) {
+  bool valid = true;
+
   for (const auto &rawReq : genericSig->getRequirements()) {
     auto req = rawReq.subst(substitutions, conformances);
     if (!req) {
       // Another requirement will fail later; just continue.
+      valid = false;
       continue;
     }
 
@@ -1138,8 +1144,10 @@
     if (kind != RequirementKind::Layout) {
       rawSecondType = rawReq.getSecondType();
       secondType = req->getSecondType().subst(substitutions, conformances);
-      if (!secondType)
+      if (!secondType) {
+        valid = false;
         continue;
+      }
     }
 
     if (listener && !listener->shouldCheck(kind, firstType, secondType))
@@ -1165,6 +1173,12 @@
       if (!result.second)
         return std::make_pair(false, false);
 
+      // Report the conformance.
+      if (listener) {
+        listener->satisfiedConformance(rawReq.getFirstType(), firstType,
+                                       *result.second);
+      }
+      
       continue;
     }
 
@@ -1207,5 +1221,5 @@
     }
   }
 
-  return std::make_pair(false, true);
+  return std::make_pair(false, valid);
 }
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index ddf4d8a..7a92f22 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -28,6 +28,7 @@
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/GenericSignature.h"
 #include "swift/AST/NameLookup.h"
+#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/ReferencedNameTracker.h"
 #include "swift/AST/TypeMatcher.h"
 #include "swift/AST/TypeWalker.h"
@@ -38,6 +39,9 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/SaveAndRestore.h"
 
+#define DEBUG_TYPE "protocol-conformance-checking"
+#include "llvm/Support/Debug.h"
+
 using namespace swift;
 
 namespace {
@@ -1705,6 +1709,10 @@
     /// Whether we've already complained about problems with this conformance.
     bool AlreadyComplained = false;
 
+    /// Keep track of missing witnesses, either type or value, for later
+    /// diagnosis emits.
+    llvm::SetVector<ValueDecl*> MissingWitnesses;
+
     /// Retrieve the associated types that are referenced by the given
     /// requirement with a base of 'Self'.
     ArrayRef<AssociatedTypeDecl *> getReferencedAssociatedTypes(ValueDecl *req);
@@ -1778,6 +1786,8 @@
                         llvm::SmallPtrSetImpl<ProtocolConformance *> &visited);
     void addUsedConformances(ProtocolConformance *conformance);
 
+    /// Call this to diagnose currently known missing witnesses.
+    void diagnoseMissingWitnesses();
   public:
     /// Emit any diagnostics that have been delayed.
     void emitDelayedDiags();
@@ -2396,50 +2406,77 @@
   return true;
 }
 
-
-/// Generates a note for a protocol requirement for which no witness was found
-/// and provides a fixit to add a stub to the adopter
-static void diagnoseNoWitness(ValueDecl *Requirement, Type RequirementType,
-                              NormalProtocolConformance *Conformance) {
-  // FIXME: Try an ignore-access lookup?
-
-  DeclContext *Adopter = Conformance->getDeclContext();
-
-  SourceLoc FixitLocation;
-  SourceLoc TypeLoc;
-  if (auto Extension = dyn_cast<ExtensionDecl>(Adopter)) {
-    FixitLocation = Extension->getBraces().Start;
-    TypeLoc = Extension->getStartLoc();
-  } else if (auto Nominal = dyn_cast<NominalTypeDecl>(Adopter)) {
-    FixitLocation = Nominal->getBraces().Start;
-    TypeLoc = Nominal->getStartLoc();
-  } else {
-    llvm_unreachable("Unknown adopter kind");
-  }
-
-  ASTContext &Ctx = Requirement->getASTContext();
-  auto &Diags = Ctx.Diags;
-  std::string FixitString;
+/// Print the stubs for an array of witnesses, either type or value, to
+/// FixitString. If for a witness we cannot have stub printed, insert it to
+/// NoStubRequirements.
+static void
+printProtocolStubFixitString(SourceLoc TypeLoc, ProtocolConformance *Conf,
+                             ArrayRef<ValueDecl*> MissingWitnesses,
+                             std::string &FixitString,
+                             llvm::SetVector<ValueDecl*> &NoStubRequirements) {
   llvm::raw_string_ostream FixitStream(FixitString);
+  std::for_each(MissingWitnesses.begin(), MissingWitnesses.end(),
+    [&](ValueDecl* VD) {
+      if (!printRequirementStub(VD, Conf->getDeclContext(), Conf->getType(),
+                                TypeLoc, FixitStream)) {
+        NoStubRequirements.insert(VD);
+      }
+    });
+}
 
-  bool AddFixit = printRequirementStub(Requirement, Adopter,
-                                       Conformance->getType(), TypeLoc,
-                                       FixitStream);
+void ConformanceChecker::diagnoseMissingWitnesses() {
+  if (MissingWitnesses.empty())
+    return;
 
-  if (auto MissingTypeWitness = dyn_cast<AssociatedTypeDecl>(Requirement)) {
-    Diags.diagnose(MissingTypeWitness, diag::no_witnesses_type,
-                   MissingTypeWitness->getName())
-      .fixItInsertAfter(FixitLocation, FixitStream.str());
-  } else {
-    // Point out the requirement that wasn't met.
-    auto diag = Diags.diagnose(Requirement, diag::no_witnesses,
-                               getRequirementKind(Requirement),
-                               Requirement->getFullName(),
-                               RequirementType, AddFixit);
-    if (AddFixit) {
-      diag.fixItInsertAfter(FixitLocation, FixitStream.str());
-    }
-  }
+  // Make sure we clear the missing witness bucket when exiting.
+  SWIFT_DEFER { MissingWitnesses.clear(); };
+  llvm::SetVector<ValueDecl*> MissingWitnesses = this->MissingWitnesses;
+  diagnoseOrDefer(MissingWitnesses[0], true,
+    [MissingWitnesses](NormalProtocolConformance *Conf) {
+      DeclContext *DC = Conf->getDeclContext();
+      // The location where to insert stubs.
+      SourceLoc FixitLocation;
+
+      // The location where the type starts.
+      SourceLoc TypeLoc;
+      if (auto Extension = dyn_cast<ExtensionDecl>(DC)) {
+        FixitLocation = Extension->getBraces().Start;
+        TypeLoc = Extension->getStartLoc();
+      } else if (auto Nominal = dyn_cast<NominalTypeDecl>(DC)) {
+        FixitLocation = Nominal->getBraces().Start;
+        TypeLoc = Nominal->getStartLoc();
+      } else {
+        llvm_unreachable("Unknown adopter kind");
+      }
+      std::string FixIt;
+      llvm::SetVector<ValueDecl*> NoStubRequirements;
+
+      // Print stubs for all known missing witnesses.
+      printProtocolStubFixitString(TypeLoc, Conf,
+                                   MissingWitnesses.getArrayRef(),
+                                   FixIt, NoStubRequirements);
+      auto &Diags = DC->getASTContext().Diags;
+      for (auto VD : MissingWitnesses) {
+        // Whether this VD has a stub printed.
+        bool AddFixit = !NoStubRequirements.count(VD);
+
+        // Issue diagnostics for witness types.
+        if (auto MissingTypeWitness = dyn_cast<AssociatedTypeDecl>(VD)) {
+          Diags.diagnose(MissingTypeWitness, diag::no_witnesses_type,
+                         MissingTypeWitness->getName()).
+          fixItInsertAfter(FixitLocation, FixIt);
+          continue;
+        }
+        // Issue diagnostics for witness values.
+        Type RequirementType =
+          getRequirementTypeForDisplay(DC->getParentModule(), Conf, VD);
+        auto Diag = Diags.diagnose(VD, diag::no_witnesses,
+                                   getRequirementKind(VD), VD->getFullName(),
+                                   RequirementType, AddFixit);
+        if (AddFixit)
+          Diag.fixItInsertAfter(FixitLocation, FixIt);
+      }
+  });
 }
 
 ResolveWitnessResult
@@ -2753,30 +2790,36 @@
     return ResolveWitnessResult::ExplicitFailed;
   }
 
+
+  if (!numViable) {
+    // Save the missing requirement for later diagnosis.
+    MissingWitnesses.insert(requirement);
+    diagnoseOrDefer(requirement, true,
+      [requirement, matches](NormalProtocolConformance *conformance) {
+        auto dc = conformance->getDeclContext();
+        // Diagnose each of the matches.
+        for (const auto &match : matches)
+          diagnoseMatch(dc->getParentModule(), conformance, requirement, match);
+      });
+    return ResolveWitnessResult::ExplicitFailed;
+  }
+
   diagnoseOrDefer(requirement, true,
-    [requirement, matches, ignoringNames, numViable](
+    [requirement, matches, ignoringNames](
       NormalProtocolConformance *conformance) {
       auto dc = conformance->getDeclContext();
-      auto &diags = dc->getASTContext().Diags;
-
       // Determine the type that the requirement is expected to have.
       Type reqType = getRequirementTypeForDisplay(dc->getParentModule(),
                                                   conformance, requirement);
-
-      if (numViable > 0) {
-        auto diagnosticMessage = diag::ambiguous_witnesses;
-        if (ignoringNames) {
-          diagnosticMessage = diag::ambiguous_witnesses_wrong_name;
-        }
-        diags.diagnose(requirement, diagnosticMessage,
-                       getRequirementKind(requirement),
-                       requirement->getFullName(),
-                       reqType);
-      } else {
-        // Generate diagnostics for the missing requirement and a fixit to add
-        // it
-        diagnoseNoWitness(requirement, reqType, conformance);
+      auto &diags = dc->getASTContext().Diags;
+      auto diagnosticMessage = diag::ambiguous_witnesses;
+      if (ignoringNames) {
+        diagnosticMessage = diag::ambiguous_witnesses_wrong_name;
       }
+      diags.diagnose(requirement, diagnosticMessage,
+                     getRequirementKind(requirement),
+                     requirement->getFullName(),
+                     reqType);
 
       // Diagnose each of the matches.
       for (const auto &match : matches)
@@ -2840,21 +2883,8 @@
     recordOptionalWitness(requirement);
     return ResolveWitnessResult::Success;
   }
-
-  diagnoseOrDefer(requirement, true,
-    [requirement](NormalProtocolConformance *conformance) {
-    auto dc = conformance->getDeclContext();
-    auto &diags = dc->getASTContext().Diags;
-    // Determine the type that the requirement is expected to have.
-    Type reqType = getRequirementTypeForDisplay(dc->getParentModule(),
-                                                conformance, requirement);
-
-    // Point out the requirement that wasn't met.
-    diags.diagnose(requirement, diag::no_witnesses,
-                   getRequirementKind(requirement), requirement->getName(),
-                   reqType, false);
-    });
-
+  // Save the missing requirement for later diagnosis.
+  MissingWitnesses.insert(requirement);
   return ResolveWitnessResult::ExplicitFailed;
 }
 
@@ -2948,13 +2978,13 @@
 
     return ResolveWitnessResult::ExplicitFailed;
   }
+  // Save the missing type witness for later diagnosis.
+  MissingWitnesses.insert(assocType);
 
   // None of the candidates were viable.
   diagnoseOrDefer(assocType, true,
-    [assocType, nonViable](NormalProtocolConformance *conformance) {
-      auto &diags = assocType->getASTContext().Diags;
-      diags.diagnose(assocType, diag::no_witnesses_type, assocType->getName());
-
+    [nonViable](NormalProtocolConformance *conformance) {
+      auto &diags = conformance->getDeclContext()->getASTContext().Diags;
       for (auto candidate : nonViable) {
         if (candidate.first->getDeclaredInterfaceType()->hasError())
           continue;
@@ -3037,6 +3067,9 @@
   };
 
   for (auto witness : lookupValueWitnesses(req, /*ignoringNames=*/nullptr)) {
+    DEBUG(llvm::dbgs() << "Inferring associated types from decl:\n";
+          witness->dump(llvm::dbgs()));
+  
     // If the potential witness came from an extension, and our `Self`
     // type can't use it regardless of what associated types we end up
     // inferring, skip the witness.
@@ -3057,18 +3090,27 @@
 }
       auto &result = witnessResult.Inferred[i];
 
+      DEBUG(llvm::dbgs() << "Considering whether " << result.first->getName()
+                         << " can infer to:\n";
+            result.second->dump(llvm::dbgs()));
+
       // Filter out errors.
-      if (result.second->hasError())
+      if (result.second->hasError()) {
+        DEBUG(llvm::dbgs() << "-- has error type\n");
         REJECT;
+      }
 
       // Filter out duplicates.
       if (!known.insert({result.first, result.second->getCanonicalType()})
-                .second)
+                .second) {
+        DEBUG(llvm::dbgs() << "-- duplicate\n");
         REJECT;
+      }
      
       // Filter out circular possibilities, e.g. that
       // AssocType == S.AssocType or
       // AssocType == Foo<S.AssocType>.
+      bool canInferFromOtherAssociatedType = false;
       bool containsTautologicalType =
         result.second.findIf([&](Type t) -> bool {
           auto dmt = t->getAs<DependentMemberType>();
@@ -3080,11 +3122,63 @@
           if (!dmt->getBase()->isEqual(Conformance->getType()))
             return false;
           
+          // If this associated type is same-typed to another associated type
+          // on `Self`, then it may still be an interesting candidate if we find
+          // an answer for that other type.
+          auto witnessContext = witness->getDeclContext();
+          if (witnessContext->getAsProtocolExtensionContext()
+              && witnessContext->getGenericSignatureOfContext()) {
+            auto selfTy = witnessContext->getSelfInterfaceType();
+            auto selfAssocTy = DependentMemberType::get(selfTy,
+                                                        dmt->getAssocType());
+            for (auto &reqt : witnessContext->getGenericSignatureOfContext()
+                                            ->getRequirements()) {
+              switch (reqt.getKind()) {
+              case RequirementKind::Conformance:
+              case RequirementKind::Superclass:
+              case RequirementKind::Layout:
+                break;
+              
+              case RequirementKind::SameType:
+                Type other;
+                if (reqt.getFirstType()->isEqual(selfAssocTy)) {
+                  other = reqt.getSecondType();
+                } else if (reqt.getSecondType()->isEqual(selfAssocTy)) {
+                  other = reqt.getFirstType();
+                } else {
+                  break;
+                }
+                
+                if (auto otherAssoc = other->getAs<DependentMemberType>()) {
+                  if (otherAssoc->getBase()->isEqual(selfTy)) {
+                    auto otherDMT = DependentMemberType::get(dmt->getBase(),
+                                                    otherAssoc->getAssocType());
+                    
+                    // We may be able to infer one associated type from the
+                    // other.
+                    result.second = result.second.transform([&](Type t) -> Type{
+                      if (t->isEqual(dmt))
+                        return otherDMT;
+                      return t;
+                    });
+                    canInferFromOtherAssociatedType = true;
+                    DEBUG(llvm::dbgs() << "++ we can same-type to:\n";
+                          result.second->dump(llvm::dbgs()));
+                    return false;
+                  }
+                }
+                break;
+              }
+            }
+          }
+          
           return true;
         });
       
-      if (containsTautologicalType)
+      if (containsTautologicalType) {
+        DEBUG(llvm::dbgs() << "-- tautological\n");
         REJECT;
+      }
       
       // Check that the type witness doesn't contradict an
       // explicitly-given type witness. If it does contradict, throw out the
@@ -3101,19 +3195,27 @@
         auto newWitness = result.second->getCanonicalType();
         if (!newWitness->hasTypeParameter()
             && !existingWitness->isEqual(newWitness)) {
+          DEBUG(llvm::dbgs() << "** contradicts explicit type witness, "
+                                "rejecting inference from this decl\n");
           goto next_witness;
         }
       }
       
-      // Check that the type witness meets the
-      // requirements on the associated type.
-      if (auto failed = checkTypeWitness(TC, DC, result.first,
-                                         result.second)) {
-        witnessResult.NonViable.push_back(
-                            std::make_tuple(result.first,result.second,failed));
-        REJECT;
+      // If we same-typed to another unresolved associated type, we won't
+      // be able to check conformances yet.
+      if (!canInferFromOtherAssociatedType) {
+        // Check that the type witness meets the
+        // requirements on the associated type.
+        if (auto failed = checkTypeWitness(TC, DC, result.first,
+                                           result.second)) {
+          witnessResult.NonViable.push_back(
+                              std::make_tuple(result.first,result.second,failed));
+          DEBUG(llvm::dbgs() << "-- doesn't fulfill requirements\n");
+          REJECT;
+        }
       }
       
+      DEBUG(llvm::dbgs() << "++ seems legit\n");
       ++i;
     }
 #undef REJECT
@@ -3630,6 +3732,8 @@
 
   // Infer type witnesses from value witnesses.
   auto inferred = inferTypeWitnessesViaValueWitnesses(unresolvedAssocTypes);
+  DEBUG(llvm::dbgs() << "Candidates for inference:\n";
+        dumpInferredAssociatedTypes(inferred));
 
   // Compute the set of solutions.
   SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4> valueWitnesses;
@@ -3820,6 +3924,9 @@
         Type replaced = known->first.transform(foldDependentMemberTypes);
         if (replaced.isNull())
           return true;
+        
+        if (checkTypeWitness(TC, DC, assocType, replaced))
+          return true;
 
         known->first = replaced;
       }
@@ -4223,12 +4330,9 @@
       return;
     }
 
-    for (auto missingTypeWitness : unresolvedAssocTypes) {
-      diagnoseOrDefer(missingTypeWitness, true,
-        [missingTypeWitness](NormalProtocolConformance *conformance) {
-          diagnoseNoWitness(missingTypeWitness, Type(), conformance);
-        });
-    }
+    // Save the missing type witnesses for later diagnosis.
+    MissingWitnesses.insert(unresolvedAssocTypes.begin(),
+                            unresolvedAssocTypes.end());
 
     return;
   }
@@ -4302,6 +4406,8 @@
 
 void ConformanceChecker::resolveSingleTypeWitness(
        AssociatedTypeDecl *assocType) {
+  // Ensure we diagnose if the witness is missing.
+  SWIFT_DEFER { diagnoseMissingWitnesses(); };
   switch (resolveTypeWitnessViaLookup(assocType)) {
   case ResolveWitnessResult::Success:
   case ResolveWitnessResult::ExplicitFailed:
@@ -4458,23 +4564,40 @@
 void ConformanceChecker::ensureRequirementsAreSatisfied() {
   auto proto = Conformance->getProtocol();
   // Some other problem stopped the signature being computed.
-  if (!proto->isRequirementSignatureComputed())
+  if (!proto->isRequirementSignatureComputed()) {
+    Conformance->setInvalid();
     return;
+  }
 
   auto reqSig = proto->getRequirementSignature();
 
   auto substitutions = SubstitutionMap::getProtocolSubstitutions(
       proto, Conformance->getType(), ProtocolConformanceRef(Conformance));
 
+  class GatherConformancesListener : public GenericRequirementsCheckListener {
+  public:
+    SmallVector<ProtocolConformanceRef, 4> conformances;
+
+    void satisfiedConformance(Type depTy, Type replacementTy,
+                              ProtocolConformanceRef conformance) override {
+      conformances.push_back(conformance);
+    }
+  } listener;
+
   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);
+      LookUpConformanceInSubstitutionMap{substitutions}, nullptr,
+      ConformanceCheckFlags::Used, &listener);
 
-  // Errors are emitted inside the checker.
-  (void)result;
+  // If there were no errors, record the conformances.
+  if (result.second) {
+    Conformance->setSignatureConformances(listener.conformances);
+  } else {
+    Conformance->setInvalid();
+  }
 }
 
 #pragma mark Protocol conformance checking
@@ -4492,6 +4615,11 @@
   // Resolve all of the type witnesses.
   resolveTypeWitnesses();
 
+  // Diagnose missing type witnesses for now.
+  diagnoseMissingWitnesses();
+  // Diagnose missing value witnesses later.
+  SWIFT_DEFER { diagnoseMissingWitnesses(); };
+
   // Resolution attempts to have the witnesses be correct by construction, but
   // this isn't guaranteed, so let's double check.
   ensureRequirementsAreSatisfied();
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index 211b3de..32ad28f 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -267,12 +267,46 @@
               return LHS->getNameStr().compare(RHS->getNameStr()) < 0;
             });
 
+  auto printPayloads = [](EnumElementDecl *EE, llvm::raw_ostream &OS) {
+    // If the enum element has no payloads, return.
+    auto TL = EE->getArgumentTypeLoc();
+    if (TL.isNull())
+      return;
+    TypeRepr* TR = EE->getArgumentTypeLoc().getTypeRepr();
+    if (auto *TTR = dyn_cast<TupleTypeRepr>(TR)) {
+      SmallVector<Identifier, 4> NameBuffer;
+      ArrayRef<Identifier> Names;
+      if (TTR->hasElementNames()) {
+        // Get the name from the tuple repr, if exist.
+        Names = TTR->getElementNames();
+      } else {
+        // Create same amount of empty names to the elements.
+        NameBuffer.resize(TTR->getNumElements());
+        Names = llvm::makeArrayRef(NameBuffer);
+      }
+      OS << "(";
+      // Print each element in the pattern match.
+      for (unsigned I = 0, N = Names.size(); I < N; I ++) {
+        auto Id = Names[I];
+        if (Id.empty())
+          OS << "_";
+        else
+          OS << tok::kw_let << " " << Id.str();
+        if (I + 1 != N) {
+          OS << ", ";
+        }
+      }
+      OS << ")";
+    }
+  };
+
   // Print each enum element name.
   std::for_each(SortedElements.begin(), SortedElements.end(),
-                [&](EnumElementDecl *EE) {
-                  OS << tok::kw_case << " ." << EE->getNameStr() << ": " <<
-                  Placeholder << "\n";
-                });
+    [&](EnumElementDecl *EE) {
+      OS << tok::kw_case << " ." << EE->getNameStr();
+      printPayloads(EE, OS);
+      OS <<": " << Placeholder << "\n";
+  });
   Context.Diags.diagnose(EndLoc, Id).fixItInsert(EndLoc, Buffer.str());
 }
 
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index e0ee038..1d0bec1 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -2269,7 +2269,7 @@
 
     params = genericSig->getGenericParams();
     if (repr->getGenericArguments().size()
-          != genericSig->getAllDependentTypes().size()) {
+          != genericSig->getSubstitutionListSize()) {
       TC.diagnose(repr->getLoc(), diag::sil_box_arg_mismatch);
       return ErrorType::get(Context);
     }
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index e681c7a..d33538c 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -410,7 +410,8 @@
   ::bindExtensionDecl(ext, *this);
 }
 
-static bool shouldValidateDeclForLayout(NominalTypeDecl *nominal, ValueDecl *VD) {
+static bool shouldValidateMemberDuringFinalization(NominalTypeDecl *nominal,
+                                                   ValueDecl *VD) {
   // For enums, we only need to validate enum elements to know
   // the layout.
   if (isa<EnumDecl>(nominal) &&
@@ -440,7 +441,7 @@
   return false;
 }
 
-static void validateDeclForLayout(TypeChecker &TC, NominalTypeDecl *nominal) {
+static void finalizeType(TypeChecker &TC, NominalTypeDecl *nominal) {
   Optional<bool> lazyVarsAlreadyHaveImplementation;
 
   for (auto *D : nominal->getMembers()) {
@@ -448,7 +449,7 @@
     if (!VD)
       continue;
 
-    if (!shouldValidateDeclForLayout(nominal, VD))
+    if (!shouldValidateMemberDuringFinalization(nominal, VD))
       continue;
 
     TC.validateDecl(VD);
@@ -489,6 +490,15 @@
     TC.addImplicitConstructors(CD);
     TC.addImplicitDestructor(CD);
   }
+
+  // validateDeclForNameLookup will not trigger an immediate full
+  // validation of protocols, but clients will assume that things
+  // like the requirement signature have been set.
+  if (auto PD = dyn_cast<ProtocolDecl>(nominal)) {
+    if (!PD->isRequirementSignatureComputed()) {
+      TC.validateDecl(PD);
+    }
+  }
 }
 
 static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) {
@@ -541,12 +551,12 @@
     // Note: if we ever start putting extension members in vtables, we'll need
     // to validate those members too.
     // FIXME: If we're not planning to run SILGen, this is wasted effort.
-    while (!TC.ValidatedTypes.empty()) {
-      auto nominal = TC.ValidatedTypes.pop_back_val();
+    while (!TC.TypesToFinalize.empty()) {
+      auto nominal = TC.TypesToFinalize.pop_back_val();
       if (nominal->isInvalid() || TC.Context.hadError())
         continue;
 
-      validateDeclForLayout(TC, nominal);
+      finalizeType(TC, nominal);
     }
 
     // Complete any conformances that we used.
@@ -559,7 +569,7 @@
 
   } while (currentFunctionIdx < TC.definedFunctions.size() ||
            currentExternalDef < TC.Context.ExternalDefinitions.size() ||
-           !TC.ValidatedTypes.empty() ||
+           !TC.TypesToFinalize.empty() ||
            !TC.UsedConformances.empty());
 
   // FIXME: Horrible hack. Store this somewhere more appropriate.
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index aa56685..4dd7713 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -351,6 +351,14 @@
   ///
   /// \returns true if it's ok to validate requirement, false otherwise.
   virtual bool shouldCheck(RequirementKind kind, Type first, Type second);
+
+  /// Callback to report the result of a satisfied conformance requirement.
+  ///
+  /// \param depTy The dependent type, from the signature.
+  /// \param replacementTy The type \c depTy was replaced with.
+  /// \param conformance The conformance itself.
+  virtual void satisfiedConformance(Type depTy, Type replacementTy,
+                                    ProtocolConformanceRef conformance);
 };
 
 /// Flags that describe the context of type checking a pattern or
@@ -543,9 +551,10 @@
   /// completed before type checking is considered complete.
   llvm::SetVector<NormalProtocolConformance *> UsedConformances;
 
-  /// The list of nominal type declarations that have been validated
-  /// during type checking.
-  llvm::SetVector<NominalTypeDecl *> ValidatedTypes;
+  /// The list of nominal type declarations that we've done at least
+  /// partial validation of during type-checking and which will need
+  /// to be finalized before we can hand off to SILGen etc.
+  llvm::SetVector<NominalTypeDecl *> TypesToFinalize;
 
   using TypeAccessScopeCacheMap = llvm::DenseMap<const ValueDecl *, AccessScope>;
 
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 65e5ea5..4b091c9 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -715,6 +715,15 @@
   dc->getAsNominalTypeOrNominalTypeExtensionContext()
     ->registerProtocolConformance(conformance);
 
+  // Read requirement signature conformances.
+  SmallVector<ProtocolConformanceRef, 4> reqConformances;
+  for (auto req : proto->getRequirementSignature()->getRequirements()) {
+    if (req.getKind() == RequirementKind::Conformance) {
+      auto reqConformance = readConformance(DeclTypeCursor);
+      reqConformances.push_back(reqConformance);
+    }
+  }
+  conformance->setSignatureConformances(reqConformances);
 
   // Read inherited conformances.
   InheritedConformanceMap inheritedConformances;
@@ -4048,7 +4057,7 @@
     
     SmallVector<Substitution, 4> genericArgs;
     if (auto sig = layout->getGenericSignature()) {
-      for (unsigned i : range(sig->getAllDependentTypes().size())) {
+      for (unsigned i : range(sig->getSubstitutionListSize())) {
         (void)i;
         auto sub = maybeReadSubstitution(DeclTypeCursor);
         if (!sub) {
@@ -4336,6 +4345,14 @@
                                               typeCount, inheritedCount,
                                               rawIDs);
 
+  // Skip requirement signature conformances.
+  auto proto = conformance->getProtocol();
+  for (auto req : proto->getRequirementSignature()->getRequirements()) {
+    if (req.getKind() == RequirementKind::Conformance) {
+      (void)readConformance(DeclTypeCursor);
+    }
+  }
+
   // Skip trailing inherited conformances.
   while (inheritedCount--)
     (void)readConformance(DeclTypeCursor);
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 25c7df7..da42e5c 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -1364,6 +1364,7 @@
   UNARY_INSTRUCTION(Return)
   UNARY_INSTRUCTION(Throw)
   UNARY_INSTRUCTION(FixLifetime)
+  UNARY_INSTRUCTION(EndLifetime)
   UNARY_INSTRUCTION(CopyBlock)
   UNARY_INSTRUCTION(LoadBorrow)
   UNARY_INSTRUCTION(BeginBorrow)
@@ -1379,6 +1380,15 @@
 #undef UNARY_INSTRUCTION
 #undef REFCOUNTING_INSTRUCTION
 
+  case ValueKind::UncheckedOwnershipConversionInst: {
+    auto Ty = MF->getType(TyID);
+    auto ResultKind = ValueOwnershipKind(Attr);
+    ResultVal = Builder.createUncheckedOwnershipConversion(
+        Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)),
+        ResultKind);
+    break;
+  }
+
   case ValueKind::LoadInst: {
     auto Ty = MF->getType(TyID);
     auto Qualifier = LoadOwnershipQualifier(Attr);
@@ -2387,13 +2397,14 @@
         proto, conformance.getConcrete()
       });
     } else if (kind == SIL_WITNESS_ASSOC_PROTOCOL) {
-      DeclID assocId, protoId;
+      TypeID assocId;
+      DeclID protoId;
       WitnessAssocProtocolLayout::readRecord(scratch, assocId, protoId);
+      CanType type = MF->getType(assocId)->getCanonicalType();
       ProtocolDecl *proto = cast<ProtocolDecl>(MF->getDecl(protoId));
       auto conformance = MF->readConformance(SILCursor);
       witnessEntries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{
-        cast<AssociatedTypeDecl>(MF->getDecl(assocId)), proto,
-        conformance
+        type, proto, conformance
       });
     } else if (kind == SIL_WITNESS_ASSOC_ENTRY) {
       DeclID assocId;
diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h
index 3a9576d..6a96a2f 100644
--- a/lib/Serialization/SILFormat.h
+++ b/lib/Serialization/SILFormat.h
@@ -200,7 +200,7 @@
 
   using WitnessAssocProtocolLayout = BCRecordLayout<
     SIL_WITNESS_ASSOC_PROTOCOL,
-    DeclIDField, // ID of AssociatedTypeDecl
+    TypeIDField, // ID of associated type
     DeclIDField  // ID of ProtocolDecl
     // Trailed by the conformance itself if appropriate.
   >;
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 85f57eb..aba6f0f 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1318,6 +1318,10 @@
                                               numInheritedConformances,
                                               data);
 
+  // Write requirement signature conformances.
+  for (auto reqConformance : conformance->getSignatureConformances())
+    writeConformance(reqConformance, DeclTypeAbbrCodes);
+  
   // Write inherited conformances.
   for (auto inheritedProto : inheritedProtos) {
     writeConformance(conformance->getInheritedConformance(inheritedProto),
@@ -3287,7 +3291,7 @@
 
 #ifndef NDEBUG
     if (auto sig = boxTy->getLayout()->getGenericSignature()) {
-      assert(sig->getAllDependentTypes().size()
+      assert(sig->getSubstitutionListSize()
                == boxTy->getGenericArgs().size());
     }
 #endif
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index 5e60637..465d0cb 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -1057,6 +1057,7 @@
   case ValueKind::LoadWeakInst:
   case ValueKind::MarkUninitializedInst:
   case ValueKind::FixLifetimeInst:
+  case ValueKind::EndLifetimeInst:
   case ValueKind::CopyBlockInst:
   case ValueKind::StrongPinInst:
   case ValueKind::StrongReleaseInst:
@@ -1068,6 +1069,7 @@
   case ValueKind::IsUniqueInst:
   case ValueKind::IsUniqueOrPinnedInst:
   case ValueKind::ReturnInst:
+  case ValueKind::UncheckedOwnershipConversionInst:
   case ValueKind::ThrowInst: {
     unsigned Attr = 0;
     if (auto *LI = dyn_cast<LoadInst>(&SI))
@@ -1082,6 +1084,9 @@
       Attr = (unsigned)DRI->canAllocOnStack();
     else if (auto *RCI = dyn_cast<RefCountingInst>(&SI))
       Attr = RCI->isNonAtomic();
+    else if (auto *UOCI = dyn_cast<UncheckedOwnershipConversionInst>(&SI)) {
+      Attr = unsigned(SILValue(UOCI).getOwnershipKind());
+    }
     writeOneOperandLayout(SI.getKind(), Attr, SI.getOperand(0));
     break;
   }
@@ -1851,7 +1856,7 @@
       WitnessAssocProtocolLayout::emitRecord(
         Out, ScratchRecord,
         SILAbbrCodes[WitnessAssocProtocolLayout::Code],
-        S.addDeclRef(assoc.Requirement),
+        S.addTypeRef(assoc.Requirement),
         S.addDeclRef(assoc.Protocol));
           
       S.writeConformance(assoc.Witness, SILAbbrCodes);
diff --git a/lib/SwiftDemangle/SwiftDemangle.cpp b/lib/SwiftDemangle/SwiftDemangle.cpp
index 8c53031..c21fe7b 100644
--- a/lib/SwiftDemangle/SwiftDemangle.cpp
+++ b/lib/SwiftDemangle/SwiftDemangle.cpp
@@ -54,6 +54,13 @@
                                                  Length, Opts);
 }
 
+int swift_demangle_hasSwiftCallingConvention(const char *MangledName) {
+  swift::Demangle::Context DCtx;
+  if (DCtx.hasSwiftCallingConvention(llvm::StringRef(MangledName)))
+    return 1;
+  return 0;
+}
+
 size_t fnd_get_demangled_name(const char *MangledName, char *OutputBuffer,
                               size_t Length) {
   return swift_demangle_getDemangledName(MangledName, OutputBuffer, Length);
diff --git a/lib/Syntax/DeclSyntax.cpp b/lib/Syntax/DeclSyntax.cpp
index c26d20e..7160508 100644
--- a/lib/Syntax/DeclSyntax.cpp
+++ b/lib/Syntax/DeclSyntax.cpp
@@ -11,8 +11,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "swift/Syntax/DeclSyntax.h"
+#include "swift/Syntax/ExprSyntax.h"
+#include "swift/Syntax/GenericSyntax.h"
 #include "swift/Syntax/RawSyntax.h"
+#include "swift/Syntax/StmtSyntax.h"
 #include "swift/Syntax/SyntaxFactory.h"
+#include "swift/Syntax/TypeSyntax.h"
 
 using namespace swift;
 using namespace swift::syntax;
@@ -31,6 +35,101 @@
 DeclSyntax::DeclSyntax(const RC<SyntaxData> Root, const DeclSyntaxData *Data)
   : Syntax(Root, Data) {}
 
+#pragma mark - declaration-modifier Data
+
+DeclModifierSyntaxData::
+DeclModifierSyntaxData(const RC<RawSyntax> Raw,
+                       const SyntaxData *Parent,
+                       const CursorIndex IndexInParent)
+  : SyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Kind == SyntaxKind::DeclModifier);
+  assert(Raw->Layout.size() == 4);
+#ifndef NDEBUG
+  auto Name =
+    cast<TokenSyntax>(Raw->getChild(DeclModifierSyntax::Cursor::Name));
+  auto Kind = Name->getTokenKind();
+  assert(Kind == tok::kw_class ||
+         Kind == tok::kw_static ||
+         Kind == tok::identifier ||
+         Kind == tok::kw_public ||
+         Kind == tok::kw_private ||
+         Kind == tok::kw_fileprivate ||
+         Kind == tok::kw_internal);
+#endif
+  syntax_assert_child_token_text(Raw, DeclModifierSyntax::Cursor::LeftParen,
+                                 tok::l_paren, "(");
+  syntax_assert_child_token(Raw, DeclModifierSyntax::Cursor::Argument,
+                           tok::identifier);
+  syntax_assert_child_token_text(Raw, DeclModifierSyntax::Cursor::RightParen,
+                                 tok::r_paren, ")");
+}
+
+RC<DeclModifierSyntaxData>
+DeclModifierSyntaxData::make(const RC<RawSyntax> Raw,
+                             const SyntaxData *Parent,
+                             const CursorIndex IndexInParent) {
+  return RC<DeclModifierSyntaxData>{
+    new DeclModifierSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<DeclModifierSyntaxData> DeclModifierSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::DeclModifier,
+                             {
+                               TokenSyntax::missingToken(tok::identifier, ""),
+                               TokenSyntax::missingToken(tok::l_paren, "("),
+                               TokenSyntax::missingToken(tok::identifier, ""),
+                               TokenSyntax::missingToken(tok::r_paren, ")"),
+                             },
+                             SourcePresence::Present);
+  return make(Raw);
+}
+
+#pragma mark - declaration-modifier API
+
+RC<TokenSyntax> DeclModifierSyntax::getName() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Name));
+}
+
+DeclModifierSyntax DeclModifierSyntax::withName(RC<TokenSyntax> NewName) const {
+  assert(NewName->getTokenKind() == tok::identifier);
+  return Data->replaceChild<DeclModifierSyntax>(NewName, Cursor::Name);
+}
+
+RC<TokenSyntax> DeclModifierSyntax::getLeftParenToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::LeftParen));
+}
+
+DeclModifierSyntax
+DeclModifierSyntax::withLeftParenToken(RC<TokenSyntax> NewLeftParen) const {
+  syntax_assert_token_is(NewLeftParen, tok::l_paren, "(");
+  return Data->replaceChild<DeclModifierSyntax>(NewLeftParen,
+                                                Cursor::LeftParen);
+}
+
+RC<TokenSyntax> DeclModifierSyntax::getArgument() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Argument));
+}
+
+DeclModifierSyntax
+DeclModifierSyntax::withArgument(RC<TokenSyntax> NewArgument) const {
+  assert(NewArgument->getTokenKind() == tok::identifier);
+  return Data->replaceChild<DeclModifierSyntax>(NewArgument, Cursor::Argument);
+}
+
+RC<TokenSyntax> DeclModifierSyntax::getRightParenToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::RightParen));
+}
+
+DeclModifierSyntax
+DeclModifierSyntax::withRightParenToken(RC<TokenSyntax> NewRightParen) const {
+  syntax_assert_token_is(NewRightParen, tok::r_paren, ")");
+  return Data->replaceChild<DeclModifierSyntax>(NewRightParen,
+                                                Cursor::RightParen);
+}
+
 #pragma mark - unknown-statement Data
 
 UnknownDeclSyntaxData::UnknownDeclSyntaxData(RC<RawSyntax> Raw,
@@ -364,3 +463,573 @@
   auto Data = TypeAliasDeclSyntaxData::make(Raw);
   return { Data, Data.get() };
 }
+
+#pragma mark - function-parameter Data
+
+FunctionParameterSyntaxData::FunctionParameterSyntaxData(RC<RawSyntax> Raw,
+                            const SyntaxData *Parent,
+                            CursorIndex IndexInParent)
+  : SyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Layout.size() == 8);
+  syntax_assert_child_token(Raw, FunctionParameterSyntax::Cursor::ExternalName,
+                            tok::identifier);
+  syntax_assert_child_token(Raw, FunctionParameterSyntax::Cursor::LocalName,
+                            tok::identifier);
+  syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::Colon,
+                                 tok::colon, ":");
+  assert(Raw->getChild(FunctionParameterSyntax::Cursor::Type)->isType());
+  syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::Ellipsis,
+                                 tok::identifier, "...");
+  syntax_assert_child_token_text(Raw,
+                                 FunctionParameterSyntax::Cursor::DefaultEqual,
+                                 tok::equal, "=");
+  assert(Raw->getChild(
+    FunctionParameterSyntax::Cursor::DefaultExpression)->isExpr());
+  syntax_assert_child_token_text(Raw,
+                                 FunctionParameterSyntax::Cursor::TrailingComma,
+                                 tok::comma, ",");
+}
+
+RC<FunctionParameterSyntaxData>
+FunctionParameterSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
+     CursorIndex IndexInParent) {
+  return RC<FunctionParameterSyntaxData> {
+    new FunctionParameterSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<FunctionParameterSyntaxData> FunctionParameterSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionParameter,
+  {
+    TokenSyntax::missingToken(tok::identifier, ""),
+    TokenSyntax::missingToken(tok::identifier, ""),
+    TokenSyntax::missingToken(tok::colon, ":"),
+    RawSyntax::missing(SyntaxKind::MissingType),
+    TokenSyntax::missingToken(tok::identifier, "..."),
+    TokenSyntax::missingToken(tok::equal, "="),
+    RawSyntax::missing(SyntaxKind::MissingExpr),
+    TokenSyntax::missingToken(tok::comma, ","),
+  },
+  SourcePresence::Present);
+  return make(Raw);
+}
+
+
+#pragma mark - function-parameter API
+
+RC<TokenSyntax> FunctionParameterSyntax::getExternalName() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::ExternalName));
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withExternalName(RC<TokenSyntax> NewExternalName) const {
+  assert(NewExternalName->getTokenKind() == tok::identifier);
+  return Data->replaceChild<FunctionParameterSyntax>(NewExternalName,
+                                                     Cursor::ExternalName);
+}
+
+RC<TokenSyntax> FunctionParameterSyntax::getLocalName() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::LocalName));
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withLocalName(RC<TokenSyntax> NewLocalName) const {
+  assert(NewLocalName->getTokenKind() == tok::identifier);
+  return Data->replaceChild<FunctionParameterSyntax>(NewLocalName,
+                                                     Cursor::LocalName);
+}
+
+RC<TokenSyntax> FunctionParameterSyntax::getColonToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Colon));
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withColonToken(RC<TokenSyntax> NewColonToken) const {
+  syntax_assert_token_is(NewColonToken, tok::colon, ":");
+  return Data->replaceChild<FunctionParameterSyntax>(NewColonToken,
+                                                     Cursor::Colon);
+}
+
+llvm::Optional<TypeSyntax> FunctionParameterSyntax::getTypeSyntax() const {
+  auto RawType = getRaw()->getChild(Cursor::Type);
+  if (RawType->isMissing()) {
+    return llvm::None;
+  }
+
+  auto *MyData = getUnsafeData<FunctionParameterSyntax>();
+
+  if (MyData->CachedTypeSyntax) {
+    return TypeSyntax { Root, MyData->CachedTypeSyntax.get() };
+  }
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedTypeSyntax);
+
+  SyntaxData::realizeSyntaxNode<TypeSyntax>(ChildPtr, RawType, MyData,
+                                            cursorIndex(Cursor::Type));
+
+  return TypeSyntax { Root, MyData->CachedTypeSyntax.get() };
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withTypeSyntax(llvm::Optional<TypeSyntax> NewType) const {
+  if (!NewType.hasValue()) {
+    auto RawType = RawSyntax::missing(SyntaxKind::MissingType);
+    return Data->replaceChild<FunctionParameterSyntax>(RawType, Cursor::Type);
+  }
+
+  return Data->replaceChild<FunctionParameterSyntax>(
+    NewType.getValue().getRaw(), Cursor::Type);
+}
+
+RC<TokenSyntax> FunctionParameterSyntax::getEqualToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::DefaultEqual));
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withEqualToken(RC<TokenSyntax> NewEqualToken) const {
+  assert(NewEqualToken->getTokenKind() == tok::equal);
+  return Data->replaceChild<FunctionParameterSyntax>(NewEqualToken,
+                                                     Cursor::DefaultEqual);
+}
+
+llvm::Optional<ExprSyntax> FunctionParameterSyntax::getDefaultValue() const {
+    auto RawExpr = getRaw()->getChild(Cursor::DefaultExpression);
+    if (RawExpr->isMissing()) {
+      return llvm::None;
+    }
+
+    auto *MyData = getUnsafeData<FunctionParameterSyntax>();
+
+    if (MyData->CachedTypeSyntax) {
+      return ExprSyntax { Root, MyData->CachedDefaultValue.get() };
+    }
+
+    auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+      &MyData->CachedDefaultValue);
+
+    SyntaxData::realizeSyntaxNode<TypeSyntax>(ChildPtr, RawExpr, MyData,
+      cursorIndex(Cursor::DefaultExpression));
+    
+    return ExprSyntax { Root, MyData->CachedDefaultValue.get() };
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withDefaultValue(llvm::Optional<ExprSyntax> NewDefaultValue) const {
+  if (!NewDefaultValue.hasValue()) {
+    auto RawType = RawSyntax::missing(SyntaxKind::MissingExpr);
+    return Data->replaceChild<FunctionParameterSyntax>(RawType,
+      Cursor::DefaultExpression);
+  }
+
+  return Data->replaceChild<FunctionParameterSyntax>(
+    NewDefaultValue.getValue().getRaw(), Cursor::DefaultExpression);
+}
+
+RC<TokenSyntax> FunctionParameterSyntax::getTrailingComma() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::TrailingComma));
+}
+
+FunctionParameterSyntax FunctionParameterSyntax::
+withTrailingComma(RC<TokenSyntax> NewTrailingComma) const {
+  syntax_assert_token_is(NewTrailingComma, tok::comma, ",");
+  return Data->replaceChild<FunctionParameterSyntax>(NewTrailingComma,
+                                                     Cursor::TrailingComma);
+}
+
+#pragma mark - function-signature Data
+
+FunctionSignatureSyntaxData::
+FunctionSignatureSyntaxData(const RC<RawSyntax> Raw,
+                            const SyntaxData *Parent,
+                            const CursorIndex IndexInParent)
+  : SyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Layout.size() == 7);
+  syntax_assert_child_token_text(Raw,
+                                 FunctionSignatureSyntax::Cursor::LeftParen,
+                                 tok::l_paren, "(");
+
+  assert(Raw->getChild(FunctionSignatureSyntax::Cursor::ParameterList)->Kind ==
+         SyntaxKind::FunctionParameterList);
+
+  syntax_assert_child_token_text(Raw,
+                                 FunctionSignatureSyntax::Cursor::RightParen,
+                                 tok::r_paren, ")");
+#ifndef NDEBUG
+  auto ThrowsRethrows = cast<TokenSyntax>(
+    Raw->getChild(FunctionSignatureSyntax::Cursor::ThrowsOrRethrows));
+  assert(cast<TokenSyntax>(ThrowsRethrows)->getTokenKind() == tok::kw_throws ||
+         cast<TokenSyntax>(ThrowsRethrows)->getTokenKind() == tok::kw_rethrows);
+#endif
+  syntax_assert_child_token_text(Raw, FunctionSignatureSyntax::Cursor::Arrow,
+                                 tok::arrow, "->");
+  syntax_assert_child_kind(Raw,
+    FunctionSignatureSyntax::Cursor::ReturnTypeAttributes,
+    SyntaxKind::TypeAttributes);
+  assert(Raw->getChild(FunctionSignatureSyntax::Cursor::ReturnType)->isType());
+}
+
+RC<FunctionSignatureSyntaxData>
+FunctionSignatureSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
+                                  CursorIndex IndexInParent) {
+  return RC<FunctionSignatureSyntaxData> {
+    new FunctionSignatureSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<FunctionSignatureSyntaxData> FunctionSignatureSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionSignature,
+  {
+    TokenSyntax::missingToken(tok::l_paren, "("),
+    RawSyntax::missing(SyntaxKind::FunctionParameterList),
+    TokenSyntax::missingToken(tok::r_paren, ")"),
+    TokenSyntax::missingToken(tok::kw_throws, "throws"),
+    TokenSyntax::missingToken(tok::arrow, "->"),
+    RawSyntax::missing(SyntaxKind::TypeAttributes),
+    RawSyntax::missing(SyntaxKind::MissingType),
+  },
+  SourcePresence::Present);
+  return make(Raw);
+}
+
+#pragma mark - function-signature API
+
+RC<TokenSyntax> FunctionSignatureSyntax::getLeftParenToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::LeftParen));
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withLeftParenToken(RC<TokenSyntax> NewLeftParen) const {
+  syntax_assert_token_is(NewLeftParen, tok::l_paren, "(");
+  return Data->replaceChild<FunctionSignatureSyntax>(NewLeftParen,
+                                                     Cursor::LeftParen);
+}
+
+FunctionParameterListSyntax FunctionSignatureSyntax::getParameterList() const {
+  auto RawList = getRaw()->getChild(Cursor::ParameterList);
+
+  auto *MyData = getUnsafeData<FunctionSignatureSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedParameterList);
+
+  SyntaxData::realizeSyntaxNode<FunctionParameterListSyntax>(ChildPtr, RawList,
+    MyData, cursorIndex(Cursor::ParameterList));
+  
+  return FunctionParameterListSyntax {
+    Root,
+    MyData->CachedParameterList.get()
+  };
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withParameterList(FunctionParameterListSyntax NewParameterList) const {
+  return Data->replaceChild<FunctionSignatureSyntax>(NewParameterList.getRaw(),
+                                                     Cursor::ParameterList);
+}
+
+RC<TokenSyntax> FunctionSignatureSyntax::getRightParenToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::RightParen));
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withRightParenToken(RC<TokenSyntax> NewRightParen) const {
+  syntax_assert_token_is(NewRightParen, tok::r_paren, ")");
+  return Data->replaceChild<FunctionSignatureSyntax>(NewRightParen,
+                                                     Cursor::RightParen);
+}
+
+RC<TokenSyntax> FunctionSignatureSyntax::getThrowsToken() const {
+  auto Throw = cast<TokenSyntax>(getRaw()->getChild(Cursor::ThrowsOrRethrows));
+  if (Throw->getTokenKind() != tok::kw_throws) {
+    return TokenSyntax::missingToken(tok::kw_throws, "throws");
+  }
+  return Throw;
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withThrowsToken(RC<TokenSyntax> NewThrowsToken) const {
+  syntax_assert_token_is(NewThrowsToken, tok::kw_throws, "throws");
+  return Data->replaceChild<FunctionSignatureSyntax>(NewThrowsToken,
+                                                     Cursor::ThrowsOrRethrows);
+}
+
+RC<TokenSyntax> FunctionSignatureSyntax::getRethrowsToken() const {
+  auto Rethrow = cast<TokenSyntax>(
+    getRaw()->getChild(Cursor::ThrowsOrRethrows));
+  if (Rethrow->getTokenKind() != tok::kw_rethrows) {
+    return TokenSyntax::missingToken(tok::kw_rethrows, "rethrows");
+  }
+  return Rethrow;
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withRethrowsToken(RC<TokenSyntax> NewRethrowsToken) const {
+  syntax_assert_token_is(NewRethrowsToken, tok::kw_rethrows, "rethrows");
+  return Data->replaceChild<FunctionSignatureSyntax>(NewRethrowsToken,
+                                                     Cursor::ThrowsOrRethrows);
+}
+
+RC<TokenSyntax> FunctionSignatureSyntax::getArrowToken() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Arrow));
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withArrowToken(RC<TokenSyntax> NewArrowToken) const {
+  syntax_assert_token_is(NewArrowToken, tok::arrow, "->");
+  return Data->replaceChild<FunctionSignatureSyntax>(NewArrowToken,
+                                                     Cursor::Arrow);
+}
+
+TypeAttributesSyntax FunctionSignatureSyntax::getReturnTypeAttributes() const {
+  auto RawAttrs = getRaw()->getChild(Cursor::ReturnTypeAttributes);
+
+  auto *MyData = getUnsafeData<FunctionSignatureSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedReturnTypeAttributes);
+
+  SyntaxData::realizeSyntaxNode<TypeAttributesSyntax>(ChildPtr, RawAttrs,
+    MyData, cursorIndex(Cursor::ReturnTypeAttributes));
+
+  return TypeAttributesSyntax {
+    Root,
+    MyData->CachedReturnTypeAttributes.get()
+  };
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withReturnTypeAttributes(TypeAttributesSyntax NewAttributes) const {
+  return Data->replaceChild<FunctionSignatureSyntax>(NewAttributes.getRaw(),
+    Cursor::ReturnTypeAttributes);
+}
+
+TypeSyntax FunctionSignatureSyntax::getReturnTypeSyntax() const {
+  auto RawType = getRaw()->getChild(Cursor::ReturnType);
+
+  auto *MyData = getUnsafeData<FunctionSignatureSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedReturnTypeSyntax);
+
+  SyntaxData::realizeSyntaxNode<TypeSyntax>(ChildPtr, RawType,
+    MyData, cursorIndex(Cursor::ReturnType));
+
+  return TypeSyntax {
+    Root,
+    MyData->CachedReturnTypeSyntax.get()
+  };
+}
+
+FunctionSignatureSyntax FunctionSignatureSyntax::
+withReturnTypeSyntax(TypeSyntax NewReturnTypeSyntax) const {
+  return Data->replaceChild<FunctionSignatureSyntax>(
+    NewReturnTypeSyntax.getRaw(), Cursor::ReturnType);
+}
+
+#pragma mark - function-declaration-data
+
+FunctionDeclSyntaxData::
+FunctionDeclSyntaxData(const RC<RawSyntax> Raw,
+                       const SyntaxData *Parent,
+                       const CursorIndex IndexInParent)
+  : SyntaxData(Raw, Parent, IndexInParent) {
+  assert(Raw->Kind == SyntaxKind::FunctionDecl);
+  assert(Raw->Layout.size() == 8);
+  syntax_assert_child_kind(Raw, FunctionDeclSyntax::Cursor::Attributes,
+                           SyntaxKind::TypeAttributes);
+  syntax_assert_child_kind(Raw, FunctionDeclSyntax::Cursor::Modifiers,
+                           SyntaxKind::DeclModifierList);
+  syntax_assert_child_token_text(Raw, FunctionDeclSyntax::Cursor::FuncKeyword,
+                                 tok::kw_func, "func");
+  syntax_assert_child_token(Raw, FunctionDeclSyntax::Cursor::Identifier,
+                            tok::identifier);
+  syntax_assert_child_kind(Raw,
+                           FunctionDeclSyntax::Cursor::GenericParameterClause,
+                           SyntaxKind::GenericParameterClause);
+  syntax_assert_child_kind(Raw, FunctionDeclSyntax::Cursor::Signature,
+                           SyntaxKind::FunctionSignature);
+  syntax_assert_child_kind(Raw, FunctionDeclSyntax::Cursor::GenericWhereClause,
+                           SyntaxKind::GenericWhereClause);
+  syntax_assert_child_kind(Raw, FunctionDeclSyntax::Cursor::Body,
+                           SyntaxKind::CodeBlockStmt);
+}
+
+RC<FunctionDeclSyntaxData> FunctionDeclSyntaxData::make(const RC<RawSyntax> Raw,
+                                       const SyntaxData *Parent,
+                                       const CursorIndex IndexInParent) {
+  return RC<FunctionDeclSyntaxData> {
+    new FunctionDeclSyntaxData {
+      Raw, Parent, IndexInParent
+    }
+  };
+}
+
+RC<FunctionDeclSyntaxData> FunctionDeclSyntaxData::makeBlank() {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionDecl,
+    {
+      RawSyntax::missing(SyntaxKind::TypeAttributes),
+      RawSyntax::missing(SyntaxKind::DeclModifierList),
+      TokenSyntax::missingToken(tok::kw_func, "func"),
+      TokenSyntax::missingToken(tok::identifier, ""),
+      RawSyntax::missing(SyntaxKind::GenericParameterClause),
+      RawSyntax::missing(SyntaxKind::FunctionSignature),
+      RawSyntax::missing(SyntaxKind::GenericWhereClause),
+      RawSyntax::missing(SyntaxKind::CodeBlockStmt),
+    },
+    SourcePresence::Present);
+  return make(Raw);
+}
+
+#pragma mark - function-declaration-API
+
+TypeAttributesSyntax FunctionDeclSyntax::getAttributes() const {
+  auto RawAttrs = getRaw()->getChild(Cursor::Attributes);
+
+  auto *MyData = getUnsafeData<FunctionDeclSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedAttributes);
+
+  SyntaxData::realizeSyntaxNode<ExprSyntax>(ChildPtr, RawAttrs, MyData,
+                                            cursorIndex(Cursor::Attributes));
+  
+  return { Root, MyData->CachedAttributes.get() };
+}
+
+FunctionDeclSyntax
+FunctionDeclSyntax::withAttributes(TypeAttributesSyntax NewAttributes) const {
+  return Data->replaceChild<FunctionDeclSyntax>(NewAttributes.getRaw(),
+                                                Cursor::Attributes);
+}
+
+DeclModifierListSyntax FunctionDeclSyntax::getModifiers() const {
+  auto RawModifiers = getRaw()->getChild(Cursor::Attributes);
+
+  auto *MyData = getUnsafeData<FunctionDeclSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedModifiers);
+
+  SyntaxData::realizeSyntaxNode<DeclModifierListSyntax>(ChildPtr, RawModifiers,
+    MyData, cursorIndex(Cursor::Modifiers));
+  
+  return { Root, MyData->CachedModifiers.get() };
+}
+
+FunctionDeclSyntax
+FunctionDeclSyntax::withModifiers(DeclModifierListSyntax NewModifiers) const {
+  return Data->replaceChild<FunctionDeclSyntax>(NewModifiers.getRaw(),
+                                                Cursor::Modifiers);
+}
+
+RC<TokenSyntax> FunctionDeclSyntax::getFuncKeyword() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::FuncKeyword));
+}
+
+FunctionDeclSyntax
+FunctionDeclSyntax::withFuncKeyword(RC<TokenSyntax> NewFuncKeyword) const {
+  syntax_assert_token_is(NewFuncKeyword, tok::kw_func, "func");
+  return Data->replaceChild<FunctionDeclSyntax>(NewFuncKeyword,
+                                                Cursor::FuncKeyword);
+
+}
+
+RC<TokenSyntax> FunctionDeclSyntax::getIdentifier() const {
+  return cast<TokenSyntax>(getRaw()->getChild(Cursor::Identifier));
+}
+
+FunctionDeclSyntax
+FunctionDeclSyntax::withIdentifier(RC<TokenSyntax> NewIdentifier) const {
+  assert(NewIdentifier->getTokenKind() == tok::identifier);
+  return Data->replaceChild<FunctionDeclSyntax>(NewIdentifier,
+                                                Cursor::Identifier);
+}
+
+llvm::Optional<GenericParameterClauseSyntax>
+FunctionDeclSyntax::getGenericParameterClause() const {
+  auto RawGenericParams = getRaw()->getChild(Cursor::Attributes);
+  if (RawGenericParams->isMissing()) {
+    return llvm::None;
+  }
+
+  auto *MyData = getUnsafeData<FunctionDeclSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedGenericParams);
+
+  SyntaxData::realizeSyntaxNode<DeclModifierListSyntax>(ChildPtr,
+    RawGenericParams, MyData, cursorIndex(Cursor::GenericParameterClause));
+
+  GenericParameterClauseSyntax Params {
+    Root,
+    MyData->CachedGenericParams.get()
+  };
+  
+  return Params;
+}
+
+FunctionDeclSyntax FunctionDeclSyntax::withGenericParameterClause(
+    llvm::Optional<GenericParameterClauseSyntax> NewGenericParams) const {
+  auto RawParams = NewGenericParams.hasValue()
+    ? NewGenericParams->getRaw()
+    : SyntaxFactory::makeBlankGenericParameterClause().getRaw();
+  return Data->replaceChild<FunctionDeclSyntax>(RawParams,
+                                                Cursor::GenericParameterClause);
+
+}
+
+FunctionSignatureSyntax FunctionDeclSyntax::getSignature() const {
+  auto RawSig = getRaw()->getChild(Cursor::Attributes);
+
+  auto *MyData = getUnsafeData<FunctionDeclSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedSignature);
+
+  SyntaxData::realizeSyntaxNode<FunctionSignatureSyntax>(ChildPtr, RawSig,
+    MyData, cursorIndex(Cursor::Signature));
+
+  return { Root, MyData->CachedSignature.get() };
+}
+
+FunctionDeclSyntax
+FunctionDeclSyntax::withSignature(FunctionSignatureSyntax NewSignature) const {
+  return Data->replaceChild<FunctionDeclSyntax>(NewSignature.getRaw(),
+                                                Cursor::Signature);
+}
+
+llvm::Optional<CodeBlockStmtSyntax> FunctionDeclSyntax::getBody() const {
+  auto RawBody = getRaw()->getChild(Cursor::Body);
+  if (RawBody->isMissing()) {
+    return llvm::None;
+  }
+
+  auto *MyData = getUnsafeData<FunctionDeclSyntax>();
+
+  auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
+    &MyData->CachedBody);
+
+  SyntaxData::realizeSyntaxNode<CodeBlockStmtSyntax>(ChildPtr,
+    RawBody, MyData, cursorIndex(Cursor::Body));
+  
+  CodeBlockStmtSyntax Body {
+    Root,
+    MyData->CachedBody.get()
+  };
+  
+  return Body;
+}
+
+FunctionDeclSyntax FunctionDeclSyntax::
+withBody(llvm::Optional<CodeBlockStmtSyntax> NewBody) const {
+  auto RawBody = NewBody.hasValue()
+    ? NewBody->getRaw()
+    : SyntaxFactory::makeBlankCodeBlock().getRaw();
+  return Data->replaceChild<FunctionDeclSyntax>(RawBody,
+                                                Cursor::Body);
+}
diff --git a/lib/Syntax/ExprSyntax.cpp b/lib/Syntax/ExprSyntax.cpp
index b7d8be9..9a59dd4 100644
--- a/lib/Syntax/ExprSyntax.cpp
+++ b/lib/Syntax/ExprSyntax.cpp
@@ -301,80 +301,12 @@
     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);
-}
+  : SyntaxCollection(Root, Data) {}
 
 #pragma mark - function-call-expression Data
 
diff --git a/lib/Syntax/GenericSyntax.cpp b/lib/Syntax/GenericSyntax.cpp
index e48e33a..99a72d8 100644
--- a/lib/Syntax/GenericSyntax.cpp
+++ b/lib/Syntax/GenericSyntax.cpp
@@ -27,7 +27,7 @@
 ConformanceRequirementSyntaxData(RC<RawSyntax> Raw,
                                  const SyntaxData *Parent,
                                  CursorIndex IndexInParent)
-  : SyntaxData(Raw, Parent, IndexInParent) {
+  : GenericRequirementSyntaxData(Raw, Parent, IndexInParent) {
   assert(Raw->Kind == SyntaxKind::ConformanceRequirement);
   syntax_assert_child_kind(Raw,
     ConformanceRequirementSyntax::Cursor::LeftTypeIdentifier,
@@ -149,9 +149,9 @@
 }
 
 RC<GenericParameterClauseSyntaxData>
-GenericParameterClauseSyntaxData::make(RC<RawSyntax> Raw,
+GenericParameterClauseSyntaxData::make(const RC<RawSyntax> Raw,
                                        const SyntaxData *Parent,
-                                       CursorIndex IndexInParent) {
+                                       const CursorIndex IndexInParent) {
   return RC<GenericParameterClauseSyntaxData> {
     new GenericParameterClauseSyntaxData {
       Raw, Parent, IndexInParent,
@@ -173,7 +173,7 @@
 #pragma mark - generic-parameter-clause API
 
 GenericParameterClauseSyntax::
-GenericParameterClauseSyntax(RC<SyntaxData> Root,
+GenericParameterClauseSyntax(const RC<SyntaxData> Root,
                              const GenericParameterClauseSyntaxData *Data)
   : Syntax(Root, Data) {}
 
@@ -226,52 +226,24 @@
   return { Data, Data.get() };
 }
 
-#pragma mark - generic-requirement-list Data
-
-GenericRequirementListSyntaxData::
-GenericRequirementListSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent,
-                                 CursorIndex IndexInParent)
-  : SyntaxData(Raw, Parent, IndexInParent) {
-  assert(Raw->Kind == SyntaxKind::GenericRequirementList);
-}
-
-RC<GenericRequirementListSyntaxData>
-GenericRequirementListSyntaxData::make(RC<RawSyntax> Raw,
-                                       const SyntaxData *Parent,
-                                       CursorIndex IndexInParent) {
-  return RC<GenericRequirementListSyntaxData> {
-    new GenericRequirementListSyntaxData {
-      Raw, Parent, IndexInParent
-    }
-  };
-}
-
-RC<GenericRequirementListSyntaxData>
-GenericRequirementListSyntaxData::makeBlank() {
-  auto Raw = RawSyntax::make(SyntaxKind::GenericRequirementList,
-                             {},
-                             SourcePresence::Present);
-  return make(Raw);
-}
-
 #pragma mark - generic-where-clause Data
 
 GenericWhereClauseSyntaxData::
-GenericWhereClauseSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent,
-                             CursorIndex IndexInParent)
+GenericWhereClauseSyntaxData(const RC<RawSyntax> Raw, const SyntaxData *Parent,
+                             const CursorIndex IndexInParent)
   : SyntaxData(Raw, Parent, IndexInParent) {
   assert(Raw->Kind == SyntaxKind::GenericWhereClause);
   syntax_assert_child_token_text(Raw,
-    GenericWhereClauseSyntax::Cursor::WhereToken, tok::kw_where, "where");
+    GenericWhereClauseSyntax::Cursor::WhereKeyword, tok::kw_where, "where");
   syntax_assert_child_kind(Raw,
     GenericWhereClauseSyntax::Cursor::RequirementList,
     SyntaxKind::GenericRequirementList);
 }
 
 RC<GenericWhereClauseSyntaxData>
-GenericWhereClauseSyntaxData::make(RC<RawSyntax> Raw,
+GenericWhereClauseSyntaxData::make(const RC<RawSyntax> Raw,
                                    const SyntaxData *Parent,
-                                   CursorIndex IndexInParent) {
+                                   const CursorIndex IndexInParent) {
   return RC<GenericWhereClauseSyntaxData> {
     new GenericWhereClauseSyntaxData { Raw, Parent, IndexInParent }
   };
@@ -293,20 +265,34 @@
                          const GenericWhereClauseSyntaxData *Data)
   : Syntax(Root, Data) {}
 
+GenericWhereClauseSyntax GenericWhereClauseSyntax::
+withWhereKeyword(RC<TokenSyntax> NewWhereKeyword) const {
+  syntax_assert_token_is(NewWhereKeyword, tok::kw_where, "where");
+  return Data->replaceChild<GenericWhereClauseSyntax>(NewWhereKeyword,
+                                                      Cursor::WhereKeyword);
+}
+
+GenericWhereClauseSyntax GenericWhereClauseSyntax::
+withRequirementList(GenericRequirementListSyntax NewRequirements) const {
+  return Data->replaceChild<GenericWhereClauseSyntax>(NewRequirements.getRaw(),
+                                                      Cursor::RequirementList);
+}
+
 #pragma mark - same-type-requirement Data
 
 SameTypeRequirementSyntaxData::
 SameTypeRequirementSyntaxData(RC<RawSyntax> Raw,
                               const SyntaxData *Parent,
                               CursorIndex IndexInParent)
-  : SyntaxData(Raw, Parent, IndexInParent) {
+  : GenericRequirementSyntaxData(Raw, Parent, IndexInParent) {
   assert(Raw->Kind == SyntaxKind::SameTypeRequirement);
   assert(Raw->Layout.size() == 3);
   syntax_assert_child_kind(Raw,
     SameTypeRequirementSyntax::Cursor::LeftTypeIdentifier,
     SyntaxKind::TypeIdentifier);
   syntax_assert_child_token_text(Raw,
-    SameTypeRequirementSyntax::Cursor::EqualityToken, tok::identifier, "==");
+    SameTypeRequirementSyntax::Cursor::EqualityToken,
+    tok::oper_binary_spaced, "==");
   assert(Raw->getChild(SameTypeRequirementSyntax::Cursor::RightType)->isType());
 }
 
diff --git a/lib/Syntax/LegacyASTTransformer.cpp b/lib/Syntax/LegacyASTTransformer.cpp
index 4356df0..2337447 100644
--- a/lib/Syntax/LegacyASTTransformer.cpp
+++ b/lib/Syntax/LegacyASTTransformer.cpp
@@ -443,11 +443,11 @@
                     BufferID, Tokens)
     : TokenSyntax::missingToken(tok::l_brace, "{");
 
-  StmtListSyntaxBuilder StmtsBuilder;
+  std::vector<StmtSyntax> Stmts;
   for (auto Node : S->getElements()) {
     auto Transformed = transformAST(Node, Sema, SourceMgr, BufferID, Tokens);
     if (Transformed.hasValue()) {
-      StmtsBuilder.addStatement(Transformed.getValue());
+      Stmts.push_back(Transformed.getValue().castTo<StmtSyntax>());
     }
   }
 
@@ -456,8 +456,9 @@
                     BufferID, Tokens)
     : TokenSyntax::missingToken(tok::r_brace, "}");
 
-  return SyntaxFactory::makeCodeBlock(LeftBrace, StmtsBuilder.build(),
-                                      RightBrace).Root;
+  auto StmtList = SyntaxFactory::makeStmtList(Stmts);
+
+  return SyntaxFactory::makeCodeBlock(LeftBrace, StmtList, RightBrace).Root;
 }
 
 RC<SyntaxData>
diff --git a/lib/Syntax/Status.md b/lib/Syntax/Status.md
index 1c8a324..a2ed705 100644
--- a/lib/Syntax/Status.md
+++ b/lib/Syntax/Status.md
@@ -16,6 +16,12 @@
 
 ### Declarations
 
+- declaration-modifiers
+  - `DeclModifierListSyntax`
+
+- declaration-modifier
+  - `DeclModifierSyntax`
+
 - struct-declaration
   - `StructDeclSyntax`
 
@@ -40,6 +46,27 @@
   - `DeclMembersSyntax`
   - `StructDeclSyntax` used for the `{` `}` braces.
 
+- function-declaration
+  - `FunctionDeclSyntax`
+
+- function-body
+  - `CodeBlockSyntax`
+
+- function-result
+  - `TypeSyntax`
+
+- function-signature
+  - `FunctionSignatureSyntax`
+
+- parameter-clause
+  - `FunctionParameterClauseSyntax`
+
+- parameter-list
+  - `FunctionParameterListSyntax`
+
+- parameter
+  - `FunctionParameterSyntax`
+
 ### Statements
 
 - statement
@@ -209,8 +236,6 @@
 - as-pattern
 - case-condition
 - case-label
-- declaration-modifiers
-  - declaration-modifier
 - dynamic-type-expression
 - floating-point-literal
 - forced-value-expression
@@ -317,13 +342,6 @@
     - 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
diff --git a/lib/Syntax/StmtSyntax.cpp b/lib/Syntax/StmtSyntax.cpp
index 89b272c..15890b1 100644
--- a/lib/Syntax/StmtSyntax.cpp
+++ b/lib/Syntax/StmtSyntax.cpp
@@ -380,58 +380,3 @@
 CodeBlockStmtSyntax::CodeBlockStmtSyntax(const RC<SyntaxData> Root,
                                          CodeBlockStmtSyntaxData *Data)
     : StmtSyntax(Root, Data) {}
-
-
-#pragma mark statements Data
-
-StmtListSyntaxData::StmtListSyntaxData(RC<RawSyntax> Raw,
-                                       const SyntaxData *Parent,
-                                       CursorIndex IndexInParent)
-    : StmtSyntaxData(Raw, Parent, IndexInParent) {
-  assert(Raw->Kind == SyntaxKind::StmtList);
-}
-
-RC<StmtListSyntaxData> StmtListSyntaxData::make(RC<RawSyntax> Raw,
-                                                const SyntaxData *Parent,
-                                                CursorIndex IndexInParent) {
-  return RC<StmtListSyntaxData> {
-    new StmtListSyntaxData { Raw, Parent, IndexInParent }
-  };
-}
-
-RC<StmtListSyntaxData> StmtListSyntaxData::makeBlank() {
-  return make(RawSyntax::make(SyntaxKind::StmtList,
-                              {},
-                              SourcePresence::Present));
-}
-
-#pragma mark statements API
-
-StmtListSyntax::StmtListSyntax(const RC<SyntaxData> Root,
-                               const StmtListSyntaxData *Data)
-  : Syntax(Root, Data) {}
-
-StmtListSyntax
-StmtListSyntax::withAddedStatement(Syntax AdditionalStatement) const {
-  auto Layout = getRaw()->Layout;
-  Layout.push_back(AdditionalStatement.getRaw());
-  auto NewRaw = RawSyntax::make(SyntaxKind::StmtList, Layout,
-                                getRaw()->Presence);
-  return Data->replaceSelf<StmtListSyntax>(NewRaw);
-}
-
-#pragma mark statements Builder
-
-StmtListSyntaxBuilder &
-StmtListSyntaxBuilder::addStatement(Syntax Statement) {
-  StmtListLayout.push_back(Statement.getRaw());
-  return *this;
-}
-
-StmtListSyntax StmtListSyntaxBuilder::build() const {
-  auto Raw = RawSyntax::make(SyntaxKind::StmtList, StmtListLayout,
-                             SourcePresence::Present);
-  auto Data = StmtListSyntaxData::make(Raw);
-  return StmtListSyntax { Data, Data.get() };
-}
-
diff --git a/lib/Syntax/SyntaxData.cpp b/lib/Syntax/SyntaxData.cpp
index bc21dbf..06b008a 100644
--- a/lib/Syntax/SyntaxData.cpp
+++ b/lib/Syntax/SyntaxData.cpp
@@ -16,6 +16,7 @@
 #include "swift/Syntax/TypeSyntax.h"
 #include "swift/Syntax/StmtSyntax.h"
 #include "swift/Syntax/UnknownSyntax.h"
+#include "llvm/Support/ErrorHandling.h"
 
 using namespace swift;
 using namespace swift::syntax;
@@ -44,6 +45,8 @@
   case SyntaxKind::Token:
     llvm_unreachable("Can't make a SyntaxData from a Token!");
   }
+
+  llvm_unreachable("Unhandled SyntaxKind in switch.");
 }
 
 bool SyntaxData::isType() const {
diff --git a/lib/Syntax/SyntaxFactory.cpp b/lib/Syntax/SyntaxFactory.cpp
index cd495f2..0350e4e 100644
--- a/lib/Syntax/SyntaxFactory.cpp
+++ b/lib/Syntax/SyntaxFactory.cpp
@@ -35,6 +35,51 @@
 
 #pragma mark - Declarations
 
+#pragma mark - declaration-modifier
+
+DeclModifierSyntax SyntaxFactory::makeDeclModifier(RC<TokenSyntax> Name,
+                                                   RC<TokenSyntax> LeftParen,
+                                                   RC<TokenSyntax> Argument,
+                                                   RC<TokenSyntax> RightParen) {
+  auto Raw = RawSyntax::make(SyntaxKind::DeclModifier,
+                             {
+                               Name,
+                               LeftParen,
+                               Argument,
+                               RightParen,
+                             },
+                             SourcePresence::Present);
+  auto Data = DeclModifierSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+DeclModifierSyntax SyntaxFactory::makeBlankDeclModifier() {
+  auto Data = DeclModifierSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
+#pragma mark - declaration-modifier-list
+
+DeclModifierListSyntax SyntaxFactory::
+makeDeclModifierList(const std::vector<DeclModifierSyntax> &Modifiers) {
+  RawSyntax::LayoutList Layout;
+  for (auto Modifier : Modifiers) {
+    Layout.push_back(Modifier.getRaw());
+  }
+
+  auto Raw = RawSyntax::make(SyntaxKind::DeclModifierList, Layout,
+                             SourcePresence::Present);
+  auto Data = DeclModifierListSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+DeclModifierListSyntax SyntaxFactory::makeBlankDeclModifierList() {
+  auto Data = DeclModifierListSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
+#pragma mark - struct-declaration
+
 StructDeclSyntax
 SyntaxFactory::makeStructDecl(RC<TokenSyntax> StructToken,
                               RC<TokenSyntax> Identifier,
@@ -66,6 +111,8 @@
   };
 }
 
+#pragma mark - type-alias-declaration
+
 TypeAliasDeclSyntax SyntaxFactory::makeTypealiasDecl(
     RC<TokenSyntax> TypealiasToken, RC<TokenSyntax> Identifier,
     GenericParameterClauseSyntax GenericParams, RC<TokenSyntax> AssignmentToken,
@@ -88,130 +135,128 @@
   return DeclMembersSyntax { Data, Data.get() };
 }
 
-TypeIdentifierSyntax
-SyntaxFactory::makeTypeIdentifier(OwnedString Name,
-                                  const Trivia &LeadingTrivia,
-                                  const Trivia &TrailingTrivia) {
-  auto Raw = RawSyntax::make(
-      SyntaxKind::TypeIdentifier,
-      {
-          SyntaxFactory::makeIdentifier(Name, LeadingTrivia, TrailingTrivia),
-          RawSyntax::missing(SyntaxKind::GenericArgumentClause),
-          TokenSyntax::missingToken(tok::period, "."),
-          RawSyntax::missing(SyntaxKind::TypeIdentifier),
-      },
-      SourcePresence::Present);
-  auto Data = TypeIdentifierSyntaxData::make(Raw);
-  return TypeIdentifierSyntax { Data, Data.get() };
-}
+#pragma mark - function-parameter
 
-TupleTypeElementSyntax
-SyntaxFactory::makeTupleTypeElement(TypeSyntax ElementType) {
-  auto Data = TupleTypeElementSyntaxData::makeBlank();
-  return TupleTypeElementSyntax { Data, Data.get() }
-      .withTypeSyntax(ElementType);
-}
-
-TypeIdentifierSyntax
-SyntaxFactory::makeTypeIdentifier(RC<TokenSyntax> Identifier,
-                                  GenericArgumentClauseSyntax GenericArgs) {
-  auto Raw = RawSyntax::make(SyntaxKind::TypeIdentifier,
+FunctionParameterSyntax SyntaxFactory::
+makeFunctionParameter(RC<TokenSyntax> ExternalName,
+                      RC<TokenSyntax> LocalName,
+                      RC<TokenSyntax> Colon,
+                      llvm::Optional<TypeSyntax> ParameterTypeSyntax,
+                      RC<TokenSyntax> Ellipsis,
+                      RC<TokenSyntax> Equal,
+                      llvm::Optional<ExprSyntax> DefaultValue,
+                      RC<TokenSyntax> TrailingComma) {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionParameter,
                              {
-                                 Identifier, GenericArgs.getRaw(),
-                                 TokenSyntax::missingToken(tok::period, "."),
-                                 RawSyntax::missing(SyntaxKind::TypeIdentifier),
+                               ExternalName,
+                               LocalName,
+                               Colon,
+                               ParameterTypeSyntax.hasValue()
+                                 ? ParameterTypeSyntax.getValue().getRaw()
+                                 : RawSyntax::missing(SyntaxKind::MissingType),
+                               Ellipsis,
+                               Equal,
+                               DefaultValue.hasValue()
+                                 ? DefaultValue.getValue().getRaw()
+                                 : RawSyntax::missing(SyntaxKind::MissingExpr),
+                               TrailingComma,
                              },
                              SourcePresence::Present);
-  auto Data = TypeIdentifierSyntaxData::make(Raw);
-  return TypeIdentifierSyntax { Data, Data.get() };
+  auto Data = FunctionParameterSyntaxData::make(Raw);
+  return { Data, Data.get() };
 }
 
-OptionalTypeSyntax
-SyntaxFactory::makeOptionalType(TypeSyntax BaseType,
-                                const Trivia &TrailingTrivia) {
-  auto Raw = RawSyntax::make(SyntaxKind::OptionalType,
-    {
-     BaseType.getRaw(),
-     SyntaxFactory::makeQuestionPostfixToken(TrailingTrivia),
-    },
-    SourcePresence::Present);
-
-  auto Data = OptionalTypeSyntaxData::make(Raw);
-  return OptionalTypeSyntax { Data, Data.get() };
+FunctionParameterSyntax SyntaxFactory::makeBlankFunctionParameter() {
+  auto Data = FunctionParameterSyntaxData::makeBlank();
+  return { Data, Data.get() };
 }
 
-OptionalTypeSyntax SyntaxFactory::makeBlankOptionalType() {
-  auto Data = OptionalTypeSyntaxData::makeBlank();
-  return OptionalTypeSyntax { Data, Data.get() };
+#pragma mark - function-parameter-list
+
+FunctionParameterListSyntax SyntaxFactory::makeFunctionParameterList(
+    const std::vector<FunctionParameterSyntax> &Parameters) {
+  RawSyntax::LayoutList Layout;
+  for (auto Param : Parameters) {
+    Layout.push_back(Param.getRaw());
+  }
+
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionParameterList, Layout,
+                             SourcePresence::Present);
+  auto Data = FunctionParameterListSyntaxData::make(Raw);
+  return { Data, Data.get() };
 }
 
-ImplicitlyUnwrappedOptionalTypeSyntax
-SyntaxFactory::makeImplicitlyUnwrappedOptionalType(
-    TypeSyntax BaseType, const Trivia &TrailingTrivia) {
-  auto Raw = RawSyntax::make(SyntaxKind::ImplicitlyUnwrappedOptionalType,
-    {
-        BaseType.getRaw(), SyntaxFactory::makeExclaimPostfixToken(
-                           TrailingTrivia),
-    },
-    SourcePresence::Present);
-  auto Data = ImplicitlyUnwrappedOptionalTypeSyntaxData::make(Raw);
-  return ImplicitlyUnwrappedOptionalTypeSyntax { Data, Data.get() };
+FunctionParameterListSyntax SyntaxFactory::makeBlankFunctionParameterList() {
+  auto Data = FunctionParameterListSyntaxData::makeBlank();
+  return { Data, Data.get() };
 }
 
-ImplicitlyUnwrappedOptionalTypeSyntax
-SyntaxFactory::makeBlankImplicitlyUnwrappedOptionalType() {
-  auto Data = ImplicitlyUnwrappedOptionalTypeSyntaxData::makeBlank();
-  return ImplicitlyUnwrappedOptionalTypeSyntax { Data, Data.get() };
-}
+#pragma mark - function-signature
 
-MetatypeTypeSyntax SyntaxFactory::makeMetatypeType(TypeSyntax BaseType,
-                                                   RC<TokenSyntax> DotToken,
-                                                   RC<TokenSyntax> TypeToken) {
-  auto Raw = RawSyntax::make(SyntaxKind::MetatypeType,
-                      {
-                        BaseType.getRaw(),
-                        DotToken,
-                        TypeToken
-                      },
-                      SourcePresence::Present);
-  auto Data = MetatypeTypeSyntaxData::make(Raw);
-  return MetatypeTypeSyntax { Data, Data.get() };
-}
-
-MetatypeTypeSyntax SyntaxFactory::makeBlankMetatypeType() {
-  auto Data = MetatypeTypeSyntaxData::makeBlank();
-  return MetatypeTypeSyntax { Data, Data.get() };
-}
-
-TypeIdentifierSyntax SyntaxFactory::makeAnyTypeIdentifier() {
-  auto Data = TypeIdentifierSyntaxData::makeBlank();
-  return TypeIdentifierSyntax { Data, Data.get() }
-    .withIdentifier(makeIdentifier("Any", {}, {}));
-}
-
-TypeIdentifierSyntax SyntaxFactory::makeSelfTypeIdentifier() {
-  auto Data = TypeIdentifierSyntaxData::makeBlank();
-  return TypeIdentifierSyntax { Data, Data.get() }
-    .withIdentifier(makeIdentifier("Self", {}, {}));
-}
-
-SameTypeRequirementSyntax SyntaxFactory::makeSameTypeRequirement(
-    TypeIdentifierSyntax LeftTypeIdentifier, RC<TokenSyntax> EqualityToken,
-    TypeSyntax RightType) {
-  auto Raw = RawSyntax::make(SyntaxKind::SameTypeRequirement,
+FunctionSignatureSyntax
+SyntaxFactory::makeFunctionSignature(RC<TokenSyntax> LeftParen,
+                                     FunctionParameterListSyntax ParameterList,
+                                     RC<TokenSyntax> RightParen,
+                                     RC<TokenSyntax> ThrowsOrRethrows,
+                                     RC<TokenSyntax> Arrow,
+                                     TypeAttributesSyntax ReturnTypeAttributes,
+                                     TypeSyntax ReturnTypeSyntax) {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionSignature,
                              {
-                               LeftTypeIdentifier.getRaw(),
-                               EqualityToken,
-                               RightType.getRaw()
+                               LeftParen,
+                               ParameterList.getRaw(),
+                               RightParen,
+                               ThrowsOrRethrows,
+                               Arrow,
+                               ReturnTypeAttributes.getRaw(),
+                               ReturnTypeSyntax.getRaw()
                              },
                              SourcePresence::Present);
-  auto Data = SameTypeRequirementSyntaxData::make(Raw);
-  return SameTypeRequirementSyntax { Data, Data.get() };
+  auto Data = FunctionSignatureSyntaxData::make(Raw);
+  return { Data, Data.get() };
 }
 
-SameTypeRequirementSyntax SyntaxFactory::makeBlankSameTypeRequirement() {
-  auto Data = SameTypeRequirementSyntaxData::makeBlank();
-  return SameTypeRequirementSyntax { Data, Data.get() };
+FunctionSignatureSyntax SyntaxFactory::makeBlankFunctionSignature() {
+  auto Data = FunctionSignatureSyntaxData::makeBlank();
+  return { Data, Data.get() };
+}
+
+#pragma mark - function-declaration
+
+FunctionDeclSyntax SyntaxFactory::
+makeFunctionDecl(TypeAttributesSyntax Attributes,
+                 DeclModifierListSyntax Modifiers,
+                 RC<TokenSyntax> FuncKeyword,
+                 RC<TokenSyntax> Identifier,
+                 llvm::Optional<GenericParameterClauseSyntax> GenericParams,
+                 FunctionSignatureSyntax Signature,
+                 llvm::Optional<GenericWhereClauseSyntax> GenericWhereClause,
+                 llvm::Optional<CodeBlockStmtSyntax> Body) {
+  auto Raw = RawSyntax::make(SyntaxKind::FunctionDecl,
+    {
+      Attributes.getRaw(),
+      Modifiers.getRaw(),
+      FuncKeyword,
+      Identifier,
+      GenericParams.hasValue()
+       ? GenericParams.getValue().getRaw()
+       : SyntaxFactory::makeBlankGenericParameterClause().getRaw(),
+      Signature.getRaw(),
+      GenericWhereClause.hasValue()
+        ? GenericWhereClause.getValue().getRaw()
+        : SyntaxFactory::makeBlankGenericWhereClause().getRaw(),
+      Body.hasValue()
+       ? Body.getValue().getRaw()
+       : SyntaxFactory::makeBlankCodeBlock().getRaw()
+    },
+    SourcePresence::Present);
+  auto Data = FunctionDeclSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+FunctionDeclSyntax SyntaxFactory::makeBlankFunctionDecl() {
+  auto Data = FunctionDeclSyntaxData::makeBlank();
+  return { Data, Data.get() };
 }
 
 #pragma mark - Statements
@@ -323,6 +368,27 @@
   return { Data, Data.get() };
 }
 
+/// Make a statement list from a loosely connected list of statements.
+StmtListSyntax
+SyntaxFactory::makeStmtList(const std::vector<StmtSyntax> &Statements) {
+  RawSyntax::LayoutList Layout;
+  for (auto Stmt : Statements) {
+    Layout.push_back(Stmt.getRaw());
+  }
+
+  auto Raw = RawSyntax::make(SyntaxKind::StmtList, Layout,
+                             SourcePresence::Present);
+  auto Data = StmtListSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
+/// Make an empty statement list.
+StmtListSyntax SyntaxFactory::makeBlankStmtList() {
+  auto Raw = RawSyntax::make(SyntaxKind::StmtList, {}, SourcePresence::Present);
+  auto Data = StmtListSyntaxData::make(Raw);
+  return { Data, Data.get() };
+}
+
 #pragma mark - Expressions
 
 #pragma mark - integer-literal-expression
@@ -446,10 +512,33 @@
   return { Data, Data.get() };
 }
 
-
 #pragma mark - Tokens
 
 RC<TokenSyntax>
+SyntaxFactory::makeStaticKeyword(const Trivia &LeadingTrivia,
+                                 const Trivia &TrailingTrivia) {
+  return TokenSyntax::make(tok::kw_static, "static",
+                           SourcePresence::Present,
+                           LeadingTrivia, TrailingTrivia);
+}
+
+RC<TokenSyntax>
+SyntaxFactory::makePublicKeyword(const Trivia &LeadingTrivia,
+                                 const Trivia &TrailingTrivia) {
+  return TokenSyntax::make(tok::kw_public, "public",
+                           SourcePresence::Present,
+                           LeadingTrivia, TrailingTrivia);
+}
+
+RC<TokenSyntax>
+SyntaxFactory::makeFuncKeyword(const Trivia &LeadingTrivia,
+                                      const Trivia &TrailingTrivia) {
+  return TokenSyntax::make(tok::kw_func, "func",
+                           SourcePresence::Present,
+                           LeadingTrivia, TrailingTrivia);
+}
+
+RC<TokenSyntax>
 SyntaxFactory::makeFallthroughKeyword(const Trivia &LeadingTrivia,
                                       const Trivia &TrailingTrivia) {
   return TokenSyntax::make(tok::kw_fallthrough, "fallthrough",
@@ -514,6 +603,19 @@
   return TokenSyntax::make(tok::r_paren, ")", SourcePresence::Present,
                            LeadingTrivia, TrailingTrivia);
 }
+RC<TokenSyntax>
+SyntaxFactory::makeLeftBraceToken(const Trivia &LeadingTrivia,
+                                  const Trivia &TrailingTrivia) {
+  return TokenSyntax::make(tok::l_brace, "{", SourcePresence::Present,
+                           LeadingTrivia, TrailingTrivia);
+}
+
+RC<TokenSyntax>
+SyntaxFactory::makeRightBraceToken(const Trivia &LeadingTrivia,
+                                   const Trivia &TrailingTrivia) {
+  return TokenSyntax::make(tok::r_brace, "}", SourcePresence::Present,
+                           LeadingTrivia, TrailingTrivia);
+}
 
 RC<TokenSyntax>
 SyntaxFactory::makeLeftSquareBracketToken(const Trivia &LeadingTrivia,
@@ -731,30 +833,6 @@
   };
 }
 
-TupleTypeSyntax SyntaxFactory::makeVoidTupleType() {
-  auto Raw = RawSyntax::make(SyntaxKind::TupleType,
-    {
-        SyntaxFactory::makeLeftParenToken({}, {}),
-        RawSyntax::missing(SyntaxKind::TypeArgumentList),
-        SyntaxFactory::makeRightParenToken({}, {}),
-    },
-    SourcePresence::Present);
-  auto Data = TupleTypeSyntaxData::make(std::move(Raw));
-  return TupleTypeSyntax {
-    Data, Data.get()
-  };
-}
-
-TupleTypeElementSyntax
-SyntaxFactory::makeTupleTypeElement(RC<TokenSyntax> Name,
-                                    TypeSyntax ElementTypeSyntax) {
-  auto Data = TupleTypeElementSyntaxData::makeBlank();
-  return TupleTypeElementSyntax { Data, Data.get() }
-    .withLabel(Name)
-    .withColonToken(SyntaxFactory::makeColonToken({}, Trivia::spaces(1)))
-    .withTypeSyntax(ElementTypeSyntax);
-}
-
 #pragma mark - Generics
 
 GenericParameterClauseSyntax
@@ -791,48 +869,41 @@
   return GenericParameterSyntax { Data, Data.get() };
 }
 
-ArrayTypeSyntax
-SyntaxFactory::makeArrayType(RC<TokenSyntax> LeftSquareBracket,
-                             TypeSyntax ElementType,
-                             RC<TokenSyntax> RightSquareBracket) {
-  auto Raw = RawSyntax::make(SyntaxKind::ArrayType,
+SameTypeRequirementSyntax SyntaxFactory::
+makeSameTypeRequirement( TypeIdentifierSyntax LeftTypeIdentifier,
+                        RC<TokenSyntax> EqualityToken,
+                        TypeSyntax RightType) {
+  auto Raw = RawSyntax::make(SyntaxKind::SameTypeRequirement,
                              {
-                               LeftSquareBracket,
-                               ElementType.getRaw(),
-                               RightSquareBracket
+                               LeftTypeIdentifier.getRaw(),
+                               EqualityToken,
+                               RightType.getRaw()
                              },
                              SourcePresence::Present);
-  auto Data = ArrayTypeSyntaxData::make(Raw);
-  return ArrayTypeSyntax { Data, Data.get() };
+  auto Data = SameTypeRequirementSyntaxData::make(Raw);
+  return SameTypeRequirementSyntax { Data, Data.get() };
 }
 
-ArrayTypeSyntax SyntaxFactory::makeBlankArrayType() {
-  auto Data = ArrayTypeSyntaxData::makeBlank();
-  return ArrayTypeSyntax { Data, Data.get() };
+SameTypeRequirementSyntax SyntaxFactory::makeBlankSameTypeRequirement() {
+  auto Data = SameTypeRequirementSyntaxData::makeBlank();
+  return SameTypeRequirementSyntax { Data, Data.get() };
 }
 
-DictionaryTypeSyntax
-SyntaxFactory::makeDictionaryType(RC<TokenSyntax> LeftSquareBracket,
-                                  TypeSyntax KeyType,
-                                  RC<TokenSyntax> Colon,
-                                  TypeSyntax ValueType,
-                                  RC<TokenSyntax> RightSquareBracket) {
-  auto Raw = RawSyntax::make(SyntaxKind::DictionaryType,
-                             {
-                               LeftSquareBracket,
-                               KeyType.getRaw(),
-                               Colon,
-                               ValueType.getRaw(),
-                               RightSquareBracket
-                             },
+GenericRequirementListSyntax SyntaxFactory::
+makeGenericRequirementList(std::vector<GenericRequirementSyntax> &Requirements){
+  RawSyntax::LayoutList Layout;
+  for (auto Req : Requirements) {
+    Layout.push_back(Req.getRaw());
+  }
+  auto Raw = RawSyntax::make(SyntaxKind::GenericRequirementList, Layout,
                              SourcePresence::Present);
-  auto Data = DictionaryTypeSyntaxData::make(Raw);
-  return DictionaryTypeSyntax { Data, Data.get() };
+  auto Data = GenericRequirementListSyntaxData::make(Raw);
+  return { Data, Data.get() };
 }
 
-DictionaryTypeSyntax SyntaxFactory::makeBlankDictionaryType() {
-  auto Data = DictionaryTypeSyntaxData::makeBlank();
-  return DictionaryTypeSyntax { Data, Data.get() };
+GenericRequirementListSyntax SyntaxFactory::makeBlankGenericRequirementList() {
+  auto Data = GenericRequirementListSyntaxData::makeBlank();
+  return { Data, Data.get() };
 }
 
 #pragma mark - Operators
@@ -891,6 +962,148 @@
   return BalancedTokensSyntax { Data, Data.get() };
 }
 
+#pragma mark - type-identifier
+
+TypeIdentifierSyntax
+SyntaxFactory::makeTypeIdentifier(OwnedString Name,
+                                  const Trivia &LeadingTrivia,
+                                  const Trivia &TrailingTrivia) {
+  auto Raw = RawSyntax::make(
+                             SyntaxKind::TypeIdentifier,
+                             {
+                               SyntaxFactory::makeIdentifier(Name, LeadingTrivia, TrailingTrivia),
+                               RawSyntax::missing(SyntaxKind::GenericArgumentClause),
+                               TokenSyntax::missingToken(tok::period, "."),
+                               RawSyntax::missing(SyntaxKind::TypeIdentifier),
+                             },
+                             SourcePresence::Present);
+  auto Data = TypeIdentifierSyntaxData::make(Raw);
+  return TypeIdentifierSyntax { Data, Data.get() };
+}
+
+TypeIdentifierSyntax SyntaxFactory::makeAnyTypeIdentifier() {
+  auto Data = TypeIdentifierSyntaxData::makeBlank();
+  return TypeIdentifierSyntax { Data, Data.get() }
+  .withIdentifier(makeIdentifier("Any", {}, {}));
+}
+
+TypeIdentifierSyntax SyntaxFactory::makeSelfTypeIdentifier() {
+  auto Data = TypeIdentifierSyntaxData::makeBlank();
+  return TypeIdentifierSyntax { Data, Data.get() }
+  .withIdentifier(makeIdentifier("Self", {}, {}));
+}
+
+TypeIdentifierSyntax
+SyntaxFactory::makeTypeIdentifier(RC<TokenSyntax> Identifier,
+                                  GenericArgumentClauseSyntax GenericArgs) {
+  auto Raw = RawSyntax::make(SyntaxKind::TypeIdentifier,
+                             {
+                               Identifier, GenericArgs.getRaw(),
+                               TokenSyntax::missingToken(tok::period, "."),
+                               RawSyntax::missing(SyntaxKind::TypeIdentifier),
+                             },
+                             SourcePresence::Present);
+  auto Data = TypeIdentifierSyntaxData::make(Raw);
+  return TypeIdentifierSyntax { Data, Data.get() };
+}
+
+#pragma mark - tuple-type
+
+TupleTypeSyntax SyntaxFactory::makeVoidTupleType() {
+  auto Raw = RawSyntax::make(SyntaxKind::TupleType,
+    {
+      SyntaxFactory::makeLeftParenToken({}, {}),
+      RawSyntax::missing(SyntaxKind::TypeArgumentList),
+      SyntaxFactory::makeRightParenToken({}, {}),
+    },
+    SourcePresence::Present);
+  auto Data = TupleTypeSyntaxData::make(std::move(Raw));
+  return TupleTypeSyntax {
+    Data, Data.get()
+  };
+}
+
+TupleTypeElementSyntax
+SyntaxFactory::makeTupleTypeElement(RC<TokenSyntax> Name,
+                                    TypeSyntax ElementTypeSyntax) {
+  auto Data = TupleTypeElementSyntaxData::makeBlank();
+  return TupleTypeElementSyntax { Data, Data.get() }
+    .withLabel(Name)
+    .withColonToken(SyntaxFactory::makeColonToken({}, Trivia::spaces(1)))
+    .withTypeSyntax(ElementTypeSyntax);
+}
+
+
+TupleTypeElementSyntax
+SyntaxFactory::makeTupleTypeElement(TypeSyntax ElementType) {
+  auto Data = TupleTypeElementSyntaxData::makeBlank();
+  return TupleTypeElementSyntax { Data, Data.get() }
+  .withTypeSyntax(ElementType);
+}
+
+#pragma mark - optional-type
+
+OptionalTypeSyntax
+SyntaxFactory::makeOptionalType(TypeSyntax BaseType,
+                                const Trivia &TrailingTrivia) {
+  auto Raw = RawSyntax::make(SyntaxKind::OptionalType,
+  {
+    BaseType.getRaw(),
+    SyntaxFactory::makeQuestionPostfixToken(TrailingTrivia),
+  },
+  SourcePresence::Present);
+
+  auto Data = OptionalTypeSyntaxData::make(Raw);
+  return OptionalTypeSyntax { Data, Data.get() };
+}
+
+OptionalTypeSyntax SyntaxFactory::makeBlankOptionalType() {
+  auto Data = OptionalTypeSyntaxData::makeBlank();
+  return OptionalTypeSyntax { Data, Data.get() };
+}
+
+#pragma mark - implicitly-unwrapped-optional-type
+
+ImplicitlyUnwrappedOptionalTypeSyntax SyntaxFactory::
+makeImplicitlyUnwrappedOptionalType(TypeSyntax BaseType,
+                                    const Trivia &TrailingTrivia) {
+  auto Raw = RawSyntax::make(SyntaxKind::ImplicitlyUnwrappedOptionalType,
+    {
+      BaseType.getRaw(),
+      SyntaxFactory::makeExclaimPostfixToken(TrailingTrivia),
+    },
+    SourcePresence::Present);
+  auto Data = ImplicitlyUnwrappedOptionalTypeSyntaxData::make(Raw);
+  return ImplicitlyUnwrappedOptionalTypeSyntax { Data, Data.get() };
+}
+
+ImplicitlyUnwrappedOptionalTypeSyntax
+SyntaxFactory::makeBlankImplicitlyUnwrappedOptionalType() {
+  auto Data = ImplicitlyUnwrappedOptionalTypeSyntaxData::makeBlank();
+  return ImplicitlyUnwrappedOptionalTypeSyntax { Data, Data.get() };
+}
+
+#pragma mark - metatype-type
+
+MetatypeTypeSyntax SyntaxFactory::makeMetatypeType(TypeSyntax BaseType,
+                                                   RC<TokenSyntax> DotToken,
+                                                   RC<TokenSyntax> TypeToken) {
+  auto Raw = RawSyntax::make(SyntaxKind::MetatypeType,
+                             {
+                               BaseType.getRaw(),
+                               DotToken,
+                               TypeToken
+                             },
+                             SourcePresence::Present);
+  auto Data = MetatypeTypeSyntaxData::make(Raw);
+  return MetatypeTypeSyntax { Data, Data.get() };
+}
+
+MetatypeTypeSyntax SyntaxFactory::makeBlankMetatypeType() {
+  auto Data = MetatypeTypeSyntaxData::makeBlank();
+  return MetatypeTypeSyntax { Data, Data.get() };
+}
+
 #pragma mark - function-type
 
 FunctionTypeSyntax SyntaxFactory::makeFunctionType(
@@ -919,8 +1132,7 @@
   return FunctionTypeSyntax { Data, Data.get() };
 }
 
-#pragma mark -
-#pragma mark function-type-argument
+#pragma mark - function-type-argument
 
 FunctionTypeArgumentSyntax SyntaxFactory::
 makeFunctionTypeArgument(RC<TokenSyntax> ExternalParameterName,
@@ -986,3 +1198,53 @@
   auto Data =  TypeArgumentListSyntaxData::makeBlank();
   return TypeArgumentListSyntax { Data, Data.get() };
 }
+
+#pragma mark - array-type
+
+ArrayTypeSyntax
+SyntaxFactory::makeArrayType(RC<TokenSyntax> LeftSquareBracket,
+                             TypeSyntax ElementType,
+                             RC<TokenSyntax> RightSquareBracket) {
+  auto Raw = RawSyntax::make(SyntaxKind::ArrayType,
+                             {
+                               LeftSquareBracket,
+                               ElementType.getRaw(),
+                               RightSquareBracket
+                             },
+                             SourcePresence::Present);
+  auto Data = ArrayTypeSyntaxData::make(Raw);
+  return ArrayTypeSyntax { Data, Data.get() };
+}
+
+ArrayTypeSyntax SyntaxFactory::makeBlankArrayType() {
+  auto Data = ArrayTypeSyntaxData::makeBlank();
+  return ArrayTypeSyntax { Data, Data.get() };
+}
+
+#pragma mark - dictionary-type
+
+DictionaryTypeSyntax
+SyntaxFactory::makeDictionaryType(RC<TokenSyntax> LeftSquareBracket,
+                                  TypeSyntax KeyType,
+                                  RC<TokenSyntax> Colon,
+                                  TypeSyntax ValueType,
+                                  RC<TokenSyntax> RightSquareBracket) {
+  auto Raw = RawSyntax::make(SyntaxKind::DictionaryType,
+                             {
+                               LeftSquareBracket,
+                               KeyType.getRaw(),
+                               Colon,
+                               ValueType.getRaw(),
+                               RightSquareBracket
+                             },
+                             SourcePresence::Present);
+  auto Data = DictionaryTypeSyntaxData::make(Raw);
+  return DictionaryTypeSyntax { Data, Data.get() };
+}
+
+DictionaryTypeSyntax SyntaxFactory::makeBlankDictionaryType() {
+  auto Data = DictionaryTypeSyntaxData::makeBlank();
+  return DictionaryTypeSyntax { Data, Data.get() };
+}
+
+
diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt
index 4ad01ab..5c24007 100644
--- a/stdlib/CMakeLists.txt
+++ b/stdlib/CMakeLists.txt
@@ -28,6 +28,14 @@
   append("-fno-sanitize=all" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
 endif()
 
+# Do not enforce checks for LLVM's ABI-breaking build settings.
+# The Swift runtime uses some header-only code from LLVM's ADT classes,
+# but we do not want to link libSupport into the runtime. These checks rely
+# on the presence of symbols in libSupport to identify how the code was
+# built and cause link failures for mismatches. Without linking that library,
+# we get link failures regardless, so instead, this just disables the checks.
+append("-DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING=1" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+
 set(SWIFT_STDLIB_LIBRARY_BUILD_TYPES)
 if(SWIFT_BUILD_DYNAMIC_STDLIB)
   list(APPEND SWIFT_STDLIB_LIBRARY_BUILD_TYPES SHARED)
diff --git a/stdlib/public/SwiftShims/HeapObject.h b/stdlib/public/SwiftShims/HeapObject.h
index 4762d02..d9bf257 100644
--- a/stdlib/public/SwiftShims/HeapObject.h
+++ b/stdlib/public/SwiftShims/HeapObject.h
@@ -31,7 +31,7 @@
 // The members of the HeapObject header that are not shared by a
 // standard Objective-C instance
 #define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
-  InlineRefCounts refCounts;
+  InlineRefCounts refCounts
 
 /// The Swift heap-object header.
 struct HeapObject {
diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h
index 4164231..aebd6a2 100644
--- a/stdlib/public/SwiftShims/LibcShims.h
+++ b/stdlib/public/SwiftShims/LibcShims.h
@@ -91,35 +91,35 @@
 _swift_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound);
 
 // Math library functions
-static inline __attribute__((always_inline))
+static inline SWIFT_ALWAYS_INLINE
 float _swift_stdlib_remainderf(float _self, float _other) {
   return __builtin_remainderf(_self, _other);
 }
   
-static inline __attribute__((always_inline))
+static inline SWIFT_ALWAYS_INLINE
 float _swift_stdlib_squareRootf(float _self) {
   return __builtin_sqrt(_self);
 }
 
-static inline __attribute__((always_inline))
+static inline SWIFT_ALWAYS_INLINE
 double _swift_stdlib_remainder(double _self, double _other) {
   return __builtin_remainder(_self, _other);
 }
 
-static inline __attribute__((always_inline))
+static inline SWIFT_ALWAYS_INLINE
 double _swift_stdlib_squareRoot(double _self) {
   return __builtin_sqrt(_self);
 }
 
 // TODO: Remove horrible workaround when importer does Float80 <-> long double.
 #if (defined __i386__ || defined __x86_64__) && !defined _MSC_VER
-static inline __attribute__((always_inline))
+static inline SWIFT_ALWAYS_INLINE
 void _swift_stdlib_remainderl(void *_self, const void *_other) {
   long double *_f80self = (long double *)_self;
   *_f80self = __builtin_remainderl(*_f80self, *(const long double *)_other);
 }
 
-static inline __attribute__((always_inline))
+static inline SWIFT_ALWAYS_INLINE
 void _swift_stdlib_squareRootl(void *_self) {
   long double *_f80self = (long double *)_self;
   *_f80self = __builtin_sqrtl(*_f80self);
@@ -135,4 +135,3 @@
 #endif
 
 #endif // SWIFT_STDLIB_SHIMS_LIBCSHIMS_H
-
diff --git a/stdlib/public/SwiftShims/RefCount.h b/stdlib/public/SwiftShims/RefCount.h
index 95f102b..0b3b2b7 100644
--- a/stdlib/public/SwiftShims/RefCount.h
+++ b/stdlib/public/SwiftShims/RefCount.h
@@ -12,6 +12,8 @@
 #ifndef SWIFT_STDLIB_SHIMS_REFCOUNT_H
 #define SWIFT_STDLIB_SHIMS_REFCOUNT_H
 
+#include "Visibility.h"
+
 #if !defined(__cplusplus)
 
 // These definitions are placeholders for importing into Swift.
@@ -20,7 +22,7 @@
 #include "SwiftStdint.h"
 
 typedef struct {
-  __swift_uint64_t refCounts __attribute__((__unavailable__));
+  __swift_uint64_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE;
 } InlineRefCounts;
 
 // not __cplusplus
@@ -191,10 +193,9 @@
 }
 
 // FIXME: HACK: copied from HeapObject.cpp
-extern "C" LLVM_LIBRARY_VISIBILITY void
-_swift_release_dealloc(swift::HeapObject *object)
-  SWIFT_CC(RegisterPreservingCC_IMPL)
-    __attribute__((__noinline__, __used__));
+extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
+void _swift_release_dealloc(swift::HeapObject *object)
+SWIFT_CC(RegisterPreservingCC_IMPL);
 
 namespace swift {
 
diff --git a/stdlib/public/SwiftShims/UnicodeShims.h b/stdlib/public/SwiftShims/UnicodeShims.h
index c8c99d8..93253d9 100644
--- a/stdlib/public/SwiftShims/UnicodeShims.h
+++ b/stdlib/public/SwiftShims/UnicodeShims.h
@@ -63,21 +63,21 @@
 _swift_stdlib_ExtendedGraphemeClusterNoBoundaryRulesMatrix;
 
 SWIFT_RUNTIME_STDLIB_INTERFACE
-__attribute__((__pure__)) __swift_int32_t
+SWIFT_READONLY __swift_int32_t
 _swift_stdlib_unicode_compare_utf16_utf16(const __swift_uint16_t *Left,
                                           __swift_int32_t LeftLength,
                                           const __swift_uint16_t *Right,
                                           __swift_int32_t RightLength);
 
 SWIFT_RUNTIME_STDLIB_INTERFACE
-__attribute__((__pure__)) __swift_int32_t
+SWIFT_READONLY __swift_int32_t
 _swift_stdlib_unicode_compare_utf8_utf16(const unsigned char *Left,
                                          __swift_int32_t LeftLength,
                                          const __swift_uint16_t *Right,
                                          __swift_int32_t RightLength);
 
 SWIFT_RUNTIME_STDLIB_INTERFACE
-__attribute__((__pure__)) __swift_int32_t
+SWIFT_READONLY __swift_int32_t
 _swift_stdlib_unicode_compare_utf8_utf8(const unsigned char *Left,
                                         __swift_int32_t LeftLength,
                                         const unsigned char *Right,
diff --git a/stdlib/public/SwiftShims/Visibility.h b/stdlib/public/SwiftShims/Visibility.h
index 555e369..1d36a44 100644
--- a/stdlib/public/SwiftShims/Visibility.h
+++ b/stdlib/public/SwiftShims/Visibility.h
@@ -56,6 +56,18 @@
 #define SWIFT_READNONE
 #endif
 
+#if __has_attribute(always_inline)
+#define SWIFT_ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define SWIFT_ALWAYS_INLINE
+#endif
+
+#if __has_attribute(unavailable)
+#define SWIFT_ATTRIBUTE_UNAVAILABLE __attribute__((__unavailable__))
+#else
+#define SWIFT_ATTRIBUTE_UNAVAILABLE
+#endif
+
 // TODO: support using shims headers in overlays by parameterizing
 // SWIFT_RUNTIME_EXPORT on the library it's exported from, then setting
 // protected vs. default based on the current value of __SWIFT_CURRENT_DYLIB.
diff --git a/stdlib/public/core/RangeReplaceableCollection.swift.gyb b/stdlib/public/core/RangeReplaceableCollection.swift.gyb
index db2461f..ca34ad5 100644
--- a/stdlib/public/core/RangeReplaceableCollection.swift.gyb
+++ b/stdlib/public/core/RangeReplaceableCollection.swift.gyb
@@ -237,10 +237,10 @@
 /// add an empty initializer and the `replaceSubrange(_:with:)` method to your
 /// custom type. `RangeReplaceableCollection` provides default implementations
 /// of all its other methods using this initializer and method. For example,
-/// the `removeSubrange` method is implemented by calling `replaceRange` with
-/// an empty collection for the `newElements` parameter. You can override any
-/// of the protocol's required methods to provide your own custom
-/// implementation.
+/// the `removeSubrange(_:)` method is implemented by calling 
+/// `replaceSubrange(_:with:)` with an empty collection for the `newElements` 
+/// parameter. You can override any of the protocol's required methods to 
+/// provide your own custom implementation.
 public protocol RangeReplaceableCollection
   : _RangeReplaceableIndexable, Collection
 {
diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h
index a9ca348..1de0899 100644
--- a/stdlib/public/runtime/MetadataImpl.h
+++ b/stdlib/public/runtime/MetadataImpl.h
@@ -881,6 +881,7 @@
 
   static OpaqueValue *projectBuffer(ValueBuffer *buffer, const Metadata *self) {
     auto vwtable = self->getValueWitnesses();
+    (void)vwtable;
     if (!IsKnownAllocated && vwtable->isValueInline()) {
       return reinterpret_cast<OpaqueValue*>(buffer);
     } else {
@@ -900,6 +901,7 @@
                                                        ValueBuffer *src,
                                                        const Metadata *self) {
     auto vwtable = self->getValueWitnesses();
+    (void)vwtable;
     if (!IsKnownAllocated && !vwtable->isValueInline()) {
       return Impl::initializeWithTake(reinterpret_cast<OpaqueValue*>(dest),
                                       reinterpret_cast<OpaqueValue*>(src),
diff --git a/stdlib/public/runtime/Reflection.mm b/stdlib/public/runtime/Reflection.mm
index ebeed8c..0a55a03 100644
--- a/stdlib/public/runtime/Reflection.mm
+++ b/stdlib/public/runtime/Reflection.mm
@@ -233,6 +233,8 @@
     case MetadataKind::ErrorObject:
       return "(ErrorType Object)";
   }
+
+  swift_runtime_unreachable("Unhandled MetadataKind in switch.");
 }
 
 SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
diff --git a/stdlib/public/stubs/OptionalBridgingHelper.mm b/stdlib/public/stubs/OptionalBridgingHelper.mm
index f0cc56a..8a71e91 100644
--- a/stdlib/public/stubs/OptionalBridgingHelper.mm
+++ b/stdlib/public/stubs/OptionalBridgingHelper.mm
@@ -36,7 +36,7 @@
 
 - (NSString*)description {
   return [NSString stringWithFormat:@"<%@ %p depth = %u>", [self class],
-                                                           self,
+                                                           (void*)self,
                                                            self->depth];
 }
 
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h
index c44439f..6a509e5 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h
@@ -1,7 +1,7 @@
 #pragma clang assume_nonnull begin
 
 struct __attribute__((swift_name("VeryImportantCStruct"))) SomeCStruct {
-	int field;
+    int field;
 };
 
 #pragma clang assume_nonnull end
diff --git a/test/ClangImporter/objc_factory_method.swift b/test/ClangImporter/objc_factory_method.swift
index b26ff08..fb3bfc5 100644
--- a/test/ClangImporter/objc_factory_method.swift
+++ b/test/ClangImporter/objc_factory_method.swift
@@ -30,6 +30,7 @@
 }
 
 func testFactoryWithLaterIntroducedInit() {
+    // expected-note @-1 4{{add @available attribute to enclosing global function}}
   // Prefer importing more available factory initializer over less
   // less available convenience initializer
   _ = NSHavingConvenienceFactoryAndLaterConvenienceInit(flim:5)
@@ -44,22 +45,19 @@
   // available designated initializer
   _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flim:5) // expected-error {{'init(flim:)' is only available on OS X 10.52 or newer}} 
     // expected-note @-1 {{add 'if #available' version check}}
-    // expected-note @-2 {{add @available attribute to enclosing global function}}
   
   _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flam:5) // expected-error {{'init(flam:)' is only available on OS X 10.52 or newer}}
   // expected-note @-1 {{add 'if #available' version check}}  {{3-63=if #available(OSX 10.52, *) {\n      _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flam:5)\n  \} else {\n      // Fallback on earlier versions\n  \}}}
-  // expected-note @-2 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.52, *)\n}}
 
   
   // Don't prefer more available factory initializer over less
   // available designated initializer
   _ = NSHavingFactoryAndLaterConvenienceInit(flim:5) // expected-error {{'init(flim:)' is only available on OS X 10.52 or newer}} 
   // expected-note @-1 {{add 'if #available' version check}}
-  // expected-note @-2 {{add @available attribute to enclosing global function}}
+  
 
   _ = NSHavingFactoryAndLaterConvenienceInit(flam:5) // expected-error {{'init(flam:)' is only available on OS X 10.52 or newer}} 
   // expected-note @-1 {{add 'if #available' version check}}
-  // expected-note @-2 {{add @available attribute to enclosing global function}}
 
 
   // When both a convenience factory and a convenience initializer have the
diff --git a/test/Constraints/associated_types.swift b/test/Constraints/associated_types.swift
index 2436e92..6dee6f6 100644
--- a/test/Constraints/associated_types.swift
+++ b/test/Constraints/associated_types.swift
@@ -37,3 +37,75 @@
 func spoon<S: Spoon>(_ s: S) {
   let _: S.Runcee?
 }
+
+// SR-4143
+
+protocol SameTypedDefault {
+    associatedtype X
+    associatedtype Y
+    static var x: X { get }
+    static var y: Y { get }
+}
+extension SameTypedDefault where Y == X {
+    static var x: X {
+        return y
+    }
+}
+
+struct UsesSameTypedDefault: SameTypedDefault {
+    static var y: Int {
+        return 0
+    }
+}
+
+protocol XReqt {}
+protocol YReqt {}
+
+protocol SameTypedDefaultWithReqts {
+    associatedtype X: XReqt // expected-note{{}}
+    associatedtype Y: YReqt // expected-note{{}}
+    static var x: X { get }
+    static var y: Y { get }
+}
+extension SameTypedDefaultWithReqts where Y == X {
+    static var x: X {
+        return y
+    }
+}
+
+struct XYType: XReqt, YReqt {}
+struct YType: YReqt {}
+
+struct UsesSameTypedDefaultWithReqts: SameTypedDefaultWithReqts {
+    static var y: XYType { return XYType() }
+}
+
+// expected-error@+1{{does not conform}}
+struct UsesSameTypedDefaultWithoutSatisfyingReqts: SameTypedDefaultWithReqts {
+    static var y: YType { return YType() }
+}
+
+protocol SameTypedDefaultBaseWithReqts {
+    associatedtype X: XReqt // expected-note{{}}
+    static var x: X { get }
+}
+protocol SameTypedDefaultDerivedWithReqts: SameTypedDefaultBaseWithReqts {
+    associatedtype Y: YReqt
+    static var y: Y { get }
+}
+
+extension SameTypedDefaultDerivedWithReqts where Y == X {
+    static var x: X {
+        return y
+    }
+}
+
+struct UsesSameTypedDefaultDerivedWithReqts: SameTypedDefaultDerivedWithReqts {
+    static var y: XYType { return XYType() }
+}
+
+// expected-error@+1{{does not conform}}
+struct UsesSameTypedDefaultDerivedWithoutSatisfyingReqts: SameTypedDefaultDerivedWithReqts {
+    static var y: YType { return YType() }
+}
+
diff --git a/test/DebugInfo/inlined-generics.swift b/test/DebugInfo/inlined-generics.swift
index fc2c84c..3005ee3 100644
--- a/test/DebugInfo/inlined-generics.swift
+++ b/test/DebugInfo/inlined-generics.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -Xllvm -sil-inline-generics=true %s -O -emit-sil -g -o - -emit-ir | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -Xllvm -sil-inline-generics=true %s -O -g -o - -emit-ir | %FileCheck %s
 public protocol P {
   associatedtype DT1
   func getDT() -> DT1
@@ -18,3 +18,38 @@
   // T.DT1 should get substituted with S.DT1.
   // CHECK: ![[META]] = !DILocalVariable(name: "$swift.type.S.DT1"
 }
+
+
+// More complex example -- we inline an alloc_stack that references a VarDecl
+// with generic type.
+
+public protocol Q : class {
+  associatedtype T : Equatable
+
+  var old: T? { get set }
+  var new: T? { get }
+}
+
+@inline(__always)
+public func update<S : Q>(_ s: S) -> (S.T?, S.T?)? {
+  let oldValue = s.old
+  let newValue = s.new
+
+  if oldValue != newValue {
+    s.old = newValue
+    return (oldValue, newValue)
+  } else {
+    return nil
+  }
+}
+
+public class C : Q {
+  public typealias T = String
+
+  public var old: String? = nil
+  public var new: T? = nil
+}
+
+public func updateC(_ c: C) {
+  update(c)
+}
diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt
index 4edae05..17e8779 100644
--- a/test/Demangle/Inputs/manglings.txt
+++ b/test/Demangle/Inputs/manglings.txt
@@ -77,10 +77,12 @@
 _TF3foog3barSi ---> foo.bar.getter : Swift.Int
 _TF3foos3barSi ---> foo.bar.setter : Swift.Int
 _TFC3foo3bar3basfT3zimCS_3zim_T_ ---> foo.bar.bas (zim : foo.zim) -> ()
-_TToFC3foo3bar3basfT3zimCS_3zim_T_ ---> {T} @objc foo.bar.bas (zim : foo.zim) -> ()
-_TTOFSC3fooFTSdSd_Sd ---> {T} @nonobjc __C.foo (Swift.Double, Swift.Double) -> Swift.Double
-_T03foo3barC3basyAA3zimCAE_tFTo ---> {T} @objc foo.bar.bas (zim : foo.zim) -> ()
-_T0SC3fooSdSd_SdtFTO ---> {T} @nonobjc __C.foo (Swift.Double, Swift.Double) -> Swift.Double
+_TToFC3foo3bar3basfT3zimCS_3zim_T_ ---> {T:_TFC3foo3bar3basfT3zimCS_3zim_T_,C} @objc foo.bar.bas (zim : foo.zim) -> ()
+_TTOFSC3fooFTSdSd_Sd ---> {T:_TFSC3fooFTSdSd_Sd} @nonobjc __C.foo (Swift.Double, Swift.Double) -> Swift.Double
+_T03foo3barC3basyAA3zimCAE_tFTo ---> {T:_T03foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas (zim : foo.zim) -> ()
+_T0SC3fooSdSd_SdtFTO ---> {T:_T0SC3fooSdSd_SdtF} @nonobjc __C.foo (Swift.Double, Swift.Double) -> Swift.Double
+_S3foo3barC3basyAA3zimCAE_tFTo ---> {T:_S3foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas (zim : foo.zim) -> ()
+_SSC3fooSdSd_SdtFTO ---> {T:_SSC3fooSdSd_SdtF} @nonobjc __C.foo (Swift.Double, Swift.Double) -> Swift.Double
 _TTDFC3foo3bar3basfT3zimCS_3zim_T_ ---> dynamic foo.bar.bas (zim : foo.zim) -> ()
 _TFC3foo3bar3basfT3zimCS_3zim_T_ ---> foo.bar.bas (zim : foo.zim) -> ()
 _TF3foooi1pFTCS_3barVS_3bas_OS_3zim ---> foo.+ infix (foo.bar, foo.bas) -> foo.zim
@@ -94,31 +96,31 @@
 _TMmC3foo3bar ---> metaclass for foo.bar
 _TMC3foo3bar ---> type metadata for foo.bar
 _TMfC3foo3bar ---> full type metadata for foo.bar
-_TwalC3foo3bar ---> allocateBuffer value witness for foo.bar
-_TwcaC3foo3bar ---> assignWithCopy value witness for foo.bar
-_TwtaC3foo3bar ---> assignWithTake value witness for foo.bar
-_TwdeC3foo3bar ---> deallocateBuffer value witness for foo.bar
-_TwxxC3foo3bar ---> destroy value witness for foo.bar
-_TwXXC3foo3bar ---> destroyBuffer value witness for foo.bar
-_TwCPC3foo3bar ---> initializeBufferWithCopyOfBuffer value witness for foo.bar
-_TwCpC3foo3bar ---> initializeBufferWithCopy value witness for foo.bar
-_TwcpC3foo3bar ---> initializeWithCopy value witness for foo.bar
-_TwTKC3foo3bar ---> initializeBufferWithTakeOfBuffer value witness for foo.bar
-_TwTkC3foo3bar ---> initializeBufferWithTake value witness for foo.bar
-_TwtkC3foo3bar ---> initializeWithTake value witness for foo.bar
-_TwprC3foo3bar ---> projectBuffer value witness for foo.bar
+_TwalC3foo3bar ---> {C} allocateBuffer value witness for foo.bar
+_TwcaC3foo3bar ---> {C} assignWithCopy value witness for foo.bar
+_TwtaC3foo3bar ---> {C} assignWithTake value witness for foo.bar
+_TwdeC3foo3bar ---> {C} deallocateBuffer value witness for foo.bar
+_TwxxC3foo3bar ---> {C} destroy value witness for foo.bar
+_TwXXC3foo3bar ---> {C} destroyBuffer value witness for foo.bar
+_TwCPC3foo3bar ---> {C} initializeBufferWithCopyOfBuffer value witness for foo.bar
+_TwCpC3foo3bar ---> {C} initializeBufferWithCopy value witness for foo.bar
+_TwcpC3foo3bar ---> {C} initializeWithCopy value witness for foo.bar
+_TwTKC3foo3bar ---> {C} initializeBufferWithTakeOfBuffer value witness for foo.bar
+_TwTkC3foo3bar ---> {C} initializeBufferWithTake value witness for foo.bar
+_TwtkC3foo3bar ---> {C} initializeWithTake value witness for foo.bar
+_TwprC3foo3bar ---> {C} projectBuffer value witness for foo.bar
 _TWVC3foo3bar ---> value witness table for foo.bar
 _TWoFC3foo3bar3basFSiSi ---> witness table offset for foo.bar.bas (Swift.Int) -> Swift.Int
 _TWvdvC3foo3bar3basSi ---> direct field offset for foo.bar.bas : Swift.Int
 _TWvivC3foo3bar3basSi ---> indirect field offset for foo.bar.bas : Swift.Int
 _TWPC3foo3barS_8barrables ---> protocol witness table for foo.bar : foo.barrable in Swift
-_TWaC3foo3barS_8barrableS_ ---> protocol witness table accessor for foo.bar : foo.barrable in foo
-_TWlC3foo3barS0_S_8barrableS_ ---> lazy protocol witness table accessor for type foo.bar and conformance foo.bar : foo.barrable in foo
+_TWaC3foo3barS_8barrableS_ ---> {C} protocol witness table accessor for foo.bar : foo.barrable in foo
+_TWlC3foo3barS0_S_8barrableS_ ---> {C} lazy protocol witness table accessor for type foo.bar and conformance foo.bar : foo.barrable in foo
 _TWLC3foo3barS0_S_8barrableS_ ---> lazy protocol witness table cache variable for type foo.bar and conformance foo.bar : foo.barrable in foo
 _TWGC3foo3barS_8barrableS_ ---> generic protocol witness table for foo.bar : foo.barrable in foo
-_TWIC3foo3barS_8barrableS_ ---> instantiation function for generic protocol witness table for foo.bar : foo.barrable in foo
-_TWtC3foo3barS_8barrableS_4fred ---> associated type metadata accessor for fred in foo.bar : foo.barrable in foo
-_TWTC3foo3barS_8barrableS_4fredS_6thomas ---> associated type witness table accessor for fred : foo.thomas in foo.bar : foo.barrable in foo
+_TWIC3foo3barS_8barrableS_ ---> {C} instantiation function for generic protocol witness table for foo.bar : foo.barrable in foo
+_TWtC3foo3barS_8barrableS_4fred ---> {C} associated type metadata accessor for fred in foo.bar : foo.barrable in foo
+_TWTC3foo3barS_8barrableS_4fredS_6thomas ---> {C} associated type witness table accessor for fred : foo.thomas in foo.bar : foo.barrable in foo
 _TFSCg5greenVSC5Color ---> __C.green.getter : __C.Color
 _TIF1t1fFT1iSi1sSS_T_A_ ---> t.(f (i : Swift.Int, s : Swift.String) -> ()).(default argument 0)
 _TIF1t1fFT1iSi1sSS_T_A0_ ---> t.(f (i : Swift.Int, s : Swift.String) -> ()).(default argument 1)
@@ -141,7 +143,7 @@
 _TWa ---> _TWa
 _Twal ---> _Twal
 _T ---> _T
-_TTo ---> {T} _TTo
+_TTo ---> {T:_T} _TTo
 _TC ---> _TC
 _TM ---> _TM
 _TM ---> _TM
@@ -187,10 +189,10 @@
 _TTSgSi__xyz ---> _TTSgSi__xyz
 _TTSr5Si___TF4test7genericurFxx ---> generic not re-abstracted specialization <Swift.Int> of test.generic <A> (A) -> A
 _TTSrq5Si___TF4test7genericurFxx ---> generic not re-abstracted specialization <preserving fragile attribute, Swift.Int> of test.generic <A> (A) -> A
-_TPA__TTRXFo_oSSoSS_dSb_XFo_iSSiSS_dSb_ ---> {T} partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.String, @owned Swift.String) -> (@unowned Swift.Bool) to @callee_owned (@in Swift.String, @in Swift.String) -> (@unowned Swift.Bool)
-_TPAo__TTRGrXFo_dGSPx__dGSPx_zoPs5Error__XFo_iGSPx__iGSPx_zoPS___ ---> {T} partial apply ObjC forwarder for reabstraction thunk helper <A> from @callee_owned (@unowned Swift.UnsafePointer<A>) -> (@unowned Swift.UnsafePointer<A>, @error @owned Swift.Error) to @callee_owned (@in Swift.UnsafePointer<A>) -> (@out Swift.UnsafePointer<A>, @error @owned Swift.Error)
-_T0SSSSSbIxxxd_SSSSSbIxiid_TRTA ---> {T} partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.String, @owned Swift.String) -> (@unowned Swift.Bool) to @callee_owned (@in Swift.String, @in Swift.String) -> (@unowned Swift.Bool)
-_T0SPyxGSPyxGs5Error_pIxydzo_SPyxGSPyxGsAA_pIxirzo_lTRTa ---> {T} partial apply ObjC forwarder for reabstraction thunk helper <A> from @callee_owned (@unowned Swift.UnsafePointer<A>) -> (@unowned Swift.UnsafePointer<A>, @error @owned Swift.Error) to @callee_owned (@in Swift.UnsafePointer<A>) -> (@out Swift.UnsafePointer<A>, @error @owned Swift.Error)
+_TPA__TTRXFo_oSSoSS_dSb_XFo_iSSiSS_dSb_ ---> {T:_TTRXFo_oSSoSS_dSb_XFo_iSSiSS_dSb_} partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.String, @owned Swift.String) -> (@unowned Swift.Bool) to @callee_owned (@in Swift.String, @in Swift.String) -> (@unowned Swift.Bool)
+_TPAo__TTRGrXFo_dGSPx__dGSPx_zoPs5Error__XFo_iGSPx__iGSPx_zoPS___ ---> {T:_TTRGrXFo_dGSPx__dGSPx_zoPs5Error__XFo_iGSPx__iGSPx_zoPS___} partial apply ObjC forwarder for reabstraction thunk helper <A> from @callee_owned (@unowned Swift.UnsafePointer<A>) -> (@unowned Swift.UnsafePointer<A>, @error @owned Swift.Error) to @callee_owned (@in Swift.UnsafePointer<A>) -> (@out Swift.UnsafePointer<A>, @error @owned Swift.Error)
+_T0SSSSSbIxxxd_SSSSSbIxiid_TRTA ---> {T:_T0SSSSSbIxxxd_SSSSSbIxiid_TR} partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.String, @owned Swift.String) -> (@unowned Swift.Bool) to @callee_owned (@in Swift.String, @in Swift.String) -> (@unowned Swift.Bool)
+_T0SPyxGSPyxGs5Error_pIxydzo_SPyxGSPyxGsAA_pIxirzo_lTRTa ---> {T:_T0SPyxGSPyxGs5Error_pIxydzo_SPyxGSPyxGsAA_pIxirzo_lTR} partial apply ObjC forwarder for reabstraction thunk helper <A> from @callee_owned (@unowned Swift.UnsafePointer<A>) -> (@unowned Swift.UnsafePointer<A>, @error @owned Swift.Error) to @callee_owned (@in Swift.UnsafePointer<A>) -> (@out Swift.UnsafePointer<A>, @error @owned Swift.Error)
 _TiC4Meow5MyCls9subscriptFT1iSi_Sf ---> Meow.MyCls.subscript (i : Swift.Int) -> Swift.Float
 _TF8manglingX22egbpdajGbuEbxfgehfvwxnFT_T_ ---> mangling.ليهمابتكلموشعربي؟ () -> ()
 _TF8manglingX24ihqwcrbEcvIaIdqgAFGpqjyeFT_T_ ---> mangling.他们为什么不说中文 () -> ()
diff --git a/test/Driver/Dependencies/Inputs/only-skip-once/file1.swift b/test/Driver/Dependencies/Inputs/only-skip-once/file1.swift
new file mode 100644
index 0000000..3ebf6e5
--- /dev/null
+++ b/test/Driver/Dependencies/Inputs/only-skip-once/file1.swift
@@ -0,0 +1,3 @@
+public class Class1 {
+  public var Var1 : Int?
+}
diff --git a/test/Driver/Dependencies/Inputs/only-skip-once/file2.swift b/test/Driver/Dependencies/Inputs/only-skip-once/file2.swift
new file mode 100644
index 0000000..5b579dd
--- /dev/null
+++ b/test/Driver/Dependencies/Inputs/only-skip-once/file2.swift
@@ -0,0 +1,3 @@
+public class Class2 {
+  public var Var2c : Class1?
+}
diff --git a/test/Driver/Dependencies/Inputs/only-skip-once/main.swift b/test/Driver/Dependencies/Inputs/only-skip-once/main.swift
new file mode 100644
index 0000000..214696a
--- /dev/null
+++ b/test/Driver/Dependencies/Inputs/only-skip-once/main.swift
@@ -0,0 +1,2 @@
+var x = Class1()
+var y = Class2()
diff --git a/test/Driver/Dependencies/Inputs/only-skip-once/output-file-map.json b/test/Driver/Dependencies/Inputs/only-skip-once/output-file-map.json
new file mode 100644
index 0000000..32d28d7
--- /dev/null
+++ b/test/Driver/Dependencies/Inputs/only-skip-once/output-file-map.json
@@ -0,0 +1,23 @@
+{
+  "": {
+    "swift-dependencies": "master.swiftdeps"
+  },
+  "main.swift": {
+    "dependencies": "main.d",
+    "object": "main.o",
+    "swiftmodule": "main~partial.swiftmodule",
+    "swift-dependencies": "main.swiftdeps"
+  },
+  "file1.swift": {
+    "dependencies": "file1.d",
+    "object": "file1.o",
+    "swiftmodule": "file1~partial.swiftmodule",
+    "swift-dependencies": "file1.swiftdeps"
+  },
+  "file2.swift": {
+    "dependencies": "file2.d",
+    "object": "file2.o",
+    "swiftmodule": "file2~partial.swiftmodule",
+    "swift-dependencies": "file2.swiftdeps"
+  }
+}
diff --git a/test/Driver/Dependencies/driver-show-incremental-arguments.swift b/test/Driver/Dependencies/driver-show-incremental-arguments.swift
index 19fdb7a..3a4c37f 100644
--- a/test/Driver/Dependencies/driver-show-incremental-arguments.swift
+++ b/test/Driver/Dependencies/driver-show-incremental-arguments.swift
@@ -14,9 +14,9 @@
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-INCREMENTAL %s
 // CHECK-INCREMENTAL-NOT: Incremental compilation has been disabled
-// CHECK-INCREMENTAL: Queuing main.swift (initial)
+// CHECK-INCREMENTAL: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -g -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-ARGS-MISMATCH %s
 // CHECK-ARGS-MISMATCH: Incremental compilation has been disabled{{.*}}different arguments
-// CHECK-ARGS-MISMATCH-NOT: Queuing main.swift (initial)
+// CHECK-ARGS-MISMATCH-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
diff --git a/test/Driver/Dependencies/driver-show-incremental-conflicting-arguments.swift b/test/Driver/Dependencies/driver-show-incremental-conflicting-arguments.swift
index 8d54095..e9b2e93 100644
--- a/test/Driver/Dependencies/driver-show-incremental-conflicting-arguments.swift
+++ b/test/Driver/Dependencies/driver-show-incremental-conflicting-arguments.swift
@@ -14,18 +14,18 @@
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-INCREMENTAL %s
 // CHECK-INCREMENTAL-NOT: Incremental compilation has been disabled
-// CHECK-INCREMENTAL: Queuing main.swift (initial)
+// CHECK-INCREMENTAL: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -whole-module-optimization -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-WMO %s
 // CHECK-WMO: Incremental compilation has been disabled{{.*}}whole module optimization
-// CHECK-WMO-NOT: Queuing main.swift (initial)
+// CHECK-WMO-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -embed-bitcode -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-BITCODE %s
 // CHECK-BITCODE: Incremental compilation has been disabled{{.*}}LLVM IR bitcode
-// CHECK-BITCODE-NOT: Queuing main.swift (initial)
+// CHECK-BITCODE-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -whole-module-optimization -embed-bitcode -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-WMO-AND-BITCODE %s
 // CHECK-WMO-AND-BITCODE: Incremental compilation has been disabled{{.*}}whole module optimization
 // CHECK-WMO-AND-BITCODE-NOT: Incremental compilation has been disabled
-// CHECK-WMO-AND-BITCODE-NOT: Queuing main.swift (initial)
+// CHECK-WMO-AND-BITCODE-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
diff --git a/test/Driver/Dependencies/driver-show-incremental-inputs.swift b/test/Driver/Dependencies/driver-show-incremental-inputs.swift
index 27d3e1b..931eff9 100644
--- a/test/Driver/Dependencies/driver-show-incremental-inputs.swift
+++ b/test/Driver/Dependencies/driver-show-incremental-inputs.swift
@@ -14,10 +14,10 @@
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-INCREMENTAL %s
 // CHECK-INCREMENTAL-NOT: Incremental compilation has been disabled
-// CHECK-INCREMENTAL: Queuing main.swift (initial)
+// CHECK-INCREMENTAL: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-INPUTS-MISMATCH %s
 // CHECK-INPUTS-MISMATCH: Incremental compilation has been disabled{{.*}}inputs
 // CHECK-INPUTS-MISMATCH: ./other.swift
-// CHECK-INPUTS-MISMATCH-NOT: Queuing main.swift (initial)
+// CHECK-INPUTS-MISMATCH-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
diff --git a/test/Driver/Dependencies/driver-show-incremental-malformed.swift b/test/Driver/Dependencies/driver-show-incremental-malformed.swift
index 7885c1b..b3911ae 100644
--- a/test/Driver/Dependencies/driver-show-incremental-malformed.swift
+++ b/test/Driver/Dependencies/driver-show-incremental-malformed.swift
@@ -13,7 +13,7 @@
 // RUN: echo '{version: "'$(%swiftc_driver_plain -version | head -n1)'", inputs: {"./main.swift": [443865900, 0], "./other.swift": [443865900, 0]}}' > %t/main~buildrecord.swiftdeps
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-INCREMENTAL %s
 // CHECK-INCREMENTAL-NOT: Incremental compilation has been disabled
-// CHECK-INCREMENTAL: Queuing main.swift (initial)
+// CHECK-INCREMENTAL: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: rm %t/main~buildrecord.swiftdeps && touch %t/main~buildrecord.swiftdeps
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -g -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-MALFORMED %s
@@ -22,7 +22,7 @@
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -g -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-MALFORMED %s
 
 // CHECK-MALFORMED: Incremental compilation has been disabled{{.*}}malformed build record file
-// CHECK-MALFORMED-NOT: Queuing main.swift (initial)
+// CHECK-MALFORMED-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: echo '{version, inputs: {"./main.swift": [443865900, 0], "./other.swift": [443865900, 0]}}' > %t/main~buildrecord.swiftdeps
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -g -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-MISSING-KEY %s
@@ -31,5 +31,5 @@
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -g -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-MISSING-KEY %s
 
 // CHECK-MISSING-KEY: Incremental compilation has been disabled{{.*}}malformed build record file{{.*}}Malformed value for key
-// CHECK-MISSING-KEY-NOT: Queuing main.swift (initial)
+// CHECK-MISSING-KEY-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
diff --git a/test/Driver/Dependencies/driver-show-incremental-mutual.swift b/test/Driver/Dependencies/driver-show-incremental-mutual.swift
index b9f1765..2b8fd3b 100644
--- a/test/Driver/Dependencies/driver-show-incremental-mutual.swift
+++ b/test/Driver/Dependencies/driver-show-incremental-mutual.swift
@@ -4,14 +4,14 @@
 // RUN: touch -t 201401240005 %t/*
 
 // RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v -driver-show-incremental 2>&1 | %FileCheck -check-prefix=CHECK-FIRST %s
-// CHECK-FIRST: Queuing main.swift (initial)
+// CHECK-FIRST: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v -driver-show-incremental 2>&1 | %FileCheck -check-prefix=CHECK-SECOND %s
 // CHECK-SECOND-NOT: Queuing
 
 // RUN: touch -t 201401240006 %t/other.swift
 // RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v -driver-show-incremental 2>&1 | %FileCheck -check-prefix=CHECK-THIRD %s
-// CHECK-THIRD: Queuing other.swift (initial)
-// CHECK-THIRD: Queuing main.swift because of the initial set:
+// CHECK-THIRD: Queuing (initial): {compile: other.o <= other.swift}
+// CHECK-THIRD: Queuing because of the initial set: {compile: main.o <= main.swift}
 // CHECK-THIRD-NEXT: other.swift provides top-level name 'a'
 
diff --git a/test/Driver/Dependencies/driver-show-incremental-swift-version.swift b/test/Driver/Dependencies/driver-show-incremental-swift-version.swift
index 46c401e..79d2d37 100644
--- a/test/Driver/Dependencies/driver-show-incremental-swift-version.swift
+++ b/test/Driver/Dependencies/driver-show-incremental-swift-version.swift
@@ -14,12 +14,12 @@
 // RUN: echo '{version: "'$(%swiftc_driver_plain -version | head -n1)'", inputs: {"./main.swift": [443865900, 0], "./other.swift": [443865900, 0]}}' > %t/main~buildrecord.swiftdeps
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-INCREMENTAL %s
 // CHECK-INCREMENTAL-NOT: Incremental compilation has been disabled
-// CHECK-INCREMENTAL: Queuing main.swift (initial)
+// CHECK-INCREMENTAL: Queuing (initial): {compile: main.o <= main.swift}
 
 // RUN: echo '{version: "bogus", inputs: {"./main.swift": [443865900, 0], "./other.swift": [443865900, 0]}}' > %t/main~buildrecord.swiftdeps
 // RUN: cd %t && %swiftc_driver -driver-use-frontend-path %S/Inputs/update-dependencies.py -c ./main.swift ./other.swift -module-name main -incremental -v -driver-show-incremental -output-file-map %t/output.json | %FileCheck --check-prefix CHECK-VERSION-MISMATCH %s
 // CHECK-VERSION-MISMATCH: Incremental compilation has been disabled{{.*}}compiler version mismatch
 // CHECK-VERSION-MISMATCH: Compiling with:
 // CHECK-VERSION-MISMATCH: Previously compiled with: bogus
-// CHECK-VERSION-MISMATCH-NOT: Queuing main.swift (initial)
+// CHECK-VERSION-MISMATCH-NOT: Queuing (initial): {compile: main.o <= main.swift}
 
diff --git a/test/Driver/Dependencies/only-skip-once.swift b/test/Driver/Dependencies/only-skip-once.swift
new file mode 100644
index 0000000..391e24b
--- /dev/null
+++ b/test/Driver/Dependencies/only-skip-once.swift
@@ -0,0 +1,21 @@
+// XFAIL: linux
+// RUN: rm -rf %t && cp -r %S/Inputs/only-skip-once/ %t
+// RUN: touch -t 201401240005 %t/*
+
+// RUN: cd %t && %swiftc_driver -driver-show-job-lifecycle -output-file-map %t/output-file-map.json -incremental main.swift file1.swift file2.swift -j1 2>&1 | %FileCheck -check-prefix=CHECK-INITIAL %s
+
+// CHECK-INITIAL-NOT: warning
+// CHECK-INITIAL: Job finished: {compile: main.o <= main.swift}
+// CHECK-INITIAL: Job finished: {compile: file1.o <= file1.swift}
+// CHECK-INITIAL: Job finished: {compile: file2.o <= file2.swift}
+// CHECK-INITIAL: Job finished: {link: main <= main.o file1.o file2.o}
+
+// RUN: touch -t 201401240006 %t/file2.swift
+// RUN: cd %t && %swiftc_driver -driver-show-job-lifecycle -output-file-map %t/output-file-map.json -incremental main.swift file1.swift file2.swift -j1 2>&1 | %FileCheck -check-prefix=CHECK-REBUILD %s
+
+// We should skip the main and file1 rebuilds here, but we should only note skipping them _once_
+// CHECK-REBUILD: Job finished: {compile: file2.o <= file2.swift}
+// CHECK-REBUILD: Job skipped: {compile: main.o <= main.swift}
+// CHECK-REBUILD: Job skipped: {compile: file1.o <= file1.swift}
+// CHECK-REBUILD: Job finished: {link: main <= main.o file1.o file2.o}
+// CHECK-REBUILD-NOT: Job skipped:
diff --git a/test/Driver/driver-time-compilation.swift b/test/Driver/driver-time-compilation.swift
index 198ff9b..78a7555 100644
--- a/test/Driver/driver-time-compilation.swift
+++ b/test/Driver/driver-time-compilation.swift
@@ -5,6 +5,6 @@
 // CHECK: Total Execution Time: {{[0-9]+}}.{{[0-9]+}} seconds ({{[0-9]+}}.{{[0-9]+}} wall clock)
 // CHECK: ---Wall Time---
 // CHECK: --- Name ---
-// CHECK: compile {{.*}}driver-time-compilation.swift
-// CHECK-MULTIPLE: compile {{.*}}empty.swift
+// CHECK: {compile: {{.*}}driver-time-compilation.swift}
+// CHECK-MULTIPLE: {compile: {{.*}}empty.swift}
 // CHECK: {{[0-9]+}}.{{[0-9]+}} (100.0%)  Total
diff --git a/test/Driver/swift-version-default.swift b/test/Driver/swift-version-default.swift
index 6a9ec1f..029496a 100644
--- a/test/Driver/swift-version-default.swift
+++ b/test/Driver/swift-version-default.swift
@@ -11,8 +11,26 @@
 jkl
 #endif
 
+#if swift(>=3.1)
+asdf // expected-error {{use of unresolved identifier}}
+#else
+jkl
+#endif
+
 #if swift(>=4)
 aoeu
 #else
 htn // expected-error {{use of unresolved identifier}}
 #endif
+
+#if swift(>=4.1)
+aoeu
+#else
+htn // expected-error {{use of unresolved identifier}}
+#endif
+
+#if swift(>=5)
+aoeu
+#else
+htn // expected-error {{use of unresolved identifier}}
+#endif
diff --git a/test/Driver/swift-version.swift b/test/Driver/swift-version.swift
index 06817a0..129a2be 100644
--- a/test/Driver/swift-version.swift
+++ b/test/Driver/swift-version.swift
@@ -1,4 +1,3 @@
-// RUN: %target-swiftc_driver -swift-version 3 %s
 // RUN: not %target-swiftc_driver -swift-version foo %s 2>&1 | %FileCheck --check-prefix BAD %s
 // RUN: not %target-swiftc_driver -swift-version 1 %s 2>&1 | %FileCheck --check-prefix BAD %s
 // RUN: not %target-swiftc_driver -swift-version 2 %s 2>&1 | %FileCheck --check-prefix BAD %s
@@ -9,10 +8,50 @@
 // RUN: not %target-swiftc_driver -swift-version 3.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_3 %s
 // RUN: not %target-swiftc_driver -swift-version 4.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_4 %s
 
+// RUN: not %target-swiftc_driver -swift-version 3 -typecheck %s 2>&1 | %FileCheck --check-prefix ERROR_3 %s
+// RUN: not %target-swiftc_driver -swift-version 4 -typecheck %s 2>&1 | %FileCheck --check-prefix ERROR_4 %s
+
 // BAD: invalid value
 // BAD: note: valid arguments to '-swift-version' are '3', '4'
 
 // FIXIT_3: use major version, as in '-swift-version 3'
 // FIXIT_4: use major version, as in '-swift-version 4'
 
-let x = 1
+
+#if swift(>=3)
+asdf
+// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
+// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
+#else
+jkl
+#endif
+
+#if swift(>=3.1)
+asdf
+// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
+// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
+#else
+jkl
+#endif
+
+#if swift(>=4)
+asdf // ERROR_4: [[@LINE]]:1: error: {{use of unresolved identifier}}
+#else
+jkl // ERROR_3: [[@LINE]]:1: error: {{use of unresolved identifier}}
+#endif
+
+#if swift(>=4.1)
+asdf
+#else
+jkl
+// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
+// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
+#endif
+
+#if swift(>=5)
+asdf
+#else
+jkl
+// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
+// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
+#endif
diff --git a/test/FixCode/fixits-switch.swift b/test/FixCode/fixits-switch.swift
index 591d5a5..7309a6a 100644
--- a/test/FixCode/fixits-switch.swift
+++ b/test/FixCode/fixits-switch.swift
@@ -33,6 +33,12 @@
   case e1(a: Int, s: Int)
   case e2(a: Int)
   case e3(a: Int)
+  case e4(_: Int)
+  case e5(_: Int, _: Int)
+  case e6(a : Int, _: Int)
+  case e7
+  case e8(a : Int, Int, Int)
+  case e9(Int, Int, Int)
 }
 
 func foo4(_ e : E2) -> Int {
diff --git a/test/FixCode/fixits-switch.swift.result b/test/FixCode/fixits-switch.swift.result
index 0b0cfcd..0e6a53e 100644
--- a/test/FixCode/fixits-switch.swift.result
+++ b/test/FixCode/fixits-switch.swift.result
@@ -38,14 +38,26 @@
   case e1(a: Int, s: Int)
   case e2(a: Int)
   case e3(a: Int)
+  case e4(_: Int)
+  case e5(_: Int, _: Int)
+  case e6(a : Int, _: Int)
+  case e7
+  case e8(a : Int, Int, Int)
+  case e9(Int, Int, Int)
 }
 
 func foo4(_ e : E2) -> Int {
   switch e {
   case .e2:
     return 1
-  case .e1: <#Code#>
-case .e3: <#Code#>
+  case .e1(let a, let s): <#Code#>
+case .e3(let a): <#Code#>
+case .e4(_): <#Code#>
+case .e5(_, _): <#Code#>
+case .e6(let a, _): <#Code#>
+case .e7: <#Code#>
+case .e8(let a, _, _): <#Code#>
+case .e9(_, _, _): <#Code#>
 }
 }
 
@@ -61,8 +73,14 @@
   switch e {
   case let .e1(x, y):
     return x + y
-  case .e2: <#Code#>
-case .e3: <#Code#>
+  case .e2(let a): <#Code#>
+case .e3(let a): <#Code#>
+case .e4(_): <#Code#>
+case .e5(_, _): <#Code#>
+case .e6(let a, _): <#Code#>
+case .e7: <#Code#>
+case .e8(let a, _, _): <#Code#>
+case .e9(_, _, _): <#Code#>
 }
 }
 
@@ -71,6 +89,11 @@
   case .e2(1): return 0
   case .e1: return 0
   case .e3: return 0
-  default: <#Code#>
+  case .e4(_): <#Code#>
+case .e5(_, _): <#Code#>
+case .e6(let a, _): <#Code#>
+case .e7: <#Code#>
+case .e8(let a, _, _): <#Code#>
+case .e9(_, _, _): <#Code#>
 }
 }
\ No newline at end of file
diff --git a/test/IRGen/Inputs/witness_table_multifile_2.swift b/test/IRGen/Inputs/witness_table_multifile_2.swift
index feaf71f..7730f0b 100644
--- a/test/IRGen/Inputs/witness_table_multifile_2.swift
+++ b/test/IRGen/Inputs/witness_table_multifile_2.swift
@@ -9,3 +9,6 @@
 }
 
 func go() -> P { return X("hello") }
+
+protocol ProtocolOnlyUsedAsAType {
+}
diff --git a/test/IRGen/witness_table_multifile.swift b/test/IRGen/witness_table_multifile.swift
index 95d727e..f5a9b4b 100644
--- a/test/IRGen/witness_table_multifile.swift
+++ b/test/IRGen/witness_table_multifile.swift
@@ -11,3 +11,9 @@
   // CHECK-NEXT: getelementptr inbounds i8*, i8** [[WITNESS_TABLE]], i32 3
   go().foo()
 }
+
+// Ensure that protocols from other files get fully validated even
+// when they're only used as types.
+func useAProtocol() -> ProtocolOnlyUsedAsAType? {
+  return nil
+}
\ No newline at end of file
diff --git a/test/Index/expressions.swift b/test/Index/expressions.swift
new file mode 100644
index 0000000..bf2c1b1
--- /dev/null
+++ b/test/Index/expressions.swift
@@ -0,0 +1,15 @@
+// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s | %FileCheck %s
+
+protocol P1 {}
+
+// CHECK: [[@LINE+1]]:8 | struct/Swift | S1 | [[S1_USR:.*]] | Def
+struct S1 : P1 {}
+
+func test(_ o: P1?) {
+  switch o {
+  // CHECK-NOT: [[@LINE+2]]:17 | enumerator/Swift | some |
+  // CHECK: [[@LINE+1]]:17 | struct/Swift | S1 | [[S1_USR]] | Ref
+  case let s as S1:
+    test(s)
+  }
+}
diff --git a/test/Index/kinds.swift b/test/Index/kinds.swift
index 1ddd0bf..55d8d43 100644
--- a/test/Index/kinds.swift
+++ b/test/Index/kinds.swift
@@ -214,3 +214,13 @@
   @GKInspectable var gkString = "gk"
   // CHECK: [[@LINE-1]]:22 | instance-property(GKI)/Swift | gkString |
 }
+
+// CHECK: [[@LINE+1]]:7 | class/Swift | C1 | [[C1_USR:.*]] | Def | rel: 0
+class C1 {}
+// CHECK: [[@LINE+1]]:11 | type-alias/Swift | C1Alias | [[C1Alias_USR:.*]] | Def | rel: 0
+typealias C1Alias = C1
+// CHECK: [[@LINE+4]]:7 | class/Swift | SubC1 | [[SubC1_USR:.*]] | Def | rel: 0
+// CHECK: [[@LINE+3]]:15 | type-alias/Swift | C1Alias | [[C1Alias_USR]] | Ref | rel: 0
+// CHECK: [[@LINE+2]]:15 | class/Swift | C1 | [[C1_USR]] | Ref,Impl,RelBase | rel: 1
+// CHECK-NEXT: RelBase | SubC1 | [[SubC1_USR]]
+class SubC1 : C1Alias {}
diff --git a/test/Index/roles.swift b/test/Index/roles.swift
index 757a19a..be4a21b 100644
--- a/test/Index/roles.swift
+++ b/test/Index/roles.swift
@@ -134,27 +134,18 @@
   }
 }
 
-class AClass {
+class AClass { // used for references only
   var y: AStruct;
   var z: [Int]
-
   init(x: Int) {
     y = AStruct(x: x)
     self.z = [1, 2, 3]
   }
-
   subscript(index: Int) -> Int {
-    get {
-      return z[0]
-    }
-    set {
-      z[0] = newValue
-    }
+    get { return z[0] }
+    set { z[0] = newValue }
   }
-
-  func foo() -> Int {
-    return z[0]
-  }
+  func foo() -> Int { return z[0] }
 }
 
 let _ = AClass.foo
@@ -168,14 +159,29 @@
 // CHECK: [[@LINE-1]]:21 | instance-property/subscript/Swift | subscript(_:) | s:14swift_ide_test6AClassC9subscriptSiSici | Ref,Writ | rel: 0
 // CHECK: [[@LINE-2]]:21 | function/acc-set/Swift | setter:subscript(_:) | s:14swift_ide_test6AClassC9subscriptSiSicfs | Ref,Call,Dyn,Impl,RelRec | rel: 1
 
+// RelationBaseOf, RelationOverrideOf
+
+protocol X {}
+// CHECK: [[@LINE-1]]:10 | protocol/Swift | X | [[X_USR:.*]] | Def | rel: 0
+
+class ImplementsX : X {}
+// CHECK: [[@LINE-1]]:7 | class/Swift | ImplementsX | [[ImplementsX_USR:.*]] | Def | rel: 0
+// CHECK: [[@LINE-2]]:21 | protocol/Swift | X | [[X_USR]] | Ref,RelBase | rel: 1
+// CHECK-NEXT: RelBase | ImplementsX | [[ImplementsX_USR]]
+
 protocol AProtocol {
   // CHECK: [[@LINE-1]]:10 | protocol/Swift | AProtocol | [[AProtocol_USR:.*]] | Def | rel: 0
+
+  associatedtype T : X
+  // CHECK: [[@LINE-1]]:18 | type-alias/associated-type/Swift | T | s:14swift_ide_test9AProtocolP1T | Def,RelChild | rel: 1
+  // CHECK-NEXT: RelChild | AProtocol | [[AProtocol_USR]]
+  // CHECK: [[@LINE-3]]:22 | protocol/Swift | X | [[X_USR]] | Ref | rel: 0
+
   func foo() -> Int
   // CHECK: [[@LINE-1]]:8 | instance-method/Swift | foo() | s:14swift_ide_test9AProtocolP3fooSiyF | Def,RelChild | rel: 1
   // CHECK-NEXT: RelChild | AProtocol | s:14swift_ide_test9AProtocolP
 }
 
-// RelationBaseOf, RelationOverrideOf
 class ASubClass : AClass, AProtocol {
 // CHECK: [[@LINE-1]]:7 | class/Swift | ASubClass | s:14swift_ide_test9ASubClassC | Def | rel: 0
 // CHECK: [[@LINE-2]]:19 | class/Swift | AClass | s:14swift_ide_test6AClassC | Ref,RelBase | rel: 1
@@ -183,6 +189,8 @@
 // CHECK: [[@LINE-4]]:27 | protocol/Swift | AProtocol | s:14swift_ide_test9AProtocolP | Ref,RelBase | rel: 1
 // CHECK-NEXT: RelBase | ASubClass | s:14swift_ide_test9ASubClassC
 
+  typealias T = ImplementsX
+
   override func foo() -> Int {
     // CHECK: [[@LINE-1]]:17 | instance-method/Swift | foo() | s:14swift_ide_test9ASubClassC3fooSiyF | Def,RelChild,RelOver | rel: 3
     // CHECK-NEXT: RelOver | foo() | s:14swift_ide_test6AClassC3fooSiyF
@@ -216,7 +224,9 @@
   // CHECK: [[@LINE-4]]:27 | protocol/Swift | AProtocol | [[AProtocol_USR]] | Ref,RelBase | rel: 1
   // CHECK-NEXT: RelBase | InnerS | [[EXT_INNERS_USR]]
   // CHECK: [[@LINE-6]]:11 | struct/Swift | OuterS | [[OUTERS_USR]] | Ref | rel: 0
-  func foo() {}
+
+  typealias T = ImplementsX
+  func foo() -> Int { return 1 }
 }
 
 var anInstance = AClass(x: 1)
diff --git a/test/Inputs/clang-importer-sdk/usr/include/dispatch.h b/test/Inputs/clang-importer-sdk/usr/include/dispatch.h
index 63ceaf9..9c0aa3c 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/dispatch.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/dispatch.h
@@ -2,15 +2,21 @@
 
 @protocol OS_dispatch_object <NSObject>
 @end
-typedef NSObject <OS_dispatch_object> *dispatch_object_t;
+@interface OS_dispatch_object: NSObject <OS_dispatch_object>
+@end
+typedef OS_dispatch_object *dispatch_object_t;
 
 @protocol OS_dispatch_queue <OS_dispatch_object>
 @end
-typedef NSObject <OS_dispatch_queue> *dispatch_queue_t;
+@interface OS_dispatch_queue: OS_dispatch_object <OS_dispatch_object>
+@end
+typedef OS_dispatch_queue *dispatch_queue_t;
 
 @protocol OS_dispatch_source <OS_dispatch_object>
 @end
-typedef NSObject <OS_dispatch_source> *dispatch_source_t;
+@interface OS_dispatch_source: OS_dispatch_object <OS_dispatch_object>
+@end
+typedef OS_dispatch_source *dispatch_source_t;
 
 typedef void (^dispatch_block_t)(void);
 
diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil
index ad8b308..4d141b8 100644
--- a/test/SIL/Parser/basic.sil
+++ b/test/SIL/Parser/basic.sil
@@ -1574,6 +1574,22 @@
   return %28 : $()
 }
 
+// CHECK-LABEL: sil @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+// CHECK: end_lifetime {{%.*}} : $Builtin.NativeObject
+sil @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : $Builtin.NativeObject):
+  end_lifetime %0 : $Builtin.NativeObject
+  return undef : $()
+}
+
+// CHECK-LABEL: sil @test_unchecked_ownership_conversion : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+// CHECK: unchecked_ownership_conversion {{%.*}} : $Builtin.NativeObject, @guaranteed to @owned
+sil @test_unchecked_ownership_conversion : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+bb0(%0 : $Builtin.NativeObject):
+  %1 = unchecked_ownership_conversion %0 : $Builtin.NativeObject, @guaranteed to @owned
+  return undef : $()
+}
+
 // CHECK-LABEL: sil_vtable Foo {
 // CHECK: #Foo.subscript!getter.1: {{.*}} : hidden _TFC3tmp3Foog9subscriptFTVs5Int32S1__S1_
 // CHECK: #Foo.subscript!setter.1: {{.*}} : _TFC3tmp3Foos9subscriptFTVs5Int32S1__S1_
diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil
new file mode 100644
index 0000000..9ac3d90
--- /dev/null
+++ b/test/SIL/Serialization/basic.sil
@@ -0,0 +1,24 @@
+// First parse this and then emit a *.sib. Then read in the *.sib, then recreate
+// RUN: rm -rfv %t
+// RUN: mkdir %t
+// RUN: %target-sil-opt %s -emit-sib -o %t/tmp.sib -module-name borrow
+// RUN: %target-sil-opt %t/tmp.sib -o %t/tmp.2.sib -module-name borrow
+// RUN: %target-sil-opt %t/tmp.2.sib -module-name borrow | %FileCheck %s
+
+import Builtin
+
+// CHECK-LABEL: sil @test_unchecked_ownership_conversion : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+// CHECK: unchecked_ownership_conversion {{%.*}} : $Builtin.NativeObject, @guaranteed to @owned
+sil @test_unchecked_ownership_conversion : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+bb0(%0 : $Builtin.NativeObject):
+  unchecked_ownership_conversion %0 : $Builtin.NativeObject, @guaranteed to @owned
+  return undef : $()
+}
+
+// CHECK-LABEL: sil @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+// CHECK: end_lifetime {{%.*}} : $Builtin.NativeObject
+sil @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : $Builtin.NativeObject):
+  end_lifetime %0 : $Builtin.NativeObject
+  return undef : $()
+}
diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift
index 85097a1..516d34e 100644
--- a/test/SILGen/dynamic_self.swift
+++ b/test/SILGen/dynamic_self.swift
@@ -249,6 +249,75 @@
   _ = Factory.staticNewInstance
 }
 
+class FactoryFactory {
+
+  // CHECK-LABEL: sil hidden @_T012dynamic_self07FactoryC0C11newInstanceACXDyFZ : $@convention(method) (@thick FactoryFactory.Type) -> @owned FactoryFactory
+  static func newInstance() -> Self {
+    // CHECK: bb0(%0 : $@thick FactoryFactory.Type):
+
+    // CHECK: [[METATYPE:%.*]] = value_metatype $@thick @dynamic_self FactoryFactory.Type.Type, %0 : $@thick FactoryFactory.Type
+    // CHECK: [[ANY:%.*]] = init_existential_metatype [[METATYPE]] : $@thick @dynamic_self FactoryFactory.Type.Type, $@thick Any.Type
+    let _: Any.Type = type(of: self)
+
+    // CHECK: unreachable
+  }
+}
+
+// Super call to a method returning Self
+class Base {
+  required init() {}
+
+  func returnsSelf() -> Self {
+    return self
+  }
+
+  static func returnsSelfStatic() -> Self {
+    return self.init()
+  }
+}
+
+class Derived : Base {
+  // CHECK-LABEL: sil hidden @_T012dynamic_self7DerivedC9superCallyyF : $@convention(method) (@guaranteed Derived) -> ()
+  // CHECK: [[SELF:%.*]] = copy_value %0
+  // CHECK: [[SUPER:%.*]] = upcast [[SELF]] : $Derived to $Base
+  // CHECK: [[METHOD:%.*]] = function_ref @_T012dynamic_self4BaseC11returnsSelfACXDyF
+  // CHECK: apply [[METHOD]]([[SUPER]])
+  // CHECK: return
+  func superCall() {
+    super.returnsSelf()
+  }
+
+  // CHECK-LABEL: sil hidden @_T012dynamic_self7DerivedC15superCallStaticyyFZ : $@convention(method) (@thick Derived.Type) -> ()
+  // CHECK: [[SUPER:%.*]] = upcast %0 : $@thick Derived.Type to $@thick Base.Type
+  // CHECK: [[METHOD:%.*]] = function_ref @_T012dynamic_self4BaseC17returnsSelfStaticACXDyFZ
+  // CHECK: apply [[METHOD]]([[SUPER]])
+  // CHECK: return
+  static func superCallStatic() {
+    super.returnsSelfStatic()
+  }
+
+  // CHECK-LABEL: sil hidden @_T012dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyF : $@convention(method) (@guaranteed Derived) -> @owned Derived
+  // CHECK: [[SELF:%.*]] = copy_value %0
+  // CHECK: [[SUPER:%.*]] = upcast [[SELF]] : $Derived to $Base
+  // CHECK: [[METHOD:%.*]] = function_ref @_T012dynamic_self4BaseC11returnsSelfACXDyF
+  // CHECK: apply [[METHOD]]([[SUPER]])
+  // CHECK: return
+  func superCallFromMethodReturningSelf() -> Self {
+    super.returnsSelf()
+    return self
+  }
+
+  // CHECK-LABEL: sil hidden @_T012dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZ : $@convention(method) (@thick Derived.Type) -> @owned Derived
+  // CHECK: [[SUPER:%.*]] = upcast %0 : $@thick Derived.Type to $@thick Base.Type
+  // CHECK: [[METHOD:%.*]] = function_ref @_T012dynamic_self4BaseC17returnsSelfStaticACXDyFZ
+  // CHECK: apply [[METHOD]]([[SUPER]])
+  // CHECK: return
+  static func superCallFromMethodReturningSelfStatic() -> Self {
+    super.returnsSelfStatic()
+    return self.init()
+  }
+}
+
 // CHECK-LABEL: sil_witness_table hidden X: P module dynamic_self {
 // CHECK: method #P.f!1: {{.*}} : @_T012dynamic_self1XCAA1PAaaDP1f{{[_0-9a-zA-Z]*}}FTW
 
diff --git a/test/SILGen/lifetime.swift b/test/SILGen/lifetime.swift
index 47cad67..6eff46f 100644
--- a/test/SILGen/lifetime.swift
+++ b/test/SILGen/lifetime.swift
@@ -527,11 +527,17 @@
   // CHECK-LABEL: sil hidden @_T08lifetime3FooCfD : $@convention(method) <T> (@owned Foo<T>) -> ()
   // CHECK: bb0([[SELF:%[0-9]+]] : $Foo<T>):
   // CHECK:   [[DESTROYING_REF:%[0-9]+]] = function_ref @_T08lifetime3FooCfd : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
-  // CHECK-NEXT:   [[RESULT_SELF:%[0-9]+]] = apply [[DESTROYING_REF]]<T>([[SELF]]) : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
+  // CHECK-NEXT:   [[BORROWED_SELF:%.*]] = begin_borrow [[SELF]]
+  // CHECK-NEXT:   [[RESULT_SELF:%[0-9]+]] = apply [[DESTROYING_REF]]<T>([[BORROWED_SELF]]) : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
+  // CHECK-NEXT:   end_borrow [[BORROWED_SELF]] from [[SELF]]
+  // CHECK-NEXT:   end_lifetime [[SELF]]
   // CHECK-NEXT:   [[SELF:%[0-9]+]] = unchecked_ref_cast [[RESULT_SELF]] : $Builtin.NativeObject to $Foo<T>
   // CHECK-NEXT:   dealloc_ref [[SELF]] : $Foo<T>
   // CHECK-NEXT:   [[RESULT:%[0-9]+]] = tuple ()
   // CHECK-NEXT:   return [[RESULT]] : $()
+  // CHECK-NEXT: } // end sil function '_T08lifetime3FooCfD'
+
+  
   // CHECK-LABEL: sil hidden @_T08lifetime3FooCfd : $@convention(method) <T> (@guaranteed Foo<T>) -> @owned Builtin.NativeObject
 
   deinit {
@@ -540,8 +546,6 @@
     // CHECK: function_ref @_T08lifetime3barSiyF
     // CHECK: apply
 
-    // CHECK: [[PTR:%.*]] = unchecked_ref_cast [[THIS]] : ${{.*}} to $Builtin.NativeObject
-
     // -- don't need to destroy_value x because it's trivial
     // CHECK-NOT: ref_element_addr [[THIS]] : {{.*}}, #Foo.x
     // -- destroy_value y
@@ -554,11 +558,32 @@
     // CHECK: [[WADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #Foo.w
     // CHECK: destroy_addr [[WADDR]]
     // -- return back this
-    // CHECK: return [[PTR]]
+    // CHECK: [[PTR:%.*]] = unchecked_ref_cast [[THIS]] : $Foo<T> to $Builtin.NativeObject
+    // CHECK: [[PTR_OWNED:%.*]] = unchecked_ownership_conversion [[PTR]] : $Builtin.NativeObject, @guaranteed to @owned
+    // CHECK: return [[PTR_OWNED]]
+    // CHECK: } // end sil function '_T08lifetime3FooCfd'
   }
 
 }
 
+class FooSubclass<T> : Foo<T> {
+
+  // CHECK-LABEL: sil hidden @_T08lifetime11FooSubclassCfd : $@convention(method) <T> (@guaranteed FooSubclass<T>) -> @owned Builtin.NativeObject
+  // CHECK: bb0([[THIS:%[0-9]+]] : $FooSubclass<T>):
+  // -- base dtor
+  // CHECK: [[BASE:%[0-9]+]] = upcast [[THIS]] : ${{.*}} to $Foo<T>
+  // CHECK: [[BASE_DTOR:%[0-9]+]] = function_ref @_T08lifetime3FooCfd : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
+  // CHECK: [[PTR:%.*]] = apply [[BASE_DTOR]]<T>([[BASE]])
+  // CHECK: [[BORROWED_PTR:%.*]] = begin_borrow [[PTR]]
+  // CHECK: end_borrow [[BORROWED_PTR]] from [[PTR]]
+  // CHECK: return [[PTR]]
+  
+
+  deinit {
+    bar()
+  }
+}
+
 class ImplicitDtor {
   var x:Int
   var y:(Int, Ref)
@@ -586,14 +611,22 @@
     self.z = z
   }
 
+  // CHECK: sil hidden @_T08lifetime19ImplicitDtorDerivedCfd : $@convention(method) <T> (@guaranteed ImplicitDtorDerived<T>) -> @owned Builtin.NativeObject {
   // CHECK: bb0([[THIS:%[0-9]+]] : $ImplicitDtorDerived<T>):
   // -- base dtor
   // CHECK: [[BASE:%[0-9]+]] = upcast [[THIS]] : ${{.*}} to $ImplicitDtor
   // CHECK: [[BASE_DTOR:%[0-9]+]] = function_ref @_T08lifetime12ImplicitDtorCfd
-  // CHECK: apply [[BASE_DTOR]]([[BASE]])
+  // CHECK: [[PTR:%.*]] = apply [[BASE_DTOR]]([[BASE]])
   // -- destroy_value z
-  // CHECK: [[ZADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #ImplicitDtorDerived.z
+  // CHECK: [[BORROWED_PTR:%.*]] = begin_borrow [[PTR]]
+  // CHECK: [[CAST_BORROWED_PTR:%.*]] = unchecked_ref_cast [[BORROWED_PTR]] : $Builtin.NativeObject to $ImplicitDtorDerived<T>
+  // CHECK: [[ZADDR:%[0-9]+]] = ref_element_addr [[CAST_BORROWED_PTR]] : {{.*}}, #ImplicitDtorDerived.z
   // CHECK: destroy_addr [[ZADDR]]
+  // CHECK: end_borrow [[BORROWED_PTR]] from [[PTR]]
+  // -- epilog
+  // CHECK-NOT: unchecked_ref_cast
+  // CHECK-NOT: unchecked_ownership_conversion
+  // CHECK: return [[PTR]]
 }
 
 class ImplicitDtorDerivedFromGeneric<T> : ImplicitDtorDerived<Int> {
diff --git a/test/SILGen/materializeForSet.swift b/test/SILGen/materializeForSet.swift
index 7f3d867..55210ee 100644
--- a/test/SILGen/materializeForSet.swift
+++ b/test/SILGen/materializeForSet.swift
@@ -80,6 +80,7 @@
 // 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: end_borrow [[T0]] from %2
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 
@@ -100,12 +101,13 @@
 // CHECK-NEXT: store [[T1]] to [init] [[RESULT_ADDR]]
 // CHECK-NEXT: [[RESULT_PTR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_owned () -> @out Int to $Builtin.RawPointer
 // CHECK-NEXT: function_ref
-// CHECK-NEXT: [[T0:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction6ResultQzycfmytfU_TW
-// CHECK-NEXT: [[T1:%.*]] = thin_function_to_pointer [[T0]]
-// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T1]]
-// CHECK-NEXT: [[T0:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT: [[T2:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction6ResultQzycfmytfU_TW
+// CHECK-NEXT: [[T3:%.*]] = thin_function_to_pointer [[T2]]
+// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T3]]
+// CHECK-NEXT: [[T4:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
 // CHECK-NEXT: dealloc_stack [[TEMP]]
-// CHECK-NEXT: return [[T0]]
+// CHECK-NEXT: end_borrow [[T0]] from %2
+// CHECK-NEXT: return [[T4]]
 
 // CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP19finalStoredFunction6ResultQzycfmytfU_TW :
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
@@ -118,6 +120,7 @@
 // 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: end_borrow [[T0]] from %2
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 
@@ -134,17 +137,18 @@
 // CHECK-NEXT: store [[T1]] to [init] [[RESULT_ADDR]]
 // CHECK-NEXT: [[RESULT_PTR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_owned () -> @out Int to $Builtin.RawPointer
 // CHECK-NEXT: function_ref
-// CHECK-NEXT: [[T0:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP19finalStoredFunction6ResultQzycfmytfU_TW
-// CHECK-NEXT: [[T1:%.*]] = thin_function_to_pointer [[T0]]
-// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T1]]
-// CHECK-NEXT: [[T0:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
-// CHECK-NEXT: return [[T0]]
+// CHECK-NEXT: [[T2:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP19finalStoredFunction6ResultQzycfmytfU_TW
+// CHECK-NEXT: [[T3:%.*]] = thin_function_to_pointer [[T2]]
+// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T3]]
+// CHECK-NEXT: [[T4:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT: end_borrow [[T0]] from %2
+// CHECK-NEXT: return [[T4]]
 
 // 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: bb0([[ARG1:%.*]] : $Builtin.RawPointer, [[ARG2:%.*]] : $*Builtin.UnsafeValueBuffer, [[ARG3:%.*]] : $*@thick Derived.Type, [[ARG4:%.*]] : $@thick Derived.Type.Type):
+// CHECK-NEXT: [[SELF:%.*]] = load [trivial] [[ARG3]] : $*@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: [[BUFFER:%.*]] = pointer_to_address [[ARG1]] : $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
diff --git a/test/SILGen/objc_properties.swift b/test/SILGen/objc_properties.swift
index a9d0064..f7b7835 100644
--- a/test/SILGen/objc_properties.swift
+++ b/test/SILGen/objc_properties.swift
@@ -4,7 +4,6 @@
 
 import Foundation
 
-
 class A {
   dynamic var prop: Int
   dynamic var computedProp: Int {
@@ -183,6 +182,31 @@
   var ref: Unmanaged<AnyObject>?
 }
 
+@_silgen_name("autoreleasing_user")
+func useAutoreleasingUnsafeMutablePointer(_ a: AutoreleasingUnsafeMutablePointer<NSObject>)
+
+class NonObjCClassWithObjCProperty {
+  var property: NSObject
+
+  init(_ newValue: NSObject) {
+    property = newValue
+  }
+
+  // CHECK-LABEL: sil hidden @_T015objc_properties016NonObjCClassWithD9CPropertyC11usePropertyyyF : $@convention(method) (@guaranteed NonObjCClassWithObjCProperty) -> () {
+  // CHECK: bb0([[ARG:%.*]] : $NonObjCClassWithObjCProperty):
+  // CHECK: [[MATERIALIZE_FOR_SET:%.*]] = class_method [[ARG]] : $NonObjCClassWithObjCProperty, #NonObjCClassWithObjCProperty.property!materializeForSet.1
+  // CHECK: [[TUPLE:%.*]] = apply [[MATERIALIZE_FOR_SET]]({{.*}}, {{.*}}, [[ARG]])
+  // CHECK: [[RAW_POINTER:%.*]] = tuple_extract [[TUPLE]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>), 0
+  // CHECK: [[OBJECT:%.*]] = pointer_to_address [[RAW_POINTER]] : $Builtin.RawPointer to [strict] $*NSObject
+  // CHECK: [[OBJECT_DEP:%.*]] = mark_dependence [[OBJECT]] : $*NSObject on [[ARG]]
+  // CHECK: [[LOADED_OBJECT:%.*]] = load_borrow [[OBJECT_DEP]]
+  // CHECK: [[UNMANAGED_OBJECT:%.*]] = ref_to_unmanaged [[LOADED_OBJECT]] : $NSObject to $@sil_unmanaged NSObject
+  // CHECK: end_borrow [[LOADED_OBJECT]] from [[OBJECT_DEP]]
+  func useProperty() {
+    useAutoreleasingUnsafeMutablePointer(&property)
+  }
+}
+
 
 // <rdar://problem/21544588> crash when overriding non-@objc property with @objc property.
 class NonObjCBaseClass : NSObject {
diff --git a/test/SILOptimizer/devirtualize_existential.swift b/test/SILOptimizer/devirtualize_existential.swift
index 570460b..8072de8 100644
--- a/test/SILOptimizer/devirtualize_existential.swift
+++ b/test/SILOptimizer/devirtualize_existential.swift
@@ -8,12 +8,61 @@
 }
 
 // Everything gets devirtualized, inlined, and promoted to the stack.
-//CHECK: @_T024devirtualize_existential17interesting_stuffyyF
-//CHECK-NOT: init_existential_addr
-//CHECK-NOT: apply
-//CHECK: return
+// CHECK-LABEL: @_T024devirtualize_existential17interesting_stuffyyF
+// CHECK-NOT: init_existential_addr
+// CHECK-NOT: apply
+// CHECK: return
 public func interesting_stuff() {
- var x : Pingable = Foo()
+ var x: Pingable = Foo()
  x.ping(1)
 }
 
+protocol Cloneable {
+  func clone() -> Self
+  func maybeClone() -> Self?
+}
+
+struct Bar : Cloneable {
+  @inline(never)
+  func clone() -> Bar { return self }
+
+  @inline(never)
+  func maybeClone() -> Bar? { return self }
+}
+
+// In this example, we don't eliminate the init_existential_addr, because
+// of the stack allocated existential value used for the return.
+//
+// If the combiner was generalized to replace the opened existential type
+// with the concrete type in all instructions that use it, instead of just
+// special-casing witness_method and apply, we could eliminate the opened
+// existential type completely.
+//
+// However even though IRGen still performs more work at runtime than is
+// necessary here, the call is devirtualized.
+
+// CHECK-LABEL: sil @_T024devirtualize_existential22more_interesting_stuffyyF
+// CHECK: [[EXISTENTIAL:%.*]] = alloc_stack $Cloneable
+// CHECK: [[EXISTENTIAL_ADDR:%.*]] = init_existential_addr [[EXISTENTIAL]]
+// CHECK: [[VALUE:%.*]] = struct $Bar ()
+// CHECK: [[RESULT_ADDR:%.*]] = unchecked_addr_cast [[EXISTENTIAL_ADDR:%.*]]
+// CHECK: [[FN:%.*]] = function_ref @_T024devirtualize_existential3BarV5cloneACyF
+// CHECK: [[RETURN:%.*]] = apply [[FN]]([[VALUE]])
+// CHECK: store [[RETURN]] to [[RESULT_ADDR]]
+
+// CHECK: [[ENUM:%.*]] = alloc_stack $Optional<Cloneable>
+// CHECK: [[ENUM_ADDR:%.*]] = init_enum_data_addr [[ENUM]]
+// CHECK: [[EXISTENTIAL_ADDR:%.*]] = init_existential_addr [[ENUM_ADDR]]
+// CHECK: [[RESULT_ADDR:%.*]] = unchecked_addr_cast [[EXISTENTIAL_ADDR:%.*]]
+// CHECK: [[FN:%.*]] = function_ref @_T024devirtualize_existential3BarV10maybeCloneACSgyF
+// CHECK: [[RETURN:%.*]] = apply [[FN]]([[VALUE]])
+// CHECK: store [[RETURN]] to [[RESULT_ADDR]]
+
+// CHECK: return
+
+public func more_interesting_stuff() {
+  var x: Cloneable = Bar()
+
+  x.clone()
+  x.maybeClone()
+}
diff --git a/test/SILOptimizer/ownership_model_eliminator.sil b/test/SILOptimizer/ownership_model_eliminator.sil
index 70288dd..52ab7b6 100644
--- a/test/SILOptimizer/ownership_model_eliminator.sil
+++ b/test/SILOptimizer/ownership_model_eliminator.sil
@@ -174,3 +174,22 @@
   %9999 = tuple()
   return %9999 : $()
 }
+
+// CHECK-LABEL: sil @end_lifetime_test : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+// CHECK-NOT: end_lifetime {{%.*}} : $Builtin.NativeObject
+sil @end_lifetime_test : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : @owned $Builtin.NativeObject):
+  end_lifetime %0 : $Builtin.NativeObject
+  %9999 = tuple()
+  return %9999 : $()
+}
+
+// CHECK-LABEL: sil @unchecked_ownership_conversion_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Builtin.NativeObject):
+// CHECK: return [[ARG]] : $Builtin.NativeObject
+sil @unchecked_ownership_conversion_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
+bb0(%0 : @guaranteed $Builtin.NativeObject):
+  %1 = unchecked_ownership_conversion %0 : $Builtin.NativeObject, @guaranteed to @owned
+  return %1 : $Builtin.NativeObject
+}
+
diff --git a/test/Sema/availability_versions.swift b/test/Sema/availability_versions.swift
index 4ef62d5..c5e1294 100644
--- a/test/Sema/availability_versions.swift
+++ b/test/Sema/availability_versions.swift
@@ -28,15 +28,15 @@
 
 // Functions without annotations should reflect the minimum deployment target.
 func functionWithoutAvailability() {
+      // expected-note@-1 2{{add @available attribute to enclosing global function}}
+
   let _: Int = globalFuncAvailableOn10_9()
 
   let _: Int = globalFuncAvailableOn10_51() // expected-error {{'globalFuncAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _: Int = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available on OS X 10.52 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 // Functions with annotations should refine their bodies.
@@ -123,6 +123,8 @@
 // Unavailable methods
 
 class ClassWithUnavailableMethod {
+    // expected-note@-1 {{add @available attribute to enclosing class}}
+
   @available(OSX, introduced: 10.9)
   func methAvailableOn10_9() {}
   
@@ -133,84 +135,84 @@
   class func classMethAvailableOn10_51() {}
   
   func someOtherMethod() {
+    // expected-note@-1 {{add @available attribute to enclosing instance method}}
+
     methAvailableOn10_9()
     methAvailableOn10_51() // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add @available attribute to enclosing instance method}}
-        // expected-note@-3 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
   }
 }
 
 func callUnavailableMethods(_ o: ClassWithUnavailableMethod) {
+      // expected-note@-1 2{{add @available attribute to enclosing global function}}
+
   let m10_9 = o.methAvailableOn10_9
   m10_9()
   
   let m10_51 = o.methAvailableOn10_51 // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   m10_51()
   
   o.methAvailableOn10_9()
   o.methAvailableOn10_51() // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 func callUnavailableMethodsViaIUO(_ o: ClassWithUnavailableMethod!) {
+      // expected-note@-1 2{{add @available attribute to enclosing global function}}
+
   let m10_9 = o.methAvailableOn10_9
   m10_9()
   
   let m10_51 = o.methAvailableOn10_51 // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
+      
       // expected-note@-2 {{add 'if #available' version check}}
 
   m10_51()
   
   o.methAvailableOn10_9()
   o.methAvailableOn10_51() // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 func callUnavailableClassMethod() {
+      // expected-note@-1 2{{add @available attribute to enclosing global function}}
+
   ClassWithUnavailableMethod.classMethAvailableOn10_51() // expected-error {{'classMethAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   let m10_51 = ClassWithUnavailableMethod.classMethAvailableOn10_51 // expected-error {{'classMethAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   m10_51()
 }
 
 class SubClassWithUnavailableMethod : ClassWithUnavailableMethod {
+        // expected-note@-1 {{add @available attribute to enclosing class}}
   func someMethod() {
+        // expected-note@-1 {{add @available attribute to enclosing instance method}}
+
     methAvailableOn10_9()
     methAvailableOn10_51() // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add @available attribute to enclosing instance method}}
-        // expected-note@-3 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
   }
 }
 
 class SubClassOverridingUnavailableMethod : ClassWithUnavailableMethod {
+        // expected-note@-1 2{{add @available attribute to enclosing class}}
 
   override func methAvailableOn10_51() {
+        // expected-note@-1 2{{add @available attribute to enclosing instance method}}
     methAvailableOn10_9()
     super.methAvailableOn10_51() // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add @available attribute to enclosing instance method}}
-        // expected-note@-3 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
     
     let m10_9 = super.methAvailableOn10_9
     m10_9()
     
     let m10_51 = super.methAvailableOn10_51 // expected-error {{'methAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add @available attribute to enclosing instance method}}
-        // expected-note@-3 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
     m10_51()
   }
   
@@ -230,15 +232,18 @@
 }
 
 func callUnavailableOverloadedMethod(_ o: ClassWithUnavailableOverloadedMethod) {
+      // expected-note@-1 {{add @available attribute to enclosing global function}}
+
   o.overloadedMethod()
   o.overloadedMethod(0) // expected-error {{'overloadedMethod' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 // Initializers
 
 class ClassWithUnavailableInitializer {
+    // expected-note@-1 {{add @available attribute to enclosing class}}
+
   @available(OSX, introduced: 10.9)
   required init() {  }
   
@@ -246,10 +251,10 @@
   required init(_ val: Int) {  }
   
   convenience init(s: String) {
+        // expected-note@-1 {{add @available attribute to enclosing initializer}}
+    
     self.init(5) // expected-error {{'init' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add @available attribute to enclosing initializer}}
-        // expected-note@-3 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
   }
   
   @available(OSX, introduced: 10.51)
@@ -259,16 +264,16 @@
 }
 
 func callUnavailableInitializer() {
+      // expected-note@-1 2{{add @available attribute to enclosing global function}}
+
   _ = ClassWithUnavailableInitializer()
   _ = ClassWithUnavailableInitializer(5) // expected-error {{'init' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   let i = ClassWithUnavailableInitializer.self 
   _ = i.init()
   _ = i.init(5) // expected-error {{'init' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 class SuperWithWithUnavailableInitializer {
@@ -280,11 +285,13 @@
 }
 
 class SubOfClassWithUnavailableInitializer : SuperWithWithUnavailableInitializer {
+    // expected-note@-1 {{add @available attribute to enclosing class}}
+
   override init(_ val: Int) {
+        // expected-note@-1 {{add @available attribute to enclosing initializer}}
+
     super.init(5) // expected-error {{'init' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add @available attribute to enclosing initializer}}
-        // expected-note@-3 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
   }
   
   override init() {
@@ -300,6 +307,7 @@
 // Properties
 
 class ClassWithUnavailableProperties {
+    // expected-note@-1 4{{add @available attribute to enclosing class}}
 
   @available(OSX, introduced: 10.9) // expected-error {{stored properties cannot be marked potentially unavailable with '@available'}}
   var nonLazyAvailableOn10_9Stored: Int = 9
@@ -313,7 +321,6 @@
   // Make sure that we don't emit a Fix-It to mark a stored property as potentially unavailable.
   // We don't support potentially unavailable stored properties yet.
   var storedPropertyOfUnavailableType: ClassAvailableOn10_51? = nil // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing class}}
 
   @available(OSX, introduced: 10.9)
   lazy var availableOn10_9Stored: Int = 9
@@ -325,8 +332,7 @@
   var availableOn10_9Computed: Int {
     get {
       let _: Int = availableOn10_51Stored // expected-error {{'availableOn10_51Stored' is only available on OS X 10.51 or newer}}
-          // expected-note@-1 {{add @available attribute to enclosing class}}
-          // expected-note@-2 {{add 'if #available' version check}}
+          // expected-note@-1 {{add 'if #available' version check}}
       
       if #available(OSX 10.51, *) {
         let _: Int = availableOn10_51Stored
@@ -350,11 +356,10 @@
   }
   
   var propWithSetterOnlyAvailableOn10_51 : Int {
+      // expected-note@-1 {{add @available attribute to enclosing var}}
     get {
       _ = globalFuncAvailableOn10_51() // expected-error {{'globalFuncAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-          // expected-note@-1 {{add @available attribute to enclosing class}}
-          // expected-note@-2 {{add @available attribute to enclosing var}}
-          // expected-note@-3 {{add 'if #available' version check}}
+          // expected-note@-1 {{add 'if #available' version check}}
       return 0
     }
     @available(OSX, introduced: 10.51)
@@ -364,6 +369,7 @@
   }
   
   var propWithGetterOnlyAvailableOn10_51 : Int {
+      // expected-note@-1 {{add @available attribute to enclosing var}}
     @available(OSX, introduced: 10.51)
     get {
       _ = globalFuncAvailableOn10_51()
@@ -371,9 +377,7 @@
     }
     set(newVal) {
       _ = globalFuncAvailableOn10_51() // expected-error {{'globalFuncAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-          // expected-note@-1 {{add @available attribute to enclosing class}}
-          // expected-note@-2 {{add @available attribute to enclosing var}}
-          // expected-note@-3 {{add 'if #available' version check}}
+          // expected-note@-1 {{add 'if #available' version check}}
     }
   }
   
@@ -419,33 +423,29 @@
 }
 
 func accessUnavailableProperties(_ o: ClassWithUnavailableProperties) {
+      // expected-note@-1 17{{add @available attribute to enclosing global function}}
   // Stored properties
   let _: Int = o.availableOn10_9Stored
   let _: Int = o.availableOn10_51Stored // expected-error {{'availableOn10_51Stored' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   o.availableOn10_9Stored = 9
   o.availableOn10_51Stored = 10 // expected-error {{'availableOn10_51Stored' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   // Computed Properties
   let _: Int = o.availableOn10_9Computed
   let _: Int = o.availableOn10_51Computed // expected-error {{'availableOn10_51Computed' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   o.availableOn10_9Computed = 9
   o.availableOn10_51Computed = 10 // expected-error {{'availableOn10_51Computed' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   // Getter allowed on 10.9 but setter is not
   let _: Int = o.propWithSetterOnlyAvailableOn10_51
   o.propWithSetterOnlyAvailableOn10_51 = 5 // expected-error {{setter for 'propWithSetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   if #available(OSX 10.51, *) {
     // Setter is allowed on 10.51 and greater
@@ -455,8 +455,7 @@
   // Setter allowed on 10.9 but getter is not
   o.propWithGetterOnlyAvailableOn10_51 = 5
   let _: Int = o.propWithGetterOnlyAvailableOn10_51 // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   if #available(OSX 10.51, *) {
     // Getter is allowed on 10.51 and greater
@@ -467,18 +466,15 @@
   
   // Both getters are potentially unavailable.
   let _: Int = o.propWithGetterOnlyAvailableOn10_51ForNestedMemberRef.propWithGetterOnlyAvailableOn10_51 // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51ForNestedMemberRef' is only available on OS X 10.51 or newer}} expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 2{{add @available attribute to enclosing global function}}
-      // expected-note@-2 2{{add 'if #available' version check}}
+      // expected-note@-1 2{{add 'if #available' version check}}
 
   // Nested getter is potentially unavailable, outer getter is available
   let _: Int = o.propWithGetterOnlyAvailableOn10_51ForNestedMemberRef.propWithSetterOnlyAvailableOn10_51 // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51ForNestedMemberRef' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   // Nested getter is available, outer getter is potentially unavailable
   let _:Int = o.propWithSetterOnlyAvailableOn10_51ForNestedMemberRef.propWithGetterOnlyAvailableOn10_51 // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   // Both getters are always available.
   let _: Int = o.propWithSetterOnlyAvailableOn10_51ForNestedMemberRef.propWithSetterOnlyAvailableOn10_51
@@ -488,33 +484,27 @@
   var v: Int
   
   v = o.propWithGetterOnlyAvailableOn10_51 // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   v = (o.propWithGetterOnlyAvailableOn10_51) // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   // Inout requires access to both getter and setter
   
   func takesInout(_ i : inout Int) { }
   
   takesInout(&o.propWithGetterOnlyAvailableOn10_51) // expected-error {{cannot pass as inout because getter for 'propWithGetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   takesInout(&o.propWithSetterOnlyAvailableOn10_51) // expected-error {{cannot pass as inout because setter for 'propWithSetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   takesInout(&o.propWithGetterAndSetterOnlyAvailableOn10_51) // expected-error {{cannot pass as inout because getter for 'propWithGetterAndSetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}} expected-error {{cannot pass as inout because setter for 'propWithGetterAndSetterOnlyAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 2{{add @available attribute to enclosing global function}}
-      // expected-note@-2 2{{add 'if #available' version check}}
+      // expected-note@-1 2{{add 'if #available' version check}}
 
   takesInout(&o.availableOn10_9Computed)
   takesInout(&o.propWithGetterOnlyAvailableOn10_51ForNestedMemberRef.availableOn10_9Computed) // expected-error {{getter for 'propWithGetterOnlyAvailableOn10_51ForNestedMemberRef' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 // _silgen_name
@@ -563,17 +553,15 @@
 func functionTakingEnumIntroducedOn10_52(_ e: EnumIntroducedOn10_52) { }
 
 func useEnums() {
+      // expected-note@-1 3{{add @available attribute to enclosing global function}}
   let _: CompassPoint = .North // expected-error {{'CompassPoint' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   if #available(OSX 10.51, *) {
     let _: CompassPoint = .North
 
     let _: CompassPoint = .West // expected-error {{'West' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
-
+        // expected-note@-1 {{add 'if #available' version check}}
   }
 
   if #available(OSX 10.52, *) {
@@ -595,7 +583,7 @@
         // For the moment, we do not incorporate enum element availability into 
         // TRC construction. Perhaps we should?
         functionTakingEnumIntroducedOn10_52(p)  // expected-error {{'functionTakingEnumIntroducedOn10_52' is only available on OS X 10.52 or newer}}
-          // expected-note@-1 {{add @available attribute to enclosing global function}}
+          
           // expected-note@-2 {{add 'if #available' version check}}
     }
   }
@@ -629,20 +617,18 @@
 }
 
 func classAvailability() {
+      // expected-note@-1 3{{add @available attribute to enclosing global function}}
   ClassAvailableOn10_9.someClassMethod()
   ClassAvailableOn10_51.someClassMethod() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   _ = ClassAvailableOn10_9.self
   _ = ClassAvailableOn10_51.self // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   let o10_9 = ClassAvailableOn10_9()
   let o10_51 = ClassAvailableOn10_51() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   o10_9.someMethod()
   o10_51.someMethod()
@@ -652,17 +638,15 @@
 }
 
 func castingUnavailableClass(_ o : AnyObject) {
+      // expected-note@-1 3{{add @available attribute to enclosing global function}}
   let _ = o as! ClassAvailableOn10_51 // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _ = o as? ClassAvailableOn10_51 // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _ = o is ClassAvailableOn10_51 // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 protocol Creatable {
@@ -683,45 +667,39 @@
 class ClassWithTwoGenericTypeParameter<T, S> { }
 
 func classViaTypeParameter() {
+  // expected-note@-1 9{{add @available attribute to enclosing global function}}
   let _ : ClassAvailableOn10_51_Creatable = // expected-error {{'ClassAvailableOn10_51_Creatable' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
       create()
       
   let _ = create() as
       ClassAvailableOn10_51_Creatable // expected-error {{'ClassAvailableOn10_51_Creatable' is only available on OS X 10.51 or newer}}
-          // expected-note@-1 {{add @available attribute to enclosing global function}}
-          // expected-note@-2 {{add 'if #available' version check}}
+          // expected-note@-1 {{add 'if #available' version check}}
 
   let _ = [ClassAvailableOn10_51]() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _: ClassWithGenericTypeParameter<ClassAvailableOn10_51> = ClassWithGenericTypeParameter() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _: ClassWithTwoGenericTypeParameter<ClassAvailableOn10_51, String> = ClassWithTwoGenericTypeParameter() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _: ClassWithTwoGenericTypeParameter<String, ClassAvailableOn10_51> = ClassWithTwoGenericTypeParameter() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _: ClassWithTwoGenericTypeParameter<ClassAvailableOn10_51, ClassAvailableOn10_51> = ClassWithTwoGenericTypeParameter() // expected-error 2{{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 2{{add @available attribute to enclosing global function}}
-      // expected-note@-2 2{{add 'if #available' version check}}
+      // expected-note@-1 2{{add 'if #available' version check}}
 
   let _: ClassAvailableOn10_51? = nil // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
 }
 
 // Unavailable class used in declarations
 
 class ClassWithDeclarationsOfUnavailableClasses {
+      // expected-note@-1 5{{add @available attribute to enclosing class}}
 
   @available(OSX, introduced: 10.51)
   init() {
@@ -730,7 +708,6 @@
   }
 
   var propertyOfUnavailableType: ClassAvailableOn10_51 // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing class}}
 
   @available(OSX, introduced: 10.51)
   lazy var unavailablePropertyOfUnavailableType: ClassAvailableOn10_51 = ClassAvailableOn10_51()
@@ -748,9 +725,7 @@
   static var unavailableStaticPropertyOfOptionalUnavailableType: ClassAvailableOn10_51?
 
   func methodWithUnavailableParameterType(_ o : ClassAvailableOn10_51) { // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing class}}
-      // expected-note@-2 {{add @available attribute to enclosing instance method}}
-
+      // expected-note@-1 {{add @available attribute to enclosing instance method}}
   }
   
   @available(OSX, introduced: 10.51)
@@ -758,13 +733,10 @@
   }
   
   func methodWithUnavailableReturnType() -> ClassAvailableOn10_51 { // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing class}}
-      // expected-note@-2 {{add @available attribute to enclosing instance method}}
+      // expected-note@-1 2{{add @available attribute to enclosing instance method}}
 
     return ClassAvailableOn10_51() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing class}}
-      // expected-note@-2 {{add @available attribute to enclosing instance method}}
-      // expected-note@-3 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   }
   
   @available(OSX, introduced: 10.51)
@@ -773,10 +745,9 @@
   }
 
   func methodWithUnavailableLocalDeclaration() {
+      // expected-note@-1 {{add @available attribute to enclosing instance method}}
     let _ : ClassAvailableOn10_51 = methodWithUnavailableReturnType() // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing class}}
-      // expected-note@-2 {{add @available attribute to enclosing instance method}}
-      // expected-note@-3 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   }
   
   @available(OSX, introduced: 10.51)
@@ -786,14 +757,13 @@
 }
 
 func referToUnavailableStaticProperty() {
-  let _ = ClassWithDeclarationsOfUnavailableClasses.unavailableStaticPropertyOfUnavailableType // expected-error {{'unavailableStaticPropertyOfUnavailableType' is only available on OS X 10.51 or newer}}
       // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+  let _ = ClassWithDeclarationsOfUnavailableClasses.unavailableStaticPropertyOfUnavailableType // expected-error {{'unavailableStaticPropertyOfUnavailableType' is only available on OS X 10.51 or newer}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 class ClassExtendingUnavailableClass : ClassAvailableOn10_51 { // expected-error {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
     // expected-note@-1 {{add @available attribute to enclosing class}}
-
 }
 
 @available(OSX, introduced: 10.51)
@@ -860,11 +830,11 @@
 }
 
 class SubWithLargerMemberAvailability : SuperWithLimitedMemberAvailability {
+        // expected-note@-1 2{{add @available attribute to enclosing class}}
   @available(OSX, introduced: 10.9)
   override func someMethod() {
     super.someMethod() // expected-error {{'someMethod()' is only available on OS X 10.51 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing class}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
     
     if #available(OSX 10.51, *) {
       super.someMethod()
@@ -875,8 +845,7 @@
   override var someProperty: Int {
     get { 
       let _ = super.someProperty // expected-error {{'someProperty' is only available on OS X 10.51 or newer}}
-          // expected-note@-1 {{add @available attribute to enclosing class}}
-          // expected-note@-2 {{add 'if #available' version check}}
+          // expected-note@-1 {{add 'if #available' version check}}
       
       if #available(OSX 10.51, *) {
         let _ = super.someProperty
@@ -916,15 +885,14 @@
 }
 
 func castToUnavailableProtocol() {
+      // expected-note@-1 2{{add @available attribute to enclosing global function}}
   let o: ClassAvailableOn10_9AdoptingProtocolAvailableOn10_51 = ClassAvailableOn10_9AdoptingProtocolAvailableOn10_51()
 
   let _: ProtocolAvailableOn10_51 = o // expected-error {{'ProtocolAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _ = o as ProtocolAvailableOn10_51 // expected-error {{'ProtocolAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 @available(OSX, introduced: 10.9)
@@ -953,10 +921,10 @@
 @available(OSX, introduced: 10.51)
 extension ClassAvailableOn10_51 {
   func m() {
+      // expected-note@-1 {{add @available attribute to enclosing instance method}}
     let _ = globalFuncAvailableOn10_51()
     let _ = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available on OS X 10.52 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing instance method}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   }
 }
 
@@ -991,19 +959,17 @@
 }
 
 func useUnavailableExtension() {
+      // expected-note@-1 3{{add @available attribute to enclosing global function}}
   let o = ClassToExtend()
 
   o.extensionMethod() // expected-error {{'extensionMethod()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   let _ = ClassToExtend.ExtensionClass() // expected-error {{'ExtensionClass' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   o.extensionMethod10_52() // expected-error {{'extensionMethod10_52()' is only available on OS X 10.52 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 // Useless #available(...) checks
@@ -1136,11 +1102,11 @@
 // Tests for the guard control construct.
 
 func useGuardAvailable() {
+        // expected-note@-1 3{{add @available attribute to enclosing global function}}
   // Guard fallthrough should refine context
   guard #available(OSX 10.51, *) else { // expected-note {{enclosing scope here}}
     let _ = globalFuncAvailableOn10_51() // expected-error {{'globalFuncAvailableOn10_51()' is only available on OS X 10.51 or newer}}
         // expected-note@-1 {{add 'if #available' version check}}
-        // expected-note@-2 {{add @available attribute to enclosing global function}}
     return
   }
 
@@ -1148,7 +1114,6 @@
 
   let _ = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available on OS X 10.52 or newer}}
         // expected-note@-1 {{add 'if #available' version check}}
-        // expected-note@-2 {{add @available attribute to enclosing global function}}
 
   if #available(OSX 10.51, *) { // expected-warning {{unnecessary check for 'OSX'; enclosing scope ensures guard will always be true}}
   }
@@ -1161,11 +1126,10 @@
 
   let _ = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available on OS X 10.52 or newer}}
         // expected-note@-1 {{add 'if #available' version check}}
-        // expected-note@-2 {{add @available attribute to enclosing global function}}
-
 }
 
 func twoGuardsInSameBlock(_ p: Int) {
+        // expected-note@-1 {{add @available attribute to enclosing global function}}
   if (p > 0) {
     guard #available(OSX 10.51, *) else { return }
 
@@ -1178,7 +1142,6 @@
 
   let _ = globalFuncAvailableOn10_51() // expected-error {{'globalFuncAvailableOn10_51()' is only available on OS X 10.51 or newer}}
         // expected-note@-1 {{add 'if #available' version check}}
-        // expected-note@-2 {{add @available attribute to enclosing global function}}
 }
 
 // Refining while loops
@@ -1219,134 +1182,125 @@
       // expected-note@-2 {{add 'if #available' version check}} {{1-57=if #available(OSX 10.51, *) {\n    let declForFixitAtTopLevel: ClassAvailableOn10_51? = nil\n} else {\n    // Fallback on earlier versions\n}}}
 
 func fixitForReferenceInGlobalFunction() {
+      // expected-note@-1 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.51, *)\n}}
   functionAvailableOn10_51()
       // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add 'if #available' version check}} {{3-29=if #available(OSX 10.51, *) {\n      functionAvailableOn10_51()\n  } else {\n      // Fallback on earlier versions\n  }}}
-      // expected-note@-3 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.51, *)\n}}
+      
 }
 
 public func fixitForReferenceInGlobalFunctionWithDeclModifier() {
+      // expected-note@-1 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.51, *)\n}}
   functionAvailableOn10_51()
       // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add 'if #available' version check}} {{3-29=if #available(OSX 10.51, *) {\n      functionAvailableOn10_51()\n  } else {\n      // Fallback on earlier versions\n  }}}
-      // expected-note@-3 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.51, *)\n}}
+      
 }
 
 func fixitForReferenceInGlobalFunctionWithAttribute() -> Never {
+    // expected-note@-1 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.51, *)\n}}
   functionAvailableOn10_51()
     // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
     // expected-note@-2 {{add 'if #available' version check}} {{3-29=if #available(OSX 10.51, *) {\n      functionAvailableOn10_51()\n  } else {\n      // Fallback on earlier versions\n  }}}
-    // expected-note@-3 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.51, *)\n}}
+    
 }
 
 func takesAutoclosure(_ c : @autoclosure () -> ()) {
 }
 
 class ClassForFixit {
+        // expected-note@-1 12{{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
   func fixitForReferenceInMethod() {
+        // expected-note@-1 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
     functionAvailableOn10_51()
         // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
         // expected-note@-2 {{add 'if #available' version check}} {{5-31=if #available(OSX 10.51, *) {\n        functionAvailableOn10_51()\n    } else {\n        // Fallback on earlier versions\n    }}}
-        // expected-note@-3 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
-        // expected-note@-4 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
   }
 
   func fixitForReferenceNestedInMethod() {
+          // expected-note@-1 3{{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
     func inner() {
       functionAvailableOn10_51()
           // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
           // expected-note@-2 {{add 'if #available' version check}} {{7-33=if #available(OSX 10.51, *) {\n          functionAvailableOn10_51()\n      } else {\n          // Fallback on earlier versions\n      }}}
-          // expected-note@-3 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
-          // expected-note@-4 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
     }
 
     let _: () -> () = { () in
       functionAvailableOn10_51()
           // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
           // expected-note@-2 {{add 'if #available' version check}} {{7-33=if #available(OSX 10.51, *) {\n          functionAvailableOn10_51()\n      } else {\n          // Fallback on earlier versions\n      }}}
-          // expected-note@-3 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
-          // expected-note@-4 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
     }
 
     takesAutoclosure(functionAvailableOn10_51())
           // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
           // expected-note@-2 {{add 'if #available' version check}} {{5-49=if #available(OSX 10.51, *) {\n        takesAutoclosure(functionAvailableOn10_51())\n    } else {\n        // Fallback on earlier versions\n    }}}
-          // expected-note@-3 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
-          // expected-note@-4 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
+          
   }
 
   var fixitForReferenceInPropertyAccessor: Int {
+        // expected-note@-1 {{add @available attribute to enclosing var}} {{3-3=@available(OSX 10.51, *)\n  }}
     get {
       functionAvailableOn10_51()
         // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
         // expected-note@-2 {{add 'if #available' version check}} {{7-33=if #available(OSX 10.51, *) {\n          functionAvailableOn10_51()\n      } else {\n          // Fallback on earlier versions\n      }}}
-        // expected-note@-3 {{add @available attribute to enclosing var}} {{3-3=@available(OSX 10.51, *)\n  }}
-        // expected-note@-4 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
-
+        
       return 5
     }
   }
 
   var fixitForReferenceInPropertyType: ClassAvailableOn10_51? = nil
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-2 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
 
   lazy var fixitForReferenceInLazyPropertyType: ClassAvailableOn10_51? = nil
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add @available attribute to enclosing var}} {{3-3=@available(OSX 10.51, *)\n  }}
-      // expected-note@-3 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
 
   private lazy var fixitForReferenceInPrivateLazyPropertyType: ClassAvailableOn10_51? = nil
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add @available attribute to enclosing var}} {{3-3=@available(OSX 10.51, *)\n  }}
-      // expected-note@-3 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
 
   lazy private var fixitForReferenceInLazyPrivatePropertyType: ClassAvailableOn10_51? = nil
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add @available attribute to enclosing var}} {{3-3=@available(OSX 10.51, *)\n  }}
-      // expected-note@-3 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
 
   static var fixitForReferenceInStaticPropertyType: ClassAvailableOn10_51? = nil
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add @available attribute to enclosing static var}} {{3-3=@available(OSX 10.51, *)\n  }}
-      // expected-note@-3 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
 
   var fixitForReferenceInPropertyTypeMultiple: ClassAvailableOn10_51? = nil, other: Int = 7
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-2 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
 
   func fixitForRefInGuardOfIf() {
+        // expected-note@-1 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
     if (globalFuncAvailableOn10_51() > 1066) {
       let _ = 5
       let _ = 6
     }
         // expected-error@-4 {{'globalFuncAvailableOn10_51()' is only available on OS X 10.51 or newer}}
         // expected-note@-5 {{add 'if #available' version check}} {{5-6=if #available(OSX 10.51, *) {\n        if (globalFuncAvailableOn10_51() > 1066) {\n          let _ = 5\n          let _ = 6\n        }\n    } else {\n        // Fallback on earlier versions\n    }}}
-        // expected-note@-6 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
-        // expected-note@-7 {{add @available attribute to enclosing class}} {{1-1=@available(OSX 10.51, *)\n}}
   }
 }
 
 extension ClassToExtend {
+        // expected-note@-1 {{add @available attribute to enclosing extension}}
   func fixitForReferenceInExtensionMethod() {
+        // expected-note@-1 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
     functionAvailableOn10_51()
         // expected-error@-1 {{'functionAvailableOn10_51()' is only available on OS X 10.51 or newer}}
         // expected-note@-2 {{add 'if #available' version check}} {{5-31=if #available(OSX 10.51, *) {\n        functionAvailableOn10_51()\n    } else {\n        // Fallback on earlier versions\n    }}}
-        // expected-note@-3 {{add @available attribute to enclosing instance method}} {{3-3=@available(OSX 10.51, *)\n  }}
-        // expected-note@-4 {{add @available attribute to enclosing extension}} {{1-1=@available(OSX 10.51, *)\n}}
   }
 }
 
 enum EnumForFixit {
+      // expected-note@-1 2{{add @available attribute to enclosing enum}} {{1-1=@available(OSX 10.51, *)\n}}
   case CaseWithUnavailablePayload(p: ClassAvailableOn10_51)
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add @available attribute to enclosing case}} {{3-3=@available(OSX 10.51, *)\n  }}
-      // expected-note@-3 {{add @available attribute to enclosing enum}} {{1-1=@available(OSX 10.51, *)\n}}
 
   case CaseWithUnavailablePayload2(p: ClassAvailableOn10_51), WithoutPayload
       // expected-error@-1 {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-2 {{add @available attribute to enclosing case}} {{3-3=@available(OSX 10.51, *)\n  }}
-      // expected-note@-3 {{add @available attribute to enclosing enum}} {{1-1=@available(OSX 10.51, *)\n}}
+      
 }
 
 @objc
@@ -1360,31 +1314,31 @@
 }
 
 func testForFixitWithNestedMemberRefExpr() {
+    // expected-note@-1 2{{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.52, *)\n}}
   let x = X()
 
   x.y.z = globalFuncAvailableOn10_52()
       // expected-error@-1 {{'globalFuncAvailableOn10_52()' is only available on OS X 10.52 or newer}}
       // expected-note@-2 {{add 'if #available' version check}} {{3-39=if #available(OSX 10.52, *) {\n      x.y.z = globalFuncAvailableOn10_52()\n  } else {\n      // Fallback on earlier versions\n  }}}
-      // expected-note@-3 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.52, *)\n}}
 
   // Access via dynamic member reference
   let anyX: AnyObject = x
   anyX.y?.z = globalFuncAvailableOn10_52()
       // expected-error@-1 {{'globalFuncAvailableOn10_52()' is only available on OS X 10.52 or newer}}
       // expected-note@-2 {{add 'if #available' version check}} {{3-43=if #available(OSX 10.52, *) {\n      anyX.y?.z = globalFuncAvailableOn10_52()\n  } else {\n      // Fallback on earlier versions\n  }}}
-      // expected-note@-3 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.52, *)\n}}
+      
 }
 
 // Protocol Conformances
 
 protocol ProtocolWithRequirementMentioningUnavailable {
+      // expected-note@-1 6{{add @available attribute to enclosing protocol}}
   func hasUnavailableParameter(_ p: ClassAvailableOn10_51) // expected-error * {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-1 * {{add @available attribute to enclosing instance method}}
-      // expected-note@-2 * {{add @available attribute to enclosing protocol}}
+      
 
   func hasUnavailableReturn() -> ClassAvailableOn10_51 // expected-error * {{'ClassAvailableOn10_51' is only available on OS X 10.51 or newer}}
       // expected-note@-1 * {{add @available attribute to enclosing instance method}}
-      // expected-note@-2 * {{add @available attribute to enclosing protocol}}
 
   @available(OSX 10.51, *)
   func hasUnavailableWithAnnotation(_ p: ClassAvailableOn10_51) -> ClassAvailableOn10_51
@@ -1530,15 +1484,15 @@
 }
 
 func useUnavailableProtocolMethod(_ h: HasUnavailableMethodF) {
-  h.f("Foo") // expected-error {{'f' is only available on OS X 10.51 or newer}}
       // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+  h.f("Foo") // expected-error {{'f' is only available on OS X 10.51 or newer}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 func useUnavailableProtocolMethod<H : HasUnavailableMethodF> (_ h: H) {
-  h.f("Foo") // expected-error {{'f' is only available on OS X 10.51 or newer}}
       // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+  h.f("Foo") // expected-error {{'f' is only available on OS X 10.51 or newer}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 
@@ -1569,9 +1523,9 @@
 
 @available(iOS 14.0, *)
 func funcWithShortFormAvailableOniOS14() {
+  // expected-note@-1 {{add @available attribute to enclosing global function}}
   let _ = ClassWithShortFormAvailableOn10_51() // expected-error {{'ClassWithShortFormAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 @available(iOS 14.0, OSX 10.53, *)
@@ -1601,25 +1555,23 @@
 func unavailableWins() { } // expected-note {{'unavailableWins()' has been explicitly marked unavailable here}}
 
 func useShortFormAvailable() {
+  // expected-note@-1 4{{add @available attribute to enclosing global function}}
+
   funcWithShortFormAvailableOn10_9()
 
   funcWithShortFormAvailableOn10_51() // expected-error {{'funcWithShortFormAvailableOn10_51()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   funcWithShortFormAvailableOniOS14()
 
   funcWithShortFormAvailableOniOS14AndOSX10_53() // expected-error {{'funcWithShortFormAvailableOniOS14AndOSX10_53()' is only available on OS X 10.53 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   funcWithMultipleShortFormAnnotationsForDifferentPlatforms() // expected-error {{'funcWithMultipleShortFormAnnotationsForDifferentPlatforms()' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   funcWithMultipleShortFormAnnotationsForTheSamePlatform() // expected-error {{'funcWithMultipleShortFormAnnotationsForTheSamePlatform()' is only available on OS X 10.53 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   unavailableWins() // expected-error {{'unavailableWins()' is unavailable}}
-}
+}
\ No newline at end of file
diff --git a/test/Sema/availability_versions_objc_api.swift b/test/Sema/availability_versions_objc_api.swift
index 265e943..8eb9821 100644
--- a/test/Sema/availability_versions_objc_api.swift
+++ b/test/Sema/availability_versions_objc_api.swift
@@ -8,9 +8,9 @@
 
 // Tests for uses of version-based potential unavailability imported from ObjC APIs.
 func callUnavailableObjC() {
+      // expected-note@-1 5{{add @available attribute to enclosing global function}}
   _ = NSAvailableOn10_51() // expected-error {{'NSAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
   
   
   if #available(OSX 10.51, *) {
@@ -18,23 +18,19 @@
     
     // Properties
     _ = o.propertyOn10_52 // expected-error {{'propertyOn10_52' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
 
     o.propertyOn10_52 = 22 // expected-error {{'propertyOn10_52' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
     
     // Methods
     o.methodAvailableOn10_52() // expected-error {{'methodAvailableOn10_52()' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
     
     // Initializers
     
     _ = NSAvailableOn10_51(stringOn10_52:"Hi") // expected-error {{'init(stringOn10_52:)' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
   }
 }
 
@@ -74,50 +70,43 @@
 // Differing availability on getters and setters imported from ObjC.
 
 func gettersAndSettersFromObjC(o: NSAvailableOn10_9) {
+      // expected-note@-1 6{{add @available attribute to enclosing global function}}
   let _: Int = o.propertyOn10_51WithSetterOn10_52After  // expected-error {{'propertyOn10_51WithSetterOn10_52After' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   if #available(OSX 10.51, *) {
     // Properties with unavailable accessors declared before property in Objective-C header
     o.propertyOn10_51WithSetterOn10_52Before = 5 // expected-error {{setter for 'propertyOn10_51WithSetterOn10_52Before' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
 
     let _: Int = o.propertyOn10_51WithGetterOn10_52Before // expected-error {{getter for 'propertyOn10_51WithGetterOn10_52Before' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
 
     // Properties with unavailable accessors declared after property in Objective-C header
     o.propertyOn10_51WithSetterOn10_52After = 5 // expected-error {{setter for 'propertyOn10_51WithSetterOn10_52After' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
 
     let _: Int = o.propertyOn10_51WithGetterOn10_52After // expected-error {{getter for 'propertyOn10_51WithGetterOn10_52After' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
 
     // Property with unavailable setter redeclared in Objective-C category
     o.readOnlyRedeclaredWithSetterInCategory = 5 // expected-error {{setter for 'readOnlyRedeclaredWithSetterInCategory' is only available on OS X 10.52 or newer}}
-        // expected-note@-1 {{add @available attribute to enclosing global function}}
-        // expected-note@-2 {{add 'if #available' version check}}
+        // expected-note@-1 {{add 'if #available' version check}}
   }
 }
 
 // Globals from Objective-C
 
 func useGlobalsFromObjectiveC() {
+      // expected-note@-1 3{{add @available attribute to enclosing global function}}
   _ = globalStringAvailableOn10_51 // expected-error {{'globalStringAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   _ = globalStringAvailableOn10_52 // expected-error {{'globalStringAvailableOn10_52' is only available on OS X 10.52 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   _ = globalClassInstanceAvailableOn10_51 // expected-error {{'globalClassInstanceAvailableOn10_51' is only available on OS X 10.51 or newer}}
-      // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+      // expected-note@-1 {{add 'if #available' version check}}
 
   if #available(OSX 10.51, *) {
     _ = globalStringAvailableOn10_51
@@ -177,9 +166,9 @@
 }
 
 func callViaUnannotatedFrameworkProtocol(p: UnannotatedFrameworkProtocol) {
-  let _ = p.returnSomething() // expected-error {{'returnSomething()' is only available on OS X 10.51 or newer}}
       // expected-note@-1 {{add @available attribute to enclosing global function}}
-      // expected-note@-2 {{add 'if #available' version check}}
+  let _ = p.returnSomething() // expected-error {{'returnSomething()' is only available on OS X 10.51 or newer}}
+      // expected-note@-1 {{add 'if #available' version check}}
 }
 
 func callViaAnnotatedFrameworkProtocol(p: AnnotatedFrameworkProtocol) {
diff --git a/test/Serialization/Inputs/def_objc_conforming.swift b/test/Serialization/Inputs/def_objc_conforming.swift
new file mode 100644
index 0000000..c229fa7
--- /dev/null
+++ b/test/Serialization/Inputs/def_objc_conforming.swift
@@ -0,0 +1,9 @@
+import Foundation
+
+@objc public protocol Proto {
+  @objc optional func badness()
+}
+
+public class Foo: Proto {
+  public var badness: Int = 0 // unrelated
+}
diff --git a/test/Serialization/objc_optional_reqs.swift b/test/Serialization/objc_optional_reqs.swift
new file mode 100644
index 0000000..998c062
--- /dev/null
+++ b/test/Serialization/objc_optional_reqs.swift
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// FIXME: BEGIN -enable-source-import hackaround
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t %clang-importer-sdk-path/swift-modules/Foundation.swift
+// FIXME: END -enable-source-import hackaround
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t %S/Inputs/def_objc_conforming.swift
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -typecheck %s -verify
+
+// REQUIRES: objc_interop
+
+// SR-3917
+import def_objc_conforming
+
+func test(x: Foo) { _ = x.badness }
diff --git a/test/SourceKit/CursorInfo/cursor_info_expressions.swift b/test/SourceKit/CursorInfo/cursor_info_expressions.swift
new file mode 100644
index 0000000..56f1ee3
--- /dev/null
+++ b/test/SourceKit/CursorInfo/cursor_info_expressions.swift
@@ -0,0 +1,14 @@
+protocol P1 {}
+
+struct S1 : P1 {}
+
+func test(_ o: P1?) {
+  switch o {
+  case let s as S1:
+    test(s)
+  }
+}
+
+// RUN: %sourcekitd-test -req=cursor -pos=7:17 %s -- %s | %FileCheck -check-prefix=CHECK1 %s
+// CHECK1: source.lang.swift.ref.struct (3:8-3:10)
+// CHECK1: S1
diff --git a/test/api-digester/Outputs/Cake.txt b/test/api-digester/Outputs/Cake.txt
index 3a7fdcd..b12cbeb 100644
--- a/test/api-digester/Outputs/Cake.txt
+++ b/test/api-digester/Outputs/Cake.txt
@@ -7,8 +7,8 @@
 Func S1.foo5(x:y:) has been renamed to Func S1.foo5(x:y:z:)
 
 /* Type Changes */
-Constructor S1.init(_:) has 1st parameter type change from Int to Double
-Func C1.foo2(_:) has 1st parameter type change from Int to () -> ()
+Constructor S1.init(_:) has parameter 0 type change from Int to Double
+Func C1.foo2(_:) has parameter 0 type change from Int to () -> ()
 
 /* Decl Attribute changes */
 Var C1.CIIns1 changes from weak to strong
diff --git a/test/api-digester/source-stability.swift.expected b/test/api-digester/source-stability.swift.expected
index 89f7ef7..113fda8 100644
--- a/test/api-digester/source-stability.swift.expected
+++ b/test/api-digester/source-stability.swift.expected
@@ -26,20 +26,20 @@
 Var Dictionary.startIndex has declared type change from DictionaryIndex<Key, Value> to Dictionary<Key, Value>.Index
 Var Set.endIndex has declared type change from SetIndex<Element> to Set<Element>.Index
 Var Set.startIndex has declared type change from SetIndex<Element> to Set<Element>.Index
-Constructor AnyIterator.init(_:) has 1st parameter type change from () -> Element? to () -> AnyIterator.Element?
-Constructor BidirectionalSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<BidirectionalSlice.Index>
-Constructor MutableBidirectionalSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<MutableBidirectionalSlice.Index>
-Constructor MutableRandomAccessSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<MutableRandomAccessSlice.Index>
-Constructor MutableRangeReplaceableBidirectionalSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableBidirectionalSlice.Index>
-Constructor MutableRangeReplaceableRandomAccessSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableRandomAccessSlice.Index>
-Constructor MutableRangeReplaceableSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableSlice.Index>
-Constructor MutableSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<MutableSlice.Index>
-Constructor RandomAccessSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<RandomAccessSlice.Index>
-Constructor RangeReplaceableBidirectionalSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<RangeReplaceableBidirectionalSlice.Index>
-Constructor RangeReplaceableRandomAccessSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<RangeReplaceableRandomAccessSlice.Index>
-Constructor RangeReplaceableSlice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<RangeReplaceableSlice.Index>
-Constructor Slice.init(base:bounds:) has 2nd parameter type change from Range<Base.Index> to Range<Slice.Index>
-Constructor String.init(stringInterpolationSegment:) has 1st parameter type change from String to T
+Constructor AnyIterator.init(_:) has parameter 0 type change from () -> Element? to () -> AnyIterator.Element?
+Constructor BidirectionalSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<BidirectionalSlice.Index>
+Constructor MutableBidirectionalSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<MutableBidirectionalSlice.Index>
+Constructor MutableRandomAccessSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<MutableRandomAccessSlice.Index>
+Constructor MutableRangeReplaceableBidirectionalSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<MutableRangeReplaceableBidirectionalSlice.Index>
+Constructor MutableRangeReplaceableRandomAccessSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<MutableRangeReplaceableRandomAccessSlice.Index>
+Constructor MutableRangeReplaceableSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<MutableRangeReplaceableSlice.Index>
+Constructor MutableSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<MutableSlice.Index>
+Constructor RandomAccessSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<RandomAccessSlice.Index>
+Constructor RangeReplaceableBidirectionalSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<RangeReplaceableBidirectionalSlice.Index>
+Constructor RangeReplaceableRandomAccessSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<RangeReplaceableRandomAccessSlice.Index>
+Constructor RangeReplaceableSlice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<RangeReplaceableSlice.Index>
+Constructor Slice.init(base:bounds:) has parameter 1 type change from Range<Base.Index> to Range<Slice.Index>
+Constructor String.init(stringInterpolationSegment:) has parameter 0 type change from String to T
 Func AnyBidirectionalCollection.makeIterator() has return type change from AnyIterator<Element> to AnyBidirectionalCollection.Iterator
 Func AnyCollection.makeIterator() has return type change from AnyIterator<Element> to AnyCollection.Iterator
 Func AnyRandomAccessCollection.makeIterator() has return type change from AnyIterator<Element> to AnyRandomAccessCollection.Iterator
@@ -73,30 +73,30 @@
 Func FlattenBidirectionalCollection.index(after:) has return type change from FlattenBidirectionalCollectionIndex<Base> to FlattenBidirectionalCollection.Index
 Func FlattenBidirectionalCollection.index(before:) has return type change from FlattenBidirectionalCollectionIndex<Base> to FlattenBidirectionalCollection.Index
 Func FlattenCollection.index(after:) has return type change from FlattenCollectionIndex<Base> to FlattenCollection.Index
-Func LazyBidirectionalCollection.distance(from:to:) has 1st parameter type change from Base.Index to LazyBidirectionalCollection.Index
+Func LazyBidirectionalCollection.distance(from:to:) has parameter 0 type change from Base.Index to LazyBidirectionalCollection.Index
 Func LazyBidirectionalCollection.index(_:offsetBy:) has return type change from Base.Index to LazyBidirectionalCollection.Index
 Func LazyBidirectionalCollection.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to LazyBidirectionalCollection.Index?
-Func LazyCollection.distance(from:to:) has 1st parameter type change from Base.Index to LazyCollection.Index
+Func LazyCollection.distance(from:to:) has parameter 0 type change from Base.Index to LazyCollection.Index
 Func LazyCollection.index(_:offsetBy:) has return type change from Base.Index to LazyCollection.Index
 Func LazyCollection.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to LazyCollection.Index?
 Func LazyFilterBidirectionalCollection.index(after:) has return type change from LazyFilterIndex<Base> to LazyFilterBidirectionalCollection.Index
 Func LazyFilterBidirectionalCollection.index(before:) has return type change from LazyFilterIndex<Base> to LazyFilterBidirectionalCollection.Index
 Func LazyFilterCollection.index(after:) has return type change from LazyFilterIndex<Base> to LazyFilterCollection.Index
-Func LazyMapBidirectionalCollection.distance(from:to:) has 1st parameter type change from Base.Index to LazyMapBidirectionalCollection.Index
+Func LazyMapBidirectionalCollection.distance(from:to:) has parameter 0 type change from Base.Index to LazyMapBidirectionalCollection.Index
 Func LazyMapBidirectionalCollection.index(_:offsetBy:) has return type change from Base.Index to LazyMapBidirectionalCollection.Index
 Func LazyMapBidirectionalCollection.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to LazyMapBidirectionalCollection.Index?
 Func LazyMapBidirectionalCollection.index(after:) has return type change from Base.Index to LazyMapBidirectionalCollection.Index
 Func LazyMapBidirectionalCollection.index(before:) has return type change from Base.Index to LazyMapBidirectionalCollection.Index
-Func LazyMapCollection.distance(from:to:) has 1st parameter type change from Base.Index to LazyMapCollection.Index
+Func LazyMapCollection.distance(from:to:) has parameter 0 type change from Base.Index to LazyMapCollection.Index
 Func LazyMapCollection.index(_:offsetBy:) has return type change from Base.Index to LazyMapCollection.Index
 Func LazyMapCollection.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to LazyMapCollection.Index?
 Func LazyMapCollection.index(after:) has return type change from Base.Index to LazyMapCollection.Index
-Func LazyMapRandomAccessCollection.distance(from:to:) has 1st parameter type change from Base.Index to LazyMapRandomAccessCollection.Index
+Func LazyMapRandomAccessCollection.distance(from:to:) has parameter 0 type change from Base.Index to LazyMapRandomAccessCollection.Index
 Func LazyMapRandomAccessCollection.index(_:offsetBy:) has return type change from Base.Index to LazyMapRandomAccessCollection.Index
 Func LazyMapRandomAccessCollection.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to LazyMapRandomAccessCollection.Index?
 Func LazyMapRandomAccessCollection.index(after:) has return type change from Base.Index to LazyMapRandomAccessCollection.Index
 Func LazyMapRandomAccessCollection.index(before:) has return type change from Base.Index to LazyMapRandomAccessCollection.Index
-Func LazyRandomAccessCollection.distance(from:to:) has 1st parameter type change from Base.Index to LazyRandomAccessCollection.Index
+Func LazyRandomAccessCollection.distance(from:to:) has parameter 0 type change from Base.Index to LazyRandomAccessCollection.Index
 Func LazyRandomAccessCollection.index(_:offsetBy:) has return type change from Base.Index to LazyRandomAccessCollection.Index
 Func LazyRandomAccessCollection.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to LazyRandomAccessCollection.Index?
 Func MutableBidirectionalSlice.distance(from:to:) has return type change from Base.IndexDistance to MutableBidirectionalSlice.IndexDistance
@@ -114,30 +114,30 @@
 Func MutableRangeReplaceableBidirectionalSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to MutableRangeReplaceableBidirectionalSlice.Index?
 Func MutableRangeReplaceableBidirectionalSlice.index(after:) has return type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
 Func MutableRangeReplaceableBidirectionalSlice.index(before:) has return type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
-Func MutableRangeReplaceableBidirectionalSlice.insert(_:at:) has 2nd parameter type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
-Func MutableRangeReplaceableBidirectionalSlice.insert(contentsOf:at:) has 2nd parameter type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
-Func MutableRangeReplaceableBidirectionalSlice.remove(at:) has 1st parameter type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
-Func MutableRangeReplaceableBidirectionalSlice.removeSubrange(_:) has 1st parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableBidirectionalSlice.Index>
-Func MutableRangeReplaceableBidirectionalSlice.replaceSubrange(_:with:) has 1st parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableBidirectionalSlice.Index>
+Func MutableRangeReplaceableBidirectionalSlice.insert(_:at:) has parameter 1 type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
+Func MutableRangeReplaceableBidirectionalSlice.insert(contentsOf:at:) has parameter 1 type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
+Func MutableRangeReplaceableBidirectionalSlice.remove(at:) has parameter 0 type change from Base.Index to MutableRangeReplaceableBidirectionalSlice.Index
+Func MutableRangeReplaceableBidirectionalSlice.removeSubrange(_:) has parameter 0 type change from Range<Base.Index> to Range<MutableRangeReplaceableBidirectionalSlice.Index>
+Func MutableRangeReplaceableBidirectionalSlice.replaceSubrange(_:with:) has parameter 0 type change from Range<Base.Index> to Range<MutableRangeReplaceableBidirectionalSlice.Index>
 Func MutableRangeReplaceableRandomAccessSlice.distance(from:to:) has return type change from Base.IndexDistance to MutableRangeReplaceableRandomAccessSlice.IndexDistance
 Func MutableRangeReplaceableRandomAccessSlice.index(_:offsetBy:) has return type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
 Func MutableRangeReplaceableRandomAccessSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to MutableRangeReplaceableRandomAccessSlice.Index?
 Func MutableRangeReplaceableRandomAccessSlice.index(after:) has return type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
 Func MutableRangeReplaceableRandomAccessSlice.index(before:) has return type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
-Func MutableRangeReplaceableRandomAccessSlice.insert(_:at:) has 2nd parameter type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
-Func MutableRangeReplaceableRandomAccessSlice.insert(contentsOf:at:) has 2nd parameter type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
-Func MutableRangeReplaceableRandomAccessSlice.remove(at:) has 1st parameter type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
-Func MutableRangeReplaceableRandomAccessSlice.removeSubrange(_:) has 1st parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableRandomAccessSlice.Index>
-Func MutableRangeReplaceableRandomAccessSlice.replaceSubrange(_:with:) has 1st parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableRandomAccessSlice.Index>
+Func MutableRangeReplaceableRandomAccessSlice.insert(_:at:) has parameter 1 type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
+Func MutableRangeReplaceableRandomAccessSlice.insert(contentsOf:at:) has parameter 1 type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
+Func MutableRangeReplaceableRandomAccessSlice.remove(at:) has parameter 0 type change from Base.Index to MutableRangeReplaceableRandomAccessSlice.Index
+Func MutableRangeReplaceableRandomAccessSlice.removeSubrange(_:) has parameter 0 type change from Range<Base.Index> to Range<MutableRangeReplaceableRandomAccessSlice.Index>
+Func MutableRangeReplaceableRandomAccessSlice.replaceSubrange(_:with:) has parameter 0 type change from Range<Base.Index> to Range<MutableRangeReplaceableRandomAccessSlice.Index>
 Func MutableRangeReplaceableSlice.distance(from:to:) has return type change from Base.IndexDistance to MutableRangeReplaceableSlice.IndexDistance
 Func MutableRangeReplaceableSlice.index(_:offsetBy:) has return type change from Base.Index to MutableRangeReplaceableSlice.Index
 Func MutableRangeReplaceableSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to MutableRangeReplaceableSlice.Index?
 Func MutableRangeReplaceableSlice.index(after:) has return type change from Base.Index to MutableRangeReplaceableSlice.Index
-Func MutableRangeReplaceableSlice.insert(_:at:) has 2nd parameter type change from Base.Index to MutableRangeReplaceableSlice.Index
-Func MutableRangeReplaceableSlice.insert(contentsOf:at:) has 2nd parameter type change from Base.Index to MutableRangeReplaceableSlice.Index
-Func MutableRangeReplaceableSlice.remove(at:) has 1st parameter type change from Base.Index to MutableRangeReplaceableSlice.Index
-Func MutableRangeReplaceableSlice.removeSubrange(_:) has 1st parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableSlice.Index>
-Func MutableRangeReplaceableSlice.replaceSubrange(_:with:) has 1st parameter type change from Range<Base.Index> to Range<MutableRangeReplaceableSlice.Index>
+Func MutableRangeReplaceableSlice.insert(_:at:) has parameter 1 type change from Base.Index to MutableRangeReplaceableSlice.Index
+Func MutableRangeReplaceableSlice.insert(contentsOf:at:) has parameter 1 type change from Base.Index to MutableRangeReplaceableSlice.Index
+Func MutableRangeReplaceableSlice.remove(at:) has parameter 0 type change from Base.Index to MutableRangeReplaceableSlice.Index
+Func MutableRangeReplaceableSlice.removeSubrange(_:) has parameter 0 type change from Range<Base.Index> to Range<MutableRangeReplaceableSlice.Index>
+Func MutableRangeReplaceableSlice.replaceSubrange(_:with:) has parameter 0 type change from Range<Base.Index> to Range<MutableRangeReplaceableSlice.Index>
 Func MutableSlice.distance(from:to:) has return type change from Base.IndexDistance to MutableSlice.IndexDistance
 Func MutableSlice.index(_:offsetBy:) has return type change from Base.Index to MutableSlice.Index
 Func MutableSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to MutableSlice.Index?
@@ -146,7 +146,7 @@
 Func OptionSet.remove(_:) has return type change from Self? to Self.Element?
 Func OptionSet.update(with:) has return type change from Self? to Self.Element?
 Func RandomAccessCollection.distance(from:to:) has return type change from Self.IndexDistance to Self.Index.Stride
-Func RandomAccessCollection.index(_:offsetBy:) has 2nd parameter type change from Self.IndexDistance to Self.Index.Stride
+Func RandomAccessCollection.index(_:offsetBy:) has parameter 1 type change from Self.IndexDistance to Self.Index.Stride
 Func RandomAccessSlice.distance(from:to:) has return type change from Base.IndexDistance to RandomAccessSlice.IndexDistance
 Func RandomAccessSlice.index(_:offsetBy:) has return type change from Base.Index to RandomAccessSlice.Index
 Func RandomAccessSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to RandomAccessSlice.Index?
@@ -157,30 +157,30 @@
 Func RangeReplaceableBidirectionalSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to RangeReplaceableBidirectionalSlice.Index?
 Func RangeReplaceableBidirectionalSlice.index(after:) has return type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
 Func RangeReplaceableBidirectionalSlice.index(before:) has return type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
-Func RangeReplaceableBidirectionalSlice.insert(_:at:) has 2nd parameter type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
-Func RangeReplaceableBidirectionalSlice.insert(contentsOf:at:) has 2nd parameter type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
-Func RangeReplaceableBidirectionalSlice.remove(at:) has 1st parameter type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
-Func RangeReplaceableBidirectionalSlice.removeSubrange(_:) has 1st parameter type change from Range<Base.Index> to Range<RangeReplaceableBidirectionalSlice.Index>
-Func RangeReplaceableBidirectionalSlice.replaceSubrange(_:with:) has 1st parameter type change from Range<Base.Index> to Range<RangeReplaceableBidirectionalSlice.Index>
+Func RangeReplaceableBidirectionalSlice.insert(_:at:) has parameter 1 type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
+Func RangeReplaceableBidirectionalSlice.insert(contentsOf:at:) has parameter 1 type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
+Func RangeReplaceableBidirectionalSlice.remove(at:) has parameter 0 type change from Base.Index to RangeReplaceableBidirectionalSlice.Index
+Func RangeReplaceableBidirectionalSlice.removeSubrange(_:) has parameter 0 type change from Range<Base.Index> to Range<RangeReplaceableBidirectionalSlice.Index>
+Func RangeReplaceableBidirectionalSlice.replaceSubrange(_:with:) has parameter 0 type change from Range<Base.Index> to Range<RangeReplaceableBidirectionalSlice.Index>
 Func RangeReplaceableRandomAccessSlice.distance(from:to:) has return type change from Base.IndexDistance to RangeReplaceableRandomAccessSlice.IndexDistance
 Func RangeReplaceableRandomAccessSlice.index(_:offsetBy:) has return type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
 Func RangeReplaceableRandomAccessSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to RangeReplaceableRandomAccessSlice.Index?
 Func RangeReplaceableRandomAccessSlice.index(after:) has return type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
 Func RangeReplaceableRandomAccessSlice.index(before:) has return type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
-Func RangeReplaceableRandomAccessSlice.insert(_:at:) has 2nd parameter type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
-Func RangeReplaceableRandomAccessSlice.insert(contentsOf:at:) has 2nd parameter type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
-Func RangeReplaceableRandomAccessSlice.remove(at:) has 1st parameter type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
-Func RangeReplaceableRandomAccessSlice.removeSubrange(_:) has 1st parameter type change from Range<Base.Index> to Range<RangeReplaceableRandomAccessSlice.Index>
-Func RangeReplaceableRandomAccessSlice.replaceSubrange(_:with:) has 1st parameter type change from Range<Base.Index> to Range<RangeReplaceableRandomAccessSlice.Index>
+Func RangeReplaceableRandomAccessSlice.insert(_:at:) has parameter 1 type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
+Func RangeReplaceableRandomAccessSlice.insert(contentsOf:at:) has parameter 1 type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
+Func RangeReplaceableRandomAccessSlice.remove(at:) has parameter 0 type change from Base.Index to RangeReplaceableRandomAccessSlice.Index
+Func RangeReplaceableRandomAccessSlice.removeSubrange(_:) has parameter 0 type change from Range<Base.Index> to Range<RangeReplaceableRandomAccessSlice.Index>
+Func RangeReplaceableRandomAccessSlice.replaceSubrange(_:with:) has parameter 0 type change from Range<Base.Index> to Range<RangeReplaceableRandomAccessSlice.Index>
 Func RangeReplaceableSlice.distance(from:to:) has return type change from Base.IndexDistance to RangeReplaceableSlice.IndexDistance
 Func RangeReplaceableSlice.index(_:offsetBy:) has return type change from Base.Index to RangeReplaceableSlice.Index
 Func RangeReplaceableSlice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to RangeReplaceableSlice.Index?
 Func RangeReplaceableSlice.index(after:) has return type change from Base.Index to RangeReplaceableSlice.Index
-Func RangeReplaceableSlice.insert(_:at:) has 2nd parameter type change from Base.Index to RangeReplaceableSlice.Index
-Func RangeReplaceableSlice.insert(contentsOf:at:) has 2nd parameter type change from Base.Index to RangeReplaceableSlice.Index
-Func RangeReplaceableSlice.remove(at:) has 1st parameter type change from Base.Index to RangeReplaceableSlice.Index
-Func RangeReplaceableSlice.removeSubrange(_:) has 1st parameter type change from Range<Base.Index> to Range<RangeReplaceableSlice.Index>
-Func RangeReplaceableSlice.replaceSubrange(_:with:) has 1st parameter type change from Range<Base.Index> to Range<RangeReplaceableSlice.Index>
+Func RangeReplaceableSlice.insert(_:at:) has parameter 1 type change from Base.Index to RangeReplaceableSlice.Index
+Func RangeReplaceableSlice.insert(contentsOf:at:) has parameter 1 type change from Base.Index to RangeReplaceableSlice.Index
+Func RangeReplaceableSlice.remove(at:) has parameter 0 type change from Base.Index to RangeReplaceableSlice.Index
+Func RangeReplaceableSlice.removeSubrange(_:) has parameter 0 type change from Range<Base.Index> to Range<RangeReplaceableSlice.Index>
+Func RangeReplaceableSlice.replaceSubrange(_:with:) has parameter 0 type change from Range<Base.Index> to Range<RangeReplaceableSlice.Index>
 Func ReversedCollection.distance(from:to:) has return type change from Base.IndexDistance to ReversedCollection.IndexDistance
 Func ReversedCollection.index(_:offsetBy:) has return type change from ReversedIndex<Base> to ReversedCollection.Index
 Func ReversedCollection.index(_:offsetBy:limitedBy:) has return type change from ReversedIndex<Base>? to ReversedCollection.Index?
@@ -191,19 +191,19 @@
 Func ReversedRandomAccessCollection.index(_:offsetBy:limitedBy:) has return type change from ReversedRandomAccessIndex<Base>? to ReversedRandomAccessCollection.Index?
 Func ReversedRandomAccessCollection.index(after:) has return type change from ReversedRandomAccessIndex<Base> to ReversedRandomAccessCollection.Index
 Func ReversedRandomAccessCollection.index(before:) has return type change from ReversedRandomAccessIndex<Base> to ReversedRandomAccessCollection.Index
-Func Set.formSymmetricDifference(_:) has 1st parameter type change from Set<Element> to Set<Set.Element>
+Func Set.formSymmetricDifference(_:) has parameter 0 type change from Set<Element> to Set<Set.Element>
 Func Set.index(after:) has return type change from SetIndex<Element> to Set<Element>.Index
 Func Set.index(of:) has return type change from SetIndex<Element>? to Set<Element>.Index?
 Func Set.intersection(_:) has return type change from Set<Element> to Set<Set.Element>
-Func Set.isDisjoint(with:) has 1st parameter type change from Set<Element> to Set<Set.Element>
-Func Set.isStrictSubset(of:) has 1st parameter type change from Set<Element> to Set<Set.Element>
-Func Set.isStrictSuperset(of:) has 1st parameter type change from Set<Element> to Set<Set.Element>
-Func Set.isSubset(of:) has 1st parameter type change from Set<Element> to Set<Set.Element>
-Func Set.isSuperset(of:) has 1st parameter type change from Set<Element> to Set<Set.Element>
+Func Set.isDisjoint(with:) has parameter 0 type change from Set<Element> to Set<Set.Element>
+Func Set.isStrictSubset(of:) has parameter 0 type change from Set<Element> to Set<Set.Element>
+Func Set.isStrictSuperset(of:) has parameter 0 type change from Set<Element> to Set<Set.Element>
+Func Set.isSubset(of:) has parameter 0 type change from Set<Element> to Set<Set.Element>
+Func Set.isSuperset(of:) has parameter 0 type change from Set<Element> to Set<Set.Element>
 Func Set.popFirst() has return type change from Element? to Set.Element?
-Func Set.remove(at:) has 1st parameter type change from SetIndex<Element> to Set<Element>.Index
+Func Set.remove(at:) has parameter 0 type change from SetIndex<Element> to Set<Element>.Index
 Func Set.removeFirst() has return type change from Element to Set.Element
-Func Set.subtract(_:) has 1st parameter type change from Set<Element> to Set<Set.Element>
+Func Set.subtract(_:) has parameter 0 type change from Set<Element> to Set<Set.Element>
 Func Set.subtracting(_:) has return type change from Set<Element> to Set<Set.Element>
 Func Set.symmetricDifference(_:) has return type change from Set<Element> to Set<Set.Element>
 Func Set.union(_:) has return type change from Set<Element> to Set<Set.Element>
@@ -213,7 +213,7 @@
 Func Slice.index(after:) has return type change from Base.Index to Slice.Index
 
 /* Function type change */
-Func UnsafePointer.withMemoryRebound(to:capacity:_:) has 3rd parameter type change from (UnsafeMutablePointer<T>) throws -> Result to (UnsafePointer<T>) throws -> Result
+Func UnsafePointer.withMemoryRebound(to:capacity:_:) has parameter 2 type change from (UnsafeMutablePointer<T>) throws -> Result to (UnsafePointer<T>) throws -> Result
 
 /* FIXME: Bogus */
 Func Zip2Iterator.next() has return type change from (Iterator1.Element, Iterator2.Element)? to Zip2Iterator.Element?
diff --git a/test/attr/attr_availability_narrow.swift b/test/attr/attr_availability_narrow.swift
index 1dee604..836c504 100644
--- a/test/attr/attr_availability_narrow.swift
+++ b/test/attr/attr_availability_narrow.swift
@@ -32,10 +32,10 @@
 }
 
 func useFooWayOff() {
+    // expected-note@-1{{add @available attribute to enclosing global function}}
   if #available(OSX 10.10, *) {
     foo() // expected-error {{'foo()' is only available on OS X 10.12.2 or newer}}
-    // expected-note@-1{{add @available attribute to enclosing global function}}
-    // expected-note@-2{{add 'if #available' version check}}
+    // expected-note@-1{{add 'if #available' version check}}
   }
 }
 
diff --git a/test/decl/protocol/conforms/fixit_stub.swift b/test/decl/protocol/conforms/fixit_stub.swift
index 6fd9a29..95b82c0 100644
--- a/test/decl/protocol/conforms/fixit_stub.swift
+++ b/test/decl/protocol/conforms/fixit_stub.swift
@@ -1,14 +1,14 @@
 // RUN: %target-typecheck-verify-swift
 
 protocol Protocol1 {
-  func foo(arg1: Int, arg2: String) -> String // expected-note{{protocol requires function 'foo(arg1:arg2:)' with type '(Int, String) -> String'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n}}
-  func bar() throws -> String // expected-note{{protocol requires function 'bar()' with type '() throws -> String'; do you want to add a stub?}} {{27-27=\n    func bar() throws -> String {\n        <#code#>\n    \}\n}}
-  func generic<T>(t: T) // expected-note{{protocol requires function 'generic(t:)' with type '<T> (t: T) -> ()'; do you want to add a stub?}} {{27-27=\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n}}
-  init(arg: Int) // expected-note{{protocol requires initializer 'init(arg:)' with type '(arg: Int)'; do you want to add a stub?}} {{27-27=\n    required init(arg: Int) {\n        <#code#>\n    \}\n}}
-  var baz: Int { get } // expected-note{{protocol requires property 'baz' with type 'Int'; do you want to add a stub?}} {{27-27=\n    var baz: Int\n}}
-  var baz2: Int { get set } // expected-note{{protocol requires property 'baz2' with type 'Int'; do you want to add a stub?}} {{27-27=\n    var baz2: Int\n}}
-  subscript(arg: Int) -> String { get } //expected-note{{rotocol requires subscript with type '(Int) -> String'; do you want to add a stub?}} {{27-27=\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n}}
-  subscript(arg1: Int, arg2: Int) -> String { get set } //expected-note{{protocol requires subscript with type '(Int, Int) -> String'; do you want to add a stub?}} {{27-27=\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  func foo(arg1: Int, arg2: String) -> String // expected-note{{protocol requires function 'foo(arg1:arg2:)' with type '(Int, String) -> String'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  func bar() throws -> String // expected-note{{protocol requires function 'bar()' with type '() throws -> String'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  func generic<T>(t: T) // expected-note{{protocol requires function 'generic(t:)' with type '<T> (t: T) -> ()'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  init(arg: Int) // expected-note{{protocol requires initializer 'init(arg:)' with type '(arg: Int)'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  var baz: Int { get } // expected-note{{protocol requires property 'baz' with type 'Int'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  var baz2: Int { get set } // expected-note{{protocol requires property 'baz2' with type 'Int'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  subscript(arg: Int) -> String { get } //expected-note{{rotocol requires subscript with type '(Int) -> String'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  subscript(arg1: Int, arg2: Int) -> String { get set } //expected-note{{protocol requires subscript with type '(Int, Int) -> String'; do you want to add a stub?}} {{27-27=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    func generic<T>(t: T) {\n        <#code#>\n    \}\n\n    required init(arg: Int) {\n        <#code#>\n    \}\n\n    var baz: Int\n\n    var baz2: Int\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
 }
 
 class Adopter: Protocol1 { // expected-error{{type 'Adopter' does not conform to protocol 'Protocol1'}} expected-note{{candidate has non-matching type '()'}}
@@ -17,13 +17,13 @@
 
 
 protocol Protocol2 {
-  func foo(arg1: Int, arg2: String) -> String // expected-note{{protocol requires function 'foo(arg1:arg2:)' with type '(Int, String) -> String'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n}}
-  func bar() throws -> String // expected-note{{protocol requires function 'bar()' with type '() throws -> String'; do you want to add a stub?}} {{32-32=\n    func bar() throws -> String {\n        <#code#>\n    \}\n}}
+  func foo(arg1: Int, arg2: String) -> String // expected-note{{protocol requires function 'foo(arg1:arg2:)' with type '(Int, String) -> String'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    var baz: Int {\n        <#code#>\n    \}\n\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  func bar() throws -> String // expected-note{{protocol requires function 'bar()' with type '() throws -> String'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    var baz: Int {\n        <#code#>\n    \}\n\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
   init(arg: Int) // expected-note{{protocol requires initializer 'init(arg:)' with type '(arg: Int)'}} {{none}}
-  var baz: Int { get } // expected-note{{protocol requires property 'baz' with type 'Int'; do you want to add a stub?}} {{32-32=\n    var baz: Int {\n        <#code#>\n    \}\n}}
-  var baz2: Int { get set } // expected-note{{protocol requires property 'baz2' with type 'Int'; do you want to add a stub?}} {{32-32=\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
-  subscript(arg: Int) -> String { get } //expected-note{{rotocol requires subscript with type '(Int) -> String'; do you want to add a stub?}} {{32-32=\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n}}
-  subscript(arg1: Int, arg2: Int) -> String { get set } //expected-note{{protocol requires subscript with type '(Int, Int) -> String'; do you want to add a stub?}} {{32-32=\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  var baz: Int { get } // expected-note{{protocol requires property 'baz' with type 'Int'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    var baz: Int {\n        <#code#>\n    \}\n\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  var baz2: Int { get set } // expected-note{{protocol requires property 'baz2' with type 'Int'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    var baz: Int {\n        <#code#>\n    \}\n\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  subscript(arg: Int) -> String { get } //expected-note{{rotocol requires subscript with type '(Int) -> String'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    var baz: Int {\n        <#code#>\n    \}\n\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
+  subscript(arg1: Int, arg2: Int) -> String { get set } //expected-note{{protocol requires subscript with type '(Int, Int) -> String'; do you want to add a stub?}} {{32-32=\n    func foo(arg1: Int, arg2: String) -> String {\n        <#code#>\n    \}\n\n    func bar() throws -> String {\n        <#code#>\n    \}\n\n    var baz: Int {\n        <#code#>\n    \}\n\n    var baz2: Int {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n\n    subscript(arg: Int) -> String {\n        <#code#>\n    \}\n\n    subscript(arg1: Int, arg2: Int) -> String {\n        get {\n            <#code#>\n        \}\n        set {\n            <#code#>\n        \}\n    \}\n}}
 }
 
 class Adopter2 {} //  expected-note{{candidate has non-matching type '()'}}
@@ -55,8 +55,8 @@
 
 
 protocol ProtocolWithSelfRequirement {
-  func foo() -> Self // expected-note{{protocol requires function 'foo()' with type '() -> Adopter5'; do you want to add a stub?}} {{47-47=\n    func foo() -> Adopter5 {\n        <#code#>\n    \}\n}}
-  func foo(lhs: Self, rhs: Self) -> Self //expected-note{{protocol requires function 'foo(lhs:rhs:)' with type '(Adopter5, Adopter5) -> Adopter5'; do you want to add a stub?}} {{47-47=\n    func foo(lhs: Adopter5, rhs: Adopter5) -> Adopter5 {\n        <#code#>\n    \}\n}}
+  func foo() -> Self // expected-note{{protocol requires function 'foo()' with type '() -> Adopter5'; do you want to add a stub?}} {{47-47=\n    func foo() -> Adopter5 {\n        <#code#>\n    \}\n\n    func foo(lhs: Adopter5, rhs: Adopter5) -> Adopter5 {\n        <#code#>\n    \}\n}}
+  func foo(lhs: Self, rhs: Self) -> Self //expected-note{{protocol requires function 'foo(lhs:rhs:)' with type '(Adopter5, Adopter5) -> Adopter5'; do you want to add a stub?}} {{47-47=\n    func foo() -> Adopter5 {\n        <#code#>\n    \}\n\n    func foo(lhs: Adopter5, rhs: Adopter5) -> Adopter5 {\n        <#code#>\n    \}\n}}
 }
 
 struct Adopter5: ProtocolWithSelfRequirement { //expected-error{{type 'Adopter5' does not conform to protocol 'ProtocolWithSelfRequirement'}}
@@ -65,8 +65,8 @@
 
 
 protocol ProtocolWithSelfRequirement2 {
-  func foo() -> Self // expected-note{{protocol requires function 'foo()' with type '() -> Adopter6'; do you want to add a stub?}} {{51-51=\n    func foo() -> Adopter6 {\n        <#code#>\n    \}\n}}
-  func foo(lhs: Self, rhs: Self) -> Self //expected-note{{protocol requires function 'foo(lhs:rhs:)' with type '(Adopter6, Adopter6) -> Adopter6'; do you want to add a stub?}} {{51-51=\n    func foo(lhs: Adopter6, rhs: Adopter6) -> Adopter6 {\n        <#code#>\n    \}\n}}
+  func foo() -> Self // expected-note{{protocol requires function 'foo()' with type '() -> Adopter6'; do you want to add a stub?}} {{51-51=\n    func foo() -> Adopter6 {\n        <#code#>\n    \}\n\n    func foo(lhs: Adopter6, rhs: Adopter6) -> Adopter6 {\n        <#code#>\n    \}\n}}
+  func foo(lhs: Self, rhs: Self) -> Self //expected-note{{protocol requires function 'foo(lhs:rhs:)' with type '(Adopter6, Adopter6) -> Adopter6'; do you want to add a stub?}} {{51-51=\n    func foo() -> Adopter6 {\n        <#code#>\n    \}\n\n    func foo(lhs: Adopter6, rhs: Adopter6) -> Adopter6 {\n        <#code#>\n    \}\n}}
 }
 
 struct Adopter6 {}
@@ -76,8 +76,8 @@
 
 
 protocol ProtocolWithSelfRequirement3 {
-  func foo() -> Self // expected-note{{protocol requires function 'foo()' with type '() -> Self'; do you want to add a stub?}} {{47-47=\n    func foo() -> Self {\n        <#code#>\n    \}\n}}
-  func foo(lhs: Self, rhs: Self) -> Self //expected-note{{protocol requires function 'foo(lhs:rhs:)' with type '(Adopter7, Adopter7) -> Self'; do you want to add a stub?}} {{47-47=\n    func foo(lhs: Adopter7, rhs: Adopter7) -> Self {\n        <#code#>\n    \}\n}}
+  func foo() -> Self // expected-note{{protocol requires function 'foo()' with type '() -> Self'; do you want to add a stub?}} {{47-47=\n    func foo() -> Self {\n        <#code#>\n    \}\n\n    func foo(lhs: Adopter7, rhs: Adopter7) -> Self {\n        <#code#>\n    \}\n}}
+  func foo(lhs: Self, rhs: Self) -> Self //expected-note{{protocol requires function 'foo(lhs:rhs:)' with type '(Adopter7, Adopter7) -> Self'; do you want to add a stub?}} {{47-47=\n    func foo() -> Self {\n        <#code#>\n    \}\n\n    func foo(lhs: Adopter7, rhs: Adopter7) -> Self {\n        <#code#>\n    \}\n}}
 }
 
 class Adopter7: ProtocolWithSelfRequirement3 { //expected-error{{type 'Adopter7' does not conform to protocol 'ProtocolWithSelfRequirement3'}}
diff --git a/test/decl/protocol/protocols.swift b/test/decl/protocol/protocols.swift
index f82826b..5a188c7 100644
--- a/test/decl/protocol/protocols.swift
+++ b/test/decl/protocol/protocols.swift
@@ -422,7 +422,7 @@
 struct X3<T : P1> where T.Assoc : P2 {}
 
 struct X4 : P1 { // expected-error{{type 'X4' does not conform to protocol 'P1'}}
-  func getX1() -> X3<X4> { return X3() } // expected-error{{cannot convert return expression of type 'X3<_>' to return type 'X3<X4>'}}
+  func getX1() -> X3<X4> { return X3() }
 }
 
 protocol ShouldntCrash {
diff --git a/test/lit.cfg b/test/lit.cfg
index dd05346..a08a49e 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -1079,3 +1079,5 @@
     # finishSwigPythonLLDB.py in the lldb repo
     python_lib_dir = get_python_lib(True, False, config.lldb_build_root)
     config.substitutions.append(('%lldb-python-path', python_lib_dir))
+
+lit_config.note("Available features: " + ", ".join(config.available_features))
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 7c22c6f..d51b958 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -737,16 +737,10 @@
                                                       unsigned Index) {
   if (Index == 0) {
     return Ctx.buffer("return");
-  } else if (Index == 1) {
-    return Ctx.buffer("1st parameter");
-  } else if (Index == 2) {
-    return Ctx.buffer("2nd parameter");
-  } else if (Index == 3) {
-    return Ctx.buffer("3rd parameter");
   } else {
     llvm::SmallString<4> Buffer;
-    Buffer += std::to_string(Index);
-    Buffer += "th parameter";
+    Buffer += "parameter ";
+    Buffer += std::to_string(Index - 1);
     return Ctx.buffer(Buffer.str());
   }
 }
@@ -3497,15 +3491,19 @@
   options::ModuleCachePath;
 
   if (!options::SwiftVersion.empty()) {
-    if (auto Version = version::Version::
-        parseVersionString(options::SwiftVersion, SourceLoc(), nullptr)) {
-      if (Version.getValue().isValidEffectiveLanguageVersion())
-        InitInvok.getLangOptions().EffectiveLanguageVersion = Version.getValue();
-      else {
-        llvm::errs() << "Unsupported Swift Version.\n";
-        return 1;
+    using version::Version;
+    bool isValid = false;
+    if (auto Version = Version::parseVersionString(options::SwiftVersion,
+                                                   SourceLoc(), nullptr)) {
+      if (auto Effective = Version.getValue().getEffectiveLanguageVersion()) {
+        InitInvok.getLangOptions().EffectiveLanguageVersion = *Effective;
+        isValid = true;
       }
     }
+    if (!isValid) {
+      llvm::errs() << "Unsupported Swift Version.\n";
+      return 1;
+    }
   }
 
   if (!options::ResourceDir.empty()) {
diff --git a/tools/swift-demangle/swift-demangle.cpp b/tools/swift-demangle/swift-demangle.cpp
index e4b1a3e..596fc88 100644
--- a/tools/swift-demangle/swift-demangle.cpp
+++ b/tools/swift-demangle/swift-demangle.cpp
@@ -99,8 +99,15 @@
       // mangling and demangling tests.
       remangled = name;
     } else {
+      // Also accept the future mangling prefix.
+      // TODO: remove the "_S" as soon as MANGLING_PREFIX_STR gets "_S".
       remangled = swift::Demangle::mangleNode(pointer,
-                          /*NewMangling*/ name.startswith(MANGLING_PREFIX_STR));
+                          /*NewMangling*/ name.startswith(MANGLING_PREFIX_STR)
+                                          || name.startswith("_S"));
+      if (name.startswith("_S")) {
+        assert(remangled.find(MANGLING_PREFIX_STR) == 0);
+        remangled = "_S" + remangled.substr(3);
+      }
       if (name != remangled) {
         llvm::errs() << "\nError: re-mangled name \n  " << remangled
                      << "\ndoes not match original name\n  " << name << '\n';
@@ -130,8 +137,19 @@
       std::string cName = name.str();
       if (!swift::Demangle::isSwiftSymbol(cName.c_str()))
         Classifications += 'N';
-      if (DCtx.isThunkSymbol(name))
-        Classifications += 'T';
+      if (DCtx.isThunkSymbol(name)) {
+        if (!Classifications.empty())
+          Classifications += ',';
+        Classifications += "T:";
+        Classifications += DCtx.getThunkTarget(name);
+      } else {
+        assert(DCtx.getThunkTarget(name).empty());
+      }
+      if (pointer && !DCtx.hasSwiftCallingConvention(name)) {
+        if (!Classifications.empty())
+          Classifications += ',';
+        Classifications += 'C';
+      }
       if (!Classifications.empty())
         llvm::outs() << '{' << Classifications << "} ";
     }
@@ -142,7 +160,9 @@
 
 static int demangleSTDIN(const swift::Demangle::DemangleOptions &options) {
   // This doesn't handle Unicode symbols, but maybe that's okay.
-  llvm::Regex maybeSymbol("(_T|" MANGLING_PREFIX_STR ")[_a-zA-Z0-9$]+");
+  // Also accept the future mangling prefix.
+  // TODO: remove the "_S" as soon as MANGLING_PREFIX_STR gets "_S".
+  llvm::Regex maybeSymbol("(_T|_S|" MANGLING_PREFIX_STR ")[_a-zA-Z0-9$]+");
 
   swift::Demangle::Context DCtx;
   for (std::string mangled; std::getline(std::cin, mangled);) {
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index 00f11f4..83425c7 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -2957,7 +2957,8 @@
     if (auto swiftVersion =
           version::Version::parseVersionString(options::SwiftVersion,
                                                SourceLoc(), nullptr)) {
-      InitInvok.getLangOptions().EffectiveLanguageVersion = *swiftVersion;
+      if (auto actual = swiftVersion.getValue().getEffectiveLanguageVersion())
+        InitInvok.getLangOptions().EffectiveLanguageVersion = actual.getValue();
     }
   }
   InitInvok.getClangImporterOptions().ModuleCachePath =
diff --git a/unittests/Syntax/CMakeLists.txt b/unittests/Syntax/CMakeLists.txt
index d812d93..1b9f0cf 100644
--- a/unittests/Syntax/CMakeLists.txt
+++ b/unittests/Syntax/CMakeLists.txt
@@ -4,6 +4,7 @@
   GenericSyntaxTests.cpp
   RawSyntaxTests.cpp
   StmtSyntaxTests.cpp
+  SyntaxCollectionTests.cpp
   ThreadSafeCachingTests.cpp
   TriviaTests.cpp
   TypeSyntaxTests.cpp
diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp
index ae6d857..7640dfe 100644
--- a/unittests/Syntax/DeclSyntaxTests.cpp
+++ b/unittests/Syntax/DeclSyntaxTests.cpp
@@ -1,5 +1,7 @@
 #include "swift/Syntax/SyntaxFactory.h"
 #include "swift/Syntax/DeclSyntax.h"
+#include "swift/Syntax/ExprSyntax.h"
+#include "swift/Syntax/StmtSyntax.h"
 #include "llvm/ADT/SmallString.h"
 #include "gtest/gtest.h"
 
@@ -9,6 +11,63 @@
 using namespace swift;
 using namespace swift::syntax;
 
+#pragma mark - declaration-modifier
+
+DeclModifierSyntax getCannedDeclModifier() {
+  auto Private = SyntaxFactory::makeIdentifier("private", {}, {});
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto Set = SyntaxFactory::makeIdentifier("set", {}, {});
+  auto RParen = SyntaxFactory::makeRightParenToken({}, {});
+  return SyntaxFactory::makeDeclModifier(Private, LParen, Set, RParen);
+}
+
+TEST(DeclSyntaxTests, DeclModifierMakeAPIs) {
+  {
+    SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankDeclModifier().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+  {
+    SmallString<24> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    getCannedDeclModifier().print(OS);
+    ASSERT_EQ(OS.str().str(), "private(set)");
+  }
+}
+
+TEST(DeclSyntaxTests, DeclModifierGetAPIs) {
+  auto Private = SyntaxFactory::makeIdentifier("private", {}, {});
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto Set = SyntaxFactory::makeIdentifier("set", {}, {});
+  auto RParen = SyntaxFactory::makeRightParenToken({}, {});
+  auto Mod = SyntaxFactory::makeDeclModifier(Private, LParen, Set, RParen);
+
+  ASSERT_EQ(Private, Mod.getName());
+  ASSERT_EQ(LParen, Mod.getLeftParenToken());
+  ASSERT_EQ(Set, Mod.getArgument());
+  ASSERT_EQ(RParen, Mod.getRightParenToken());
+}
+
+TEST(DeclSyntaxTests, DeclModifierWithAPIs) {
+  auto Private = SyntaxFactory::makeIdentifier("private", {}, {});
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto Set = SyntaxFactory::makeIdentifier("set", {}, {});
+  auto RParen = SyntaxFactory::makeRightParenToken({}, {});
+
+  SmallString<24> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  SyntaxFactory::makeBlankDeclModifier()
+    .withName(Private)
+    .withLeftParenToken(LParen)
+    .withArgument(Set)
+    .withRightParenToken(RParen)
+    .print(OS);
+  ASSERT_EQ(OS.str().str(), "private(set)");
+}
+
+#pragma mark - typealias-decl
+
 TEST(DeclSyntaxTests, TypealiasMakeAPIs) {
   {
     SmallString<1> Scratch;
@@ -25,8 +84,7 @@
     auto ElementParam =
       SyntaxFactory::makeGenericParameter("Element", {}, {});
     auto LeftAngle = SyntaxFactory::makeLeftAngleToken({}, {});
-    auto RightAngle =
-      SyntaxFactory::makeRightAngleToken({}, { Trivia::spaces(1) });
+    auto RightAngle = SyntaxFactory::makeRightAngleToken({}, Trivia::spaces(1));
     auto GenericParams = GenericParameterClauseBuilder()
       .useLeftAngleBracket(LeftAngle)
       .useRightAngleBracket(RightAngle)
@@ -137,3 +195,402 @@
   ASSERT_EQ(OS.str().str(),
             "typealias MyCollection<Element> = Array<Element>");
 }
+
+#pragma mark - parameter
+
+FunctionParameterSyntax getCannedFunctionParameter() {
+  auto ExternalName = SyntaxFactory::makeIdentifier("with", {},
+                                                    Trivia::spaces(1));
+  auto LocalName = SyntaxFactory::makeIdentifier("radius", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {},
+                                               Trivia::spaces(1));
+  auto NoEllipsis = TokenSyntax::missingToken(tok::identifier, "...");
+  auto Equal = SyntaxFactory::makeEqualToken({}, Trivia::spaces(1));
+
+  auto Sign = SyntaxFactory::makePrefixOpereator("-", {});
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(Sign, OneDigits);
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+
+  return SyntaxFactory::makeFunctionParameter(ExternalName, LocalName, Colon,
+                                              Int, NoEllipsis, Equal, One,
+                                              Comma);
+}
+
+TEST(DeclSyntaxTests, FunctionParameterMakeAPIs) {
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    getCannedFunctionParameter().print(OS);
+    ASSERT_EQ(OS.str().str(), "with radius: Int = -1, ");
+  }
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionParameter().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+}
+
+TEST(DeclSyntaxTests, FunctionParameterGetAPIs) {
+  auto ExternalName = SyntaxFactory::makeIdentifier("with", {},
+                                                    Trivia::spaces(1));
+  auto LocalName = SyntaxFactory::makeIdentifier("radius", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1));
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {},
+                                                  Trivia::spaces(1));
+  auto NoEllipsis = TokenSyntax::missingToken(tok::identifier, "...");
+  auto Equal = SyntaxFactory::makeEqualToken({}, Trivia::spaces(1));
+
+  auto Sign = SyntaxFactory::makePrefixOpereator("-", {});
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(Sign, OneDigits);
+  auto Comma = SyntaxFactory::makeCommaToken({}, {});
+
+  auto Param = SyntaxFactory::makeFunctionParameter(ExternalName, LocalName,
+                                                    Colon, Int, NoEllipsis,
+                                                    Equal, One, Comma);
+
+  ASSERT_EQ(ExternalName, Param.getExternalName());
+  ASSERT_EQ(LocalName, Param.getLocalName());
+  ASSERT_EQ(Colon, Param.getColonToken());
+
+  auto GottenType = Param.getTypeSyntax().getValue();
+  auto GottenType2 = Param.getTypeSyntax().getValue();
+  ASSERT_TRUE(GottenType.hasSameIdentityAs(GottenType2));
+
+  ASSERT_EQ(Equal, Param.getEqualToken());
+
+  auto GottenDefaultValue = Param.getDefaultValue().getValue();
+  auto GottenDefaultValue2 = Param.getDefaultValue().getValue();
+  ASSERT_TRUE(GottenDefaultValue.hasSameIdentityAs(GottenDefaultValue2));
+
+  ASSERT_EQ(Comma, Param.getTrailingComma());
+
+  // Test that llvm::None is returned for non-token missing children:
+  auto Decimated = Param
+    .withTypeSyntax(llvm::None)
+    .withDefaultValue(llvm::None);
+
+  ASSERT_FALSE(Decimated.getTypeSyntax().hasValue());
+  ASSERT_FALSE(Decimated.getDefaultValue().hasValue());
+}
+
+TEST(DeclSyntaxTests, FunctionParameterWithAPIs) {
+  auto ExternalName = SyntaxFactory::makeIdentifier("for", {},
+                                                    Trivia::spaces(1));
+  auto LocalName = SyntaxFactory::makeIdentifier("integer", {}, {});
+  auto Colon = SyntaxFactory::makeColonToken(Trivia::spaces(1),
+                                             Trivia::spaces(1));
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {},
+                                                  Trivia::spaces(1));
+  auto Equal = SyntaxFactory::makeEqualToken({}, Trivia::spaces(1));
+
+  auto NoSign = TokenSyntax::missingToken(tok::oper_prefix, "");
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(NoSign, OneDigits);
+  auto Comma = SyntaxFactory::makeCommaToken({}, {});
+
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    getCannedFunctionParameter()
+      .withExternalName(ExternalName)
+      .withLocalName(LocalName)
+      .withColonToken(Colon)
+      .withTypeSyntax(Int)
+      .withEqualToken(Equal)
+      .withDefaultValue(One)
+      .withTrailingComma(Comma)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "for integer : Int = 1,");
+  }
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    getCannedFunctionParameter()
+      .withTypeSyntax(llvm::None)
+      .withDefaultValue(llvm::None)
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "with radius: = , ");
+  }
+}
+
+#pragma mark - parameter-list
+
+TEST(DeclSyntaxTests, FunctionParameterListMakeAPIs) {
+  {
+    SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionParameterList().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto Param = getCannedFunctionParameter();
+    std::vector<FunctionParameterSyntax> Params { Param, Param, Param };
+    SyntaxFactory::makeFunctionParameterList(Params).print(OS);
+    ASSERT_EQ(OS.str().str(),
+      "with radius: Int = -1, with radius: Int = -1, with radius: Int = -1, ");
+  }
+}
+
+#pragma mark - function-signature
+
+FunctionSignatureSyntax getCannedFunctionSignature() {
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto Param = getCannedFunctionParameter();
+  auto List = SyntaxFactory::makeBlankFunctionParameterList()
+    .appending(Param)
+    .appending(Param)
+    .appending(Param)
+    .castTo<FunctionParameterListSyntax>();
+  auto RParen = SyntaxFactory::makeRightParenToken({}, Trivia::spaces(1));
+  auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
+  auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
+  auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1));
+
+  return SyntaxFactory::makeFunctionSignature(LParen, List, RParen, Throws,
+                                              Arrow, NoAttributes, Int);
+}
+
+TEST(DeclSyntaxTests, FunctionSignatureMakeAPIs) {
+  {
+    SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionSignature().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    getCannedFunctionSignature().print(OS);
+    ASSERT_EQ(OS.str().str(),
+      "(with radius: Int = -1, "
+      "with radius: Int = -1, "
+      "with radius: Int = -1, ) throws -> Int ");
+  }
+}
+
+TEST(DeclSyntaxTests, FunctionSignatureGetAPIs) {
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto Param = getCannedFunctionParameter();
+  auto List = SyntaxFactory::makeBlankFunctionParameterList()
+    .appending(Param)
+    .appending(Param)
+    .appending(Param)
+    .castTo<FunctionParameterListSyntax>();
+  auto RParen = SyntaxFactory::makeRightParenToken({}, Trivia::spaces(1));
+  auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
+  auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
+  auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
+
+  auto Sig = SyntaxFactory::makeFunctionSignature(LParen, List, RParen, Throws,
+                                                  Arrow, NoAttributes, Int);
+
+  ASSERT_EQ(LParen, Sig.getLeftParenToken());
+
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto GottenList1 = Sig.getParameterList();
+    auto GottenList2 = Sig.getParameterList();
+    ASSERT_TRUE(GottenList1.hasSameIdentityAs(GottenList2));
+    GottenList1.print(OS);
+    ASSERT_EQ(OS.str().str(),
+              "with radius: Int = -1, "
+              "with radius: Int = -1, "
+              "with radius: Int = -1, ");
+  }
+
+  ASSERT_EQ(RParen, Sig.getRightParenToken());
+  ASSERT_EQ(Throws, Sig.getThrowsToken());
+  ASSERT_TRUE(Sig.getRethrowsToken()->isMissing());
+  ASSERT_EQ(Arrow, Sig.getArrowToken());
+
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto GottenAttrs1 = Sig.getReturnTypeAttributes();
+    auto GottenAttrs2 = Sig.getReturnTypeAttributes();
+    ASSERT_TRUE(GottenAttrs1.hasSameIdentityAs(GottenAttrs2));
+    ASSERT_EQ(OS.str().str(), "");
+  }
+
+  {
+    SmallString<3> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    auto GottenReturnType1 = Sig.getReturnTypeSyntax();
+    auto GottenReturnType2 = Sig.getReturnTypeSyntax();
+    ASSERT_TRUE(GottenReturnType1.hasSameIdentityAs(GottenReturnType2));
+    GottenReturnType1.print(OS);
+    ASSERT_EQ(OS.str().str(), "Int");
+  }
+}
+
+TEST(DeclSyntaxTests, FunctionSignatureWithAPIs) {
+  auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
+  auto Param = getCannedFunctionParameter();
+  auto List = SyntaxFactory::makeBlankFunctionParameterList()
+    .appending(Param)
+    .appending(Param)
+    .appending(Param)
+    .castTo<FunctionParameterListSyntax>();
+  auto RParen = SyntaxFactory::makeRightParenToken({}, Trivia::spaces(1));
+  auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
+  auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
+  auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
+
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  SyntaxFactory::makeBlankFunctionSignature()
+    .withLeftParenToken(LParen)
+    .withParameterList(List)
+    .withRightParenToken(RParen)
+    .withThrowsToken(Throws)
+    .withReturnTypeAttributes(NoAttributes)
+    .withArrowToken(Arrow)
+    .withReturnTypeSyntax(Int)
+    .print(OS);
+  ASSERT_EQ(OS.str().str(),
+            "(with radius: Int = -1, "
+            "with radius: Int = -1, "
+            "with radius: Int = -1, ) throws -> Int");
+}
+
+#pragma mark - function-declaration
+
+DeclModifierListSyntax getCannedModifiers() {
+  auto PublicID = SyntaxFactory::makePublicKeyword({}, Trivia::spaces(1));
+  auto NoLParen = TokenSyntax::missingToken(tok::l_paren, "(");
+  auto NoArgument = TokenSyntax::missingToken(tok::identifier, "");
+  auto NoRParen = TokenSyntax::missingToken(tok::r_paren, ")");
+  auto Public = SyntaxFactory::makeDeclModifier(PublicID, NoLParen, NoArgument,
+                                                NoRParen);
+
+  auto StaticKW = SyntaxFactory::makeStaticKeyword({}, Trivia::spaces(1));
+  auto Static = SyntaxFactory::makeDeclModifier(StaticKW, NoLParen, NoArgument,
+                                                NoRParen);
+
+  return SyntaxFactory::makeBlankDeclModifierList()
+    .appending(Public)
+    .appending(Static)
+    .castTo<DeclModifierListSyntax>();
+}
+
+GenericParameterClauseSyntax getCannedGenericParams() {
+  GenericParameterClauseBuilder GB;
+
+  auto LAngle = SyntaxFactory::makeLeftAngleToken({}, {});
+  auto RAngle = SyntaxFactory::makeRightAngleToken({}, {});
+
+  auto T = SyntaxFactory::makeGenericParameter("T", {}, {});
+  auto U = SyntaxFactory::makeGenericParameter("U", {}, {});
+
+  auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1));
+
+  GB.addParameter(llvm::None, T);
+  GB.addParameter(Comma, U);
+  GB.useLeftAngleBracket(LAngle);
+  GB.useRightAngleBracket(RAngle);
+
+  return GB.build();
+}
+
+CodeBlockStmtSyntax getCannedBody() {
+  auto NoSign = TokenSyntax::missingToken(tok::oper_prefix, "-");
+  auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
+  auto One = SyntaxFactory::makeIntegerLiteralExpr(NoSign, OneDigits);
+  auto ReturnKW =
+    SyntaxFactory::makeReturnKeyword(Trivia::newlines(1) + Trivia::spaces(2),
+                                     {});
+  auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, One);
+
+  auto Stmts = SyntaxFactory::makeBlankStmtList()
+    .appending(Return)
+    .castTo<StmtListSyntax>();
+
+  auto LBrace = SyntaxFactory::makeLeftBraceToken({}, {});
+  auto RBrace = SyntaxFactory::makeRightBraceToken(Trivia::newlines(1), {});
+
+  return SyntaxFactory::makeCodeBlock(LBrace, Stmts, RBrace);
+}
+
+GenericWhereClauseSyntax getCannedWhereClause() {
+  auto WhereKW = SyntaxFactory::makeWhereKeyword({}, Trivia::spaces(1));
+  auto T = SyntaxFactory::makeTypeIdentifier("T", {}, Trivia::spaces(1));
+  auto EqualEqual = SyntaxFactory::makeEqualityOperator({}, Trivia::spaces(1));
+  auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1));
+  auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int);
+
+  auto Requirements = SyntaxFactory::makeBlankGenericRequirementList()
+    .appending(SameType.castTo<GenericRequirementSyntax>())
+    .castTo<GenericRequirementListSyntax>();
+
+  return SyntaxFactory::makeBlankGenericWhereClause()
+    .withWhereKeyword(WhereKW)
+    .withRequirementList(Requirements);
+}
+
+FunctionDeclSyntax getCannedFunctionDecl() {
+  auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
+  auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
+  auto FuncKW = SyntaxFactory::makeFuncKeyword({}, Trivia::spaces(1));
+  auto Modifiers = getCannedModifiers();
+  auto GenericParams = getCannedGenericParams();
+  auto GenericWhere = getCannedWhereClause();
+  auto Signature = getCannedFunctionSignature();
+  auto Body = getCannedBody();
+
+  return SyntaxFactory::makeFunctionDecl(NoAttributes, Modifiers, FuncKW, Foo,
+                                         GenericParams, Signature, GenericWhere,
+                                         Body);
+}
+
+TEST(DeclSyntaxTests, FunctionDeclMakeAPIs) {
+  {
+    SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionDecl().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+  {
+    SmallString<64> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    getCannedFunctionDecl().print(OS);
+    ASSERT_EQ(OS.str().str(),
+              "public static func foo<T, U>"
+              "(with radius: Int = -1, "
+              "with radius: Int = -1, "
+              "with radius: Int = -1, ) "
+              "throws -> Int "
+              "where T == Int {\n"
+              "  return1\n"
+              "}");
+  }
+}
+
+TEST(DeclSyntaxTests, FunctionDeclGetAPIs) {
+  {
+    SmallString<1> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionDecl().print(OS);
+    ASSERT_EQ(OS.str().str(), "");
+  }
+  {
+
+  }
+}
+
+TEST(DeclSyntaxTests, FunctionDeclWithAPIs) {
+
+}
+
+TEST(DeclSyntaxTests, FunctionDeclBuilderAPIs) {
+
+}
diff --git a/unittests/Syntax/ExprSyntaxTests.cpp b/unittests/Syntax/ExprSyntaxTests.cpp
index ae95b65..52254fe 100644
--- a/unittests/Syntax/ExprSyntaxTests.cpp
+++ b/unittests/Syntax/ExprSyntaxTests.cpp
@@ -209,9 +209,10 @@
                                                      Comma);
 
   return SyntaxFactory::makeBlankFunctionCallArgumentList()
-    .withAdditionalArgument(Arg)
-    .withAdditionalArgument(Arg.withLabel(Y))
-    .withAdditionalArgument(Arg.withLabel(Z).withTrailingComma(NoComma));
+    .appending(Arg)
+    .appending(Arg.withLabel(Y))
+    .appending(Arg.withLabel(Z).withTrailingComma(NoComma))
+    .castTo<FunctionCallArgumentListSyntax>();
 }
 
 FunctionCallArgumentListSyntax getLabellessArgumentList() {
@@ -235,9 +236,10 @@
                                                           Three, NoComma);
 
   return SyntaxFactory::makeBlankFunctionCallArgumentList()
-    .withAdditionalArgument(OneArg)
-    .withAdditionalArgument(TwoArg)
-    .withAdditionalArgument(ThreeArg);
+    .appending(OneArg)
+    .appending(TwoArg)
+    .appending(ThreeArg)
+    .castTo<FunctionCallArgumentListSyntax>();
 }
 }
 
@@ -255,17 +257,18 @@
                                                      Comma);
 
   auto ArgList = SyntaxFactory::makeBlankFunctionCallArgumentList()
-    .withAdditionalArgument(Arg)
-    .withAdditionalArgument(Arg.withLabel(Y))
-    .withAdditionalArgument(Arg.withLabel(Z).withTrailingComma(NoComma));
+    .appending(Arg)
+    .appending(Arg.withLabel(Y))
+    .appending(Arg.withLabel(Z).withTrailingComma(NoComma))
+    .castTo<FunctionCallArgumentListSyntax>();
 
-  ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+  ASSERT_EQ(ArgList.size(), size_t(3));
 
   {
     llvm::SmallString<16> Scratch;
     llvm::raw_svector_ostream OS(Scratch);
-    auto GottenArg1 = ArgList.getArgument(0);
-    auto GottenArg1_2 = ArgList.getArgument(0);
+    auto GottenArg1 = ArgList[0];
+    auto GottenArg1_2 = ArgList[0];
     ASSERT_TRUE(GottenArg1.hasSameIdentityAs(GottenArg1_2));
     GottenArg1.print(OS);
     ASSERT_EQ(OS.str().str(), "x: foo, ");
@@ -274,8 +277,8 @@
   {
     llvm::SmallString<16> Scratch;
     llvm::raw_svector_ostream OS(Scratch);
-    auto GottenArg2 = ArgList.getArgument(1);
-    auto GottenArg2_2 = ArgList.getArgument(1);
+    auto GottenArg2 = ArgList[1];
+    auto GottenArg2_2 = ArgList[1];
     ASSERT_TRUE(GottenArg2.hasSameIdentityAs(GottenArg2_2));
     GottenArg2.print(OS);
     ASSERT_EQ(OS.str().str(), "y: foo, ");
@@ -284,8 +287,8 @@
   {
     llvm::SmallString<16> Scratch;
     llvm::raw_svector_ostream OS(Scratch);
-    auto GottenArg3 = ArgList.getArgument(2);
-    auto GottenArg3_2 = ArgList.getArgument(2);
+    auto GottenArg3 = ArgList[2];
+    auto GottenArg3_2 = ArgList[2];
     ASSERT_TRUE(GottenArg3.hasSameIdentityAs(GottenArg3_2));
     GottenArg3.print(OS);
     ASSERT_EQ(OS.str().str(), "z: foo");
@@ -321,7 +324,7 @@
     llvm::raw_svector_ostream OS(Scratch);
     auto ArgList = SyntaxFactory::makeFunctionCallArgumentList(Args);
     ArgList.print(OS);
-    ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+    ASSERT_EQ(ArgList.size(), size_t(3));
     ASSERT_EQ(OS.str().str(), "x: foo, y: foo, z: foo");
   }
 }
@@ -330,9 +333,9 @@
   auto ArgList = getFullArgumentList();
   llvm::SmallString<64> Scratch;
   llvm::raw_svector_ostream OS(Scratch);
-  ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+  ASSERT_EQ(ArgList.size(), size_t(3));
   ArgList.print(OS);
-  ASSERT_EQ(ArgList.getNumArguments(), size_t(3));
+  ASSERT_EQ(ArgList.size(), size_t(3));
   ASSERT_EQ(OS.str().str(), "x: foo, y: foo, z: foo");
 }
 
diff --git a/unittests/Syntax/SyntaxCollectionTests.cpp b/unittests/Syntax/SyntaxCollectionTests.cpp
new file mode 100644
index 0000000..656c44d
--- /dev/null
+++ b/unittests/Syntax/SyntaxCollectionTests.cpp
@@ -0,0 +1,260 @@
+#include "swift/Syntax/ExprSyntax.h"
+#include "swift/Syntax/SyntaxFactory.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using llvm::None;
+using llvm::SmallString;
+
+using namespace swift;
+using namespace swift::syntax;
+
+FunctionCallArgumentSyntax getCannedArgument() {
+  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 NoComma = TokenSyntax::missingToken(tok::comma, ",");
+
+  return SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef, Comma);
+}
+
+TEST(SyntaxCollectionTests, empty) {
+  auto Empty = SyntaxFactory::makeBlankFunctionCallArgumentList();
+  ASSERT_TRUE(Empty.empty());
+  ASSERT_FALSE(Empty.appending(getCannedArgument()).empty());
+}
+
+TEST(SyntaxCollectionTests, size) {
+  auto Empty = SyntaxFactory::makeBlankFunctionCallArgumentList();
+  ASSERT_EQ(Empty.size(), size_t(0));
+  ASSERT_EQ(Empty.appending(getCannedArgument()).size(), size_t(1));
+}
+
+TEST(SyntaxCollectionTests, subscript) {
+  auto Empty = SyntaxFactory::makeBlankFunctionCallArgumentList();
+#ifndef NDEBUG
+  ASSERT_DEATH({ Empty[0]; }, "");
+#endif
+
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  auto Arg = getCannedArgument();
+  Arg.print(OS);
+
+  auto List = Empty.appending(Arg);
+
+  SmallString<48> GottenScratch;
+  llvm::raw_svector_ostream GottenOS(Scratch);
+  List[0].print(GottenOS);
+
+  ASSERT_EQ(OS.str().str(), GottenOS.str().str());
+
+  auto GottenArg1 = List[0];
+  auto GottenArg2 = List[0];
+  ASSERT_TRUE(GottenArg1.hasSameIdentityAs(GottenArg2));
+}
+
+TEST(SyntaxCollectionTests, appending) {
+  auto Arg = getCannedArgument();
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+  auto List = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .appending(Arg)
+    .appending(Arg)
+    .appending(Arg.withTrailingComma(NoComma));
+
+  ASSERT_EQ(List.size(), size_t(3));
+
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  List.print(OS);
+
+  ASSERT_EQ(OS.str().str(), "x: foo, x: foo, x: foo");
+
+  auto GottenArg0_1 = List[0];
+  auto GottenArg0_2 = List[0];
+  ASSERT_TRUE(GottenArg0_1.hasSameIdentityAs(GottenArg0_2));
+
+  auto GottenArg1_1 = List[1];
+  auto GottenArg1_2 = List[1];
+  ASSERT_TRUE(GottenArg1_1.hasSameIdentityAs(GottenArg1_2));
+
+  auto GottenArg2_1 = List[2];
+  auto GottenArg2_2 = List[2];
+  ASSERT_TRUE(GottenArg2_1.hasSameIdentityAs(GottenArg2_2));
+}
+
+TEST(SyntaxCollectionTests, removingLast) {
+  ASSERT_DEATH({
+    SyntaxFactory::makeBlankFunctionCallArgumentList().removingLast();
+  }, "");
+  auto Arg = getCannedArgument();
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+  auto List = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .appending(Arg)
+    .appending(Arg)
+    .appending(Arg.withTrailingComma(NoComma))
+    .removingLast();
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  List.print(OS);
+  ASSERT_EQ(OS.str().str(), "x: foo, x: foo, ");
+}
+
+TEST(SyntaxCollectionTests, prepending) {
+  auto Arg = getCannedArgument();
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+  auto List = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .prepending(Arg.withTrailingComma(NoComma))
+    .prepending(Arg
+                  .withLabel(SyntaxFactory::makeIdentifier("schwifty", {}, {})))
+    .prepending(Arg);
+
+  ASSERT_EQ(List.size(), size_t(3));
+
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  List.print(OS);
+
+  ASSERT_EQ(OS.str().str(), "x: foo, schwifty: foo, x: foo");
+
+  auto GottenArg0_1 = List[0];
+  auto GottenArg0_2 = List[0];
+  ASSERT_TRUE(GottenArg0_1.hasSameIdentityAs(GottenArg0_2));
+
+  auto GottenArg1_1 = List[1];
+  auto GottenArg1_2 = List[1];
+  ASSERT_TRUE(GottenArg1_1.hasSameIdentityAs(GottenArg1_2));
+
+  auto GottenArg2_1 = List[2];
+  auto GottenArg2_2 = List[2];
+  ASSERT_TRUE(GottenArg2_1.hasSameIdentityAs(GottenArg2_2));
+}
+
+TEST(SyntaxCollectionTests, removingFirst) {
+  ASSERT_DEATH({
+    SyntaxFactory::makeBlankFunctionCallArgumentList().removingFirst();
+  }, "");
+  auto Arg = getCannedArgument();
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+  auto List = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .appending(Arg
+                 .withLabel(SyntaxFactory::makeIdentifier("schwifty", {}, {})))
+    .appending(Arg)
+    .appending(Arg.withTrailingComma(NoComma))
+    .removingFirst();
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  List.print(OS);
+  ASSERT_EQ(OS.str().str(), "x: foo, x: foo");
+}
+
+TEST(SyntaxCollectionTests, inserting) {
+  auto Arg = getCannedArgument();
+  auto NoComma = TokenSyntax::missingToken(tok::comma, ",");
+#ifndef NDEBUG
+  ASSERT_DEATH({
+    SyntaxFactory::makeBlankFunctionCallArgumentList().inserting(1, Arg);
+  }, "");
+#endif
+
+  {
+    SmallString<48> InsertedScratch;
+    llvm::raw_svector_ostream InsertedOS(InsertedScratch);
+    SyntaxFactory::makeBlankFunctionCallArgumentList()
+      .inserting(0, Arg)
+      .inserting(0, Arg)
+      .inserting(0, Arg)
+      .print(InsertedOS);
+
+    SmallString<48> PrependedScratch;
+    llvm::raw_svector_ostream PrependedOS(PrependedScratch);
+    SyntaxFactory::makeBlankFunctionCallArgumentList()
+      .prepending(Arg)
+      .prepending(Arg)
+      .prepending(Arg)
+      .print(PrependedOS);
+    ASSERT_EQ(InsertedOS.str().str(), PrependedOS.str().str());
+  }
+
+  {
+    SmallString<48> InsertedScratch;
+    llvm::raw_svector_ostream InsertedOS(InsertedScratch);
+    SyntaxFactory::makeBlankFunctionCallArgumentList()
+      .inserting(0, Arg)
+      .inserting(1, Arg)
+      .inserting(2, Arg)
+      .print(InsertedOS);
+
+    SmallString<48> AppendedScratch;
+    llvm::raw_svector_ostream AppendedOS(AppendedScratch);
+    SyntaxFactory::makeBlankFunctionCallArgumentList()
+      .appending(Arg)
+      .appending(Arg)
+      .appending(Arg)
+      .print(AppendedOS);
+    ASSERT_EQ(InsertedOS.str().str(), AppendedOS.str().str());
+  }
+
+  {
+    SmallString<48> Scratch;
+    llvm::raw_svector_ostream OS(Scratch);
+    SyntaxFactory::makeBlankFunctionCallArgumentList()
+      .appending(Arg)
+      .appending(Arg)
+      .inserting(1,
+                 Arg.withLabel(SyntaxFactory::makeIdentifier("schwifty",
+                                                             {}, {})))
+      .print(OS);
+    ASSERT_EQ(OS.str().str(), "x: foo, schwifty: foo, x: foo, ");
+  }
+}
+
+TEST(SyntaxCollectionTests, cleared) {
+  auto Arg = getCannedArgument();
+  SmallString<1> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  auto List = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .appending(Arg)
+    .appending(Arg)
+    .appending(Arg)
+    .cleared();
+
+  List.print(OS);
+  ASSERT_EQ(OS.str().str(), "");
+  ASSERT_TRUE(List.empty());
+  ASSERT_EQ(List.size(), size_t(0));
+}
+
+TEST(SyntaxCollectionTests, Iteration) {
+  auto Arg = getCannedArgument();
+  auto List = SyntaxFactory::makeBlankFunctionCallArgumentList()
+    .appending(Arg)
+    .appending(Arg)
+    .appending(Arg);
+
+  auto Element0 = List[0];
+  auto Element1 = List[1];
+  auto Element2 = List[2];
+
+  SmallString<48> IteratedScratch;
+  llvm::raw_svector_ostream IteratedOS(IteratedScratch);
+  for (auto Element : List) {
+    Element.print(IteratedOS);
+  }
+  ASSERT_EQ(IteratedOS.str().str(), "x: foo, x: foo, x: foo, ");
+
+  auto IteratedElement0 = List[0];
+  auto IteratedElement1 = List[1];
+  auto IteratedElement2 = List[2];
+
+  ASSERT_TRUE(Element0.hasSameIdentityAs(IteratedElement0));
+  ASSERT_TRUE(Element1.hasSameIdentityAs(IteratedElement1));
+  ASSERT_TRUE(Element2.hasSameIdentityAs(IteratedElement2));
+
+  SmallString<48> Scratch;
+  llvm::raw_svector_ostream OS(Scratch);
+  List.print(OS);
+  ASSERT_EQ(OS.str().str(), IteratedOS.str().str());
+}
diff --git a/unittests/runtime/Refcounting.cpp b/unittests/runtime/Refcounting.cpp
index d01b279..2ac88d0 100644
--- a/unittests/runtime/Refcounting.cpp
+++ b/unittests/runtime/Refcounting.cpp
@@ -180,7 +180,7 @@
   // RC big, unpinned
   EXPECT_FALSE(swift_isUniquelyReferencedOrPinned_nonNull_native(object));
 
-  auto pinResult = swift_tryPin(object);
+  swift_tryPin(object);
   // RC big, pinned
   EXPECT_TRUE(swift_isUniquelyReferencedOrPinned_nonNull_native(object));
 
diff --git a/unittests/runtime/weak.mm b/unittests/runtime/weak.mm
index 4d55479..80137fa 100644
--- a/unittests/runtime/weak.mm
+++ b/unittests/runtime/weak.mm
@@ -14,7 +14,6 @@
 #include <objc/runtime.h>
 #include "swift/Runtime/HeapObject.h"
 #include "swift/Runtime/Metadata.h"
-#include "swift/Runtime/Metadata.h"
 #include "gtest/gtest.h"
 
 using namespace swift;
diff --git a/utils/build-presets.ini b/utils/build-presets.ini
index 2d5b62e..980335c 100644
--- a/utils/build-presets.ini
+++ b/utils/build-presets.ini
@@ -1002,6 +1002,16 @@
 
 assertions
 
+[preset: LLDB_Swift_DebugAssert_with_devices]
+mixin-preset=
+    LLDB_Swift_DebugAssert
+
+ios
+tvos
+watchos
+build-swift-static-stdlib
+build-swift-static-sdk-overlay
+
 [preset: LLDB_Swift_ReleaseAssert]
 mixin-preset=
     LLDB_Nested
@@ -1009,6 +1019,16 @@
 release-debuginfo
 assertions
 
+[preset: LLDB_Swift_ReleaseAssert_with_devices]
+mixin-preset=
+    LLDB_Swift_ReleaseAssert
+
+ios
+tvos
+watchos
+build-swift-static-stdlib
+build-swift-static-sdk-overlay
+
 #===------------------------------------------------------------------------===#
 # Test all platforms on OS X builder
 #===------------------------------------------------------------------------===#
@@ -1475,3 +1495,23 @@
 swift-stdlib-build-type=RelWithDebInfo
 swift-stdlib-enable-assertions=true
 build-serialized-stdlib-unittest
+
+#===------------------------------------------------------------------------===#
+# Swift Coverage Preset
+#===------------------------------------------------------------------------===#
+
+[preset: buildbot_incremental,tools=RDA,stdlib=RDA,coverage]
+build-subdir=buildbot_incremental_coverage
+release-debuginfo
+assertions
+swift-analyze-code-coverage=not-merged
+test
+validation-test
+skip-test-ios
+skip-test-tvos
+skip-test-watchos
+skip-build-benchmark
+verbose-build
+lit-args=-v
+reconfigure
+build-ninja
diff --git a/utils/build-script-impl b/utils/build-script-impl
index c1e12b2..4779e4a 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -725,7 +725,6 @@
     llvm_cmake_options+=(
         -DLLVM_TOOL_COMPILER_RT_BUILD:BOOL="$(false_true ${SKIP_BUILD_COMPILER_RT})"
         -DLLVM_BUILD_EXTERNAL_COMPILER_RT:BOOL="$(false_true ${SKIP_BUILD_COMPILER_RT})"
-        -DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING:BOOL=TRUE
     )
 
     # If we are asked to not generate test targets for LLVM and or Swift,
diff --git a/utils/coverage/coverage-generate-data b/utils/coverage/coverage-generate-data
index ca1bf34..35943e8 100755
--- a/utils/coverage/coverage-generate-data
+++ b/utils/coverage/coverage-generate-data
@@ -194,8 +194,6 @@
     parser = argparse.ArgumentParser(
         description='Generate, parse test run profdata')
     parser.add_argument('swift_dir', metavar='swift-dir')
-    parser.add_argument('--build-dir')
-    parser.add_argument('--build-subdir', default='coverage')
     parser.add_argument('--log',
                         help='the level of information to log (default: info)',
                         metavar='LEVEL',
@@ -208,36 +206,17 @@
     logging.debug(args)
 
     swift_dir = os.path.realpath(os.path.abspath(args.swift_dir))
-    if args.build_dir:
-        build_dir = os.path.realpath(os.path.abspath(args.build_dir))
-    else:
-        build_dir = os.path.realpath(os.path.join(os.path.dirname(swift_dir),
-                                                  'build'))
-    build_subdir = os.path.join(build_dir, args.build_subdir)
+    build_dir = os.path.realpath(os.path.join(os.path.dirname(swift_dir),
+                                              'build'))
+    build_subdir = os.path.join(build_dir, 'buildbot_incremental_coverage')
 
     global_build_subdir = build_subdir
 
     build_script_cmd = [
         os.path.join(swift_dir, 'utils/build-script'),
-        '--release',
-        '--no-assertions',
-        '--swift-analyze-code-coverage', 'not-merged',
-        '--test',
-        '--validation-test',
-        '--skip-test-ios',
-        '--skip-test-tvos',
-        '--skip-test-watchos',
-        '--skip-build-benchmark',
-        '--verbose-build',
-        '--lit-args=-v',
-        '--reconfigure',
-        '--build-ninja',
-        '--build-subdir', build_subdir
+        '--preset=buildbot_incremental,tools=RDA,stdlib=RDA,coverage',
     ]
 
-    if args.build_dir:
-        build_script_cmd += ['--build-dir', build_dir]
-
     call(build_script_cmd)
 
     assert global_build_subdir
diff --git a/utils/sil-mode.el b/utils/sil-mode.el
index 6d390d0..b13b3e4 100644
--- a/utils/sil-mode.el
+++ b/utils/sil-mode.el
@@ -76,6 +76,9 @@
    `(,(regexp-opt '("load_borrow" "begin_borrow" "store_borrow" "end_borrow_argument") 'words) . font-lock-keyword-face)
    '("\\(end_borrow\\) %[[:alnum:]] \\(from\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face))
 
+   ;; SIL Instructions - ownership
+   `(,(regexp-opt '("unchecked_ownership_conversion") 'words) . font-lock-keyword-face)
+
    ;; SIL Instructions - Reference Counting.
    `(,(regexp-opt '("strong_retain"
                     "strong_release" "strong_retain_unowned"
@@ -83,6 +86,7 @@
                     "load_weak" "store_weak"
                     "load_unowned" "store_unowned"
                     "fix_lifetime" "mark_dependence"
+                    "end_lifetime"
                     "is_unique" "is_unique_or_pinned"
                     "copy_block"
                     "strong_unpin" "strong_pin" "is_unique" "is_unique_or_pinned")
diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py
index 5cd6a67..ab3e6dc 100644
--- a/utils/swift_build_support/swift_build_support/targets.py
+++ b/utils/swift_build_support/swift_build_support/targets.py
@@ -126,6 +126,8 @@
 
     Android = Platform("android", archs=["armv7"])
 
+    Windows = Platform("windows", archs=["x86_64"])
+
     # The list of known platforms.
     known_platforms = [
         OSX,
@@ -135,7 +137,8 @@
         Linux,
         FreeBSD,
         Cygwin,
-        Android]
+        Android,
+        Windows]
 
     # Cache of targets by name.
     _targets_by_name = dict((target.name, target)
@@ -181,6 +184,10 @@
             if machine == 'x86_64':
                 return StdlibDeploymentTarget.Cygwin.x86_64
 
+        elif system == 'Windows':
+            if machine == "AMD64":
+                return StdlibDeploymentTarget.Windows.x86_64
+
         raise NotImplementedError('System "%s" with architecture "%s" is not '
                                   'supported' % (system, machine))
 
diff --git a/utils/swift_build_support/swift_build_support/toolchain.py b/utils/swift_build_support/swift_build_support/toolchain.py
index 061d224..367384d 100644
--- a/utils/swift_build_support/swift_build_support/toolchain.py
+++ b/utils/swift_build_support/swift_build_support/toolchain.py
@@ -45,8 +45,13 @@
     setattr(Toolchain, name, cache_util.reify(_getter))
 
 
-_register("cc", "clang")
-_register("cxx", "clang++")
+if platform.system() == 'Windows':
+    _register("cc", "clang-cl")
+    _register("cxx", "clang-cl")
+else:
+    _register("cc", "clang")
+    _register("cxx", "clang++")
+
 _register("ninja", "ninja", "ninja-build")
 _register("cmake", "cmake")
 _register("distcc", "distcc")
@@ -173,6 +178,15 @@
     pass
 
 
+class Windows(Toolchain):
+    def find_tool(self, *names):
+        for name in names:
+            found = which(name)
+            if found is not None:
+                return found
+        return None
+
+
 def host_toolchain(**kwargs):
     sys = platform.system()
     if sys == 'Darwin':
@@ -183,6 +197,8 @@
         return FreeBSD()
     elif sys.startswith('CYGWIN'):
         return Cygwin()
+    elif sys == 'Windows':
+        return Windows()
     else:
         raise NotImplementedError('The platform "%s" does not have a defined '
                                   'toolchain.' % sys)
diff --git a/validation-test/compiler_crashers/28700-isactuallycanonicalornull-forming-a-cantype-out-of-a-non-canonical-type.swift b/validation-test/compiler_crashers/28700-isactuallycanonicalornull-forming-a-cantype-out-of-a-non-canonical-type.swift
index 4cba9a3..3894ba7 100644
--- a/validation-test/compiler_crashers/28700-isactuallycanonicalornull-forming-a-cantype-out-of-a-non-canonical-type.swift
+++ b/validation-test/compiler_crashers/28700-isactuallycanonicalornull-forming-a-cantype-out-of-a-non-canonical-type.swift
@@ -6,5 +6,6 @@
 // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
 // REQUIRES: asserts
+// REQUIRES: deterministic-behavior
 // RUN: not --crash %target-swift-frontend %s -emit-ir
 { struct c{func ulntatin(UInt=1 + 1 as?Int){a{a
diff --git a/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift b/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift
index 479b7b8..e628c7d 100644
--- a/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift
+++ b/validation-test/compiler_crashers/28702-swift-typebase-getcanonicaltype.swift
@@ -5,5 +5,6 @@
 // See https://swift.org/LICENSE.txt for license information
 // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
+// REQUIRES: deterministic-behavior
 // 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/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift b/validation-test/compiler_crashers/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift
new file mode 100644
index 0000000..8df4f0e
--- /dev/null
+++ b/validation-test/compiler_crashers/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift
@@ -0,0 +1,10 @@
+// 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
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol P{let c{}typealias e:RangeReplaceableCollection}extension P{typealias e:a
diff --git a/validation-test/compiler_crashers/28707-false-encountered-error-in-diagnostic-text.swift b/validation-test/compiler_crashers/28707-false-encountered-error-in-diagnostic-text.swift
new file mode 100644
index 0000000..96aad26
--- /dev/null
+++ b/validation-test/compiler_crashers/28707-false-encountered-error-in-diagnostic-text.swift
@@ -0,0 +1,12 @@
+// 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
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+class a{@_versioned
+public
+protocol r
diff --git a/validation-test/compiler_crashers/28709-unreachable-executed-at-swift-lib-ast-type-cpp-1005.swift b/validation-test/compiler_crashers/28709-unreachable-executed-at-swift-lib-ast-type-cpp-1005.swift
new file mode 100644
index 0000000..4eb8150
--- /dev/null
+++ b/validation-test/compiler_crashers/28709-unreachable-executed-at-swift-lib-ast-type-cpp-1005.swift
@@ -0,0 +1,12 @@
+// 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
+{
+class C{func o(UInt=1 + 1 + 1 + 1 + 1 as?Int){{
+{r
+p
diff --git a/validation-test/compiler_crashers_2_fixed/0079-rdar30702721.swift b/validation-test/compiler_crashers_2_fixed/0079-rdar30702721.swift
new file mode 100644
index 0000000..5965987
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0079-rdar30702721.swift
@@ -0,0 +1,9 @@
+// RUN: %target-swift-frontend %s -emit-ir
+
+extension Sequence {
+	typealias Element = Iterator.Element
+}
+
+func f<C: Sequence>(c: C) where C.Iterator == C {
+  c.makeIterator()
+}