Merge pull request #14482 from xedin/rdar-37291371

[CSBindings] Look through optional types when trying to validate l-va…
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index 7882950..ec7a91b 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -59,6 +59,7 @@
     single-source/DictTest
     single-source/DictTest2
     single-source/DictTest3
+    single-source/DictTest4
     single-source/DictionaryBridge
     single-source/DictionaryGroup
     single-source/DictionaryLiteral
diff --git a/benchmark/single-source/DictTest4.swift b/benchmark/single-source/DictTest4.swift
new file mode 100644
index 0000000..d2849fa
--- /dev/null
+++ b/benchmark/single-source/DictTest4.swift
@@ -0,0 +1,129 @@
+//===--- DictTest4.swift --------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+import TestsUtils
+
+// This benchmark mostly measures lookups in dictionaries with complex keys,
+// exercising the default hash compression function.
+
+public let Dictionary4 = [
+  BenchmarkInfo(name: "Dictionary4", runFunction: run_Dictionary4, tags: [.validation, .api, .Dictionary]),
+  BenchmarkInfo(name: "Dictionary4OfObjects", runFunction: run_Dictionary4OfObjects, tags: [.validation, .api, .Dictionary]),
+]
+
+struct LargeKey: Hashable {
+  let i: Int
+  let j: Int
+  let k: Double
+  let l: UInt32
+  let m: Bool
+  let n: Bool
+  let o: Bool
+  let p: Bool
+  let q: Bool
+
+  init(_ value: Int) {
+    self.i = value
+    self.j = 2 * value
+    self.k = Double(value) / 7
+    self.l = UInt32(truncatingIfNeeded: value)
+    self.m = value & 1 == 0
+    self.n = value & 2 == 0
+    self.o = value & 4 == 0
+    self.p = value & 8 == 0
+    self.q = value & 16 == 0
+  }
+}
+
+@inline(never)
+public func run_Dictionary4(_ N: Int) {
+  let size1 = 100
+  let reps = 20
+  let ref_result = "1 99 \(reps) \(reps * 99)"
+  var hash1 = [LargeKey: Int]()
+  var hash2 = [LargeKey: Int]()
+  var res = ""
+
+  for _ in 1...N {
+    // Test insertions
+    hash1 = [:]
+    for i in 0..<size1 {
+      hash1[LargeKey(i)] = i
+    }
+
+    hash2 = hash1
+
+    // Test lookups & value replacement
+    for _ in 1..<reps {
+      for (k, v) in hash1 {
+        hash2[k] = hash2[k]! + v
+      }
+    }
+
+    res = "\(hash1[LargeKey(1)]!) \(hash1[LargeKey(99)]!)" +
+      " \(hash2[LargeKey(1)]!) \(hash2[LargeKey(99)]!)"
+    if res != ref_result {
+      break
+    }
+  }
+  CheckResults(res == ref_result)
+}
+
+class Box<T : Hashable> : Hashable {
+  var value: T
+
+  init(_ v: T) {
+    value = v
+  }
+
+  var hashValue: Int {
+    return value.hashValue
+  }
+  
+  static func ==(lhs: Box, rhs: Box) -> Bool {
+    return lhs.value == rhs.value
+  }
+}
+
+@inline(never)
+public func run_Dictionary4OfObjects(_ N: Int) {
+  let size1 = 100
+  let reps = 20
+  let ref_result = "1 99 \(reps) \(reps * 99)"
+  var hash1 = [Box<LargeKey>: Int]()
+  var hash2 = [Box<LargeKey>: Int]()
+  var res = ""
+
+  for _ in 1...N {
+    // Test insertions
+    hash1 = [:]
+    for i in 0..<size1 {
+      hash1[Box(LargeKey(i))] = i
+    }
+
+    hash2 = hash1
+
+    // Test lookups & value replacement
+    for _ in 1..<reps {
+      for (k, v) in hash1 {
+        hash2[k] = hash2[k]! + v
+      }
+    }
+
+    res = "\(hash1[Box(LargeKey(1))]!) \(hash1[Box(LargeKey(99))]!)" +
+      " \(hash2[Box(LargeKey(1))]!) \(hash2[Box(LargeKey(99))]!)"
+    if res != ref_result {
+      break
+    }
+  }
+  CheckResults(res == ref_result)
+}
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index f723816..adb28b5 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -46,6 +46,7 @@
 import DictTest
 import DictTest2
 import DictTest3
+import DictTest4
 import DictionaryBridge
 import DictionaryGroup
 import DictionaryLiteral
@@ -189,6 +190,7 @@
 registerBenchmark(Dictionary)
 registerBenchmark(Dictionary2)
 registerBenchmark(Dictionary3)
+registerBenchmark(Dictionary4)
 registerBenchmark(DictionaryBridge)
 registerBenchmark(DictionaryGroup)
 registerBenchmark(DictionaryLiteral)
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index b9c0e8d..dff956a 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -258,11 +258,13 @@
     Type getTypeInContext(GenericSignatureBuilder &builder,
                           GenericEnvironment *genericEnv);
 
-    /// Dump a debugging representation of this equivalence class.
-    void dump(llvm::raw_ostream &out) const;
+    /// Dump a debugging representation of this equivalence class,
+    void dump(llvm::raw_ostream &out,
+              GenericSignatureBuilder *builder = nullptr) const;
 
-    LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
-                              "only for use in the debugger");
+    LLVM_ATTRIBUTE_DEPRECATED(
+                  void dump(GenericSignatureBuilder *builder = nullptr) const,
+                  "only for use in the debugger");
 
     /// Caches.
 
@@ -271,9 +273,8 @@
       /// The cached anchor itself.
       Type anchor;
 
-      /// The number of members of the equivalence class when the archetype
-      /// anchor was cached.
-      unsigned numMembers;
+      /// The generation at which the anchor was last computed.
+      unsigned lastGeneration;
     } archetypeAnchorCache;
 
     /// Describes a cached nested type.
@@ -444,6 +445,11 @@
   /// Note that we have added the nested type nestedPA
   void addedNestedType(PotentialArchetype *nestedPA);
 
+  /// Add a rewrite rule for a same-type constraint between the given
+  /// types.
+  void addSameTypeRewriteRule(PotentialArchetype *type1,
+                              PotentialArchetype *type2);
+
   /// \brief Add a new conformance requirement specifying that the given
   /// potential archetypes are equivalent.
   ConstraintResult addSameTypeRequirementBetweenArchetypes(
@@ -802,6 +808,12 @@
   /// Determine whether the two given types are in the same equivalence class.
   bool areInSameEquivalenceClass(Type type1, Type type2);
 
+  /// Simplify the given dependent type down to its canonical representation.
+  ///
+  /// \returns null if the type involved dependent member types that
+  /// don't have associated types.
+  Type getCanonicalTypeParameter(Type type);
+
   /// Verify the correctness of the given generic signature.
   ///
   /// This routine will test that the given generic signature is both minimal
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 6048734..350a246 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -573,6 +573,12 @@
   /// whether a type parameter exists at any position.
   bool isTypeParameter();
 
+  /// \brief Determine whether this type can dynamically be an optional type.
+  ///
+  /// \param includeExistential Whether an existential type should be considered
+  /// such a type.
+  bool canDynamicallyBeOptionalType(bool includeExistential);
+
   /// Determine whether this type contains a type parameter somewhere in it.
   bool hasTypeParameter() {
     return getRecursiveProperties().hasTypeParameter();
@@ -4998,6 +5004,14 @@
   return false;
 }
 
+inline bool TypeBase::canDynamicallyBeOptionalType(bool includeExistential) {
+  CanType T = getCanonicalType();
+  auto isArchetypeOrExistential = isa<ArchetypeType>(T) ||
+    (includeExistential && T.isExistentialType());
+
+  return isArchetypeOrExistential && !T.isAnyClassReferenceType();
+}
+
 inline ClassDecl *TypeBase::getClassOrBoundGenericClass() {
   return getCanonicalType().getClassOrBoundGenericClass();
 }
diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h
index 872f3c7..b5b4ae4 100644
--- a/include/swift/SIL/TypeSubstCloner.h
+++ b/include/swift/SIL/TypeSubstCloner.h
@@ -170,7 +170,11 @@
 
 protected:
   SILType remapType(SILType Ty) {
-    return Ty.subst(Original.getModule(), SubsMap);
+    SILType &Sty = TypeCache[Ty];
+    if (!Sty) {
+      Sty = Ty.subst(Original.getModule(), SubsMap);
+    }
+    return Sty;
   }
 
   CanType remapASTType(CanType ty) {
@@ -286,6 +290,8 @@
   ModuleDecl *SwiftMod;
   /// The substitutions list for the specialization.
   SubstitutionMap SubsMap;
+  /// Cache for substituted types.
+  llvm::DenseMap<SILType, SILType> TypeCache;
   /// The original function to specialize.
   SILFunction &Original;
   /// The substitutions used at the call site.
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 2a28e95..492d385 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 = 397; // No resilience expansion in SILDeclRef
+const uint16_t VERSION_MINOR = 398; // Private discriminators for type xrefs
 
 using DeclIDField = BCFixed<31>;
 
@@ -1288,6 +1288,7 @@
   using XRefTypePathPieceLayout = BCRecordLayout<
     XREF_TYPE_PATH_PIECE,
     IdentifierIDField, // name
+    IdentifierIDField, // private discriminator
     BCFixed<1>         // restrict to protocol extension
   >;
 
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index f473456..d657f7c 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -107,6 +107,190 @@
           "Delayed requirements left unresolved");
 STATISTIC(NumConditionalRequirementsAdded,
           "# of conditional requirements added");
+STATISTIC(NumComponentsCollapsedViaRewriting,
+          "# of same-type components collapsed via term rewriting");
+
+namespace  {
+
+/// A purely-relative rewrite path consisting of a (possibly empty)
+/// sequence of associated type references.
+using RelativeRewritePath = ArrayRef<AssociatedTypeDecl *>;
+
+/// Describes a rewrite path, which contains an optional base (generic
+/// parameter) followed by a sequence of associated type references.
+class RewritePath {
+  Optional<GenericParamKey> base;
+  TinyPtrVector<AssociatedTypeDecl *> path;
+
+public:
+  RewritePath() { }
+
+  enum PathOrder {
+    Forward,
+    Reverse,
+  };
+
+  /// Form a rewrite path given an optional base and a relative rewrite path.
+  RewritePath(Optional<GenericParamKey> base, RelativeRewritePath path,
+              PathOrder order);
+
+  /// Retrieve the base of the given rewrite path.
+  ///
+  /// When present, it indicates that the entire path will be rebased on
+  /// the given base generic parameter. This is required for describing
+  /// rewrites on type parameters themselves, e.g., T == U.
+  Optional<GenericParamKey> getBase() const { return base; }
+
+  /// Retrieve the sequence of associated type references that describes
+  /// the path.
+  ArrayRef<AssociatedTypeDecl *> getPath() const { return path; }
+
+  /// Decompose a type into a path.
+  ///
+  /// \returns the path, or None if it contained unresolved dependent member
+  /// types.
+  Optional<RewritePath> static createPath(Type type);
+
+  /// Decompose a potential archetype into a patch.
+  ///
+  /// \returns the path, or None if it contained potential archetypes
+  /// with concrete declarations.
+  Optional<RewritePath> static createPath(PotentialArchetype *pa);
+
+  /// Compute the common path between this path and \c other, if one exists.
+  Optional<RewritePath> commonPath(const RewritePath &other) const;
+
+  /// Form a canonical, dependent type.
+  ///
+  /// This requires that the rewrite path have a base.
+  CanType formDependentType(ASTContext &ctx) const;
+
+  /// Compare the given rewrite paths.
+  int compare(const RewritePath &other) const;
+
+  /// Print this path.
+  void print(llvm::raw_ostream &out) const;
+
+  LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
+                            "only for use within the debugger") {
+    print(llvm::errs());
+  }
+
+  friend bool operator==(const RewritePath &lhs, const RewritePath &rhs) {
+    return lhs.getBase() == rhs.getBase() && lhs.getPath() == rhs.getPath();
+  }
+};
+
+/// A node within the prefix tree that is used to match associated type
+/// references.
+class RewriteTreeNode {
+  /// The associated type that leads to this node.
+  ///
+  /// The bit indicates whether there is a rewrite rule for this particular
+  /// node. If the bit is not set, \c rewrite is invalid.
+  llvm::PointerIntPair<AssociatedTypeDecl *, 1, bool> assocTypeAndHasRewrite;
+
+  /// The sequence of associated types to which a reference to this associated
+  /// type (from the equivalence class root) can be rewritten. This field is
+  /// only valid when the bit of \c assocTypeAndHasRewrite is set.
+  ///
+  /// Consider a requirement "Self.A.B.C == C". This will be encoded as
+  /// a prefix tree starting at the equivalence class for Self with
+  /// the following nodes:
+  ///
+  /// (assocType: A,
+  ///   children: [
+  ///     (assocType: B,
+  ///       children: [
+  ///         (assocType: C, rewrite: [C], children: [])
+  ///       ])
+  ///   ])
+  RewritePath rewrite;
+
+  /// The child nodes, which extend the sequence to be matched.
+  ///
+  /// The child nodes are sorted by the associated type declaration
+  /// pointers, so we can perform binary searches quickly.
+  llvm::TinyPtrVector<RewriteTreeNode *> children;
+
+public:
+  ~RewriteTreeNode();
+
+  RewriteTreeNode(AssociatedTypeDecl *assocType)
+    : assocTypeAndHasRewrite(assocType, false) { }
+
+  /// Retrieve the associated type declaration one must match to use this
+  /// node, which may the
+  AssociatedTypeDecl *getMatch() const {
+    return assocTypeAndHasRewrite.getPointer();
+  }
+
+  /// Determine whether this particular node has a rewrite rule.
+  bool hasRewriteRule() const {
+    return assocTypeAndHasRewrite.getInt();
+  }
+
+  /// Set a new rewrite rule for this particular node. This can only be
+  /// performed once.
+  void setRewriteRule(RewritePath replacementPath) {
+    assert(!hasRewriteRule());
+    assocTypeAndHasRewrite.setInt(true);
+    rewrite = replacementPath;
+  }
+
+  /// Retrieve the path to which this node will be rewritten.
+  const RewritePath &getRewriteRule() const {
+    assert(hasRewriteRule());
+    return rewrite;
+  }
+
+  /// Add a new rewrite rule to this tree node.
+  ///
+  /// \param matchPath The path of associated type declarations that must
+  /// be matched to produce a rewrite.
+  ///
+  /// \param replacementPath The sequence of associated type declarations
+  /// with which a match will be replaced.
+  void addRewriteRule(RelativeRewritePath matchPath,
+                      RewritePath replacementPath);
+
+  /// Enumerate all of the paths to which the given matched path can be
+  /// rewritten.
+  ///
+  /// \param matchPath The path to match.
+  ///
+  /// \param callback A callback that will be invoked with (prefix, rewrite)
+  /// pairs, where \c prefix is the length of the matching prefix of
+  /// \c matchPath that matched and \c rewrite is the path to which it can
+  /// be rewritten.
+  void enumerateRewritePaths(
+                       RelativeRewritePath matchPath,
+                       llvm::function_ref<void(unsigned, RewritePath)> callback,
+                       unsigned depth = 0) const;
+
+  /// Find the best rewrite rule to match the given path.
+  ///
+  /// \param path The path to match.
+  /// \param prefixLength The length of the prefix leading up to \c path.
+  Optional<std::pair<unsigned, RewritePath>>
+  bestMatch(GenericParamKey base, RelativeRewritePath path,
+            unsigned prefixLength);
+
+  /// Merge the given rewrite tree into \c other.
+  void mergeInto(RewriteTreeNode *other);
+
+  LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
+                            "only for use within the debugger");
+
+  /// Dump the tree.
+  void dump(llvm::raw_ostream &out, bool lastChild = true) const;
+
+private:
+  /// Merge the given rewrite tree into \c other.
+  void mergeIntoRec(RewriteTreeNode *other,
+                    llvm::SmallVectorImpl<AssociatedTypeDecl *> &matchPath);
+};
+}
 
 struct GenericSignatureBuilder::Implementation {
   /// Allocator.
@@ -131,6 +315,9 @@
   /// Equivalence classes that are not currently being used.
   std::vector<void *> FreeEquivalenceClasses;
 
+  /// The roots of the rewrite tree.
+  DenseMap<const EquivalenceClass *, RewriteTreeNode *> RewriteTreeRoots;
+
   /// The generation number, which is incremented whenever we successfully
   /// introduce a new constraint.
   unsigned Generation = 0;
@@ -141,16 +328,6 @@
   /// Whether we are currently processing delayed requirements.
   bool ProcessingDelayedRequirements = false;
 
-  /// Tear down an implementation.
-  ~Implementation();
-
-  /// Allocate a new equivalence class with the given representative.
-  EquivalenceClass *allocateEquivalenceClass(
-                                       PotentialArchetype *representative);
-
-  /// Deallocate the given equivalence class, returning it to the free list.
-  void deallocateEquivalenceClass(EquivalenceClass *equivClass);
-
   /// Whether there were any errors.
   bool HadAnyError = false;
 
@@ -161,12 +338,35 @@
   /// Whether we've already finalized the builder.
   bool finalized = false;
 #endif
+
+  /// Tear down an implementation.
+  ~Implementation();
+
+  /// Allocate a new equivalence class with the given representative.
+  EquivalenceClass *allocateEquivalenceClass(
+                                       PotentialArchetype *representative);
+
+  /// Deallocate the given equivalence class, returning it to the free list.
+  void deallocateEquivalenceClass(EquivalenceClass *equivClass);
+
+  /// Retrieve the rewrite tree root for the given equivalence class,
+  /// if present.
+  RewriteTreeNode *getRewriteTreeRootIfPresent(
+                                      const EquivalenceClass *equivClass);
+
+  /// Retrieve the rewrite tree root for the given equivalence class,
+  /// creating it if needed.
+  RewriteTreeNode *getOrCreateRewriteTreeRoot(
+                                        const EquivalenceClass *equivClass);
 };
 
 #pragma mark Memory management
 GenericSignatureBuilder::Implementation::~Implementation() {
   for (auto pa : PotentialArchetypes)
     pa->~PotentialArchetype();
+
+  for (const auto &root : RewriteTreeRoots)
+    delete root.second;
 }
 
 EquivalenceClass *
@@ -1915,31 +2115,13 @@
   return populateResult((nestedTypeNameCache[name] = std::move(entry)));
 }
 
