Merge pull request #8430 from palimondo/benchmark-conformance-constraint-sources

diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 51962f3..8d3995b 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2316,8 +2316,10 @@
 }
 
 Type AbstractTypeParamDecl::getSuperclass() const {
-  auto *dc = getDeclContext();
-  auto contextTy = dc->mapTypeIntoContext(getDeclaredInterfaceType());
+  auto *genericEnv = getDeclContext()->getGenericEnvironmentOfContext();
+  assert(genericEnv != nullptr && "Too much circularity");
+
+  auto contextTy = genericEnv->mapTypeIntoContext(getDeclaredInterfaceType());
   if (auto *archetype = contextTy->getAs<ArchetypeType>())
     return archetype->getSuperclass();
 
@@ -2327,8 +2329,10 @@
 
 ArrayRef<ProtocolDecl *>
 AbstractTypeParamDecl::getConformingProtocols() const {
-  auto *dc = getDeclContext();
-  auto contextTy = dc->mapTypeIntoContext(getDeclaredInterfaceType());
+  auto *genericEnv = getDeclContext()->getGenericEnvironmentOfContext();
+  assert(genericEnv != nullptr && "Too much circularity");
+
+  auto contextTy = genericEnv->mapTypeIntoContext(getDeclaredInterfaceType());
   if (auto *archetype = contextTy->getAs<ArchetypeType>())
     return archetype->getConformsTo();
 
diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp
index 251b236..602ec48 100644
--- a/lib/AST/SubstitutionMap.cpp
+++ b/lib/AST/SubstitutionMap.cpp
@@ -135,9 +135,16 @@
 
     if (protoAssocType) {
       if (conformance.isAbstract()) {
-        for (auto assocProto : protoAssocType->getConformingProtocols()) {
-          if (auto found = fn(ProtocolConformanceRef(assocProto)))
-            return found;
+        // Narrow fix since this whole code path is going away soon
+        // (if you find this code still here a year from now, I will be
+        // very ashamed).
+        //
+        // FIXME: Should always have a valid generic environment.
+        if (protoAssocType->getProtocol()->getGenericEnvironment()) {
+          for (auto assocProto : protoAssocType->getConformingProtocols()) {
+            if (auto found = fn(ProtocolConformanceRef(assocProto)))
+              return found;
+          }
         }
       } else {
         auto sub = conformance.getConcrete()->getTypeWitnessSubstAndDecl(
diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
index a1b9089..7817786 100644
--- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
+++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
@@ -19,7 +19,6 @@
 #include "swift/SIL/SILCloner.h"
 #include "swift/SILOptimizer/PassManager/Transforms.h"
 #include "swift/SILOptimizer/Utils/Local.h"
-#include "swift/SILOptimizer/Utils/StackNesting.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallSet.h"
@@ -396,7 +395,8 @@
 
 /// rewriteAllocBoxAsAllocStack - Replace uses of the alloc_box with a
 /// new alloc_stack, but do not delete the alloc_box yet.
-static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
+static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI,
+                                   llvm::SmallVectorImpl<TermInst *> &Returns) {
   DEBUG(llvm::dbgs() << "*** Promoting alloc_box to stack: " << *ABI);
 
   llvm::SmallVector<SILInstruction*, 4> FinalReleases;
@@ -405,7 +405,8 @@
 
   // Promote this alloc_box to an alloc_stack. Insert the alloc_stack
   // at the beginning of the function.
-  SILBuilder BuildAlloc(ABI);
+  auto &Entry = ABI->getFunction()->front();
+  SILBuilder BuildAlloc(&Entry, Entry.begin());
   BuildAlloc.setCurrentDebugScope(ABI->getDebugScope());
   assert(ABI->getBoxType()->getLayout()->getFields().size() == 1
          && "rewriting multi-field box not implemented");
@@ -439,18 +440,25 @@
     .getTypeLowering(ABI->getBoxType()->getFieldType(ABI->getModule(), 0));
   auto Loc = CleanupLocation::get(ABI->getLoc());
 
-  for (auto LastRelease : FinalReleases) {
-    SILBuilderWithScope Builder(LastRelease);
-    if (!isa<DeallocBoxInst>(LastRelease)&& !Lowering.isTrivial()) {
-      // For non-trivial types, insert destroys for each final release-like
-      // instruction we found that isn't an explicit dealloc_box.
-      Builder.emitDestroyAddrAndFold(Loc, PointerResult);
+  // For non-trivial types, insert destroys for each final release-like
+  // instruction we found that isn't an explicit dealloc_box.
+  if (!Lowering.isTrivial()) {
+    for (auto LastRelease : FinalReleases) {
+      if (isa<DeallocBoxInst>(LastRelease))
+        continue;
+
+      SILBuilderWithScope BuildDestroy(LastRelease);
+      BuildDestroy.emitDestroyAddrAndFold(Loc, PointerResult);
     }
-    Builder.createDeallocStack(Loc, ASI);
   }
 
-  // Remove any retain and release instructions.  Since all uses of project_box
-  // are gone, this only walks through uses of the box itself (the retain count
+  for (auto Return : Returns) {
+    SILBuilderWithScope BuildDealloc(Return);
+    BuildDealloc.createDeallocStack(Loc, ASI);
+  }
+
+  // Remove any retain and release instructions.  Since all uses of result #1
+  // are gone, this only walks through uses of result #0 (the retain count
   // pointer).
   while (!ABI->use_empty()) {
     auto *User = (*ABI->use_begin())->getUser();
@@ -817,6 +825,7 @@
 static unsigned
 rewritePromotedBoxes(llvm::SmallVectorImpl<AllocBoxInst *> &Promoted,
                      llvm::SmallVectorImpl<Operand *> &PromotedOperands,
+                     llvm::SmallVectorImpl<TermInst *> &Returns,
                      bool &CFGChanged) {
   // First we'll rewrite any partial applies that we can to remove the
   // box container pointer from the operands.
@@ -826,7 +835,7 @@
   auto rend = Promoted.rend();
   for (auto I = Promoted.rbegin(); I != rend; ++I) {
     auto *ABI = *I;
-    if (rewriteAllocBoxAsAllocStack(ABI)) {
+    if (rewriteAllocBoxAsAllocStack(ABI, Returns)) {
       ++Count;
       ABI->eraseFromParent();
     }
@@ -840,8 +849,13 @@
   void run() override {
     llvm::SmallVector<AllocBoxInst *, 8> Promotable;
     llvm::SmallVector<Operand *, 8> PromotedOperands;
+    llvm::SmallVector<TermInst *, 8> Returns;
 
     for (auto &BB : *getFunction()) {
+      auto *Term = BB.getTerminator();
+      if (Term->isFunctionExiting())
+        Returns.push_back(Term);
+
       for (auto &I : BB)
         if (auto *ABI = dyn_cast<AllocBoxInst>(&I))
           if (canPromoteAllocBox(ABI, PromotedOperands))
@@ -850,14 +864,9 @@
 
     if (!Promotable.empty()) {
       bool CFGChanged = false;
-      auto Count = rewritePromotedBoxes(Promotable, PromotedOperands,
+      auto Count = rewritePromotedBoxes(Promotable, PromotedOperands, Returns,
                                         CFGChanged);
       NumStackPromoted += Count;
-      if (Count) {
-        StackNesting SN;
-        if (SN.correctStackNesting(getFunction()) == StackNesting::Changes::CFG)
-          CFGChanged = true;
-      }
       
       invalidateAnalysis(CFGChanged ?
                          SILAnalysis::InvalidationKind::FunctionBody :
diff --git a/test/DebugInfo/ProtocolContainer.swift b/test/DebugInfo/ProtocolContainer.swift
index 8a8261d..c591db4 100644
--- a/test/DebugInfo/ProtocolContainer.swift
+++ b/test/DebugInfo/ProtocolContainer.swift
@@ -13,7 +13,7 @@
 }
 // CHECK: define hidden {{.*}}void @_T017ProtocolContainer3foo{{[_0-9a-zA-Z]*}}F
 // CHECK-NEXT: entry:
-// CHECK:      %[[X:.*]] = alloca %T17ProtocolContainer9AProtocolP, align {{(4|8)}}
+// CHECK-NEXT: %[[X:.*]] = alloca %T17ProtocolContainer9AProtocolP, align {{(4|8)}}
 // CHECK:      call void @llvm.dbg.declare(metadata %T17ProtocolContainer9AProtocolP* %[[X]], metadata ![[XMD:.*]], metadata !{{[0-9]+}})
 // CHECK-NOT: !DILocalVariable({{.*}} name: "x"
 // CHECK-NOT: !DILocalVariable({{.*}} name: "x"
diff --git a/test/DebugInfo/letstring.swift b/test/DebugInfo/letstring.swift
index bd07910..d5b2f0f 100644
--- a/test/DebugInfo/letstring.swift
+++ b/test/DebugInfo/letstring.swift
@@ -7,16 +7,15 @@
   // CHECK: define hidden {{.*}}i1 {{.*}}11AppDelegateC1f
   func f() -> Bool {
     // Test for -O0 shadow copies.
-    // CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[SELF:.*]], metadata !{{[0-9]+}})
-    // CHECK-NOT: call void @llvm.dbg.value
-    // CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[A:.*]], metadata !{{[0-9]+}})
-    let a = "let"
-    // CHECK-NOT: call void @llvm.dbg.value
     // CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[B:.*]], metadata !{{[0-9]+}})
-    // CHECK-NOT: call void @llvm.dbg.value
-    // CHECK: ret
+    // CHECK-NOT: call void @llvm.dbg.value({{.*}}, metadata ![[B]], metadata !{{[0-9]+}})
+    // CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[SELF:.*]], metadata !{{[0-9]+}})
+    let a = "let"
+    // CHECK-NOT: call void @llvm.dbg.value({{.*}}, metadata ![[SELF]], metadata !{{[0-9]+}})
+    // CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[A:.*]], metadata !{{[0-9]+}})
+    // CHECK-NOT: call void @llvm.dbg.value({{.*}}, metadata ![[A]], metadata !{{[0-9]+}})
+    // CHECK-DAG: ![[A]] = !DILocalVariable(name: "a",{{.*}} line: [[@LINE-4]],
     // CHECK-DAG: ![[SELF]] = !DILocalVariable(name: "self", arg: 1{{.*}} line: [[@LINE-10]],
-    // CHECK-DAG: ![[A]] = !DILocalVariable(name: "a",{{.*}} line: [[@LINE-6]],
     // CHECK-DAG: ![[B]] = !DILocalVariable(name: "b",{{.*}} line: [[@LINE+1]],
     var b = "var"
     self.window = UIWindow()
@@ -33,7 +32,7 @@
 // DWARF-CHECK:  DW_AT_name {{.*}} "self"
 //
 // DWARF-CHECK:  DW_TAG_variable
-// DWARF-CHECK:  DW_AT_name {{.*}} "a"
+// DWARF-CHECK:  DW_AT_name {{.*}} "b"
 //
 // DWARF-CHECK:  DW_TAG_variable
-// DWARF-CHECK:  DW_AT_name {{.*}} "b"
+// DWARF-CHECK:  DW_AT_name {{.*}} "a"
diff --git a/test/DebugInfo/linetable-cleanups.swift b/test/DebugInfo/linetable-cleanups.swift
index 9183355..caa9b8a 100644
--- a/test/DebugInfo/linetable-cleanups.swift
+++ b/test/DebugInfo/linetable-cleanups.swift
@@ -1,8 +1,5 @@
 // RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
 
-// TODO: check why this is failing on linux
-// REQUIRES: OS=macosx
-
 func markUsed<T>(_ t: T) {}
 
 class Person {
@@ -24,10 +21,12 @@
 // CHECK: call void {{.*[rR]}}elease{{.*}} {{#[0-9]+}}, !dbg ![[LOOPHEADER_LOC]]
 // CHECK: call {{.*}}void @_T04main8markUsedyxlF
 // The cleanups should share the line number with the ret stmt.
-// CHECK:  call void @swift_bridgeObjectRelease({{.*}}) {{#[0-9]+}}, !dbg ![[CLEANUPS:.*]]
+// CHECK:  call void {{.*[rR]}}elease{{.*}} {{#[0-9]+}}, !dbg ![[CLEANUPS:.*]]
 // CHECK-NEXT:  !dbg ![[CLEANUPS]]
+// CHECK-NEXT:  bitcast
 // CHECK-NEXT:  llvm.lifetime.end
 // CHECK-NEXT:  bitcast
+// CHECK-NEXT:  llvm.lifetime.end
 // CHECK-NEXT:  bitcast
 // CHECK-NEXT:  llvm.lifetime.end
 // CHECK-NEXT:  ret void, !dbg ![[CLEANUPS]]
diff --git a/test/DebugInfo/linetable.swift b/test/DebugInfo/linetable.swift
index f9ba1c2..33b5201 100644
--- a/test/DebugInfo/linetable.swift
+++ b/test/DebugInfo/linetable.swift
@@ -34,9 +34,9 @@
             var result = my_class.do_something(x)
             markUsed(result)
 // CHECK: call {{.*}} @swift_rt_swift_release {{.*}}
-// CHECK: bitcast
-// CHECK: llvm.lifetime.end
 // CHECK: call {{.*}} @swift_rt_swift_release {{.*}}, !dbg ![[CLOSURE_END:.*]]
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: llvm.lifetime.end
 // CHECK-NEXT: ret void, !dbg ![[CLOSURE_END]]
 // CHECK: ![[CLOSURE_END]] = !DILocation(line: [[@LINE+1]],
         }
diff --git a/test/DebugInfo/protocolarg.swift b/test/DebugInfo/protocolarg.swift
index c7ed868..80ea033 100644
--- a/test/DebugInfo/protocolarg.swift
+++ b/test/DebugInfo/protocolarg.swift
@@ -8,21 +8,21 @@
 }
 
 // CHECK: define {{.*}}@_T011protocolarg16printSomeNumbersyAA12IGiveOutInts_pF
-// CHECK: @llvm.dbg.declare(metadata %T11protocolarg12IGiveOutIntsP** %
-// CHECK-SAME:              metadata ![[ARG:.*]], metadata ![[DEREF:.*]])
 // CHECK: @llvm.dbg.declare(metadata %T11protocolarg12IGiveOutIntsP* %
 // CHECK-SAME:              metadata ![[VAR:.*]], metadata ![[EMPTY:.*]])
+// CHECK: @llvm.dbg.declare(metadata %T11protocolarg12IGiveOutIntsP** %
+// CHECK-SAME:              metadata ![[ARG:.*]], metadata ![[DEREF:.*]])
 
 // CHECK: ![[EMPTY]] = !DIExpression()
 
 public func printSomeNumbers(_ gen: IGiveOutInts) {
   var gen = gen
+  // CHECK: ![[VAR]] = !DILocalVariable(name: "gen", {{.*}} line: [[@LINE-1]]
   // FIXME: Should be DW_TAG_interface_type
+  // CHECK: ![[PT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "IGiveOutInts"
   // CHECK: ![[ARG]] = !DILocalVariable(name: "gen", arg: 1,
-  // CHECK-SAME:                        line: [[@LINE-4]], type: ![[PT:[0-9]+]]
-  // CHECK: ![[PT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "IGiveOutInts"
+  // CHECK-SAME:                        line: [[@LINE-6]], type: ![[PT]]
   // CHECK: ![[DEREF]] = !DIExpression(DW_OP_deref)
-  // CHECK: ![[VAR]] = !DILocalVariable(name: "gen", {{.*}} line: [[@LINE-6]]
   markUsed(gen.callMe())
   use(&gen)
 }
diff --git a/test/IRGen/dynamic_lookup.sil b/test/IRGen/dynamic_lookup.sil
index bcfa4d8..3390828 100644
--- a/test/IRGen/dynamic_lookup.sil
+++ b/test/IRGen/dynamic_lookup.sil
@@ -76,8 +76,6 @@
   br bb3
 
 bb3:
-  strong_release %1 : $<τ_0_0> { var τ_0_0 } <AnyObject>
-  strong_release %3 : $<τ_0_0> { var τ_0_0 } <Optional<() -> ()>>
   %43 = tuple ()
   return %43 : $()
 }
@@ -121,7 +119,6 @@
   br bb3
 
 bb3:
-  strong_release %1 : $<τ_0_0> { var τ_0_0 } <AnyObject>
   %43 = tuple ()
   return %43 : $()
 }
@@ -156,8 +153,6 @@
   br bb3
 
 bb3:
-  strong_release %3 : $<τ_0_0> { var τ_0_0 } <Int>
-  strong_release %2 : $<τ_0_0> { var τ_0_0 } <AnyObject>
   %30 = tuple ()
   return %30 : $()
 }
diff --git a/test/SILOptimizer/allocbox_to_stack.sil b/test/SILOptimizer/allocbox_to_stack.sil
index 385dc0f..1a72426 100644
--- a/test/SILOptimizer/allocbox_to_stack.sil
+++ b/test/SILOptimizer/allocbox_to_stack.sil
@@ -243,8 +243,8 @@
   strong_release %1 : ${ var SomeUnion }
   %10 = tuple ()
   return %10 : $()
-// CHECK: dealloc_stack [[UNION]]
 // CHECK:  [[T0:%.*]] = tuple ()
+// CHECK: dealloc_stack [[UNION]]
 // CHECK-NEXT:  return [[T0]] : $()
 }
 
@@ -276,27 +276,24 @@
 //
 // CHECK-LABEL: sil @box_reachable_from_release_test
 sil @box_reachable_from_release_test : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK: alloc_stack
 bb0:
   br bb1
 
-// CHECK: bb1:
-// CHECK-NEXT: alloc_stack
 bb1:
   %1 = alloc_box ${ var Bool }
   cond_br undef, bb2, bb3
 
-// CHECK: bb2:
-// CHECK-NEXT: dealloc_stack
 bb2:
   strong_release %1 : ${ var Bool }
   br bb1
 
-// CHECK: bb3:
-// CHECK-NEXT: dealloc_stack
 bb3:
   strong_release %1 : ${ var Bool }
   %2 = tuple ()
-// CHECK: return
+// CHECK: dealloc_stack
+// CHECK-NEXT: return
   return %2 : $()
 }
 
@@ -337,19 +334,18 @@
 
   strong_release %2 : ${ var SomeClass }
   // CHECK: destroy_addr [[MUI]]
-  // CHECK-NEXT: dealloc_stack [[STACK]]
   br bb2
 
   // CHECK: bb2
 bb2:
   %17 = tuple ()
-  // CHECK: return
+  // CHECK: dealloc_stack [[STACK]]
+  // CHECK-NEXT: return
   return %17 : $()
 
 bb3:
   strong_release %2 : ${ var SomeClass }
   // CHECK: destroy_addr [[MUI]]
-  // CHECK-NEXT: dealloc_stack [[STACK]]
   br bb2
 }
 
@@ -490,13 +486,13 @@
 sil @callWithAutoclosure : $@convention(thin) <T where T : P> (@in T) -> () {
 // CHECK: bb0
 bb0(%0 : $*T):
+  // CHECK: [[STACK:%[0-9a-zA-Z_]+]] = alloc_stack $T
   // CHECK: debug_value_addr
   debug_value_addr %0 : $*T
   // CHECK: function_ref @mightApply
   %2 = function_ref @mightApply : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
   %3 = function_ref @closure_to_specialize : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
   // CHECK-NOT: alloc_box
-  // CHECK: [[STACK:%[0-9a-zA-Z_]+]] = alloc_stack $T
   %4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
   %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
   // CHECK: copy_addr %0 to [initialization] [[STACK]] : $*T
@@ -506,10 +502,10 @@
   %6 = partial_apply %3<T>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
   %7 = apply %2<T>(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
   // CHECK: destroy_addr [[STACK]] : $*T
-  // CHECK: dealloc_stack [[STACK]] : $*T
   destroy_addr %0 : $*T
   %9 = tuple ()
-  // CHECK: return
+ // CHECK: dealloc_stack [[STACK]] : $*T
+ // CHECK: return
   return %9 : $()
 }
 
@@ -749,253 +745,3 @@
   strong_release %2 : ${ var ThrowDerivedClass }
   throw %25 : $Error
 }
-
-// CHECK-LABEL: sil @deal_with_wrong_nesting
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK:      bb1:
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK:      bb2:
-// CHECK:        store
-// CHECK:        [[STACK2:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   dealloc_stack [[STACK2]]
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK:      bb3:
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-sil @deal_with_wrong_nesting : $(Int) -> () {
-bb0(%0 : $Int):
-  %as1 = alloc_stack $Bool
-  %1 = alloc_box ${ var Int }
-  cond_br undef, bb1, bb2
-
-bb1:
-  strong_release %1 : ${ var Int }
-  dealloc_stack %as1 : $*Bool
-  br bb3
-
-bb2:
-  %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to %1a : $*Int
-  dealloc_stack %as1 : $*Bool
-  %3 = load %1a : $*Int
-  %as2 = alloc_stack $Bool
-  strong_release %1 : ${ var Int }
-  dealloc_stack %as2 : $*Bool
-  br bb3
-
-bb3:
-  %r = tuple ()
-  %5 = return %r : $()
-}
-
-// CHECK-LABEL: sil @wrong_nesting_with_alloc_ref
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[REF:%[0-9]+]] = alloc_ref [stack] $SomeClass
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK:        store
-// CHECK:        dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_ref [stack] [[REF]]
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-sil @wrong_nesting_with_alloc_ref : $(Int) -> () {
-bb0(%0 : $Int):
-  %as1 = alloc_ref [stack] $SomeClass
-  %1 = alloc_box ${ var Int }
-  %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to %1a : $*Int
-  dealloc_ref [stack] %as1 : $SomeClass
-  %3 = load %1a : $*Int
-  strong_release %1 : ${ var Int }
-  %r = tuple ()
-  %5 = return %r : $()
-}
-
-// CHECK-LABEL: sil @nesting_and_unreachable1
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK:      bb1:
-// CHECK-NEXT:   [[STACK2:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   dealloc_stack [[STACK2]]
-// CHECK-NEXT:   unreachable
-// CHECK:      bb2:
-// CHECK:        store
-// CHECK:        dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-sil @nesting_and_unreachable1 : $(Int) -> () {
-bb0(%0 : $Int):
-  %as1 = alloc_stack $Bool
-  %1 = alloc_box ${ var Int }
-  %1a = project_box %1 : ${ var Int }, 0
-  cond_br undef, bb1, bb2
-
-bb1:
-  %as2 = alloc_stack $Bool
-  dealloc_stack %as2 : $*Bool
-  unreachable
-
-bb2:
-  %2 = store %0 to %1a : $*Int
-  dealloc_stack %as1 : $*Bool
-  %3 = load %1a : $*Int
-  strong_release %1 : ${ var Int }
-  %r = tuple ()
-  %5 = return %r : $()
-}
-
-// CHECK-LABEL: sil @nesting_and_unreachable2
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK:      bb1:
-// CHECK-NEXT:   [[STACK2:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   dealloc_stack [[STACK2]]
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK-NEXT:   unreachable
-// CHECK:      bb2:
-// CHECK:        store
-// CHECK:        dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-sil @nesting_and_unreachable2 : $(Int) -> () {
-bb0(%0 : $Int):
-  %as1 = alloc_stack $Bool
-  %1 = alloc_box ${ var Int }
-  %1a = project_box %1 : ${ var Int }, 0
-  cond_br undef, bb1, bb2
-
-bb1:
-  %as2 = alloc_stack $Bool
-  strong_release %1 : ${ var Int }
-  dealloc_stack %as2 : $*Bool
-  unreachable
-
-bb2:
-  %2 = store %0 to %1a : $*Int
-  dealloc_stack %as1 : $*Bool
-  %3 = load %1a : $*Int
-  strong_release %1 : ${ var Int }
-  %r = tuple ()
-  %5 = return %r : $()
-}
-
-// CHECK-LABEL: sil @nesting_and_unreachable3
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK-NEXT:   [[STACK:%[0-9]+]] = alloc_stack $Bool
-// CHECK:      bb1:
-// CHECK-NEXT:   dealloc_stack [[STACK]]
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   unreachable
-// CHECK:      bb2:
-// CHECK:        store
-// CHECK:        dealloc_stack [[STACK]]
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-sil @nesting_and_unreachable3 : $(Int) -> () {
-bb0(%0 : $Int):
-  %1 = alloc_box ${ var Int }
-  %as1 = alloc_stack $Bool
-  %1a = project_box %1 : ${ var Int }, 0
-  cond_br undef, bb1, bb2
-
-bb1:
-  strong_release %1 : ${ var Int }
-  unreachable
-
-bb2:
-  %2 = store %0 to %1a : $*Int
-  %3 = load %1a : $*Int
-  dealloc_stack %as1 : $*Bool
-  strong_release %1 : ${ var Int }
-  %r = tuple ()
-  %5 = return %r : $()
-}
-
-// CHECK-LABEL: sil @nesting_and_unreachable4
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK:      bb1:
-// CHECK-NEXT:   unreachable
-// CHECK:      bb2:
-// CHECK:        store
-// CHECK:        dealloc_stack [[BOX]]
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-sil @nesting_and_unreachable4 : $(Int) -> () {
-bb0(%0 : $Int):
-  %1 = alloc_box ${ var Int }
-  %1a = project_box %1 : ${ var Int }, 0
-  cond_br undef, bb1, bb2
-
-bb1:
-  unreachable
-
-bb2:
-  %2 = store %0 to %1a : $*Int
-  %3 = load %1a : $*Int
-  strong_release %1 : ${ var Int }
-  %r = tuple ()
-  %5 = return %r : $()
-}
-
-// CHECK-LABEL: sil @nesting_and_unreachable_critical_edge
-// CHECK:      bb0(%0 : $Int):
-// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
-// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   cond_br
-// CHECK:      bb1:
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK-NEXT:   br bb5
-// CHECK:      bb2:
-// CHECK-NEXT:   [[STACK2:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   cond_br
-// CHECK:      bb3:
-// CHECK-NEXT:   dealloc_stack [[STACK2]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK-NEXT:   br bb5
-// CHECK:      bb4:
-// CHECK:        store
-// CHECK:        dealloc_stack [[STACK2]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   tuple
-// CHECK-NEXT:   return
-// CHECK:      bb5:
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   unreachable
-sil @nesting_and_unreachable_critical_edge : $(Int) -> () {
-bb0(%0 : $Int):
-  %1 = alloc_box ${ var Int }
-  %as1 = alloc_stack $Bool
-  %1a = project_box %1 : ${ var Int }, 0
-  cond_br undef, bb1, bb3
-
-bb1:
-  %as2 = alloc_stack $Bool
-  cond_br undef, bb2, bb3
-
-bb2:
-  %2 = store %0 to %1a : $*Int
-  %3 = load %1a : $*Int
-  dealloc_stack %as2 : $*Bool
-  dealloc_stack %as1 : $*Bool
-  strong_release %1 : ${ var Int }
-  %r = tuple ()
-  %5 = return %r : $()
-
-bb3:
-  strong_release %1 : ${ var Int }
-  unreachable
-
-}
-
diff --git a/test/SILOptimizer/definite_init_failable_initializers.swift b/test/SILOptimizer/definite_init_failable_initializers.swift
index d5b7e4f..ea5c4c8 100644
--- a/test/SILOptimizer/definite_init_failable_initializers.swift
+++ b/test/SILOptimizer/definite_init_failable_initializers.swift
@@ -40,10 +40,10 @@
 // CHECK:         [[SELF_BOX:%.*]] = alloc_stack $FailableStruct
 // CHECK:         br bb1
 // CHECK:       bb1:
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[SELF]]
   init?(failBeforeInitialization: ()) {
     return nil
@@ -59,10 +59,10 @@
 // CHECK:       bb1:
 // CHECK-NEXT:    [[X_ADDR:%.*]] = struct_element_addr [[SELF_BOX]]
 // CHECK-NEXT:    strong_release [[CANARY]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[SELF]]
   init?(failAfterPartialInitialization: ()) {
     x = Canary()
@@ -82,10 +82,10 @@
 // CHECK:       bb1:
 // CHECK-NEXT:    [[SELF:%.*]] = struct $FailableStruct ([[CANARY1]] : $Canary, [[CANARY2]] : $Canary)
 // CHECK-NEXT:    release_value [[SELF]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[NEW_SELF]]
   init?(failAfterFullInitialization: ()) {
     x = Canary()
@@ -101,10 +101,10 @@
 // CHECK-NEXT:    br bb1
 // CHECK:       bb1:
 // CHECK-NEXT:    release_value [[CANARY]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[SELF_VALUE:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[SELF_VALUE]]
   init?(failAfterWholeObjectInitializationByAssignment: ()) {
     self = FailableStruct(noFail: ())
@@ -120,10 +120,10 @@
 // CHECK-NEXT:    br bb1
 // CHECK:       bb1:
 // CHECK-NEXT:    release_value [[NEW_SELF]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[NEW_SELF]]
   init?(failAfterWholeObjectInitializationByDelegation: ()) {
     self.init(noFail: ())
@@ -146,15 +146,14 @@
 // CHECK-NEXT:    [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]]
 // CHECK-NEXT:    store [[SELF_VALUE]] to [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.some!enumelt.1, [[SELF_VALUE]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableStruct>)
 //
 // CHECK:       [[FAIL_EPILOG_BB]]:
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableStruct>)
 //
 // CHECK:       [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<FailableStruct>)
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[NEW_SELF]]
   // Optional to optional
   init?(failDuringDelegation: ()) {
@@ -205,11 +204,11 @@
 // CHECK:         [[SELF_BOX:%.*]] = alloc_stack $FailableAddrOnlyStruct<T>
 // CHECK:         br bb1
 // CHECK:       bb1:
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    inject_enum_addr %0
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
-// CHECK:         return
+// CHECK:         dealloc_stack [[SELF_BOX]]
+// CHECK-NEXT:    return
   init?(failBeforeInitialization: ()) {
     return nil
   }
@@ -228,11 +227,11 @@
 // CHECK:       bb1:
 // CHECK-NEXT:    [[X_ADDR:%.*]] = struct_element_addr [[SELF_BOX]]
 // CHECK-NEXT:    destroy_addr [[X_ADDR]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    inject_enum_addr %0
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
-// CHECK:         return
+// CHECK:         dealloc_stack [[SELF_BOX]]
+// CHECK-NEXT:    return
   init?(failAfterPartialInitialization: ()) {
     x = T()
     return nil
@@ -258,11 +257,11 @@
 // CHECK-NEXT:    br bb1
 // CHECK:       bb1:
 // CHECK-NEXT:    destroy_addr [[SELF_BOX]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    inject_enum_addr %0
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
-// CHECK:         return
+// CHECK:         dealloc_stack [[SELF_BOX]]
+// CHECK-NEXT:    return
   init?(failAfterFullInitialization: ()) {
     x = T()
     y = T()
@@ -528,15 +527,14 @@
 // CHECK-NEXT:    [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]]
 // CHECK-NEXT:    store [[SELF_VALUE]] to [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<ThrowStruct>, #Optional.some!enumelt.1, [[SELF_VALUE]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<ThrowStruct>)
 //
 // CHECK:       [[FAIL_EPILOG_BB]]:
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<ThrowStruct>, #Optional.none!enumelt
 // CHECK-NEXT:    br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<ThrowStruct>)
 //
 // CHECK:       [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<ThrowStruct>):
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[NEW_SELF]] : $Optional<ThrowStruct>
 //
 // CHECK:       [[TRY_APPLY_FAIL_TRAMPOLINE_BB:bb[0-9]+]]:
@@ -748,10 +746,10 @@
 // CHECK:       bb1:
 // CHECK-NEXT:    [[METATYPE:%.*]] = value_metatype $@thick FailableBaseClass.Type, %0 : $FailableBaseClass
 // CHECK-NEXT:    dealloc_partial_ref %0 : $FailableBaseClass, [[METATYPE]] : $@thick FailableBaseClass.Type
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[RESULT:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[RESULT]]
   convenience init?(failBeforeDelegation: ()) {
     return nil
@@ -767,10 +765,10 @@
 // CHECK-NEXT:    br bb1
 // CHECK:       bb1:
 // CHECK-NEXT:    strong_release [[NEW_SELF]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[RESULT:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[RESULT]]
   convenience init?(failAfterDelegation: ()) {
     self.init(noFail: ())
@@ -794,15 +792,14 @@
 // CHECK-NEXT:    [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]]
 // CHECK-NEXT:    store [[SELF_VALUE]] to [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableBaseClass>, #Optional.some!enumelt.1, [[SELF_VALUE]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableBaseClass>)
 //
 // CHECK:       [[FAIL_TRAMPOLINE_BB]]:
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
 // CHECK-NEXT:    br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableBaseClass>)
 //
 // CHECK:       [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<FailableBaseClass>):
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[NEW_SELF]]
   // Optional to optional
   convenience init?(failDuringDelegation: ()) {
@@ -843,10 +840,10 @@
 // CHECK:       bb1:
 // CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thick FailableDerivedClass.Type
 // CHECK-NEXT:    dealloc_partial_ref %0 : $FailableDerivedClass, [[METATYPE]] : $@thick FailableDerivedClass.Type
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[RESULT:%.*]] = enum $Optional<FailableDerivedClass>, #Optional.none!enumelt
 // CHECK-NEXT:    br bb2
 // CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[RESULT]]
   init?(derivedFailBeforeDelegation: ()) {
     return nil
@@ -874,15 +871,14 @@
 // CHECK-NEXT:    [[SELF_VALUE:%.*]] = unchecked_ref_cast [[BASE_SELF_VALUE]]
 // CHECK-NEXT:    store [[SELF_VALUE]] to [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableDerivedClass>, #Optional.some!enumelt.1, [[SELF_VALUE]]
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableDerivedClass>)
 //
 // CHECK:       [[FAIL_TRAMPOLINE_BB]]:
-// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    [[NEW_SELF:%.*]] = enum $Optional<FailableDerivedClass>, #Optional.none!enumelt
 // CHECK-NEXT:    br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableDerivedClass>)
 //
 // CHECK:       [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<FailableDerivedClass>):
+// CHECK-NEXT:    dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT:    return [[NEW_SELF]] : $Optional<FailableDerivedClass>
   init?(derivedFailDuringDelegation: ()) {
     self.otherMember = Canary()
diff --git a/test/SILOptimizer/definite_init_protocol_init.swift b/test/SILOptimizer/definite_init_protocol_init.swift
index f24d78b..b109ff3 100644
--- a/test/SILOptimizer/definite_init_protocol_init.swift
+++ b/test/SILOptimizer/definite_init_protocol_init.swift
@@ -100,8 +100,8 @@
 // CHECK-NEXT: copy_addr [take] [[SELF_BOX]] to [initialization] [[SELF]]
 // CHECK-NEXT: dealloc_stack [[SELF_BOX]]
 // CHECK-NEXT: copy_addr [take] [[SELF]] to [initialization] %0
-// CHECK-NEXT: dealloc_stack [[SELF]]
 // CHECK-NEXT: [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT: dealloc_stack [[SELF]]
 // CHECK-NEXT: return [[RESULT]]
   init(upper: Int) {
     self.init(middle: upper)
diff --git a/test/SILOptimizer/sroa_unreferenced_members.swift b/test/SILOptimizer/sroa_unreferenced_members.swift
index 9c7775c..cce1ea7 100644
--- a/test/SILOptimizer/sroa_unreferenced_members.swift
+++ b/test/SILOptimizer/sroa_unreferenced_members.swift
@@ -3,7 +3,7 @@
 import gizmo
 
 // CHECK: ModifyStruct
-// CHECK:   = alloc_stack $Drill
+// CHECK: %1 = alloc_stack $Drill
 // CHECK: ret
 func ModifyStruct(inDrill : Drill) -> Int32 {
   var D : Drill = inDrill
diff --git a/test/multifile/Inputs/protocol-conformance/rdar31302713.swift b/test/multifile/Inputs/protocol-conformance/rdar31302713.swift
new file mode 100644
index 0000000..5c8e442
--- /dev/null
+++ b/test/multifile/Inputs/protocol-conformance/rdar31302713.swift
@@ -0,0 +1,24 @@
+public protocol Animal {
+  associatedtype AnimalSnackType : AnimalSnack
+  func snack(on: AnimalSnackType)
+}
+
+public protocol AnimalSnack {
+  associatedtype EatWith
+  func eat(with: EatWith)
+}
+
+extension AnimalSnack where EatWith : Animal {}
+
+public protocol FurryAnimal : Animal {
+    associatedtype Fangs : Animal
+    func bite(with: Fangs)
+}
+
+extension FurryAnimal {
+  public func snack(on: FurryAnimalSnack<Self>) {}
+}
+
+public struct FurryAnimalSnack<T : FurryAnimal> : AnimalSnack {
+  public func eat(with: T) {}
+}
diff --git a/test/multifile/protocol-conformance-rdar31302713.swift b/test/multifile/protocol-conformance-rdar31302713.swift
new file mode 100644
index 0000000..b2a8a01
--- /dev/null
+++ b/test/multifile/protocol-conformance-rdar31302713.swift
@@ -0,0 +1,6 @@
+// RUN: %target-swift-frontend -emit-ir -primary-file %s %S/Inputs/protocol-conformance/rdar31302713.swift -module-name animal_snack
+
+public struct FunctionalFurryAnimal<Fangs : Animal> : FurryAnimal
+    where Fangs.AnimalSnackType.EatWith == Fangs {
+  public func bite(with: Fangs) {}
+}