-/// Determine whether any part of this potential archetype's path to the
-/// root contains the given equivalence class.
-static bool pathContainsEquivalenceClass(GenericSignatureBuilder &builder,
-                                         PotentialArchetype *pa,
-                                         EquivalenceClass *equivClass) {
-  // Chase the potential archetype up to the root.
-  for (; pa; pa = pa->getParent()) {
-    // Check whether this potential archetype is in the given equivalence
-    // class.
-    if (pa->getOrCreateEquivalenceClass(builder) == equivClass)
-      return true;
-  }
-
-  return false;
-}
-
 Type EquivalenceClass::getAnchor(
                             GenericSignatureBuilder &builder,
                             TypeArrayView<GenericTypeParamType> genericParams) {
-  // Check whether the cache is valid.
-  if (archetypeAnchorCache.anchor &&
-      archetypeAnchorCache.numMembers == members.size()) {
-    ++NumArchetypeAnchorCacheHits;
+  // Substitute into the anchor with the given generic parameters.
+  auto substAnchor = [&] {
+    if (genericParams.empty()) return archetypeAnchorCache.anchor;
 
-    // Reparent the anchor using genericParams.
     return archetypeAnchorCache.anchor.subst(
              [&](SubstitutableType *dependentType) {
                if (auto gp = dyn_cast<GenericTypeParamType>(dependentType)) {
@@ -1951,73 +2133,43 @@
                return Type(dependentType);
              },
              MakeAbstractConformanceForGenericType());
+
+  };
+
+  // Check whether the cache is valid.
+  if (archetypeAnchorCache.anchor &&
+      archetypeAnchorCache.lastGeneration == builder.Impl->Generation) {
+    ++NumArchetypeAnchorCacheHits;
+    return substAnchor();
   }
 
-  // Map the members of this equivalence class to the best associated type
-  // within that equivalence class.
-  llvm::SmallDenseMap<EquivalenceClass *, AssociatedTypeDecl *> nestedTypes;
+  // Check whether we already have an anchor, in which case we
+  // can simplify it further.
+  if (archetypeAnchorCache.anchor) {
+    // Record the cache miss.
+    ++NumArchetypeAnchorCacheMisses;
 
-  Type bestGenericParam;
+    // Update the anchor by simplifying it further.
+    archetypeAnchorCache.anchor =
+      builder.getCanonicalTypeParameter(archetypeAnchorCache.anchor);
+    archetypeAnchorCache.lastGeneration = builder.Impl->Generation;
+    return substAnchor();
+  }
+
+  // Form the anchor.
   for (auto member : members) {
-    // If the member is a generic parameter, keep the best generic parameter.
-    if (member->isGenericParam()) {
-      Type genericParamType = member->getDependentType(genericParams);
-      if (!bestGenericParam ||
-          compareDependentTypes(genericParamType, bestGenericParam) < 0)
-        bestGenericParam = genericParamType;
-      continue;
-    }
+    auto anchorType =
+      builder.getCanonicalTypeParameter(member->getDependentType(genericParams));
+    if (!anchorType) continue;
 
-    // If we saw a generic parameter, ignore any nested types.
-    if (bestGenericParam) continue;
-
-    // If the nested type doesn't have an associated type, skip it.
-    auto assocType = member->getResolvedAssociatedType();
-    if (!assocType) continue;
-
-    // Dig out the equivalence class of the parent.
-    auto parentEquivClass =
-      member->getParent()->getOrCreateEquivalenceClass(builder);
-
-    // If the path from this member to the root contains this equivalence
-    // class, it cannot be part of the anchor.
-    if (pathContainsEquivalenceClass(builder, member->getParent(), this))
-      continue;
-
-    // Take the best associated type for this equivalence class.
-    assocType = assocType->getAssociatedTypeAnchor();
-    auto &bestAssocType = nestedTypes[parentEquivClass];
-    if (!bestAssocType ||
-        compareAssociatedTypes(assocType, bestAssocType) < 0)
-      bestAssocType = assocType;
+    // Record the cache miss and update the cache.
+    ++NumArchetypeAnchorCacheMisses;
+    archetypeAnchorCache.anchor = anchorType;
+    archetypeAnchorCache.lastGeneration = builder.Impl->Generation;
+    return substAnchor();
   }
 
-  // If we found a generic parameter, return that.
-  if (bestGenericParam)
-    return bestGenericParam;
-
-  // Determine the best anchor among the parent equivalence classes.
-  Type bestParentAnchor;
-  AssociatedTypeDecl *bestAssocType = nullptr;
-  std::pair<EquivalenceClass *, Identifier> bestNestedType;
-  for (const auto &nestedType : nestedTypes) {
-    auto parentAnchor = nestedType.first->getAnchor(builder, genericParams);
-    if (!bestParentAnchor ||
-        compareDependentTypes(parentAnchor, bestParentAnchor) < 0) {
-      bestParentAnchor = parentAnchor;
-      bestAssocType = nestedType.second;
-    }
-  }
-
-  // Form the anchor type.
-  Type anchorType = DependentMemberType::get(bestParentAnchor, bestAssocType);
-
-  // Record the cache miss and update the cache.
-  ++NumArchetypeAnchorCacheMisses;
-  archetypeAnchorCache.anchor = anchorType;
-  archetypeAnchorCache.numMembers = members.size();
-
-  return anchorType;
+  llvm_unreachable("Unable to compute anchor");
 }
 
 Type EquivalenceClass::getTypeInContext(GenericSignatureBuilder &builder,
@@ -2138,7 +2290,8 @@
   return archetype;
 }
 
-void EquivalenceClass::dump(llvm::raw_ostream &out) const {
+void EquivalenceClass::dump(llvm::raw_ostream &out,
+                            GenericSignatureBuilder *builder) const {
   out << "Equivalence class represented by "
     << members.front()->getRepresentative()->getDebugName() << ":\n";
   out << "Members: ";
@@ -2183,6 +2336,13 @@
 
   out << "\n";
 
+  if (builder) {
+    if (auto rewriteRoot = builder->Impl->getRewriteTreeRootIfPresent(this)) {
+      out << "---Rewrite tree---\n";
+      rewriteRoot->dump(out);
+    }
+  }
+
   {
     out << "---GraphViz output for same-type constraints---\n";
 
@@ -2215,8 +2375,8 @@
   }
 }
 
-void EquivalenceClass::dump() const {
-  dump(llvm::errs());
+void EquivalenceClass::dump(GenericSignatureBuilder *builder) const {
+  dump(llvm::errs(), builder);
 }
 
 void DelayedRequirement::dump(llvm::raw_ostream &out) const {
@@ -2523,6 +2683,24 @@
   return 0;
 }
 
+/// Compare two dependent paths to determine which is better.
+static int compareDependentPaths(ArrayRef<AssociatedTypeDecl *> path1,
+                                 ArrayRef<AssociatedTypeDecl *> path2) {
+  // Shorter paths win.
+  if (path1.size() != path2.size())
+    return path1.size() < path2.size() ? -1 : 1;
+
+  // The paths are the same length, so order by comparing the associted
+  // types.
+  for (unsigned index : indices(path1)) {
+    if (int result = compareAssociatedTypes(path1[index], path2[index]))
+      return result;
+  }
+
+  // Identical paths.
+  return 0;
+}
+
 namespace {
   /// Function object used to suppress conflict diagnoses when we know we'll
   /// see them again later.
@@ -2883,6 +3061,507 @@
   }
 }
 
+#pragma mark Rewrite tree
+RewritePath::RewritePath(Optional<GenericParamKey> base,
+                         RelativeRewritePath path,
+                         PathOrder order)
+  : base(base)
+{
+  switch (order) {
+  case Forward:
+    this->path.insert(this->path.begin(), path.begin(), path.end());
+    break;
+
+  case Reverse:
+    this->path.insert(this->path.begin(), path.rbegin(), path.rend());
+    break;
+  }
+}
+
+Optional<RewritePath> RewritePath::createPath(PotentialArchetype *pa) {
+  SmallVector<AssociatedTypeDecl *, 4> path;
+  while (auto parent = pa->getParent()) {
+    auto assocType = pa->getResolvedAssociatedType();
+    if (!assocType) return None;
+
+    path.push_back(assocType);
+    pa = parent;
+  }
+
+  return RewritePath(pa->getGenericParamKey(), path, Reverse);
+}
+
+Optional<RewritePath> RewritePath::createPath(Type type) {
+  SmallVector<AssociatedTypeDecl *, 4> path;
+  while (auto depMemTy = type->getAs<DependentMemberType>()) {
+    auto assocType = depMemTy->getAssocType();
+    if (!assocType) return None;
+
+    path.push_back(assocType);
+    type = depMemTy->getBase();
+  }
+
+  auto genericParam = type->getAs<GenericTypeParamType>();
+  if (!genericParam) return None;
+
+  return RewritePath(GenericParamKey(genericParam), path, Reverse);
+}
+
+Optional<RewritePath> RewritePath::commonPath(const RewritePath &other) const {
+  assert(getBase().hasValue() && other.getBase().hasValue());
+
+  if (*getBase() != *other.getBase()) return None;
+
+  // Find the longest common prefix.
+  RelativeRewritePath path1 = getPath();
+  RelativeRewritePath path2 = other.getPath();
+  if (path1.size() > path2.size())
+    std::swap(path1, path2);
+  unsigned prefixLength =
+    std::mismatch(path1.begin(), path1.end(), path2.begin()).first
+      - path1.begin();
+
+  // Form the common path.
+  return RewritePath(getBase(), path1.slice(0, prefixLength), Forward);
+}
+
+/// Form a dependent type with the given generic parameter, then following the
+/// path of associated types.
+static Type formDependentType(GenericTypeParamType *base,
+                              RelativeRewritePath path) {
+  return std::accumulate(path.begin(), path.end(), Type(base),
+                         [](Type type, AssociatedTypeDecl *assocType) -> Type {
+                           return DependentMemberType::get(type, assocType);
+                         });
+}
+
+/// Form a dependent type with the (canonical) generic parameter for the given
+/// parameter key, then following the path of associated types.
+static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam,
+                              RelativeRewritePath path) {
+  return formDependentType(GenericTypeParamType::get(genericParam.Depth,
+                                                     genericParam.Index,
+                                                     ctx),
+                           path);
+}
+
+CanType RewritePath::formDependentType(ASTContext &ctx) const {
+  assert(getBase());
+  return CanType(::formDependentType(ctx, *getBase(), getPath()));
+}
+
+int RewritePath::compare(const RewritePath &other) const {
+  // Prefer relative to absolute paths.
+  if (getBase().hasValue() != other.getBase().hasValue()) {
+    return other.getBase().hasValue() ? -1 : 1;
+  }
+
+  // Order based on the bases.
+  if (getBase() && *getBase() != *other.getBase())
+    return (*getBase() < *other.getBase()) ? -1 : 1;
+
+  // Order based on the path contents.
+  return compareDependentPaths(getPath(), other.getPath());
+}
+
+void RewritePath::print(llvm::raw_ostream &out) const {
+  out << "[";
+
+  if (getBase()) {
+    out << "(" << getBase()->Depth << ", " << getBase()->Index << ")";
+    if (!getPath().empty()) out << " -> ";
+  }
+
+  interleave(getPath().begin(), getPath().end(),
+             [&](AssociatedTypeDecl *assocType) {
+               out.changeColor(raw_ostream::BLUE);
+               out << assocType->getProtocol()->getName() << "."
+               << assocType->getName();
+               out.resetColor();
+             }, [&] {
+               out << " -> ";
+             });
+  out << "]";
+}
+
+RewriteTreeNode::~RewriteTreeNode() {
+  for (auto child : children)
+    delete child;
+}
+
+namespace {
+/// Function object used to order rewrite tree nodes based on the address
+/// of the associated type.
+class OrderTreeRewriteNode {
+  bool compare(AssociatedTypeDecl *lhs, AssociatedTypeDecl *rhs) const {
+    // Make sure null pointers precede everything else.
+    if (static_cast<bool>(lhs) != static_cast<bool>(rhs))
+      return static_cast<bool>(rhs);
+
+    // Use std::less to provide a defined ordering.
+    return std::less<AssociatedTypeDecl *>()(lhs, rhs);
+  }
+
+public:
+  bool operator()(RewriteTreeNode *lhs, AssociatedTypeDecl *rhs) const {
+    return compare(lhs->getMatch(), rhs);
+  }
+
+  bool operator()(AssociatedTypeDecl *lhs, RewriteTreeNode *rhs) const {
+    return compare(lhs, rhs->getMatch());
+  }
+
+  bool operator()(RewriteTreeNode *lhs, RewriteTreeNode *rhs) const {
+    return compare(lhs->getMatch(), rhs->getMatch());
+  }
+};
+}
+
+void RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
+                                     RewritePath replacementPath) {
+  // If the match path is empty, we're adding the rewrite rule to this node.
+  if (matchPath.empty()) {
+    // If we don't already have a rewrite rule, add it.
+    if (!hasRewriteRule()) {
+      setRewriteRule(replacementPath);
+      return;
+    }
+
+    // If we already have this rewrite rule, we're done.
+    if (getRewriteRule() == replacementPath) return;
+
+    // Check whether any of the continuation children matches.
+    auto insertPos = children.begin();
+    while (insertPos != children.end() && !(*insertPos)->getMatch()) {
+      if ((*insertPos)->hasRewriteRule() &&
+          (*insertPos)->getRewriteRule() == replacementPath)
+        return;
+
+      ++insertPos;
+    }
+
+    // We already have a rewrite rule, so add a new child with a
+    // null associated type match to hold the rewrite rule.
+    auto newChild = new RewriteTreeNode(nullptr);
+    newChild->setRewriteRule(replacementPath);
+    children.insert(insertPos, newChild);
+    return;
+  }
+
+  // Find (or create) a child node describing the next step in the match.
+  auto matchFront = matchPath.front();
+  auto childPos =
+    std::lower_bound(children.begin(), children.end(), matchFront,
+                     OrderTreeRewriteNode());
+  if (childPos == children.end() || (*childPos)->getMatch() != matchFront) {
+    childPos = children.insert(childPos, new RewriteTreeNode(matchFront));
+  }
+
+  // Add the rewrite rule to the child.
+  (*childPos)->addRewriteRule(matchPath.slice(1), replacementPath);
+}
+
+void RewriteTreeNode::enumerateRewritePaths(
+                       RelativeRewritePath matchPath,
+                       llvm::function_ref<void(unsigned, RewritePath)> callback,
+                       unsigned depth) const {
+  // Determine whether we know anything about the next step in the path.
+  auto childPos =
+    depth < matchPath.size()
+      ? std::lower_bound(children.begin(), children.end(),
+                         matchPath[depth], OrderTreeRewriteNode())
+      : children.end();
+  if (childPos != children.end() &&
+      (*childPos)->getMatch() == matchPath[depth]) {
+    // Try to match the rest of the path.
+    (*childPos)->enumerateRewritePaths(matchPath, callback, depth + 1);
+  }
+
+  // If we have a rewrite rule at this position, invoke it.
+  if (hasRewriteRule()) {
+    // Invoke the callback with the first result.
+    callback(depth, rewrite);
+  }
+
+  // Walk any children with NULL associated types; they might have more matches.
+  for (auto otherRewrite : children) {
+    if (otherRewrite->getMatch()) break;
+    otherRewrite->enumerateRewritePaths(matchPath, callback, depth);
+  }
+}
+
+Optional<std::pair<unsigned, RewritePath>>
+RewriteTreeNode::bestMatch(GenericParamKey base, RelativeRewritePath path,
+                           unsigned prefixLength) {
+  Optional<std::pair<unsigned, RewritePath>> best;
+  unsigned bestAdjustedLength = 0;
+  enumerateRewritePaths(path,
+                        [&](unsigned length, RewritePath path) {
+    // Determine how much of the original path will be replaced by the rewrite.
+    unsigned adjustedLength = length;
+    if (auto newBase = path.getBase()) {
+      adjustedLength += prefixLength;
+
+      // If the base is unchanged, make sure we're reducing the length.
+      if (*newBase == base && adjustedLength <= path.getPath().size())
+        return;
+    }
+
+    if (adjustedLength == 0) return;
+
+    if (adjustedLength > bestAdjustedLength ||
+        (adjustedLength == bestAdjustedLength &&
+         path.compare(best->second) < 0)) {
+      best = { length, path };
+      bestAdjustedLength = adjustedLength;
+    }
+  });
+
+  return best;
+}
+
+void RewriteTreeNode::mergeInto(RewriteTreeNode *other) {
+  SmallVector<AssociatedTypeDecl *, 4> matchPath;
+  mergeIntoRec(other, matchPath);
+}
+
+void RewriteTreeNode::mergeIntoRec(
+                     RewriteTreeNode *other,
+                     llvm::SmallVectorImpl<AssociatedTypeDecl *> &matchPath) {
+  // FIXME: A destructive version of this operation would be more efficient,
+  // since we generally don't care about \c other after doing this.
+  if (auto assocType = getMatch())
+    matchPath.push_back(assocType);
+
+  // Add this rewrite rule, if there is one.
+  if (hasRewriteRule())
+    other->addRewriteRule(matchPath, rewrite);
+
+  // Recurse into the child nodes.
+  for (auto child : children)
+    child->mergeIntoRec(other, matchPath);
+
+  if (auto assocType = getMatch())
+    matchPath.pop_back();
+}
+
+void RewriteTreeNode::dump() const {
+  dump(llvm::errs());
+}
+
+void RewriteTreeNode::dump(llvm::raw_ostream &out, bool lastChild) const {
+  std::string prefixStr;
+
+  std::function<void(const RewriteTreeNode *, bool lastChild)> print;
+  print = [&](const RewriteTreeNode *node, bool lastChild) {
+    out << prefixStr << " `--";
+
+    // Print the node name.
+    out.changeColor(raw_ostream::GREEN);
+    if (auto assoc = node->getMatch())
+      out << assoc->getProtocol()->getName() << "." << assoc->getName();
+    else
+      out << "(cont'd)";
+    out.resetColor();
+
+    // Print the rewrite, if there is one.
+    if (node->hasRewriteRule()) {
+      out << " --> ";
+      node->rewrite.print(out);
+    }
+
+    out << "\n";
+
+    // Print children.
+    prefixStr += ' ';
+    prefixStr += (lastChild ? ' ' : '|');
+    prefixStr += "  ";
+
+    for (auto child : node->children) {
+      print(child, child == node->children.back());
+    }
+
+    prefixStr.erase(prefixStr.end() - 4, prefixStr.end());
+  };
+
+  print(this, lastChild);
+}
+
+RewriteTreeNode *
+GenericSignatureBuilder::Implementation::getRewriteTreeRootIfPresent(
+                                          const EquivalenceClass *equivClass) {
+  auto known = RewriteTreeRoots.find(equivClass);
+  if (known != RewriteTreeRoots.end()) return known->second;
+
+  return nullptr;
+}
+
+RewriteTreeNode *
+GenericSignatureBuilder::Implementation::getOrCreateRewriteTreeRoot(
+                                          const EquivalenceClass *equivClass) {
+  auto known = RewriteTreeRoots.find(equivClass);
+  if (known != RewriteTreeRoots.end()) return known->second;
+
+  auto root = new RewriteTreeNode(nullptr);
+  RewriteTreeRoots[equivClass] = root;
+  return root;
+}
+
+void GenericSignatureBuilder::addSameTypeRewriteRule(PotentialArchetype *pa1,
+                                                     PotentialArchetype *pa2){
+  auto pathOpt1 = RewritePath::createPath(pa1);
+  if (!pathOpt1) return;
+
+  auto pathOpt2 = RewritePath::createPath(pa2);
+  if (!pathOpt2) return;
+
+  auto path1 = std::move(pathOpt1).getValue();
+  auto path2 = std::move(pathOpt2).getValue();
+
+  // Look for a common path.
+  auto prefix = path1.commonPath(path2);
+
+  // If we didn't find a common path, try harder.
+  Type simplifiedType1;
+  Type simplifiedType2;
+  if (!prefix) {
+    // Simplify both sides in the hope of uncovering a common path.
+    simplifiedType1 = getCanonicalTypeParameter(pa1->getDependentType({ }));
+    simplifiedType2 = getCanonicalTypeParameter(pa2->getDependentType({ }));
+    if (simplifiedType1->isEqual(simplifiedType2)) return;
+
+    // Create new paths from the simplified types.
+    path1 = *RewritePath::createPath(simplifiedType1);
+    path2 = *RewritePath::createPath(simplifiedType2);
+
+    // Find a common path.
+    prefix = path1.commonPath(path2);
+  }
+
+  // When we have a common prefix, form a rewrite rule using relative paths.
+  if (prefix) {
+    // Find the better relative rewrite path.
+    RelativeRewritePath relPath1
+      = path1.getPath().slice(prefix->getPath().size());
+    RelativeRewritePath relPath2
+      = path2.getPath().slice(prefix->getPath().size());
+    // Order the paths so that we go to the more-canonical path.
+    if (compareDependentPaths(relPath1, relPath2) < 0)
+      std::swap(relPath1, relPath2);
+
+    // Find the equivalence class for the prefix.
+    CanType commonType = prefix->formDependentType(getASTContext());
+    auto equivClass =
+      resolveEquivalenceClass(commonType, ArchetypeResolutionKind::WellFormed);
+    assert(equivClass && "Prefix cannot be resolved?");
+
+    // Add the rewrite rule.
+    auto root = Impl->getOrCreateRewriteTreeRoot(equivClass);
+    root->addRewriteRule(relPath1,
+                         RewritePath(None, relPath2, RewritePath::Forward));
+
+    return;
+  }
+
+  // Otherwise, form a rewrite rule with absolute paths.
+
+  // Find the better path and make sure it's in path2.
+  if (compareDependentTypes(simplifiedType1, simplifiedType2) < 0) {
+    std::swap(path1, path2);
+    std::swap(simplifiedType1, simplifiedType2);
+  }
+
+  // Add the rewrite rule.
+  Type firstBase =
+    GenericTypeParamType::get(path1.getBase()->Depth, path1.getBase()->Index,
+                              getASTContext());
+  auto equivClass =
+    resolveEquivalenceClass(firstBase, ArchetypeResolutionKind::WellFormed);
+  assert(equivClass && "Base cannot be resolved?");
+
+  auto root = Impl->getOrCreateRewriteTreeRoot(equivClass);
+  root->addRewriteRule(path1.getPath(), path2);
+}
+
+Type GenericSignatureBuilder::getCanonicalTypeParameter(Type type) {
+  auto initialPath = RewritePath::createPath(type);
+  if (!initialPath) return nullptr;
+
+  auto genericParamType =
+    GenericTypeParamType::get(initialPath->getBase()->Depth,
+                              initialPath->getBase()->Index,
+                              getASTContext());
+  auto initialEquivClass =
+    resolveEquivalenceClass(genericParamType,
+                            ArchetypeResolutionKind::WellFormed);
+  if (!initialEquivClass) return nullptr;
+
+  unsigned startIndex = 0;
+  auto equivClass = initialEquivClass;
+  Type currentType = genericParamType;
+  SmallVector<AssociatedTypeDecl *, 4> path(initialPath->getPath().begin(),
+                                            initialPath->getPath().end());
+  bool simplified = false;
+  do {
+    if (auto rootNode = Impl->getRewriteTreeRootIfPresent(equivClass)) {
+      // Find the best rewrite rule for the path starting at startIndex.
+      auto match =
+        rootNode->bestMatch(genericParamType,
+                            llvm::makeArrayRef(path).slice(startIndex),
+                            startIndex);
+
+      // If we have a match, replace the matched path with the replacement
+      // path.
+      if (match) {
+        // Determine the range in the path which we'll be replacing.
+        unsigned replaceStartIndex = match->second.getBase() ? 0 : startIndex;
+        unsigned replaceEndIndex = startIndex + match->first;
+
+        // Overwrite the beginning of the match.
+        auto replacementPath = match->second.getPath();
+        assert((replaceEndIndex - replaceStartIndex) >= replacementPath.size());
+        auto replacementStartPos = path.begin() + replaceStartIndex;
+        std::copy(replacementPath.begin(), replacementPath.end(),
+                  replacementStartPos);
+
+        // Erase the rest.
+        path.erase(replacementStartPos + replacementPath.size(),
+                   path.begin() + replaceEndIndex);
+
+        // If this is an absolute path, use the new base.
+        if (auto newBase = match->second.getBase()) {
+          genericParamType =
+            GenericTypeParamType::get(newBase->Depth, newBase->Index,
+                                      getASTContext());
+          initialEquivClass =
+            resolveEquivalenceClass(genericParamType,
+                                    ArchetypeResolutionKind::WellFormed);
+          assert(initialEquivClass && "Must have an equivalence class");
+        }
+
+        // Move back to the beginning; we may have opened up other rewrites.
+        simplified = true;
+        startIndex = 0;
+        currentType = genericParamType;
+        equivClass = initialEquivClass;
+        continue;
+      }
+    }
+
+    // If we've hit the end of the path, we're done.
+    if (startIndex >= path.size()) break;
+
+    // FIXME: It would be nice if there were a better way to get the equivalence
+    // class of a named nested type.
+    currentType = DependentMemberType::get(currentType, path[startIndex++]);
+    equivClass =
+      resolveEquivalenceClass(currentType, ArchetypeResolutionKind::WellFormed);
+    if (!equivClass) break;
+  } while (true);
+
+  return formDependentType(genericParamType, path);
+}
+
 #pragma mark Equivalence classes
 EquivalenceClass::EquivalenceClass(PotentialArchetype *representative)
   : recursiveConcreteType(false), invalidConcreteType(false),
@@ -3865,6 +4544,9 @@
        PotentialArchetype *OrigT2,
        const RequirementSource *Source) 
 {
+  // Add a rewrite rule based on the given same-type constraint.
+  addSameTypeRewriteRule(OrigT1, OrigT2);
+
   // Record the same-type constraint, and bail out if it was already known.
   if (!OrigT1->getOrCreateEquivalenceClass(*this)
         ->recordSameTypeConstraint(OrigT1, OrigT2, Source))
@@ -3910,6 +4592,20 @@
                                    equivClass->sameTypeConstraints.end(),
                                    equivClass2->sameTypeConstraints.begin(),
                                    equivClass2->sameTypeConstraints.end());
+
+    // Combine the rewrite rules.
+    if (auto rewriteRoot2 = Impl->getOrCreateRewriteTreeRoot(equivClass2)) {
+      if (auto rewriteRoot1 = Impl->getOrCreateRewriteTreeRoot(equivClass)) {
+        // Merge the second rewrite tree into the first.
+        rewriteRoot2->mergeInto(rewriteRoot1);
+        Impl->RewriteTreeRoots.erase(equivClass2);
+        delete rewriteRoot2;
+      } else {
+        // Take the second rewrite tree and make it the first.
+        Impl->RewriteTreeRoots.erase(equivClass2);
+        (void)Impl->RewriteTreeRoots.insert({equivClass, rewriteRoot2});
+      }
+    }
   }
 
   // Same-type-to-concrete requirements.
@@ -5446,7 +6142,7 @@
       return lhs.constraint < rhs.constraint;
     }
 
-    LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
+    LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
                               "only for use in the debugger");
   };
 }
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 8fcfcce..e506ae4 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -212,23 +212,16 @@
   case llvm::Triple::TvOS:
   case llvm::Triple::WatchOS:
     return llvm::make_unique<toolchains::Darwin>(*this, target);
-    break;
   case llvm::Triple::Linux:
-    if (target.isAndroid()) {
+    if (target.isAndroid())
       return llvm::make_unique<toolchains::Android>(*this, target);
-    } else {
-      return llvm::make_unique<toolchains::GenericUnix>(*this, target);
-    }
-    break;
+    return llvm::make_unique<toolchains::GenericUnix>(*this, target);
   case llvm::Triple::FreeBSD:
     return llvm::make_unique<toolchains::GenericUnix>(*this, target);
-    break;
   case llvm::Triple::Win32:
     return llvm::make_unique<toolchains::Cygwin>(*this, target);
-    break;
   case llvm::Triple::Haiku:
     return llvm::make_unique<toolchains::GenericUnix>(*this, target);
-    break;
   default:
     Diags.diagnose(SourceLoc(), diag::error_unknown_target,
                    ArgList.getLastArg(options::OPT_target)->getValue());
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 222dbc7..382b4ee 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3905,7 +3905,8 @@
   if (Flags.contains(PD_InProtocol) || isInSILMode()) {
     if (Tok.is(tok::r_brace)) {
       // Give syntax node an empty statement list.
-      SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+      SyntaxParsingContext StmtListContext(SyntaxContext,
+                                           SyntaxKind::CodeBlockItemList);
     }
     while (Tok.isNot(tok::r_brace)) {
       if (Tok.is(tok::eof))
@@ -3988,7 +3989,8 @@
   // an implicit fallthrough off the end.
   if (Tok.is(tok::r_brace)) {
     // Give syntax node an empty statement list.
-    SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+    SyntaxParsingContext StmtListContext(SyntaxContext,
+                                         SyntaxKind::CodeBlockItemList);
     diagnose(Tok, diag::computed_property_no_accessors);
     return true;
   }
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 84d5bc9..5915b16 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -89,6 +89,7 @@
 
 ParserStatus Parser::parseExprOrStmt(ASTNode &Result) {
   if (Tok.is(tok::semi)) {
+    SyntaxParsingContext ErrorCtxt(SyntaxContext, SyntaxContextKind::Stmt);
     diagnose(Tok, diag::illegal_semi_stmt)
       .fixItRemove(SourceRange(Tok.getLoc()));
     consumeToken();
@@ -112,6 +113,7 @@
   if (Tok.is(tok::code_complete)) {
     if (CodeCompletion)
       CodeCompletion->completeStmtOrExpr();
+    SyntaxParsingContext ErrorCtxt(SyntaxContext, SyntaxContextKind::Stmt);
     consumeToken(tok::code_complete);
     return makeParserCodeCompletionStatus();
   }
@@ -228,7 +230,8 @@
 ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
                                      BraceItemListKind Kind,
                                      BraceItemListKind ConditionalBlockKind) {
-  SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+  SyntaxParsingContext ItemListContext(SyntaxContext,
+                                       SyntaxKind::CodeBlockItemList);
 
   bool IsTopLevel = (Kind == BraceItemListKind::TopLevelCode) ||
                     (Kind == BraceItemListKind::TopLevelLibrary);
@@ -264,9 +267,10 @@
          (isConditionalBlock ||
           !isTerminatorForBraceItemListKind(Kind, Entries))) {
 
-    SyntaxParsingContext StmtContext(SyntaxContext, SyntaxContextKind::Stmt);
+    SyntaxParsingContext NodeContext(SyntaxContext, SyntaxKind::CodeBlockItem);
 
     if (Tok.is(tok::r_brace)) {
+      SyntaxParsingContext ErrContext(SyntaxContext, SyntaxContextKind::Stmt);
       assert(IsTopLevel);
       diagnose(Tok, diag::extra_rbrace)
         .fixItRemove(Tok.getLoc());
@@ -275,8 +279,11 @@
     }
 
     // Eat invalid tokens instead of allowing them to produce downstream errors.
-    if (consumeIf(tok::unknown))
+    if (Tok.is(tok::unknown)) {
+      SyntaxParsingContext ErrContext(SyntaxContext, SyntaxContextKind::Stmt);
+      consumeToken();
       continue;
+    }
            
     bool NeedParseErrorRecovery = false;
     ASTNode Result;
@@ -411,6 +418,11 @@
     }
 
     if (NeedParseErrorRecovery) {
+      SyntaxContext->createNodeInPlace(SyntaxKind::CodeBlockItem);
+      SyntaxContext->setTransparent();
+
+      SyntaxParsingContext ItemCtxt(SyntaxContext, SyntaxKind::CodeBlockItem);
+      SyntaxParsingContext StmtCtxt(SyntaxContext, SyntaxContextKind::Stmt);
       // If we had a parse error, skip to the start of the next stmt, decl or
       // '{'.
       //
diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp
index 825e607..c17400e 100644
--- a/lib/Parse/SyntaxParsingContext.cpp
+++ b/lib/Parse/SyntaxParsingContext.cpp
@@ -68,17 +68,10 @@
   if (Parts.size() == 1) {
     auto RawNode = Parts.front();
     switch (Kind) {
-    case SyntaxContextKind::Stmt: {
-      if (RawNode->isStmt())
-        return RawNode;
-      else if (RawNode->isDecl())
-        return createSyntaxAs(SyntaxKind::DeclarationStmt, Parts);
-      else if (RawNode->isExpr())
-        return createSyntaxAs(SyntaxKind::ExpressionStmt, Parts);
-      else
+    case SyntaxContextKind::Stmt:
+      if (!RawNode->isStmt())
         return makeUnknownSyntax(SyntaxKind::UnknownStmt, Parts);
       break;
-    }
     case SyntaxContextKind::Decl:
       if (!RawNode->isDecl())
         return makeUnknownSyntax(SyntaxKind::UnknownDecl, Parts);
@@ -186,6 +179,7 @@
     createNodeInPlace(Kind, Pair.first);
     break;
   }
+  case SyntaxKind::CodeBlockItem:
   case SyntaxKind::IdentifierExpr:
   case SyntaxKind::SpecializeExpr:
   case SyntaxKind::MemberAccessExpr:
@@ -255,8 +249,8 @@
 
   if (SF.hasSyntaxRoot()) {
     auto SourceRaw = SF.getSyntaxRoot().getRaw();
-    auto Decls = SourceRaw->getChild(SourceFileSyntax::Cursor::TopLevelDecls)
-                     ->getLayout();
+    auto Decls =
+        SourceRaw->getChild(SourceFileSyntax::Cursor::Items)->getLayout();
     std::copy(Decls.begin(), Decls.end(), std::back_inserter(AllTopLevel));
     EOFToken = SourceRaw->getChild(SourceFileSyntax::Cursor::EOFToken);
   }
@@ -267,12 +261,13 @@
   }
 
   for (auto RawNode : Parts) {
-    if (RawNode->getKind() != SyntaxKind::StmtList)
+    if (RawNode->getKind() != SyntaxKind::CodeBlockItemList)
       // FIXME: Skip toplevel garbage nodes for now. we shouldn't emit them in
       // the first place.
       continue;
-    AllTopLevel.push_back(
-        SyntaxFactory::createRaw(SyntaxKind::TopLevelCodeDecl, {RawNode}));
+
+    auto Items = RawNode->getLayout();
+    std::copy(Items.begin(), Items.end(), std::back_inserter(AllTopLevel));
   }
 
   if (!EOFToken)
@@ -281,8 +276,10 @@
   auto newRaw = SyntaxFactory::createRaw(
       SyntaxKind::SourceFile,
       {
-          SyntaxFactory::createRaw(SyntaxKind::DeclList, AllTopLevel), EOFToken,
+          SyntaxFactory::createRaw(SyntaxKind::CodeBlockItemList, AllTopLevel),
+          EOFToken,
       });
+  assert(newRaw);
   SF.setSyntaxRoot(make<SourceFileSyntax>(newRaw));
 
   if (SF.getASTContext().LangOpts.VerifySyntaxTree) {
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index 4f2c181..2df2022 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -239,14 +239,13 @@
   return false;
 }
 
-/// Given that a type is not statically known to be an optional type, check whether
-/// it might dynamically be an optional type.
-static bool canDynamicallyBeOptionalType(CanType type) {
+/// Given that a type is not statically known to be an optional type, check
+/// whether it might dynamically be able to store an optional.
+static bool canDynamicallyStoreOptional(CanType type) {
   assert(!type.getOptionalObjectType());
-  return (isa<ArchetypeType>(type) || type.isExistentialType())
-      && !type.isAnyClassReferenceType();
+  return type->canDynamicallyBeOptionalType(/* includeExistential */ true);
 }
-
+  
 /// Given two class types, check whether there's a hierarchy relationship
 /// between them.
 static DynamicCastFeasibility
@@ -326,7 +325,7 @@
     auto result = classifyDynamicCast(M, source, targetObject,
                                       /* isSourceTypeExact */ false,
                                       isWholeModuleOpts);
-    if (canDynamicallyBeOptionalType(source))
+    if (canDynamicallyStoreOptional(source))
       result = atWorst(result, DynamicCastFeasibility::MaySucceed);
     return result;
 
diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp
index 85188ca..fe0371b 100644
--- a/lib/SIL/Projection.cpp
+++ b/lib/SIL/Projection.cpp
@@ -73,8 +73,6 @@
     Value = ValueTy(ProjectionKind::Struct, SEAI->getFieldNo());
     assert(getKind() == ProjectionKind::Struct);
     assert(getIndex() == SEAI->getFieldNo());
-    assert(getType(SEAI->getOperand()->getType(), SEAI->getModule()) ==
-           SEAI->getType());
     break;
   }
   case SILInstructionKind::StructExtractInst: {
@@ -82,8 +80,6 @@
     Value = ValueTy(ProjectionKind::Struct, SEI->getFieldNo());
     assert(getKind() == ProjectionKind::Struct);
     assert(getIndex() == SEI->getFieldNo());
-    assert(getType(SEI->getOperand()->getType(), SEI->getModule()) ==
-           SEI->getType());
     break;
   }
   case SILInstructionKind::RefElementAddrInst: {
@@ -91,8 +87,6 @@
     Value = ValueTy(ProjectionKind::Class, REAI->getFieldNo());
     assert(getKind() == ProjectionKind::Class);
     assert(getIndex() == REAI->getFieldNo());
-    assert(getType(REAI->getOperand()->getType(), REAI->getModule()) ==
-           REAI->getType());
     break;
   }
   case SILInstructionKind::RefTailAddrInst: {
@@ -107,8 +101,6 @@
     Value = ValueTy(ProjectionKind::Box, static_cast<uintptr_t>(0));
     assert(getKind() == ProjectionKind::Box);
     assert(getIndex() == 0);
-    assert(getType(PBI->getOperand()->getType(), PBI->getModule()) ==
-           PBI->getType());
     (void) PBI;
     break;
   }
@@ -117,8 +109,6 @@
     Value = ValueTy(ProjectionKind::Tuple, TEI->getFieldNo());
     assert(getKind() == ProjectionKind::Tuple);
     assert(getIndex() == TEI->getFieldNo());
-    assert(getType(TEI->getOperand()->getType(), TEI->getModule()) ==
-           TEI->getType());
     break;
   }
   case SILInstructionKind::TupleElementAddrInst: {
@@ -126,8 +116,6 @@
     Value = ValueTy(ProjectionKind::Tuple, TEAI->getFieldNo());
     assert(getKind() == ProjectionKind::Tuple);
     assert(getIndex() == TEAI->getFieldNo());
-    assert(getType(TEAI->getOperand()->getType(), TEAI->getModule()) ==
-           TEAI->getType());
     break;
   }
   case SILInstructionKind::UncheckedEnumDataInst: {
@@ -135,8 +123,6 @@
     Value = ValueTy(ProjectionKind::Enum, UEDI->getElementNo());
     assert(getKind() == ProjectionKind::Enum);
     assert(getIndex() == UEDI->getElementNo());
-    assert(getType(UEDI->getOperand()->getType(), UEDI->getModule()) ==
-           UEDI->getType());
     break;
   }
   case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
@@ -144,8 +130,6 @@
     Value = ValueTy(ProjectionKind::Enum, UTEDAI->getElementNo());
     assert(getKind() == ProjectionKind::Enum);
     assert(getIndex() == UTEDAI->getElementNo());
-    assert(getType(UTEDAI->getOperand()->getType(), UTEDAI->getModule()) ==
-           UTEDAI->getType());
     break;
   }
   case SILInstructionKind::IndexAddrInst: {
@@ -168,8 +152,6 @@
     assert(Ty->isCanonical());
     Value = ValueTy(ProjectionKind::Upcast, Ty);
     assert(getKind() == ProjectionKind::Upcast);
-    assert(getType(I->getOperand(0)->getType(), I->getModule()) ==
-           I->getType());
     break;
   }
   case SILInstructionKind::UncheckedRefCastInst: {
@@ -177,8 +159,6 @@
     assert(Ty->isCanonical());
     Value = ValueTy(ProjectionKind::RefCast, Ty);
     assert(getKind() == ProjectionKind::RefCast);
-    assert(getType(I->getOperand(0)->getType(), I->getModule()) ==
-           I->getType());
     break;
   }
   case SILInstructionKind::UncheckedBitwiseCastInst:
@@ -187,8 +167,6 @@
     assert(Ty->isCanonical());
     Value = ValueTy(ProjectionKind::BitwiseCast, Ty);
     assert(getKind() == ProjectionKind::BitwiseCast);
-    assert(getType(I->getOperand(0)->getType(), I->getModule()) ==
-           I->getType());
     break;
   }
   }
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index bce425e..112a213 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -3299,14 +3299,21 @@
       auto destValueType
         = finalResultType->lookThroughAllOptionalTypes(destOptionals);
 
-      // When performing a bridging operation, if the destination value type
-      // is 'AnyObject', leave any extra optionals on the source in place.
-      if (castKind == OptionalBindingsCastKind::Bridged &&
-          srcOptionals.size() > destOptionals.size() &&
-          destValueType->isAnyObject()) {
-        srcType = srcOptionals[destOptionals.size()];
-        srcOptionals.erase(srcOptionals.begin() + destOptionals.size(),
-                           srcOptionals.end());
+      auto isBridgeToAnyObject =
+        castKind == OptionalBindingsCastKind::Bridged &&
+        destValueType->isAnyObject();
+
+      // If the destination value type is 'AnyObject' when performing a
+      // bridging operation, or if the destination value type could dynamically
+      // be an optional type, leave any extra optionals on the source in place.
+      if (isBridgeToAnyObject || destValueType->canDynamicallyBeOptionalType(
+                                              /* includeExistential */ false)) {
+        auto destOptionalsCount = destOptionals.size() - destExtraOptionals;
+        if (srcOptionals.size() > destOptionalsCount) {
+          srcType = srcOptionals[destOptionalsCount];
+          srcOptionals.erase(srcOptionals.begin() + destOptionalsCount,
+                             srcOptionals.end());
+        }
       }
 
       // When performing a bridging operation, if the destination type
@@ -4482,9 +4489,6 @@
     /// Diagnose an optional injection that is probably not what the
     /// user wanted, because it comes from a forced downcast.
     void diagnoseOptionalInjection(InjectIntoOptionalExpr *injection) {
-      // Don't diagnose when we're injecting into 
-      auto toOptionalType = cs.getType(injection);
-
       // Check whether we have a forced downcast.
       auto &tc = cs.getTypeChecker();
       auto *cast = findForcedDowncast(tc.Context, injection->getSubExpr());
@@ -6152,7 +6156,10 @@
       // func bar() -> ((()) -> Void)? { return nil }
       // foo(bar) // This expression should compile in Swift 3 mode
       // ```
-      if (tc.getLangOpts().isSwiftVersion3()) {
+      //
+      // See also: https://bugs.swift.org/browse/SR-6796
+      if (cs.getASTContext().isSwiftVersionAtLeast(3) &&
+          !cs.getASTContext().isSwiftVersionAtLeast(5)) {
         auto obj1 = fromType->getOptionalObjectType();
         auto obj2 = toType->getOptionalObjectType();
 
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 802b9b5..7971360 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1168,6 +1168,35 @@
     }
   }
 
+  // https://bugs.swift.org/browse/SR-6796
+  // Add a super-narrow hack to allow:
+  //   (()) -> T to be passed in place of () -> T
+  if (getASTContext().isSwiftVersionAtLeast(4) &&
+      !getASTContext().isSwiftVersionAtLeast(5)) {
+    SmallVector<LocatorPathElt, 4> path;
+    locator.getLocatorParts(path);
+
+    // Find the last path element, skipping GenericArgument elements
+    // so that we allow this exception in cases of optional types, and
+    // skipping OptionalPayload elements so that we allow this
+    // exception in cases of optional injection.
+    auto last = std::find_if(
+        path.rbegin(), path.rend(), [](LocatorPathElt &elt) -> bool {
+          return elt.getKind() != ConstraintLocator::GenericArgument &&
+                 elt.getKind() != ConstraintLocator::OptionalPayload;
+        });
+
+    if (last != path.rend()) {
+      if (last->getKind() == ConstraintLocator::ApplyArgToParam) {
+        if (auto *paren1 = dyn_cast<ParenType>(func1Input.getPointer())) {
+          auto innerTy = paren1->getUnderlyingType();
+          if (func2Input->isVoid() && innerTy->isVoid())
+            func1Input = innerTy;
+        }
+      }
+    }
+  }
+
   // Input types can be contravariant (or equal).
   SmallVector<AnyFunctionType::Param, 4> func1Params;
   SmallVector<AnyFunctionType::Param, 4> func2Params;
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 682b604..50a8c09 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1264,18 +1264,22 @@
   case XREF_TYPE_PATH_PIECE:
   case XREF_VALUE_PATH_PIECE: {
     IdentifierID IID;
+    IdentifierID privateDiscriminator = 0;
     TypeID TID = 0;
     bool isType = (recordID == XREF_TYPE_PATH_PIECE);
     bool inProtocolExt = false;
     bool isStatic = false;
     if (isType)
-      XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
+      XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
+                                          inProtocolExt);
     else
       XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
                                            isStatic);
 
     DeclBaseName name = getDeclBaseName(IID);
     pathTrace.addValue(name);
+    if (privateDiscriminator)
+      pathTrace.addValue(getIdentifier(privateDiscriminator));
 
     Type filterTy;
     if (!isType) {
@@ -1290,9 +1294,14 @@
       pathTrace.addType(filterTy);
     }
 
-    baseModule->lookupQualified(ModuleType::get(baseModule), name,
-                                NL_QualifiedDefault | NL_KnownNoDependency,
-                                /*typeResolver=*/nullptr, values);
+    if (privateDiscriminator) {
+      baseModule->lookupMember(values, baseModule, name,
+                               getIdentifier(privateDiscriminator));
+    } else {
+      baseModule->lookupQualified(ModuleType::get(baseModule), name,
+                                  NL_QualifiedDefault | NL_KnownNoDependency,
+                                  /*typeResolver=*/nullptr, values);
+    }
     filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt, isStatic,
                  None, values);
     break;
@@ -1348,7 +1357,7 @@
       switch (recordID) {
       case XREF_TYPE_PATH_PIECE: {
         IdentifierID IID;
-        XRefTypePathPieceLayout::readRecord(scratch, IID, None);
+        XRefTypePathPieceLayout::readRecord(scratch, IID, None, None);
         result = getIdentifier(IID);
         break;
       }
@@ -1405,8 +1414,13 @@
         // Fast path for nested types that avoids deserializing all
         // members of the parent type.
         IdentifierID IID;
+        IdentifierID privateDiscriminator;
         bool onlyInNominal = false;
-        XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
+        XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
+                                            onlyInNominal);
+        if (privateDiscriminator)
+          goto giveUpFastPath;
+
         Identifier memberName = getIdentifier(IID);
         pathTrace.addValue(memberName);
 
@@ -1449,21 +1463,25 @@
 
         pathTrace.removeLast();
       }
+giveUpFastPath:
       LLVM_FALLTHROUGH;
     }
     case XREF_VALUE_PATH_PIECE:
     case XREF_INITIALIZER_PATH_PIECE: {
       TypeID TID = 0;
       DeclBaseName memberName;
+      Identifier privateDiscriminator;
       Optional<swift::CtorInitializerKind> ctorInit;
       bool isType = false;
       bool inProtocolExt = false;
       bool isStatic = false;
       switch (recordID) {
       case XREF_TYPE_PATH_PIECE: {
-        IdentifierID IID;
-        XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
+        IdentifierID IID, discriminatorID;
+        XRefTypePathPieceLayout::readRecord(scratch, IID, discriminatorID,
+                                            inProtocolExt);
         memberName = getDeclBaseName(IID);
+        privateDiscriminator = getIdentifier(discriminatorID);
         isType = true;
         break;
       }
@@ -1490,6 +1508,8 @@
       }
 
       pathTrace.addValue(memberName);
+      if (!privateDiscriminator.empty())
+        pathTrace.addPrivateDiscriminator(privateDiscriminator);
 
       Type filterTy;
       if (!isType) {
@@ -1519,8 +1539,17 @@
                                            getXRefDeclNameForError());
       }
 
-      auto members = nominal->lookupDirect(memberName);
-      values.append(members.begin(), members.end());
+      if (!privateDiscriminator.empty()) {
+        ModuleDecl *searchModule = M;
+        if (!searchModule)
+          searchModule = nominal->getModuleContext();
+        searchModule->lookupMember(values, nominal, memberName,
+                                   privateDiscriminator);
+
+      } else {
+        auto members = nominal->lookupDirect(memberName);
+        values.append(members.begin(), members.end());
+      }
       filterValues(filterTy, M, genericSig, isType, inProtocolExt, isStatic,
                    ctorInit, values);
       break;
diff --git a/lib/Serialization/DeserializationErrors.h b/lib/Serialization/DeserializationErrors.h
index b5424c3..0703ea4 100644
--- a/lib/Serialization/DeserializationErrors.h
+++ b/lib/Serialization/DeserializationErrors.h
@@ -37,6 +37,7 @@
       Accessor,
       Extension,
       GenericParam,
+      PrivateDiscriminator,
       Unknown
     };
 
@@ -55,11 +56,12 @@
       : kind(K),
         data(llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(value)) {}
 
-    Identifier getAsIdentifier() const {
+    DeclBaseName getAsBaseName() const {
       switch (kind) {
       case Kind::Value:
       case Kind::Operator:
-        return getDataAs<Identifier>();
+      case Kind::PrivateDiscriminator:
+        return getDataAs<DeclBaseName>();
       case Kind::Type:
       case Kind::OperatorFilter:
       case Kind::Accessor:
@@ -73,7 +75,7 @@
     void print(raw_ostream &os) const {
       switch (kind) {
       case Kind::Value:
-        os << getDataAs<Identifier>();
+        os << getDataAs<DeclBaseName>();
         break;
       case Kind::Type:
         os << "with type " << getDataAs<Type>();
@@ -137,6 +139,9 @@
       case Kind::GenericParam:
         os << "generic param #" << getDataAs<uintptr_t>();
         break;
+      case Kind::PrivateDiscriminator:
+        os << "(in " << getDataAs<Identifier>() << ")";
+        break;
       case Kind::Unknown:
         os << "unknown xref kind " << getDataAs<uintptr_t>();
         break;
@@ -180,17 +185,21 @@
     path.push_back({ PathPiece::Kind::GenericParam, index });
   }
 
+  void addPrivateDiscriminator(Identifier name) {
+    path.push_back({ PathPiece::Kind::PrivateDiscriminator, name });
+  }
+
   void addUnknown(uintptr_t kind) {
     path.push_back({ PathPiece::Kind::Unknown, kind });
   }
 
-  Identifier getLastName() const {
+  DeclBaseName getLastName() const {
     for (auto &piece : reversed(path)) {
-      Identifier result = piece.getAsIdentifier();
+      DeclBaseName result = piece.getAsBaseName();
       if (!result.empty())
         return result;
     }
-    return Identifier();
+    return DeclBaseName();
   }
 
   void removeLast() {
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 1eca569..a020f9d 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1868,8 +1868,16 @@
 
     auto generic = cast<GenericTypeDecl>(DC);
     abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
+
+    Identifier discriminator;
+    if (generic->isOutermostPrivateOrFilePrivateScope()) {
+      auto *containingFile = cast<FileUnit>(generic->getModuleScopeContext());
+      discriminator = containingFile->getDiscriminatorForPrivateValue(generic);
+    }
+
     XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
                                         addDeclBaseNameRef(generic->getName()),
+                                        addDeclBaseNameRef(discriminator),
                                         false);
     break;
   }
@@ -2019,8 +2027,17 @@
   bool isProtocolExt = D->getDeclContext()->getAsProtocolExtensionContext();
   if (auto type = dyn_cast<TypeDecl>(D)) {
     abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
+
+    Identifier discriminator;
+    if (type->isOutermostPrivateOrFilePrivateScope()) {
+      auto *containingFile =
+         cast<FileUnit>(type->getDeclContext()->getModuleScopeContext());
+      discriminator = containingFile->getDiscriminatorForPrivateValue(type);
+    }
+
     XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
                                         addDeclBaseNameRef(type->getName()),
+                                        addDeclBaseNameRef(discriminator),
                                         isProtocolExt);
     return;
   }
diff --git a/lib/Syntax/RawSyntax.cpp b/lib/Syntax/RawSyntax.cpp
index 14a22ec..0613fec 100644
--- a/lib/Syntax/RawSyntax.cpp
+++ b/lib/Syntax/RawSyntax.cpp
@@ -30,7 +30,7 @@
     return true;
   switch(Kind) {
   case SyntaxKind::SourceFile:
-  case SyntaxKind::TopLevelCodeDecl:
+  case SyntaxKind::CodeBlockItem:
   case SyntaxKind::ExpressionStmt:
   case SyntaxKind::DeclarationStmt:
     return true;
@@ -179,6 +179,8 @@
       Trailer.accumulateAbsolutePosition(Pos);
   } else {
     for (auto &Child : getLayout()) {
+      if (!Child)
+        continue;
       auto Result = Child->accumulateAbsolutePosition(Pos);
       if (!Ret && Result)
         Ret = Result;
@@ -254,6 +256,8 @@
     }
   } else {
     for (auto &Child : getLayout()) {
+      if (!Child)
+        continue;
       OS << "\n";
       Child->dump(OS, Indent + 1);
     }
diff --git a/test/Compatibility/tuple_arguments.swift b/test/Compatibility/tuple_arguments_3.swift
similarity index 98%
rename from test/Compatibility/tuple_arguments.swift
rename to test/Compatibility/tuple_arguments_3.swift
index e5e87d0..ad90c25 100644
--- a/test/Compatibility/tuple_arguments.swift
+++ b/test/Compatibility/tuple_arguments_3.swift
@@ -1,7 +1,8 @@
 // RUN: %target-typecheck-verify-swift -swift-version 3
 
 // Tests for tuple argument behavior in Swift 3, which was broken.
-// The Swift 4 test is in test/Constraints/tuple_arguments.swift.
+// The Swift 4 test is in test/Compatibility/tuple_arguments_4.swift.
+// The test for the most recent version is in test/Constraints/tuple_arguments.swift.
 
 // Key:
 // - "Crashes in actual Swift 3" -- snippets which crashed in Swift 3.0.1.
@@ -1516,3 +1517,20 @@
   takeFn(fn: { (pair: (Int, Int?)) in } )
   takeFn { (pair: (Int, Int?)) in }
 }
+
+// https://bugs.swift.org/browse/SR-6796
+do {
+  func f(a: (() -> Void)? = nil) {}
+  func log<T>() -> ((T) -> Void)? { return nil }
+
+  f(a: log() as ((()) -> Void)?) // Allow ((()) -> Void)? to be passed in place of (() -> Void)?
+
+  func logNoOptional<T>() -> (T) -> Void { }
+  f(a: logNoOptional() as ((()) -> Void)) // Also allow the optional-injected form.
+
+  func g() {}
+  g(())
+
+  func h(_: ()) {}
+  h()
+}
diff --git a/test/Compatibility/tuple_arguments.swift b/test/Compatibility/tuple_arguments_4.swift
similarity index 68%
copy from test/Compatibility/tuple_arguments.swift
copy to test/Compatibility/tuple_arguments_4.swift
index e5e87d0..1432f0c 100644
--- a/test/Compatibility/tuple_arguments.swift
+++ b/test/Compatibility/tuple_arguments_4.swift
@@ -1,26 +1,10 @@
-// RUN: %target-typecheck-verify-swift -swift-version 3
+// RUN: %target-typecheck-verify-swift -swift-version 4
 
-// Tests for tuple argument behavior in Swift 3, which was broken.
-// The Swift 4 test is in test/Constraints/tuple_arguments.swift.
-
-// Key:
-// - "Crashes in actual Swift 3" -- snippets which crashed in Swift 3.0.1.
-//   These don't have well-defined semantics in Swift 3 mode and don't
-//   matter for source compatibility purposes.
-//
-// - "Does not diagnose in Swift 3 mode" -- snippets which failed to typecheck
-//   in Swift 3.0.1, but now typecheck. This is fine.
-//
-// - "Diagnoses in Swift 3 mode" -- snippets which typechecked in Swift 3.0.1,
-//   but now fail to typecheck. These are bugs in Swift 3 mode that should be
-//   fixed.
-//
-// - "Crashes in Swift 3 mode" -- snippets which did not crash Swift 3.0.1,
-//   but now crash. These are bugs in Swift 3 mode that should be fixed.
+// See test/Compatibility/tuple_arguments_3.swift for the Swift 3 behavior.
 
 func concrete(_ x: Int) {}
 func concreteLabeled(x: Int) {}
-func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 3 {{'concreteTwo' declared here}}
+func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 5 {{'concreteTwo' declared here}}
 func concreteTuple(_ x: (Int, Int)) {}
 
 do {
@@ -49,10 +33,10 @@
   concrete(c)
 
   concreteTwo(a, b)
-  concreteTwo((a, b))
-  concreteTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  concreteTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  concreteTwo(d) // expected-error {{missing argument for parameter #2 in call}}
 
-  concreteTuple(a, b)
+  concreteTuple(a, b) // expected-error {{global function 'concreteTuple' expects a single parameter of type '(Int, Int)'}} {{17-17=(}} {{21-21=)}}
   concreteTuple((a, b))
   concreteTuple(d)
 }
@@ -83,7 +67,7 @@
 
 do {
   generic(3)
-  generic(3, 4)
+  generic(3, 4) // expected-error {{extra argument in call}}
   generic((3))
   generic((3, 4))
 
@@ -106,7 +90,7 @@
   let d = (a, b)
 
   generic(a)
-  generic(a, b)
+  generic(a, b) // expected-error {{extra argument in call}}
   generic((a))
   generic(c)
   generic((a, b))
@@ -128,7 +112,7 @@
   var d = (a, b)
 
   generic(a)
-  // generic(a, b) // Crashes in actual Swift 3
+  generic(a, b) // expected-error {{extra argument in call}}
   generic((a))
   generic(c)
   generic((a, b))
@@ -144,7 +128,7 @@
 }
 
 var function: (Int) -> ()
-var functionTwo: (Int, Int) -> () // expected-note 3 {{'functionTwo' declared here}}
+var functionTwo: (Int, Int) -> () // expected-note 5 {{'functionTwo' declared here}}
 var functionTuple: ((Int, Int)) -> ()
 
 do {
@@ -169,10 +153,10 @@
   function(c)
 
   functionTwo(a, b)
-  functionTwo((a, b))
-  functionTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  functionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  functionTwo(d) // expected-error {{missing argument for parameter #2 in call}}
 
-  functionTuple(a, b)
+  functionTuple(a, b) // expected-error {{var 'functionTuple' expects a single parameter of type '(Int, Int)'}} {{17-17=(}} {{21-21=)}}
   functionTuple((a, b))
   functionTuple(d)
 }
@@ -200,7 +184,7 @@
 
 extension Concrete {
   func concrete(_ x: Int) {}
-  func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 3 {{'concreteTwo' declared here}}
+  func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 5 {{'concreteTwo' declared here}}
   func concreteTuple(_ x: (Int, Int)) {}
 }
 
@@ -230,10 +214,10 @@
   s.concrete(c)
 
   s.concreteTwo(a, b)
-  s.concreteTwo((a, b))
-  s.concreteTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  s.concreteTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  s.concreteTwo(d) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.concreteTuple(a, b)
+  s.concreteTuple(a, b) // expected-error {{instance method 'concreteTuple' expects a single parameter of type '(Int, Int)'}} {{19-19=(}} {{23-23=)}}
   s.concreteTuple((a, b))
   s.concreteTuple(d)
 }
@@ -270,7 +254,7 @@
   let s = Concrete()
 
   s.generic(3)
-  s.generic(3, 4)
+  s.generic(3, 4) // expected-error {{extra argument in call}}
   s.generic((3))
   s.generic((3, 4))
 
@@ -295,7 +279,7 @@
   let d = (a, b)
 
   s.generic(a)
-  s.generic(a, b)
+  s.generic(a, b) // expected-error {{extra argument in call}}
   s.generic((a))
   s.generic((a, b))
   s.generic(d)
@@ -318,7 +302,7 @@
   var d = (a, b)
 
   s.generic(a)
-  // s.generic(a, b) // Crashes in actual Swift 3
+  s.generic(a, b) // expected-error {{extra argument in call}}
   s.generic((a))
   s.generic((a, b))
   s.generic(d)
@@ -334,7 +318,7 @@
 
 extension Concrete {
   mutating func mutatingConcrete(_ x: Int) {}
-  mutating func mutatingConcreteTwo(_ x: Int, _ y: Int) {} // expected-note 3 {{'mutatingConcreteTwo' declared here}}
+  mutating func mutatingConcreteTwo(_ x: Int, _ y: Int) {} // expected-note 5 {{'mutatingConcreteTwo' declared here}}
   mutating func mutatingConcreteTuple(_ x: (Int, Int)) {}
 }
 
@@ -364,10 +348,10 @@
   s.mutatingConcrete(c)
 
   s.mutatingConcreteTwo(a, b)
-  s.mutatingConcreteTwo((a, b))
-  s.mutatingConcreteTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  s.mutatingConcreteTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  s.mutatingConcreteTwo(d) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.mutatingConcreteTuple(a, b)
+  s.mutatingConcreteTuple(a, b) // expected-error {{instance method 'mutatingConcreteTuple' expects a single parameter of type '(Int, Int)'}} {{27-27=(}} {{31-31=)}}
   s.mutatingConcreteTuple((a, b))
   s.mutatingConcreteTuple(d)
 }
@@ -404,7 +388,7 @@
   var s = Concrete()
 
   s.mutatingGeneric(3)
-  s.mutatingGeneric(3, 4)
+  s.mutatingGeneric(3, 4) // expected-error {{extra argument in call}}
   s.mutatingGeneric((3))
   s.mutatingGeneric((3, 4))
 
@@ -429,7 +413,7 @@
   let d = (a, b)
 
   s.mutatingGeneric(a)
-  s.mutatingGeneric(a, b)
+  s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
   s.mutatingGeneric((a))
   s.mutatingGeneric((a, b))
   s.mutatingGeneric(d)
@@ -452,7 +436,7 @@
   var d = (a, b)
 
   s.mutatingGeneric(a)
-  // s.mutatingGeneric(a, b) // Crashes in actual Swift 3
+  s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
   s.mutatingGeneric((a))
   s.mutatingGeneric((a, b))
   s.mutatingGeneric(d)
@@ -498,10 +482,11 @@
   s.function(c)
 
   s.functionTwo(a, b)
-  s.functionTwo((a, b))
-  s.functionTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  s.functionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  s.functionTwo(d) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.functionTuple(a, b)
+
+  s.functionTuple(a, b) // expected-error {{single parameter of type '(Int, Int)' is expected in call}} {{19-19=(}} {{23-23=)}}
   s.functionTuple((a, b))
   s.functionTuple(d)
 }
@@ -528,7 +513,7 @@
 }
 
 struct InitTwo {
-  init(_ x: Int, _ y: Int) {} // expected-note 3 {{'init' declared here}}
+  init(_ x: Int, _ y: Int) {} // expected-note 5 {{'init' declared here}}
 }
 
 struct InitTuple {
@@ -556,10 +541,10 @@
   let c = (a, b)
 
   _ = InitTwo(a, b)
-  _ = InitTwo((a, b))
-  _ = InitTwo(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  _ = InitTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  _ = InitTwo(c) // expected-error {{missing argument for parameter #2 in call}}
 
-  _ = InitTuple(a, b)
+  _ = InitTuple(a, b) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}} {{17-17=(}} {{21-21=)}}
   _ = InitTuple((a, b))
   _ = InitTuple(c)
 }
@@ -579,7 +564,7 @@
 }
 
 struct SubscriptTwo {
-  subscript(_ x: Int, _ y: Int) -> Int { get { return 0 } set { } } // expected-note 3 {{'subscript' declared here}}
+  subscript(_ x: Int, _ y: Int) -> Int { get { return 0 } set { } } // expected-note 5 {{'subscript' declared here}}
 }
 
 struct SubscriptTuple {
@@ -598,10 +583,6 @@
   let s2 = SubscriptTuple()
   _ = s2[3, 4] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{10-10=(}} {{14-14=)}}
   _ = s2[(3, 4)]
-
-  let s3 = SubscriptLabeledTuple()
-  _ = s3[x: 3, 4] // expected-error {{extra argument in call}}
-  _ = s3[x: (3, 4)]
 }
 
 do {
@@ -611,13 +592,17 @@
 
   let s1 = SubscriptTwo()
   _ = s1[a, b]
-  _ = s1[(a, b)]
-  _ = s1[d]
+  _ = s1[(a, b)] // expected-error {{missing argument for parameter #2 in call}}
+  _ = s1[d] // expected-error {{missing argument for parameter #2 in call}}
 
   let s2 = SubscriptTuple()
-  _ = s2[a, b]
+  _ = s2[a, b] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{10-10=(}} {{14-14=)}}
   _ = s2[(a, b)]
   _ = s2[d]
+
+  let s3 = SubscriptLabeledTuple()
+  _ = s3[x: 3, 4] // expected-error {{extra argument in call}}
+  _ = s3[x: (3, 4)]
 }
 
 do {
@@ -638,7 +623,7 @@
 }
 
 enum Enum {
-  case two(Int, Int) // expected-note 3 {{'two' declared here}}
+  case two(Int, Int) // expected-note 6 {{'two' declared here}}
   case tuple((Int, Int))
   case labeledTuple(x: (Int, Int))
 }
@@ -646,6 +631,7 @@
 do {
   _ = Enum.two(3, 4)
   _ = Enum.two((3, 4)) // expected-error {{missing argument for parameter #2 in call}}
+  _ = Enum.two(3 > 4 ? 3 : 4) // expected-error {{missing argument for parameter #2 in call}}
 
   _ = Enum.tuple(3, 4) // expected-error {{enum element 'tuple' expects a single parameter of type '(Int, Int)'}} {{18-18=(}} {{22-22=)}}
   _ = Enum.tuple((3, 4))
@@ -660,10 +646,10 @@
   let c = (a, b)
 
   _ = Enum.two(a, b)
-  _ = Enum.two((a, b))
-  _ = Enum.two(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  _ = Enum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  _ = Enum.two(c) // expected-error {{missing argument for parameter #2 in call}}
 
-  _ = Enum.tuple(a, b)
+  _ = Enum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(Int, Int)'}} {{18-18=(}} {{22-22=)}}
   _ = Enum.tuple((a, b))
   _ = Enum.tuple(c)
 }
@@ -687,7 +673,7 @@
 extension Generic {
   func generic(_ x: T) {}
   func genericLabeled(x: T) {}
-  func genericTwo(_ x: T, _ y: T) {} // expected-note 2 {{'genericTwo' declared here}}
+  func genericTwo(_ x: T, _ y: T) {} // expected-note 3 {{'genericTwo' declared here}}
   func genericTuple(_ x: (T, T)) {}
 }
 
@@ -728,14 +714,14 @@
   s.generic(c)
 
   s.genericTwo(a, b)
-  s.genericTwo((a, b))
+  s.genericTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.genericTuple(a, b)
+  s.genericTuple(a, b) // expected-error {{instance method 'genericTuple' expects a single parameter of type '(Double, Double)'}} {{18-18=(}} {{22-22=)}}
   s.genericTuple((a, b))
 
   let sTwo = Generic<(Double, Double)>()
 
-  sTwo.generic(a, b)
+  sTwo.generic(a, b) // expected-error {{instance method 'generic' expects a single parameter of type '(Double, Double)'}} {{16-16=(}} {{20-20=)}}
   sTwo.generic((a, b))
   sTwo.generic(d)
 }
@@ -768,7 +754,7 @@
 extension Generic {
   mutating func mutatingGeneric(_ x: T) {}
   mutating func mutatingGenericLabeled(x: T) {}
-  mutating func mutatingGenericTwo(_ x: T, _ y: T) {} // expected-note 2 {{'mutatingGenericTwo' declared here}}
+  mutating func mutatingGenericTwo(_ x: T, _ y: T) {} // expected-note 3 {{'mutatingGenericTwo' declared here}}
   mutating func mutatingGenericTuple(_ x: (T, T)) {}
 }
 
@@ -809,14 +795,14 @@
   s.mutatingGeneric(c)
 
   s.mutatingGenericTwo(a, b)
-  s.mutatingGenericTwo((a, b))
+  s.mutatingGenericTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.mutatingGenericTuple(a, b)
+  s.mutatingGenericTuple(a, b) // expected-error {{instance method 'mutatingGenericTuple' expects a single parameter of type '(Double, Double)'}} {{26-26=(}} {{30-30=)}}
   s.mutatingGenericTuple((a, b))
 
   var sTwo = Generic<(Double, Double)>()
 
-  sTwo.mutatingGeneric(a, b)
+  sTwo.mutatingGeneric(a, b) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type '(Double, Double)'}} {{24-24=(}} {{28-28=)}}
   sTwo.mutatingGeneric((a, b))
   sTwo.mutatingGeneric(d)
 }
@@ -866,8 +852,8 @@
 
   let sTwo = Generic<(Double, Double)>()
 
-  sTwo.genericFunction(3.0, 4.0)
-  sTwo.genericFunction((3.0, 4.0)) // Does not diagnose in Swift 3 mode
+  sTwo.genericFunction(3.0, 4.0) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{32-32=)}}
+  sTwo.genericFunction((3.0, 4.0))
 }
 
 do {
@@ -883,16 +869,16 @@
   s.genericFunction(c)
 
   s.genericFunctionTwo(a, b)
-  s.genericFunctionTwo((a, b))
+  s.genericFunctionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.genericFunctionTuple(a, b)
+  s.genericFunctionTuple(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{26-26=(}} {{30-30=)}}
   s.genericFunctionTuple((a, b))
 
   let sTwo = Generic<(Double, Double)>()
 
-  sTwo.genericFunction(a, b)
+  sTwo.genericFunction(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{28-28=)}}
   sTwo.genericFunction((a, b))
-  sTwo.genericFunction(d) // Does not diagnose in Swift 3 mode
+  sTwo.genericFunction(d)
 }
 
 do {
@@ -915,12 +901,12 @@
 
   var sTwo = Generic<(Double, Double)>()
 
-  sTwo.genericFunction(a, b)
-  sTwo.genericFunction((a, b)) // Does not diagnose in Swift 3 mode
-  sTwo.genericFunction(d) // Does not diagnose in Swift 3 mode
+  sTwo.genericFunction(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{28-28=)}}
+  sTwo.genericFunction((a, b))
+  sTwo.genericFunction(d)
 }
 
-struct GenericInit<T> { // expected-note 2 {{'T' declared as parameter to type 'GenericInit'}}
+struct GenericInit<T> {
   init(_ x: T) {}
 }
 
@@ -929,7 +915,7 @@
 }
 
 struct GenericInitTwo<T> {
-  init(_ x: T, _ y: T) {} // expected-note 8 {{'init' declared here}}
+  init(_ x: T, _ y: T) {} // expected-note 10 {{'init' declared here}}
 }
 
 struct GenericInitTuple<T> {
@@ -941,7 +927,7 @@
 }
 
 do {
-  _ = GenericInit(3, 4)
+  _ = GenericInit(3, 4) // expected-error {{extra argument in call}}
   _ = GenericInit((3, 4))
 
   _ = GenericInitLabeled(x: 3, 4) // expected-error {{extra argument in call}}
@@ -958,8 +944,8 @@
 }
 
 do {
-  _ = GenericInit<(Int, Int)>(3, 4)
-  _ = GenericInit<(Int, Int)>((3, 4)) // expected-error {{expression type 'GenericInit<(Int, Int)>' is ambiguous without more context}}
+  _ = GenericInit<(Int, Int)>(3, 4) // expected-error {{extra argument in call}}
+  _ = GenericInit<(Int, Int)>((3, 4))
 
   _ = GenericInitLabeled<(Int, Int)>(x: 3, 4) // expected-error {{extra argument in call}}
   _ = GenericInitLabeled<(Int, Int)>(x: (3, 4))
@@ -979,7 +965,7 @@
   let b = 4
   let c = (a, b)
 
-  _ = GenericInit(a, b)
+  _ = GenericInit(a, b) // expected-error {{extra argument in call}}
   _ = GenericInit((a, b))
   _ = GenericInit(c)
 
@@ -997,15 +983,15 @@
   let b = 4
   let c = (a, b)
 
-  _ = GenericInit<(Int, Int)>(a, b)
+  _ = GenericInit<(Int, Int)>(a, b) // expected-error {{extra argument in call}}
   _ = GenericInit<(Int, Int)>((a, b))
   _ = GenericInit<(Int, Int)>(c)
 
   _ = GenericInitTwo<Int>(a, b)
-  _ = GenericInitTwo<Int>((a, b)) // Does not diagnose in Swift 3 mode
-  _ = GenericInitTwo<Int>(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  _ = GenericInitTwo<Int>((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  _ = GenericInitTwo<Int>(c) // expected-error {{missing argument for parameter #2 in call}}
 
-  _ = GenericInitTuple<Int>(a, b) // Does not diagnose in Swift 3 mode
+  _ = GenericInitTuple<Int>(a, b) // expected-error {{initializer expects a single parameter of type '(T, T)'}} {{29-29=(}} {{33-33=)}}
   _ = GenericInitTuple<Int>((a, b))
   _ = GenericInitTuple<Int>(c)
 }
@@ -1016,8 +1002,8 @@
   var c = (a, b)
 
   _ = GenericInit(a, b) // expected-error {{extra argument in call}}
-  _ = GenericInit((a, b)) // expected-error {{generic parameter 'T' could not be inferred}} // expected-note {{explicitly specify the generic arguments to fix this issue}}
-  _ = GenericInit(c) // expected-error {{generic parameter 'T' could not be inferred}} // expected-note {{explicitly specify the generic arguments to fix this issue}}
+  _ = GenericInit((a, b))
+  _ = GenericInit(c)
 
   _ = GenericInitTwo(a, b)
   _ = GenericInitTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1033,9 +1019,9 @@
   var b = 4 // expected-warning {{variable 'b' was never mutated; consider changing to 'let' constant}}
   var c = (a, b) // expected-warning {{variable 'c' was never mutated; consider changing to 'let' constant}}
 
-  // _ = GenericInit<(Int, Int)>(a, b) // Crashes in Swift 3
-  _ = GenericInit<(Int, Int)>((a, b)) // expected-error {{expression type 'GenericInit<(Int, Int)>' is ambiguous without more context}}
-   _ = GenericInit<(Int, Int)>(c) // expected-error {{expression type 'GenericInit<(Int, Int)>' is ambiguous without more context}}
+  _ = GenericInit<(Int, Int)>(a, b) // expected-error {{extra argument in call}}
+  _ = GenericInit<(Int, Int)>((a, b))
+   _ = GenericInit<(Int, Int)>(c)
 
   _ = GenericInitTwo<Int>(a, b)
   _ = GenericInitTwo<Int>((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1047,8 +1033,7 @@
 }
 
 struct GenericSubscript<T> {
-  // TODO: Restore regressed diagnostics rdar://problem/31724211
-  subscript(_ x: T) -> Int { get { return 0 } set { } } // expected-note* {{}}
+  subscript(_ x: T) -> Int { get { return 0 } set { } }
 }
 
 struct GenericSubscriptLabeled<T> {
@@ -1056,22 +1041,21 @@
 }
 
 struct GenericSubscriptTwo<T> {
-  subscript(_ x: T, _ y: T) -> Int { get { return 0 } set { } } // expected-note 3 {{'subscript' declared here}}
-}
-
-struct GenericSubscriptTuple<T> {
-  subscript(_ x: (T, T)) -> Int { get { return 0 } set { } }
+  subscript(_ x: T, _ y: T) -> Int { get { return 0 } set { } } // expected-note 5 {{'subscript' declared here}}
 }
 
 struct GenericSubscriptLabeledTuple<T> {
   subscript(x x: (T, T)) -> Int { get { return 0 } set { } }
 }
 
+struct GenericSubscriptTuple<T> {
+  subscript(_ x: (T, T)) -> Int { get { return 0 } set { } }
+}
+
 do {
   let s1 = GenericSubscript<(Double, Double)>()
-  _ = s1[3.0, 4.0]
-  // TODO: Restore regressed diagnostics rdar://problem/31724211
-  _ = s1[(3.0, 4.0)] // expected-error {{}}
+  _ = s1[3.0, 4.0] // expected-error {{extra argument in call}}
+  _ = s1[(3.0, 4.0)]
 
   let s1a  = GenericSubscriptLabeled<(Double, Double)>()
   _ = s1a [x: 3.0, 4.0] // expected-error {{extra argument in call}}
@@ -1096,17 +1080,17 @@
   let d = (a, b)
 
   let s1 = GenericSubscript<(Double, Double)>()
-  _ = s1[a, b]
+  _ = s1[a, b] // expected-error {{extra argument in call}}
   _ = s1[(a, b)]
   _ = s1[d]
 
   let s2 = GenericSubscriptTwo<Double>()
   _ = s2[a, b]
-  _ = s2[(a, b)] // Does not diagnose in Swift 3 mode
-  _ = s2[d] // Does not diagnose in Swift 3 mode
+  _ = s2[(a, b)] // expected-error {{missing argument for parameter #2 in call}}
+  _ = s2[d] // expected-error {{missing argument for parameter #2 in call}}
 
   let s3 = GenericSubscriptTuple<Double>()
-  _ = s3[a, b] // Does not diagnose in Swift 3 mode
+  _ = s3[a, b] // expected-error {{subscript expects a single parameter of type '(T, T)'}} {{10-10=(}} {{14-14=)}}
   _ = s3[(a, b)]
   _ = s3[d]
 }
@@ -1118,11 +1102,9 @@
   var d = (a, b) // e/xpected-warning {{variable 'd' was never mutated; consider changing to 'let' constant}}
 
   var s1 = GenericSubscript<(Double, Double)>()
-  _ = s1[a, b]
-  // TODO: Restore regressed diagnostics rdar://problem/31724211
-  // These two lines give different regressed behavior in S3 and S4 mode
-  // _ = s1[(a, b)] // e/xpected-error {{expression type '@lvalue Int' is ambiguous without more context}}
-  // _ = s1[d] // e/xpected-error {{expression type '@lvalue Int' is ambiguous without more context}}
+  _ = s1[a, b] // expected-error {{extra argument in call}}
+  _ = s1[(a, b)]
+  _ = s1[d]
 
   var s2 = GenericSubscriptTwo<Double>()
   _ = s2[a, b]
@@ -1138,12 +1120,12 @@
 enum GenericEnum<T> {
   case one(T)
   case labeled(x: T)
-  case two(T, T) // expected-note 8 {{'two' declared here}}
+  case two(T, T) // expected-note 10 {{'two' declared here}}
   case tuple((T, T))
 }
 
 do {
-  _ = GenericEnum.one(3, 4)
+  _ = GenericEnum.one(3, 4) // expected-error {{extra argument in call}}
   _ = GenericEnum.one((3, 4))
 
   _ = GenericEnum.labeled(x: 3, 4) // expected-error {{extra argument in call}}
@@ -1159,8 +1141,8 @@
 }
 
 do {
-  _ = GenericEnum<(Int, Int)>.one(3, 4)
-  _ = GenericEnum<(Int, Int)>.one((3, 4)) // Does not diagnose in Swift 3 mode
+  _ = GenericEnum<(Int, Int)>.one(3, 4) // expected-error {{enum element 'one' expects a single parameter of type '(Int, Int)'}} {{35-35=(}} {{39-39=)}}
+  _ = GenericEnum<(Int, Int)>.one((3, 4))
 
   _ = GenericEnum<(Int, Int)>.labeled(x: 3, 4) // expected-error {{extra argument in call}}
   _ = GenericEnum<(Int, Int)>.labeled(x: (3, 4))
@@ -1179,7 +1161,7 @@
   let b = 4
   let c = (a, b)
 
-  _ = GenericEnum.one(a, b)
+  _ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
   _ = GenericEnum.one((a, b))
   _ = GenericEnum.one(c)
 
@@ -1197,15 +1179,15 @@
   let b = 4
   let c = (a, b)
 
-  _ = GenericEnum<(Int, Int)>.one(a, b)
+  _ = GenericEnum<(Int, Int)>.one(a, b) // expected-error {{enum element 'one' expects a single parameter of type '(Int, Int)'}} {{35-35=(}} {{39-39=)}}
   _ = GenericEnum<(Int, Int)>.one((a, b))
   _ = GenericEnum<(Int, Int)>.one(c)
 
   _ = GenericEnum<Int>.two(a, b)
-  _ = GenericEnum<Int>.two((a, b))
-  _ = GenericEnum<Int>.two(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+  _ = GenericEnum<Int>.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+  _ = GenericEnum<Int>.two(c) // expected-error {{missing argument for parameter #2 in call}}
 
-  _ = GenericEnum<Int>.tuple(a, b)
+  _ = GenericEnum<Int>.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(Int, Int)'}} {{30-30=(}} {{34-34=)}}
   _ = GenericEnum<Int>.tuple((a, b))
   _ = GenericEnum<Int>.tuple(c)
 }
@@ -1215,9 +1197,9 @@
   var b = 4
   var c = (a, b)
 
-  // _ = GenericEnum.one(a, b) // Crashes in actual Swift 3
-  _ = GenericEnum.one((a, b)) // Does not diagnose in Swift 3 mode
-  _ = GenericEnum.one(c) // Does not diagnose in Swift 3 mode
+  _ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
+  _ = GenericEnum.one((a, b))
+  _ = GenericEnum.one(c)
 
   _ = GenericEnum.two(a, b)
   _ = GenericEnum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1233,9 +1215,9 @@
   var b = 4
   var c = (a, b)
 
-  // _ = GenericEnum<(Int, Int)>.one(a, b) // Crashes in actual Swift 3
-  _ = GenericEnum<(Int, Int)>.one((a, b)) // Does not diagnose in Swift 3 mode
-  _ = GenericEnum<(Int, Int)>.one(c) // Does not diagnose in Swift 3 mode
+  _ = GenericEnum<(Int, Int)>.one(a, b) // expected-error {{enum element 'one' expects a single parameter of type '(Int, Int)'}} {{35-35=(}} {{39-39=)}}
+  _ = GenericEnum<(Int, Int)>.one((a, b))
+  _ = GenericEnum<(Int, Int)>.one(c)
 
   _ = GenericEnum<Int>.two(a, b)
   _ = GenericEnum<Int>.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1253,7 +1235,7 @@
 extension Protocol {
   func requirement(_ x: Element) {}
   func requirementLabeled(x: Element) {}
-  func requirementTwo(_ x: Element, _ y: Element) {} // expected-note 2 {{'requirementTwo' declared here}}
+  func requirementTwo(_ x: Element, _ y: Element) {} // expected-note 3 {{'requirementTwo' declared here}}
   func requirementTuple(_ x: (Element, Element)) {}
 }
 
@@ -1266,7 +1248,7 @@
 
   s.requirement(3.0)
   s.requirement((3.0))
-
+ 
   s.requirementLabeled(x: 3.0)
   s.requirementLabeled(x: (3.0))
 
@@ -1298,14 +1280,14 @@
   s.requirement(c)
 
   s.requirementTwo(a, b)
-  s.requirementTwo((a, b)) // Does not diagnose in Swift 3 mode
+  s.requirementTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
 
-  s.requirementTuple(a, b) // Does not diagnose in Swift 3 mode
+  s.requirementTuple(a, b) // expected-error {{instance method 'requirementTuple' expects a single parameter of type '(Double, Double)'}} {{22-22=(}} {{26-26=)}}
   s.requirementTuple((a, b))
 
   let sTwo = GenericConforms<(Double, Double)>()
 
-  sTwo.requirement(a, b)
+  sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{24-24=)}}
   sTwo.requirement((a, b))
   sTwo.requirement(d)
 }
@@ -1347,9 +1329,9 @@
   s.takesClosure({ x in })
   s.takesClosure({ (x: Double) in })
 
-  s.takesClosureTwo({ _ = $0 })
-  s.takesClosureTwo({ x in })
-  s.takesClosureTwo({ (x: (Double, Double)) in })
+  s.takesClosureTwo({ _ = $0 }) // expected-error {{contextual closure type '(Double, Double) -> ()' expects 2 arguments, but 1 was used in closure body}}
+  s.takesClosureTwo({ x in }) // expected-error {{contextual closure type '(Double, Double) -> ()' expects 2 arguments, but 1 was used in closure body}}
+  s.takesClosureTwo({ (x: (Double, Double)) in }) // expected-error {{contextual closure type '(Double, Double) -> ()' expects 2 arguments, but 1 was used in closure body}}
   s.takesClosureTwo({ _ = $0; _ = $1 })
   s.takesClosureTwo({ (x, y) in })
   s.takesClosureTwo({ (x: Double, y:Double) in })
@@ -1375,12 +1357,12 @@
   let _: ((Int, Int)) -> () = { _ = ($0.0, $0.1) }
   let _: ((Int, Int)) -> () = { t in _ = (t.0, t.1) }
 
-  let _: ((Int, Int)) -> () = { _ = ($0, $1) }
-  let _: ((Int, Int)) -> () = { t, u in _ = (t, u) }
+  let _: ((Int, Int)) -> () = { _ = ($0, $1) } // expected-error {{closure tuple parameter '(Int, Int)' does not support destructuring}}
+  let _: ((Int, Int)) -> () = { t, u in _ = (t, u) } // expected-error {{closure tuple parameter '(Int, Int)' does not support destructuring}} {{33-37=(arg)}} {{41-41=let (t, u) = arg; }}
 
-  let _: (Int, Int) -> () = { _ = $0 }
-  let _: (Int, Int) -> () = { _ = ($0.0, $0.1) }
-  let _: (Int, Int) -> () = { t in _ = (t.0, t.1) }
+  let _: (Int, Int) -> () = { _ = $0 } // expected-error {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}}
+  let _: (Int, Int) -> () = { _ = ($0.0, $0.1) } // expected-error {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}}
+  let _: (Int, Int) -> () = { t in _ = (t.0, t.1) } // expected-error {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}}
 
   let _: (Int, Int) -> () = { _ = ($0, $1) }
   let _: (Int, Int) -> () = { t, u in _ = (t, u) }
@@ -1398,19 +1380,17 @@
   let fn: (Any) -> () = { _ in }
 
   fn(123)
-  fn(data: 123)
+  fn(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
 
   takesAny(123)
-  takesAny(data: 123)
+  takesAny(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
 
   _ = HasAnyCase.any(123)
-  _ = HasAnyCase.any(data: 123)
+  _ = HasAnyCase.any(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
 }
 
 // rdar://problem/29739905 - protocol extension methods on Array had
 // ParenType sugar stripped off the element type
-typealias BoolPair = (Bool, Bool)
-
 func processArrayOfFunctions(f1: [((Bool, Bool)) -> ()],
                              f2: [(Bool, Bool) -> ()],
                              c: Bool) {
@@ -1419,24 +1399,27 @@
   f1.forEach { block in
     block(p)
     block((c, c))
-    block(c, c)
+    block(c, c) // expected-error {{parameter 'block' expects a single parameter of type '(Bool, Bool)'}} {{11-11=(}} {{15-15=)}}
   }
 
   f2.forEach { block in
-    block(p) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
-    block((c, c))
+  // expected-note@-1 2{{'block' declared here}}
+    block(p) // expected-error {{missing argument for parameter #2 in call}}
+    block((c, c)) // expected-error {{missing argument for parameter #2 in call}}
     block(c, c)
   }
 
   f2.forEach { (block: ((Bool, Bool)) -> ()) in
+  // expected-error@-1 {{cannot convert value of type '(((Bool, Bool)) -> ()) -> ()' to expected argument type '((Bool, Bool) -> ()) -> Void}}
     block(p)
     block((c, c))
     block(c, c)
   }
 
   f2.forEach { (block: (Bool, Bool) -> ()) in
-    block(p) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
-    block((c, c))
+  // expected-note@-1 2{{'block' declared here}}
+    block(p) // expected-error {{missing argument for parameter #2 in call}}
+    block((c, c)) // expected-error {{missing argument for parameter #2 in call}}
     block(c, c)
   }
 }
@@ -1449,7 +1432,7 @@
 }
 
 
-// SR-4378 -- FIXME -- this should type check, it used to work in Swift 3.0
+// SR-4378
 
 final public class MutableProperty<Value> {
     public init(_ initialValue: Value) {}
@@ -1460,38 +1443,190 @@
 }
 
 let pages1: MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)> = MutableProperty((
-    // expected-error@-1 {{expression type 'MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)>' is ambiguous without more context}}
     data: .notLoaded,
     totalCount: 0
 ))
 
 
 let pages2: MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)> = MutableProperty((
-    // expected-error@-1 {{cannot convert value of type 'MutableProperty<(data: DataSourcePage<_>, totalCount: Int)>' to specified type 'MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)>'}}
     data: DataSourcePage.notLoaded,
     totalCount: 0
 ))
 
 
 let pages3: MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)> = MutableProperty((
-    // expected-error@-1 {{expression type 'MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)>' is ambiguous without more context}}
     data: DataSourcePage<Int>.notLoaded,
     totalCount: 0
 ))
 
-// rdar://problem/32301091 - Make sure that in Swift 3 mode following expressions still compile just fine
+// SR-4745
+let sr4745 = [1, 2]
+let _ = sr4745.enumerated().map { (count, element) in "\(count): \(element)" }
+
+// SR-4738
+
+let sr4738 = (1, (2, 3))
+[sr4738].map { (x, (y, z)) -> Int in x + y + z } // expected-error {{use of undeclared type 'y'}}
+// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{20-26=arg1}} {{38-38=let (y, z) = arg1; }}
+
+// rdar://problem/31892961
+let r31892961_1 = [1: 1, 2: 2]
+r31892961_1.forEach { (k, v) in print(k + v) }
+
+let r31892961_2 = [1, 2, 3]
+let _: [Int] = r31892961_2.enumerated().map { ((index, val)) in
+  // expected-error@-1 {{closure tuple parameter does not support destructuring}} {{48-60=arg0}} {{3-3=\n  let (index, val) = arg0\n  }}
+  // expected-error@-2 {{use of undeclared type 'index'}}
+  val + 1
+}
+
+let r31892961_3 = (x: 1, y: 42)
+_ = [r31892961_3].map { (x: Int, y: Int) in x + y }
+
+_ = [r31892961_3].map { (x, y: Int) in x + y }
+
+let r31892961_4 = (1, 2)
+_ = [r31892961_4].map { x, y in x + y }
+
+let r31892961_5 = (x: 1, (y: 2, (w: 3, z: 4)))
+[r31892961_5].map { (x: Int, (y: Int, (w: Int, z: Int))) in x + y }
+// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{30-56=arg1}} {{61-61=let (y, (w, z)) = arg1; }}
+
+let r31892961_6 = (x: 1, (y: 2, z: 4))
+[r31892961_6].map { (x: Int, (y: Int, z: Int)) in x + y }
+// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{30-46=arg1}} {{51-51=let (y, z) = arg1; }}
+
+// rdar://problem/32214649 -- these regressed in Swift 4 mode
+// with SE-0110 because of a problem in associated type inference
+
+func r32214649_1<X,Y>(_ a: [X], _ f: (X)->Y) -> [Y] {
+  return a.map(f)
+}
+
+func r32214649_2<X>(_ a: [X], _ f: (X) -> Bool) -> [X] {
+  return a.filter(f)
+}
+
+func r32214649_3<X>(_ a: [X]) -> [X] {
+  return a.filter { _ in return true }
+}
+
+// rdar://problem/32301091 - [SE-0110] causes errors when passing a closure with a single underscore to a block accepting multiple parameters
 
 func rdar32301091_1(_ :((Int, Int) -> ())!) {}
-rdar32301091_1 { _ in } // Ok in Swift 3
+rdar32301091_1 { _ in }
+// expected-error@-1 {{cannot convert value of type '(_) -> ()' to expected argument type '((Int, Int) -> ())?'}}
 
 func rdar32301091_2(_ :(Int, Int) -> ()) {}
-rdar32301091_2 { _ in } // Ok in Swift 3
+rdar32301091_2 { _ in }
+// expected-error@-1 {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}} {{19-19=,_ }}
+rdar32301091_2 { x in }
+// expected-error@-1 {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}} {{19-19=,<#arg#> }}
 
-// rdar://problem/35198459 - source-compat-suite failure: Moya (toType->hasUnresolvedType() && "Should have handled this above")
+func rdar32875953() {
+  let myDictionary = ["hi":1]
+
+  myDictionary.forEach {
+    print("\($0) -> \($1)")
+  }
+
+  myDictionary.forEach { key, value in
+    print("\(key) -> \(value)")
+  }
+
+  myDictionary.forEach { (key, value) in
+    print("\(key) -> \(value)")
+  }
+
+  let array1 = [1]
+  let array2 = [2]
+
+  _ = zip(array1, array2).map(+)
+}
+
+struct SR_5199 {}
+extension Sequence where Iterator.Element == (key: String, value: String?) {
+  func f() -> [SR_5199] {
+    return self.map { (key, value) in
+        SR_5199() // Ok
+    }
+  }
+}
+
+func rdar33043106(_ records: [(Int)], _ other: [((Int))]) -> [Int] {
+  let x: [Int] = records.map { _ in
+    let i = 1
+    return i
+  }
+  let y: [Int] = other.map { _ in
+    let i = 1
+    return i
+  }
+
+  return x + y
+}
+
+func itsFalse(_: Int) -> Bool? {
+  return false
+}
+
+func rdar33159366(s: AnySequence<Int>) {
+  _ = s.compactMap(itsFalse)
+  let a = Array(s)
+  _ = a.compactMap(itsFalse)
+}
+
+func sr5429<T>(t: T) {
+  _ = AnySequence([t]).first(where: { (t: T) in true })
+}
+
+extension Concrete {
+  typealias T = (Int, Int)
+  typealias F = (T) -> ()
+  func opt1(_ fn: (((Int, Int)) -> ())?) {}
+  func opt2(_ fn: (((Int, Int)) -> ())??) {}
+  func opt3(_ fn: (((Int, Int)) -> ())???) {}
+  func optAliasT(_ fn: ((T) -> ())?) {}
+  func optAliasF(_ fn: F?) {}
+}
+
+extension Generic {
+  typealias F = (T) -> ()
+  func opt1(_ fn: (((Int, Int)) -> ())?) {}
+  func opt2(_ fn: (((Int, Int)) -> ())??) {}
+  func opt3(_ fn: (((Int, Int)) -> ())???) {}
+  func optAliasT(_ fn: ((T) -> ())?) {}
+  func optAliasF(_ fn: F?) {}
+}
+
+func rdar33239714() {
+  Concrete().opt1 { x, y in }
+  Concrete().opt1 { (x, y) in }
+  Concrete().opt2 { x, y in }
+  Concrete().opt2 { (x, y) in }
+  Concrete().opt3 { x, y in }
+  Concrete().opt3 { (x, y) in }
+  Concrete().optAliasT { x, y in }
+  Concrete().optAliasT { (x, y) in }
+  Concrete().optAliasF { x, y in }
+  Concrete().optAliasF { (x, y) in }
+  Generic<(Int, Int)>().opt1 { x, y in }
+  Generic<(Int, Int)>().opt1 { (x, y) in }
+  Generic<(Int, Int)>().opt2 { x, y in }
+  Generic<(Int, Int)>().opt2 { (x, y) in }
+  Generic<(Int, Int)>().opt3 { x, y in }
+  Generic<(Int, Int)>().opt3 { (x, y) in }
+  Generic<(Int, Int)>().optAliasT { x, y in }
+  Generic<(Int, Int)>().optAliasT { (x, y) in }
+  Generic<(Int, Int)>().optAliasF { x, y in }
+  Generic<(Int, Int)>().optAliasF { (x, y) in }
+}
+
+// rdar://problem/35198459 - source-compat-suite failure: Moya (toType->hasUnresolvedType() && "Should have handled this above"
 do {
   func foo(_: (() -> Void)?) {}
   func bar() -> ((()) -> Void)? { return nil }
-  foo(bar()) // OK in Swift 3 mode
+  foo(bar()) // Allow ((()) -> Void)? to be passed in place of (() -> Void)? for -swift-version 4 but not later.
 }
 
 // https://bugs.swift.org/browse/SR-6509
@@ -1506,13 +1641,32 @@
     where Wrapped == (Value) -> Result {
     return value.apply(self)
   }
-} 
+}
 
 // https://bugs.swift.org/browse/SR-6837
 do {
   func takeFn(fn: (_ i: Int, _ j: Int?) -> ()) {}
   func takePair(_ pair: (Int, Int?)) {}
-  takeFn(fn: takePair)
-  takeFn(fn: { (pair: (Int, Int?)) in } )
-  takeFn { (pair: (Int, Int?)) in }
+  takeFn(fn: takePair) // Allow for -swift-version 4, but not later
+  takeFn(fn: { (pair: (Int, Int?)) in } ) // Disallow for -swift-version 4 and later
+  // expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
+  takeFn { (pair: (Int, Int?)) in } // Disallow for -swift-version 4 and later
+  // expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
+}
+
+// https://bugs.swift.org/browse/SR-6796
+do {
+  func f(a: (() -> Void)? = nil) {}
+  func log<T>() -> ((T) -> Void)? { return nil }
+
+  f(a: log() as ((()) -> Void)?) // Allow ((()) -> Void)? to be passed in place of (() -> Void)? for -swift-version 4 but not later.
+
+  func logNoOptional<T>() -> (T) -> Void { }
+  f(a: logNoOptional() as ((()) -> Void)) // Also allow the optional-injected form.
+
+  func g() {}
+  g(()) // expected-error {{argument passed to call that takes no arguments}}
+
+  func h(_: ()) {} // expected-note {{'h' declared here}}
+  h() // expected-error {{missing argument for parameter #1 in call}}
 }
diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift
index 61429a7..9db51b7 100644
--- a/test/Constraints/tuple_arguments.swift
+++ b/test/Constraints/tuple_arguments.swift
@@ -1,6 +1,7 @@
-// RUN: %target-typecheck-verify-swift -swift-version 4
+// RUN: %target-typecheck-verify-swift -swift-version 5
 
-// See test/Compatibility/tuple_arguments.swift for the Swift 3 behavior.
+// See test/Compatibility/tuple_arguments_3.swift for the Swift 3 behavior.
+// See test/Compatibility/tuple_arguments_4.swift for the Swift 4 behavior.
 
 func concrete(_ x: Int) {}
 func concreteLabeled(x: Int) {}
@@ -1643,14 +1644,30 @@
   }
 }
 
-
 // https://bugs.swift.org/browse/SR-6837
 do {
   func takeFn(fn: (_ i: Int, _ j: Int?) -> ()) {}
   func takePair(_ pair: (Int, Int?)) {}
-  takeFn(fn: takePair) // Allow for -swift-version 4, but not later
+  takeFn(fn: takePair) // expected-error {{cannot convert value of type '((Int, Int?)) -> ()' to expected argument type '(Int, Int?) -> ()'}}
   takeFn(fn: { (pair: (Int, Int?)) in } ) // Disallow for -swift-version 4 and later
   // expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
   takeFn { (pair: (Int, Int?)) in } // Disallow for -swift-version 4 and later
   // expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
 }
+
+// https://bugs.swift.org/browse/SR-6796
+do {
+  func f(a: (() -> Void)? = nil) {}
+  func log<T>() -> ((T) -> Void)? { return nil }
+
+  f(a: log() as ((()) -> Void)?) // expected-error {{cannot convert value of type '((()) -> Void)?' to expected argument type '(() -> Void)?'}}
+
+  func logNoOptional<T>() -> (T) -> Void { }
+  f(a: logNoOptional() as ((()) -> Void)) // expected-error {{cannot convert value of type '(()) -> Void' to expected argument type '(() -> Void)?'}}
+
+  func g() {}
+  g(()) // expected-error {{argument passed to call that takes no arguments}}
+
+  func h(_: ()) {} // expected-note {{'h' declared here}}
+  h() // expected-error {{missing argument for parameter #1 in call}}
+}
diff --git a/test/SILGen/generic_casts.swift b/test/SILGen/generic_casts.swift
index a686c3a..6fe1f40 100644
--- a/test/SILGen/generic_casts.swift
+++ b/test/SILGen/generic_casts.swift
@@ -217,7 +217,74 @@
 }
 
 // CHECK-LABEL: sil hidden @$S13generic_casts27optional_anyobject_to_classyAA1CCSgyXlSgF
-// CHECK:         checked_cast_br {{%.*}} : $AnyObject to $C
 func optional_anyobject_to_class(_ p: AnyObject?) -> C? {
   return p as? C
+  // CHECK: checked_cast_br {{%.*}} : $AnyObject to $C
 }
+
+// The below tests are to ensure we don't dig into an optional operand when
+// casting to a non-class archetype, as it could dynamically be an optional type.
+
+// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_opaque_archetype<T>(_ x: Any?) -> T {
+  return x as! T
+  // CHECK: bb0([[RET:%.*]] : @trivial $*T, {{%.*}} : @trivial $*Optional<Any>):
+  // CHECK: unconditional_checked_cast_addr Optional<Any> in {{%.*}} : $*Optional<Any> to T in [[RET]] : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts46optional_any_conditionally_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_opaque_archetype<T>(_ x: Any?) -> T? {
+  return x as? T
+  // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_is_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
+  return x is T
+  // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to T in {{%.*}} : $*T
+}
+
+// But we can dig into at most one layer of the operand if it's
+// an optional archetype...
+
+// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_optional_opaque_archetype<T>(_ x: Any?) -> T? {
+  return x as! T?
+  // CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts030optional_any_conditionally_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_optional_opaque_archetype<T>(_ x: Any?) -> T?? {
+  return x as? T?
+  // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_is_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_optional_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
+  return x is T?
+  //   Because the levels of optional are the same, 'is' doesn't transform into an 'as?',
+  //   so we just cast directly without digging into the optional operand.
+  // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to Optional<T> in {{%.*}} : $*Optional<T>
+}
+
+// And we can dig into the operand when casting to a class archetype, as it
+// cannot dynamically be optional...
+
+// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_class_archetype<T : AnyObject>(_ x: Any?) -> T {
+  return x as! T
+  // CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts45optional_any_conditionally_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_class_archetype<T : AnyObject>(_ x: Any?) -> T? {
+  return x as? T
+  // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_is_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_class_archetype<T : AnyObject>(_ x: Any?, _: T) -> Bool {
+  return x is T
+  // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
diff --git a/test/Serialization/Inputs/xref-private-type/Lib.swift b/test/Serialization/Inputs/xref-private-type/Lib.swift
new file mode 100644
index 0000000..4292ce3
--- /dev/null
+++ b/test/Serialization/Inputs/xref-private-type/Lib.swift
@@ -0,0 +1,8 @@
+import LibCore
+
+public let lazyFoo = Foo()
+public func testFoo(_: Foo = lazyFoo) {}
+public let lazyBar = Bar()
+public func testBar(_: Bar = lazyBar) {}
+public let lazyBaz = Baz()
+public func testBaz(_: Baz = lazyBaz) {}
diff --git a/test/Serialization/Inputs/xref-private-type/LibCore.swift b/test/Serialization/Inputs/xref-private-type/LibCore.swift
new file mode 100644
index 0000000..032dbdf
--- /dev/null
+++ b/test/Serialization/Inputs/xref-private-type/LibCore.swift
@@ -0,0 +1,24 @@
+private class TopLevelInternalClass {}
+public struct Foo {
+  private var ref: TopLevelInternalClass
+  
+  public init() { self.ref = .init() }
+}
+
+public struct Bar {
+  private class NestedInternalClass {}
+
+  private var ref: NestedInternalClass
+  
+  public init() { self.ref = .init() }
+}
+
+public struct Baz {
+  fileprivate class NestedInternalClass {
+    fileprivate class DoublyNestedInternalClass {}
+  }
+
+  private var ref: NestedInternalClass.DoublyNestedInternalClass
+  
+  public init() { self.ref = .init() }
+}
diff --git a/test/Serialization/xref-private-type.swift b/test/Serialization/xref-private-type.swift
new file mode 100755
index 0000000..2ad6c92
--- /dev/null
+++ b/test/Serialization/xref-private-type.swift
@@ -0,0 +1,51 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift -swift-version 4 -O  -force-single-frontend-invocation -emit-module-path %t/LibCore.swiftmodule %S/Inputs/xref-private-type/LibCore.swift
+// RUN: %target-build-swift -swift-version 4 -O -I %t  -force-single-frontend-invocation -emit-module-path %t/Lib.swiftmodule %S/Inputs/xref-private-type/Lib.swift 
+// RUN: %target-build-swift -swift-version 4 -O -I %t -emit-sil %s | %FileCheck %s
+
+import Lib
+
+// CHECK: sil{{.*}} @[[TESTSR6874:[^ ]+10testSR6874[^ ]+]] :
+func testSR6874() {
+  // The important lines in this test are the strong_retains, which refer to
+  // private types defined in LibCore. Normally we shouldn't have references to
+  // non-public declarations in inlinable code, but because SIL passes can break
+  // apart non-resilient structs and enums we can end up in that situation.
+  // Worse, this can happen *across module boundaries.*
+  //
+  // In this test, the addressor for each global defined in Lib ends up
+  // referencing private types defined in LibCore. Using those globals in
+  // default argument position leads to the addressor getting inlined into
+  // calling code in Swift 4 and later. This results in an attempt to not just
+  // reference a private type, but to *resolve a cross-reference to a private
+  // type.*
+  //
+  // This is the situation in SR-6874 (simplified). I'm not sure of a simpler
+  // way to reliably trigger the issue. But if this test breaks, please try to
+  // find one.
+  //
+  // (We may want to revisit this whole thing later, as it violates the model.
+  // But it's also useful for performance in non-resilient code.)
+
+  // CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyFoo
+  // CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Foo
+  // CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Foo, #Foo.ref
+  // CHECK: strong_retain [[REF]] : $TopLevelInternalClass
+  // CHECK: apply {{%.+}}([[LOADED]])
+  testFoo()
+
+  // CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyBar
+  // CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Bar
+  // CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Bar, #Bar.ref
+  // CHECK: strong_retain [[REF]] : $Bar.NestedInternalClass
+  // CHECK: apply {{%.+}}([[LOADED]])
+  testBar()
+
+  // CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyBaz
+  // CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Baz
+  // CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Baz, #Baz.ref
+  // CHECK: strong_retain [[REF]] : $Baz.NestedInternalClass.DoublyNestedInternalClass
+  // CHECK: apply {{%.+}}([[LOADED]])
+  testBaz()
+} // CHECK: end sil function '[[TESTSR6874]]'
+
diff --git a/test/SwiftSyntax/SyntaxChildren.swift b/test/SwiftSyntax/SyntaxChildren.swift
index be5473a..8e4cee9 100644
--- a/test/SwiftSyntax/SyntaxChildren.swift
+++ b/test/SwiftSyntax/SyntaxChildren.swift
@@ -28,25 +28,21 @@
 SyntaxChildrenAPI.test("IterateWithAllPresent") {
   let returnStmt = SyntaxFactory.makeReturnStmt(
     returnKeyword: SyntaxFactory.makeReturnKeyword(),
-    expression: SyntaxFactory.makeBlankUnknownExpr(),
-    semicolon: SyntaxFactory.makeSemicolonToken())
+    expression: SyntaxFactory.makeBlankUnknownExpr())
 
   var iterator = returnStmt.children.makeIterator()
   expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .returnKeyword }
   expectNext(&iterator) { $0 is ExprSyntax }
-  expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .semicolon }
   expectNextIsNil(&iterator)
 }
 
 SyntaxChildrenAPI.test("IterateWithSomeMissing") {
   let returnStmt = SyntaxFactory.makeReturnStmt(
     returnKeyword: SyntaxFactory.makeReturnKeyword(),
-    expression: nil,
-    semicolon: SyntaxFactory.makeSemicolonToken())
+    expression: nil)
 
   var iterator = returnStmt.children.makeIterator()
   expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .returnKeyword }
-  expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .semicolon }
   expectNextIsNil(&iterator)
 }
 
diff --git a/test/Syntax/Inputs/serialize_multiple_decls.json b/test/Syntax/Inputs/serialize_multiple_decls.json
index 909065d..931ea25 100644
--- a/test/Syntax/Inputs/serialize_multiple_decls.json
+++ b/test/Syntax/Inputs/serialize_multiple_decls.json
@@ -2,193 +2,181 @@
   "kind": "SourceFile",
   "layout": [
     {
-      "kind": "DeclList",
+      "kind": "CodeBlockItemList",
       "layout": [
         {
-          "kind": "TopLevelCodeDecl",
+          "kind": "CodeBlockItem",
           "layout": [
             {
-              "kind": "StmtList",
+              "kind": "StructDecl",
               "layout": [
+                null,
+                null,
                 {
-                  "kind": "DeclarationStmt",
-                  "layout": [
+                  "tokenKind": {
+                    "kind": "kw_struct"
+                  },
+                  "leadingTrivia": [
                     {
-                      "kind": "StructDecl",
-                      "layout": [
-                        null,
-                        null,
-                        {
-                          "tokenKind": {
-                            "kind": "kw_struct"
-                          },
-                          "leadingTrivia": [
-                            {
-                              "kind": "LineComment",
-                              "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
-                            },
-                            {
-                              "kind": "Newline",
-                              "value": 1
-                            },
-                            {
-                              "kind": "LineComment",
-                              "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_multiple_decls.json"
-                            },
-                            {
-                              "kind": "Newline",
-                              "value": 2
-                            }
-                          ],
-                          "trailingTrivia": [
-                            {
-                              "kind": "Space",
-                              "value": 1
-                            }
-                          ],
-                          "presence": "Present"
-                        },
-                        {
-                          "tokenKind": {
-                            "kind": "identifier",
-                            "text": "A"
-                          },
-                          "leadingTrivia": [],
-                          "trailingTrivia": [
-                            {
-                              "kind": "Space",
-                              "value": 1
-                            }
-                          ],
-                          "presence": "Present"
-                        },
-                        null,
-                        null,
-                        null,
-                        {
-                          "kind": "MemberDeclBlock",
-                          "layout": [
-                            {
-                              "tokenKind": {
-                                "kind": "l_brace"
-                              },
-                              "leadingTrivia": [],
-                              "trailingTrivia": [],
-                              "presence": "Present"
-                            },
-                            {
-                              "kind": "DeclList",
-                              "layout": [],
-                              "presence": "Present"
-                            },
-                            {
-                              "tokenKind": {
-                                "kind": "r_brace"
-                              },
-                              "leadingTrivia": [
-                                {
-                                  "kind": "Newline",
-                                  "value": 1
-                                }
-                              ],
-                              "trailingTrivia": [],
-                              "presence": "Present"
-                            }
-                          ],
-                          "presence": "Present"
-                        }
-                      ],
-                      "presence": "Present"
+                      "kind": "LineComment",
+                      "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
                     },
-                    null
+                    {
+                      "kind": "Newline",
+                      "value": 1
+                    },
+                    {
+                      "kind": "LineComment",
+                      "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_multiple_decls.json"
+                    },
+                    {
+                      "kind": "Newline",
+                      "value": 2
+                    }
+                  ],
+                  "trailingTrivia": [
+                    {
+                      "kind": "Space",
+                      "value": 1
+                    }
                   ],
                   "presence": "Present"
                 },
                 {
-                  "kind": "DeclarationStmt",
+                  "tokenKind": {
+                    "kind": "identifier",
+                    "text": "A"
+                  },
+                  "leadingTrivia": [],
+                  "trailingTrivia": [
+                    {
+                      "kind": "Space",
+                      "value": 1
+                    }
+                  ],
+                  "presence": "Present"
+                },
+                null,
+                null,
+                null,
+                {
+                  "kind": "MemberDeclBlock",
                   "layout": [
                     {
-                      "kind": "StructDecl",
-                      "layout": [
-                        null,
-                        null,
-                        {
-                          "tokenKind": {
-                            "kind": "kw_struct"
-                          },
-                          "leadingTrivia": [
-                            {
-                              "kind": "Newline",
-                              "value": 2
-                            }
-                          ],
-                          "trailingTrivia": [
-                            {
-                              "kind": "Space",
-                              "value": 1
-                            }
-                          ],
-                          "presence": "Present"
-                        },
-                        {
-                          "tokenKind": {
-                            "kind": "identifier",
-                            "text": "B"
-                          },
-                          "leadingTrivia": [],
-                          "trailingTrivia": [
-                            {
-                              "kind": "Space",
-                              "value": 1
-                            }
-                          ],
-                          "presence": "Present"
-                        },
-                        null,
-                        null,
-                        null,
-                        {
-                          "kind": "MemberDeclBlock",
-                          "layout": [
-                            {
-                              "tokenKind": {
-                                "kind": "l_brace"
-                              },
-                              "leadingTrivia": [],
-                              "trailingTrivia": [],
-                              "presence": "Present"
-                            },
-                            {
-                              "kind": "DeclList",
-                              "layout": [],
-                              "presence": "Present"
-                            },
-                            {
-                              "tokenKind": {
-                                "kind": "r_brace"
-                              },
-                              "leadingTrivia": [
-                                {
-                                  "kind": "Newline",
-                                  "value": 1
-                                }
-                              ],
-                              "trailingTrivia": [],
-                              "presence": "Present"
-                            }
-                          ],
-                          "presence": "Present"
-                        }
-                      ],
+                      "tokenKind": {
+                        "kind": "l_brace"
+                      },
+                      "leadingTrivia": [],
+                      "trailingTrivia": [],
                       "presence": "Present"
                     },
-                    null
+                    {
+                      "kind": "DeclList",
+                      "layout": [],
+                      "presence": "Present"
+                    },
+                    {
+                      "tokenKind": {
+                        "kind": "r_brace"
+                      },
+                      "leadingTrivia": [
+                        {
+                          "kind": "Newline",
+                          "value": 1
+                        }
+                      ],
+                      "trailingTrivia": [],
+                      "presence": "Present"
+                    }
                   ],
                   "presence": "Present"
                 }
               ],
               "presence": "Present"
-            }
+            },
+            null
+          ],
+          "presence": "Present"
+        },
+        {
+          "kind": "CodeBlockItem",
+          "layout": [
+            {
+              "kind": "StructDecl",
+              "layout": [
+                null,
+                null,
+                {
+                  "tokenKind": {
+                    "kind": "kw_struct"
+                  },
+                  "leadingTrivia": [
+                    {
+                      "kind": "Newline",
+                      "value": 2
+                    }
+                  ],
+                  "trailingTrivia": [
+                    {
+                      "kind": "Space",
+                      "value": 1
+                    }
+                  ],
+                  "presence": "Present"
+                },
+                {
+                  "tokenKind": {
+                    "kind": "identifier",
+                    "text": "B"
+                  },
+                  "leadingTrivia": [],
+                  "trailingTrivia": [
+                    {
+                      "kind": "Space",
+                      "value": 1
+                    }
+                  ],
+                  "presence": "Present"
+                },
+                null,
+                null,
+                null,
+                {
+                  "kind": "MemberDeclBlock",
+                  "layout": [
+                    {
+                      "tokenKind": {
+                        "kind": "l_brace"
+                      },
+                      "leadingTrivia": [],
+                      "trailingTrivia": [],
+                      "presence": "Present"
+                    },
+                    {
+                      "kind": "DeclList",
+                      "layout": [],
+                      "presence": "Present"
+                    },
+                    {
+                      "tokenKind": {
+                        "kind": "r_brace"
+                      },
+                      "leadingTrivia": [
+                        {
+                          "kind": "Newline",
+                          "value": 1
+                        }
+                      ],
+                      "trailingTrivia": [],
+                      "presence": "Present"
+                    }
+                  ],
+                  "presence": "Present"
+                }
+              ],
+              "presence": "Present"
+            },
+            null
           ],
           "presence": "Present"
         }
diff --git a/test/Syntax/Inputs/serialize_struct_decl.json b/test/Syntax/Inputs/serialize_struct_decl.json
index 033ffeb..14d1da1 100644
--- a/test/Syntax/Inputs/serialize_struct_decl.json
+++ b/test/Syntax/Inputs/serialize_struct_decl.json
@@ -2,354 +2,85 @@
   "kind": "SourceFile",
   "layout": [
     {
-      "kind": "DeclList",
+      "kind": "CodeBlockItemList",
       "layout": [
         {
-          "kind": "TopLevelCodeDecl",
+          "kind": "CodeBlockItem",
           "layout": [
             {
-              "kind": "StmtList",
+              "kind": "StructDecl",
               "layout": [
+                null,
+                null,
                 {
-                  "kind": "DeclarationStmt",
+                  "tokenKind": {
+                    "kind": "kw_struct"
+                  },
+                  "leadingTrivia": [
+                    {
+                      "kind": "LineComment",
+                      "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
+                    },
+                    {
+                      "kind": "Newline",
+                      "value": 1
+                    },
+                    {
+                      "kind": "LineComment",
+                      "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_struct_decl.json"
+                    },
+                    {
+                      "kind": "Newline",
+                      "value": 2
+                    }
+                  ],
+                  "trailingTrivia": [
+                    {
+                      "kind": "Space",
+                      "value": 1
+                    }
+                  ],
+                  "presence": "Present"
+                },
+                {
+                  "tokenKind": {
+                    "kind": "identifier",
+                    "text": "Foo"
+                  },
+                  "leadingTrivia": [],
+                  "trailingTrivia": [
+                    {
+                      "kind": "Space",
+                      "value": 1
+                    }
+                  ],
+                  "presence": "Present"
+                },
+                null,
+                null,
+                null,
+                {
+                  "kind": "MemberDeclBlock",
                   "layout": [
                     {
-                      "kind": "StructDecl",
+                      "tokenKind": {
+                        "kind": "l_brace"
+                      },
+                      "leadingTrivia": [],
+                      "trailingTrivia": [],
+                      "presence": "Present"
+                    },
+                    {
+                      "kind": "DeclList",
                       "layout": [
-                        null,
-                        null,
                         {
-                          "tokenKind": {
-                            "kind": "kw_struct"
-                          },
-                          "leadingTrivia": [
-                            {
-                              "kind": "LineComment",
-                              "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
-                            },
-                            {
-                              "kind": "Newline",
-                              "value": 1
-                            },
-                            {
-                              "kind": "LineComment",
-                              "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_struct_decl.json"
-                            },
-                            {
-                              "kind": "Newline",
-                              "value": 2
-                            }
-                          ],
-                          "trailingTrivia": [
-                            {
-                              "kind": "Space",
-                              "value": 1
-                            }
-                          ],
-                          "presence": "Present"
-                        },
-                        {
-                          "tokenKind": {
-                            "kind": "identifier",
-                            "text": "Foo"
-                          },
-                          "leadingTrivia": [],
-                          "trailingTrivia": [
-                            {
-                              "kind": "Space",
-                              "value": 1
-                            }
-                          ],
-                          "presence": "Present"
-                        },
-                        null,
-                        null,
-                        null,
-                        {
-                          "kind": "MemberDeclBlock",
+                          "kind": "VariableDecl",
                           "layout": [
+                            null,
+                            null,
                             {
                               "tokenKind": {
-                                "kind": "l_brace"
-                              },
-                              "leadingTrivia": [],
-                              "trailingTrivia": [],
-                              "presence": "Present"
-                            },
-                            {
-                              "kind": "DeclList",
-                              "layout": [
-                                {
-                                  "kind": "VariableDecl",
-                                  "layout": [
-                                    null,
-                                    null,
-                                    {
-                                      "tokenKind": {
-                                        "kind": "kw_let"
-                                      },
-                                      "leadingTrivia": [
-                                        {
-                                          "kind": "Newline",
-                                          "value": 1
-                                        },
-                                        {
-                                          "kind": "Space",
-                                          "value": 2
-                                        }
-                                      ],
-                                      "trailingTrivia": [
-                                        {
-                                          "kind": "Space",
-                                          "value": 3
-                                        }
-                                      ],
-                                      "presence": "Present"
-                                    },
-                                    {
-                                      "kind": "PatternBindingList",
-                                      "layout": [
-                                        {
-                                          "kind": "PatternBinding",
-                                          "layout": [
-                                            {
-                                              "kind": "IdentifierPattern",
-                                              "layout": [
-                                                {
-                                                  "tokenKind": {
-                                                    "kind": "identifier",
-                                                    "text": "bar"
-                                                  },
-                                                  "leadingTrivia": [],
-                                                  "trailingTrivia": [
-                                                    {
-                                                      "kind": "Space",
-                                                      "value": 1
-                                                    }
-                                                  ],
-                                                  "presence": "Present"
-                                                }
-                                              ],
-                                              "presence": "Present"
-                                            },
-                                            {
-                                              "kind": "TypeAnnotation",
-                                              "layout": [
-                                                {
-                                                  "tokenKind": {
-                                                    "kind": "colon"
-                                                  },
-                                                  "leadingTrivia": [],
-                                                  "trailingTrivia": [
-                                                    {
-                                                      "kind": "Space",
-                                                      "value": 1
-                                                    }
-                                                  ],
-                                                  "presence": "Present"
-                                                },
-                                                {
-                                                  "kind": "SimpleTypeIdentifier",
-                                                  "layout": [
-                                                    {
-                                                      "tokenKind": {
-                                                        "kind": "identifier",
-                                                        "text": "Int"
-                                                      },
-                                                      "leadingTrivia": [],
-                                                      "trailingTrivia": [],
-                                                      "presence": "Present"
-                                                    },
-                                                    null
-                                                  ],
-                                                  "presence": "Present"
-                                                }
-                                              ],
-                                              "presence": "Present"
-                                            },
-                                            null,
-                                            null,
-                                            null
-                                          ],
-                                          "presence": "Present"
-                                        }
-                                      ],
-                                      "presence": "Present"
-                                    }
-                                  ],
-                                  "presence": "Present"
-                                },
-                                {
-                                  "kind": "VariableDecl",
-                                  "layout": [
-                                    null,
-                                    null,
-                                    {
-                                      "tokenKind": {
-                                        "kind": "kw_let"
-                                      },
-                                      "leadingTrivia": [
-                                        {
-                                          "kind": "Newline",
-                                          "value": 2
-                                        },
-                                        {
-                                          "kind": "Space",
-                                          "value": 2
-                                        }
-                                      ],
-                                      "trailingTrivia": [
-                                        {
-                                          "kind": "Space",
-                                          "value": 1
-                                        }
-                                      ],
-                                      "presence": "Present"
-                                    },
-                                    {
-                                      "kind": "PatternBindingList",
-                                      "layout": [
-                                        {
-                                          "kind": "PatternBinding",
-                                          "layout": [
-                                            {
-                                              "kind": "IdentifierPattern",
-                                              "layout": [
-                                                {
-                                                  "tokenKind": {
-                                                    "kind": "identifier",
-                                                    "text": "baz"
-                                                  },
-                                                  "leadingTrivia": [],
-                                                  "trailingTrivia": [
-                                                    {
-                                                      "kind": "Space",
-                                                      "value": 1
-                                                    }
-                                                  ],
-                                                  "presence": "Present"
-                                                }
-                                              ],
-                                              "presence": "Present"
-                                            },
-                                            {
-                                              "kind": "TypeAnnotation",
-                                              "layout": [
-                                                {
-                                                  "tokenKind": {
-                                                    "kind": "colon"
-                                                  },
-                                                  "leadingTrivia": [],
-                                                  "trailingTrivia": [
-                                                    {
-                                                      "kind": "Space",
-                                                      "value": 1
-                                                    }
-                                                  ],
-                                                  "presence": "Present"
-                                                },
-                                                {
-                                                  "kind": "SimpleTypeIdentifier",
-                                                  "layout": [
-                                                    {
-                                                      "tokenKind": {
-                                                        "kind": "identifier",
-                                                        "text": "Array"
-                                                      },
-                                                      "leadingTrivia": [],
-                                                      "trailingTrivia": [
-                                                        {
-                                                          "kind": "Space",
-                                                          "value": 1
-                                                        }
-                                                      ],
-                                                      "presence": "Present"
-                                                    },
-                                                    {
-                                                      "kind": "GenericArgumentClause",
-                                                      "layout": [
-                                                        {
-                                                          "tokenKind": {
-                                                            "kind": "l_angle"
-                                                          },
-                                                          "leadingTrivia": [],
-                                                          "trailingTrivia": [
-                                                            {
-                                                              "kind": "Space",
-                                                              "value": 1
-                                                            }
-                                                          ],
-                                                          "presence": "Present"
-                                                        },
-                                                        {
-                                                          "kind": "GenericArgumentList",
-                                                          "layout": [
-                                                            {
-                                                              "kind": "GenericArgument",
-                                                              "layout": [
-                                                                {
-                                                                  "kind": "SimpleTypeIdentifier",
-                                                                  "layout": [
-                                                                    {
-                                                                      "tokenKind": {
-                                                                        "kind": "identifier",
-                                                                        "text": "Int"
-                                                                      },
-                                                                      "leadingTrivia": [],
-                                                                      "trailingTrivia": [
-                                                                        {
-                                                                          "kind": "Space",
-                                                                          "value": 1
-                                                                        }
-                                                                      ],
-                                                                      "presence": "Present"
-                                                                    },
-                                                                    null
-                                                                  ],
-                                                                  "presence": "Present"
-                                                                },
-                                                                null
-                                                              ],
-                                                              "presence": "Present"
-                                                            }
-                                                          ],
-                                                          "presence": "Present"
-                                                        },
-                                                        {
-                                                          "tokenKind": {
-                                                            "kind": "r_angle"
-                                                          },
-                                                          "leadingTrivia": [],
-                                                          "trailingTrivia": [],
-                                                          "presence": "Present"
-                                                        }
-                                                      ],
-                                                      "presence": "Present"
-                                                    }
-                                                  ],
-                                                  "presence": "Present"
-                                                }
-                                              ],
-                                              "presence": "Present"
-                                            },
-                                            null,
-                                            null,
-                                            null
-                                          ],
-                                          "presence": "Present"
-                                        }
-                                      ],
-                                      "presence": "Present"
-                                    }
-                                  ],
-                                  "presence": "Present"
-                                }
-                              ],
-                              "presence": "Present"
-                            },
-                            {
-                              "tokenKind": {
-                                "kind": "r_brace"
+                                "kind": "kw_let"
                               },
                               "leadingTrivia": [
                                 {
@@ -358,10 +89,250 @@
                                 },
                                 {
                                   "kind": "Space",
-                                  "value": 6
+                                  "value": 2
                                 }
                               ],
-                              "trailingTrivia": [],
+                              "trailingTrivia": [
+                                {
+                                  "kind": "Space",
+                                  "value": 3
+                                }
+                              ],
+                              "presence": "Present"
+                            },
+                            {
+                              "kind": "PatternBindingList",
+                              "layout": [
+                                {
+                                  "kind": "PatternBinding",
+                                  "layout": [
+                                    {
+                                      "kind": "IdentifierPattern",
+                                      "layout": [
+                                        {
+                                          "tokenKind": {
+                                            "kind": "identifier",
+                                            "text": "bar"
+                                          },
+                                          "leadingTrivia": [],
+                                          "trailingTrivia": [
+                                            {
+                                              "kind": "Space",
+                                              "value": 1
+                                            }
+                                          ],
+                                          "presence": "Present"
+                                        }
+                                      ],
+                                      "presence": "Present"
+                                    },
+                                    {
+                                      "kind": "TypeAnnotation",
+                                      "layout": [
+                                        {
+                                          "tokenKind": {
+                                            "kind": "colon"
+                                          },
+                                          "leadingTrivia": [],
+                                          "trailingTrivia": [
+                                            {
+                                              "kind": "Space",
+                                              "value": 1
+                                            }
+                                          ],
+                                          "presence": "Present"
+                                        },
+                                        {
+                                          "kind": "SimpleTypeIdentifier",
+                                          "layout": [
+                                            {
+                                              "tokenKind": {
+                                                "kind": "identifier",
+                                                "text": "Int"
+                                              },
+                                              "leadingTrivia": [],
+                                              "trailingTrivia": [],
+                                              "presence": "Present"
+                                            },
+                                            null
+                                          ],
+                                          "presence": "Present"
+                                        }
+                                      ],
+                                      "presence": "Present"
+                                    },
+                                    null,
+                                    null,
+                                    null
+                                  ],
+                                  "presence": "Present"
+                                }
+                              ],
+                              "presence": "Present"
+                            }
+                          ],
+                          "presence": "Present"
+                        },
+                        {
+                          "kind": "VariableDecl",
+                          "layout": [
+                            null,
+                            null,
+                            {
+                              "tokenKind": {
+                                "kind": "kw_let"
+                              },
+                              "leadingTrivia": [
+                                {
+                                  "kind": "Newline",
+                                  "value": 2
+                                },
+                                {
+                                  "kind": "Space",
+                                  "value": 2
+                                }
+                              ],
+                              "trailingTrivia": [
+                                {
+                                  "kind": "Space",
+                                  "value": 1
+                                }
+                              ],
+                              "presence": "Present"
+                            },
+                            {
+                              "kind": "PatternBindingList",
+                              "layout": [
+                                {
+                                  "kind": "PatternBinding",
+                                  "layout": [
+                                    {
+                                      "kind": "IdentifierPattern",
+                                      "layout": [
+                                        {
+                                          "tokenKind": {
+                                            "kind": "identifier",
+                                            "text": "baz"
+                                          },
+                                          "leadingTrivia": [],
+                                          "trailingTrivia": [
+                                            {
+                                              "kind": "Space",
+                                              "value": 1
+                                            }
+                                          ],
+                                          "presence": "Present"
+                                        }
+                                      ],
+                                      "presence": "Present"
+                                    },
+                                    {
+                                      "kind": "TypeAnnotation",
+                                      "layout": [
+                                        {
+                                          "tokenKind": {
+                                            "kind": "colon"
+                                          },
+                                          "leadingTrivia": [],
+                                          "trailingTrivia": [
+                                            {
+                                              "kind": "Space",
+                                              "value": 1
+                                            }
+                                          ],
+                                          "presence": "Present"
+                                        },
+                                        {
+                                          "kind": "SimpleTypeIdentifier",
+                                          "layout": [
+                                            {
+                                              "tokenKind": {
+                                                "kind": "identifier",
+                                                "text": "Array"
+                                              },
+                                              "leadingTrivia": [],
+                                              "trailingTrivia": [
+                                                {
+                                                  "kind": "Space",
+                                                  "value": 1
+                                                }
+                                              ],
+                                              "presence": "Present"
+                                            },
+                                            {
+                                              "kind": "GenericArgumentClause",
+                                              "layout": [
+                                                {
+                                                  "tokenKind": {
+                                                    "kind": "l_angle"
+                                                  },
+                                                  "leadingTrivia": [],
+                                                  "trailingTrivia": [
+                                                    {
+                                                      "kind": "Space",
+                                                      "value": 1
+                                                    }
+                                                  ],
+                                                  "presence": "Present"
+                                                },
+                                                {
+                                                  "kind": "GenericArgumentList",
+                                                  "layout": [
+                                                    {
+                                                      "kind": "GenericArgument",
+                                                      "layout": [
+                                                        {
+                                                          "kind": "SimpleTypeIdentifier",
+                                                          "layout": [
+                                                            {
+                                                              "tokenKind": {
+                                                                "kind": "identifier",
+                                                                "text": "Int"
+                                                              },
+                                                              "leadingTrivia": [],
+                                                              "trailingTrivia": [
+                                                                {
+                                                                  "kind": "Space",
+                                                                  "value": 1
+                                                                }
+                                                              ],
+                                                              "presence": "Present"
+                                                            },
+                                                            null
+                                                          ],
+                                                          "presence": "Present"
+                                                        },
+                                                        null
+                                                      ],
+                                                      "presence": "Present"
+                                                    }
+                                                  ],
+                                                  "presence": "Present"
+                                                },
+                                                {
+                                                  "tokenKind": {
+                                                    "kind": "r_angle"
+                                                  },
+                                                  "leadingTrivia": [],
+                                                  "trailingTrivia": [],
+                                                  "presence": "Present"
+                                                }
+                                              ],
+                                              "presence": "Present"
+                                            }
+                                          ],
+                                          "presence": "Present"
+                                        }
+                                      ],
+                                      "presence": "Present"
+                                    },
+                                    null,
+                                    null,
+                                    null
+                                  ],
+                                  "presence": "Present"
+                                }
+                              ],
                               "presence": "Present"
                             }
                           ],
@@ -370,13 +341,30 @@
                       ],
                       "presence": "Present"
                     },
-                    null
+                    {
+                      "tokenKind": {
+                        "kind": "r_brace"
+                      },
+                      "leadingTrivia": [
+                        {
+                          "kind": "Newline",
+                          "value": 1
+                        },
+                        {
+                          "kind": "Space",
+                          "value": 6
+                        }
+                      ],
+                      "trailingTrivia": [],
+                      "presence": "Present"
+                    }
                   ],
                   "presence": "Present"
                 }
               ],
               "presence": "Present"
-            }
+            },
+            null
           ],
           "presence": "Present"
         }
diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp
index 6eddc66..ea0fc79 100644
--- a/unittests/Syntax/DeclSyntaxTests.cpp
+++ b/unittests/Syntax/DeclSyntaxTests.cpp
@@ -506,10 +506,10 @@
   auto ReturnKW =
     SyntaxFactory::makeReturnKeyword(Trivia::newlines(1) + Trivia::spaces(2),
                                      {});
-  auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, One, None);
+  auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, One);
+  auto ReturnItem = SyntaxFactory::makeCodeBlockItem(Return, None);
 
-  auto Stmts = SyntaxFactory::makeBlankStmtList()
-    .appending(Return);
+  auto Stmts = SyntaxFactory::makeCodeBlockItemList({ReturnItem});
 
   auto LBrace = SyntaxFactory::makeLeftBraceToken({}, {});
   auto RBrace = SyntaxFactory::makeRightBraceToken(Trivia::newlines(1), {});
diff --git a/unittests/Syntax/StmtSyntaxTests.cpp b/unittests/Syntax/StmtSyntaxTests.cpp
index 0deb1e9..7141df5 100644
--- a/unittests/Syntax/StmtSyntaxTests.cpp
+++ b/unittests/Syntax/StmtSyntaxTests.cpp
@@ -41,7 +41,7 @@
     llvm::SmallString<48> Scratch;
     llvm::raw_svector_ostream OS(Scratch);
 
-    SyntaxFactory::makeFallthroughStmt(FallthroughKW, llvm::None).print(OS);
+    SyntaxFactory::makeFallthroughStmt(FallthroughKW).print(OS);
     ASSERT_EQ(OS.str().str(), "fallthrough");
   }
 
@@ -51,7 +51,7 @@
 
     auto NewFallthroughKW = FallthroughKW.withLeadingTrivia(Trivia::spaces(2));
 
-    SyntaxFactory::makeFallthroughStmt(NewFallthroughKW, llvm::None).print(OS);
+    SyntaxFactory::makeFallthroughStmt(NewFallthroughKW).print(OS);
     ASSERT_EQ(OS.str().str(), "  fallthrough");
   }
 
@@ -62,7 +62,7 @@
     auto NewFallthroughKW = FallthroughKW.withLeadingTrivia(Trivia::spaces(2))
                                          .withTrailingTrivia(Trivia::spaces(2));
 
-    SyntaxFactory::makeFallthroughStmt(NewFallthroughKW, llvm::None).print(OS);
+    SyntaxFactory::makeFallthroughStmt(NewFallthroughKW).print(OS);
     ASSERT_EQ(OS.str().str(), "  fallthrough  ");
   }
 
@@ -80,7 +80,7 @@
 TEST(StmtSyntaxTests, BreakStmtGetAPIs) {
   auto BreakKW = SyntaxFactory::makeBreakKeyword({}, Trivia::spaces(1));
   auto Label = SyntaxFactory::makeIdentifier("sometimesYouNeedTo", {}, {});
-  auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label, llvm::None);
+  auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label);
 
   /// These should be directly shared through reference-counting.
   ASSERT_EQ(BreakKW.getRaw(), Break.getBreakKeyword().getRaw());
@@ -128,7 +128,7 @@
     llvm::raw_svector_ostream OS(Scratch);
     auto BreakKW = SyntaxFactory::makeBreakKeyword({}, Trivia::spaces(1));
     auto Label = SyntaxFactory::makeIdentifier("theBuild", {}, {});
-    auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label, llvm::None);
+    auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label);
     Break.print(OS);
     ASSERT_EQ(OS.str().str(), "break theBuild"); // don't you dare
   }
@@ -145,8 +145,7 @@
 TEST(StmtSyntaxTests, ContinueStmtGetAPIs) {
   auto ContinueKW = SyntaxFactory::makeContinueKeyword({}, Trivia::spaces(1));
   auto Label = SyntaxFactory::makeIdentifier("always", {}, {});
-  auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label,
-                                                  llvm::None);
+  auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label);
 
   /// These should be directly shared through reference-counting.
   ASSERT_EQ(ContinueKW.getRaw(), Continue.getContinueKeyword().getRaw());
@@ -194,8 +193,7 @@
     llvm::raw_svector_ostream OS(Scratch);
     auto ContinueKW = SyntaxFactory::makeContinueKeyword({}, Trivia::spaces(1));
     auto Label = SyntaxFactory::makeIdentifier("toLead", {}, {});
-    auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label,
-                                                    llvm::None);
+    auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label);
     Continue.print(OS);
     ASSERT_EQ(OS.str().str(), "continue toLead"); // by example
   }
@@ -226,7 +224,7 @@
   {
     llvm::SmallString<48> Scratch;
     llvm::raw_svector_ostream OS(Scratch);
-    SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None).print(OS);
+    SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne).print(OS);
     ASSERT_EQ(OS.str().str(), "return -1");
   }
 }
@@ -237,7 +235,7 @@
   auto OneDigits = SyntaxFactory::makeIntegerLiteral("1", {}, {});
   auto MinusOne = SyntaxFactory::makePrefixOperatorExpr(Minus,
     SyntaxFactory::makeIntegerLiteralExpr(OneDigits));
-  auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None);
+  auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
 
   ASSERT_EQ(ReturnKW.getRaw(), Return.getReturnKeyword().getRaw());
   auto GottenExpression = Return.getExpression().getValue();
diff --git a/unittests/Syntax/ThreadSafeCachingTests.cpp b/unittests/Syntax/ThreadSafeCachingTests.cpp
index 4d7fad6..184ab09 100644
--- a/unittests/Syntax/ThreadSafeCachingTests.cpp
+++ b/unittests/Syntax/ThreadSafeCachingTests.cpp
@@ -88,7 +88,7 @@
   Pool P;
 
   for (unsigned i = 0; i < 10000; ++i) {
-    auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None);
+    auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
 
     auto Future1 = P.run(getExpressionFrom, Return);
     auto Future2 = P.run(getExpressionFrom, Return);
diff --git a/utils/gyb_syntax_support/CommonNodes.py b/utils/gyb_syntax_support/CommonNodes.py
index 429ecbf..744db91 100644
--- a/utils/gyb_syntax_support/CommonNodes.py
+++ b/utils/gyb_syntax_support/CommonNodes.py
@@ -1,4 +1,5 @@
-from Node import Node
+from Child import Child
+from Node import Node  # noqa: I201
 
 COMMON_NODES = [
     Node('Decl', kind='Syntax'),
@@ -11,4 +12,29 @@
     Node('UnknownStmt', kind='Stmt'),
     Node('UnknownType', kind='Type'),
     Node('UnknownPattern', kind='Pattern'),
+
+    # code-block-item = (decl | stmt | expr) ';'?
+    Node('CodeBlockItem', kind='Syntax',
+         children=[
+             Child('Item', kind='Syntax',
+                   node_choices=[
+                       Child('Decl', kind='Decl'),
+                       Child('Stmt', kind='Stmt'),
+                       Child('Expr', kind='Expr'),
+                   ]),
+             Child('Semicolon', kind='SemicolonToken',
+                   is_optional=True),
+         ]),
+
+    # code-block-item-list -> code-block-item code-block-item-list?
+    Node('CodeBlockItemList', kind='SyntaxCollection',
+         element='CodeBlockItem'),
+
+    # code-block -> '{' stmt-list '}'
+    Node('CodeBlock', kind='Syntax',
+         children=[
+             Child('OpenBrace', kind='LeftBraceToken'),
+             Child('Statements', kind='CodeBlockItemList'),
+             Child('CloseBrace', kind='RightBraceToken'),
+         ]),
 ]
diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py
index 5878ec2..84710fc 100644
--- a/utils/gyb_syntax_support/DeclNodes.py
+++ b/utils/gyb_syntax_support/DeclNodes.py
@@ -88,7 +88,7 @@
          children=[
              Child('PoundElseif', kind='PoundElseifToken'),
              Child('Condition', kind='Expr'),
-             Child('Body', kind='StmtList'),
+             Child('Body', kind='CodeBlockItemList'),
          ]),
 
     # if-config-decl -> '#if' expr stmt-list else-if-directive-clause-list
@@ -97,7 +97,7 @@
          children=[
              Child('PoundIf', kind='PoundIfToken'),
              Child('Condition', kind='Expr'),
-             Child('Body', kind='StmtList'),
+             Child('Body', kind='CodeBlockItemList'),
              Child('ElseifDirectiveClauses', kind='ElseifDirectiveClauseList',
                    is_optional=True),
              Child('ElseClause', kind='ElseDirectiveClause',
@@ -245,19 +245,13 @@
     Node('DeclList', kind='SyntaxCollection',
          element='Decl'),
 
-    # source-file = decl-list eof
+    # source-file = code-block-item-list eof
     Node('SourceFile', kind='Syntax',
          children=[
-             Child('TopLevelDecls', kind='DeclList'),
+             Child('Items', kind='CodeBlockItemList'),
              Child('EOFToken', kind='EOFToken')
          ]),
 
-    # top-level-code-decl = stmt-list
-    Node('TopLevelCodeDecl', kind='Decl',
-         children=[
-             Child('Body', kind='StmtList')
-         ]),
-
     # initializer -> '=' expr
     Node('InitializerClause', kind='Syntax',
          children=[
@@ -408,7 +402,7 @@
     Node('ElseDirectiveClause', kind='Syntax',
          children=[
              Child('PoundElse', kind='PoundElseToken'),
-             Child('Body', kind='StmtList'),
+             Child('Body', kind='CodeBlockItemList'),
          ]),
 
     # access-level-modifier -> 'private' | 'private' '(' 'set' ')'
@@ -476,7 +470,7 @@
              Child('AccessorListOrStmtList', kind='Syntax',
                    node_choices=[
                       Child('Accessors', kind='AccessorList'),
-                      Child('Statements', kind='StmtList')]),
+                      Child('Statements', kind='CodeBlockItemList')]),
              Child('RightBrace', kind='RightBraceToken'),
          ]),
 
diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py
index b950756..9e4ee1b 100644
--- a/utils/gyb_syntax_support/ExprNodes.py
+++ b/utils/gyb_syntax_support/ExprNodes.py
@@ -387,7 +387,7 @@
          children=[
              Child('LeftBrace', kind='LeftBraceToken'),
              Child('Signature', kind='ClosureSignature', is_optional=True),
-             Child('Statements', kind='StmtList'),
+             Child('Statements', kind='CodeBlockItemList'),
              Child('RightBrace', kind='RightBraceToken'),
          ]),
 
diff --git a/utils/gyb_syntax_support/StmtNodes.py b/utils/gyb_syntax_support/StmtNodes.py
index 3cfc50e..50c7bfb 100644
--- a/utils/gyb_syntax_support/StmtNodes.py
+++ b/utils/gyb_syntax_support/StmtNodes.py
@@ -8,8 +8,6 @@
              Child('ContinueKeyword', kind='ContinueToken'),
              Child('Label', kind='IdentifierToken',
                    is_optional=True),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # while-stmt -> label? ':'? 'while' condition-list code-block ';'?
@@ -22,8 +20,6 @@
              Child('WhileKeyword', kind='WhileToken'),
              Child('Conditions', kind='ConditionElementList'),
              Child('Body', kind='CodeBlock'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # defer-stmt -> 'defer' code-block ';'?
@@ -31,16 +27,12 @@
          children=[
              Child('DeferKeyword', kind='DeferToken'),
              Child('Body', kind='CodeBlock'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # expr-stmt -> expression ';'?
     Node('ExpressionStmt', kind='Stmt',
          children=[
              Child('Expression', kind='Expr'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # switch-case-list -> switch-case switch-case-list?
@@ -58,8 +50,6 @@
              Child('Body', kind='CodeBlock'),
              Child('WhileKeyword', kind='WhileToken'),
              Child('Condition', kind='Expr'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # guard-stmt -> 'guard' condition-list 'else' code-block ';'?
@@ -69,8 +59,6 @@
              Child('Conditions', kind='ConditionElementList'),
              Child('ElseKeyword', kind='ElseToken'),
              Child('Body', kind='CodeBlock'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     Node('WhereClause', kind='Syntax',
@@ -98,8 +86,6 @@
              Child('WhereClause', kind='WhereClause',
                    is_optional=True),
              Child('Body', kind='CodeBlock'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # switch-stmt -> identifier? ':'? 'switch' expr '{'
@@ -115,8 +101,6 @@
              Child('OpenBrace', kind='LeftBraceToken'),
              Child('Cases', kind='SwitchCaseList'),
              Child('CloseBrace', kind='RightBraceToken'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # catch-clause-list -> catch-clause catch-clause-list?
@@ -134,8 +118,6 @@
              Child('Body', kind='CodeBlock'),
              Child('CatchClauses', kind='CatchClauseList',
                    is_optional=True),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # return-stmt -> 'return' expr? ';'?
@@ -144,16 +126,12 @@
              Child('ReturnKeyword', kind='ReturnToken'),
              Child('Expression', kind='Expr',
                    is_optional=True),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # fallthrough-stmt -> 'fallthrough' ';'?
     Node('FallthroughStmt', kind='Stmt',
          children=[
              Child('FallthroughKeyword', kind='FallthroughToken'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # break-stmt -> 'break' identifier? ';'?
@@ -162,16 +140,6 @@
              Child('BreakKeyword', kind='BreakToken'),
              Child('Label', kind='IdentifierToken',
                    is_optional=True),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
-         ]),
-
-    # code-block -> '{' stmt-list '}'
-    Node('CodeBlock', kind='Syntax',
-         children=[
-             Child('OpenBrace', kind='LeftBraceToken'),
-             Child('Statements', kind='StmtList'),
-             Child('CloseBrace', kind='RightBraceToken'),
          ]),
 
     # case-item-list -> case-item case-item-list?
@@ -231,8 +199,6 @@
     Node('DeclarationStmt', kind='Stmt',
          children=[
              Child('Declaration', kind='Decl'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # throw-stmt -> 'throw' expr ';'?
@@ -240,8 +206,6 @@
          children=[
              Child('ThrowKeyword', kind='ThrowToken'),
              Child('Expression', kind='Expr'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # if-stmt -> identifier? ':'? 'if' condition-list code-block
@@ -263,8 +227,6 @@
                        Child('CodeBlock', kind='CodeBlock'),
                    ],
                    is_optional=True),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
     # else-if-continuation -> label? ':'? 'while' condition-list code-block ';'
@@ -278,20 +240,14 @@
          children=[
              Child('ElseKeyword', kind='ElseToken'),
              Child('Body', kind='CodeBlock'),
-             Child('Semicolon', kind='SemicolonToken',
-                   is_optional=True),
          ]),
 
-    # stmt-list -> stmt stmt-list?
-    Node('StmtList', kind='SyntaxCollection',
-         element='Stmt'),
-
     # switch-case -> switch-case-label stmt-list
     #              | default-label stmt-list
     Node('SwitchCase', kind='Syntax',
          children=[
              Child('Label', kind='Syntax'),
-             Child('Body', kind='StmtList'),
+             Child('Body', kind='CodeBlockItemList'),
          ]),
 
     # switch-default-label -> 'default' ':'