Merge pull request #14234 from aschwaighofer/swift-4.1-branch-sil_fix_indirect_enum_box_types

[4.1] SIL : Use the enum 's generic signature and the payloads type f…
diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h
index 4637e5a..0031cb1 100644
--- a/include/swift/SIL/TypeLowering.h
+++ b/include/swift/SIL/TypeLowering.h
@@ -863,6 +863,9 @@
                               GenericEnvironment *env,
                               bool isMutable);
 
+  CanSILBoxType getBoxTypeForEnumElement(SILType enumType,
+                                         EnumElementDecl *elt);
+
 private:
   CanType getLoweredRValueType(AbstractionPattern origType, CanType substType);
 
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index c99d242..ffb53dc 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -328,17 +328,19 @@
     return SILType(objectType, getCategory());
   }
 
+  // If the case is indirect, then the payload is boxed.
+  if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) {
+    auto box = M.Types.getBoxTypeForEnumElement(*this, elt);
+    return SILType(SILType::getPrimitiveObjectType(box).getSwiftRValueType(),
+                   getCategory());
+  }
+
   auto substEltTy =
     getSwiftRValueType()->getTypeOfMember(M.getSwiftModule(), elt,
                                           elt->getArgumentInterfaceType());
   auto loweredTy =
     M.Types.getLoweredType(M.Types.getAbstractionPattern(elt), substEltTy);
 
-  // If the case is indirect, then the payload is boxed.
-  if (elt->isIndirect() || elt->getParentEnum()->isIndirect())
-    loweredTy = SILType::getPrimitiveObjectType(
-      SILBoxType::get(loweredTy.getSwiftRValueType()));
-
   return SILType(loweredTy.getSwiftRValueType(), getCategory());
 }
 
diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp
index 6dc9a84..7025d35 100644
--- a/lib/SIL/TypeLowering.cpp
+++ b/lib/SIL/TypeLowering.cpp
@@ -2527,6 +2527,45 @@
   return boxType;
 }
 
+CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType,
+                                                      EnumElementDecl *elt) {
+
+  auto *enumDecl = enumType.getEnumOrBoundGenericEnum();
+
+  assert(elt->getDeclContext() == enumDecl);
+  assert(elt->isIndirect() || elt->getParentEnum()->isIndirect());
+
+  auto &C = M.getASTContext();
+
+  auto boxSignature = getEffectiveGenericSignature(enumDecl);
+
+  if (boxSignature == CanGenericSignature()) {
+    auto eltIntfTy = elt->getArgumentInterfaceType();
+    auto boxVarTy = getLoweredType(eltIntfTy).getSwiftRValueType();
+    auto layout = SILLayout::get(C, nullptr, SILField(boxVarTy, true));
+    return SILBoxType::get(C, layout, {});
+  }
+
+  // Use the enum's signature for the box type.
+  auto boundEnum = enumType.getSwiftRValueType();
+
+  // Lower the enum element's argument in the box's context.
+  auto eltIntfTy = elt->getArgumentInterfaceType();
+  GenericContextScope scope(*this, boxSignature);
+  auto boxVarTy = getLoweredType(getAbstractionPattern(elt), eltIntfTy)
+                      .getSwiftRValueType();
+  auto layout = SILLayout::get(C, boxSignature, SILField(boxVarTy, true));
+
+  // Instantiate the layout with enum's substitution list.
+  auto subMap = boundEnum->getContextSubstitutionMap(
+      M.getSwiftModule(), enumDecl, enumDecl->getGenericEnvironment());
+  SmallVector<Substitution, 4> genericArgs;
+  boxSignature->getSubstitutions(subMap, genericArgs);
+
+  auto boxTy = SILBoxType::get(C, layout, genericArgs);
+  return boxTy;
+}
+
 static void countNumberOfInnerFields(unsigned &fieldsCount, SILModule &Module,
                                      SILType Ty) {
   if (auto *structDecl = Ty.getStructOrBoundGenericStruct()) {
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 7bf47ae..69303b1 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -3532,7 +3532,7 @@
   // throws, we know to deallocate the uninitialized box.
   if (element->isIndirect() ||
       element->getParentEnum()->isIndirect()) {
-    auto boxTy = SILBoxType::get(payloadTL.getLoweredType().getSwiftRValueType());
+    auto boxTy = SGM.M.Types.getBoxTypeForEnumElement(enumTy, element);
     auto *box = B.createAllocBox(loc, boxTy);
     auto *addr = B.createProjectBox(loc, box, 0);
 
diff --git a/test/Interpreter/enum.swift b/test/Interpreter/enum.swift
index 37cba79..2a44c7d 100644
--- a/test/Interpreter/enum.swift
+++ b/test/Interpreter/enum.swift
@@ -651,3 +651,19 @@
 }
 
 run()
+
+public enum Indirect<T> {
+  indirect case payload((T, other: T))
+  case none
+}
+
+public func testIndirectEnum<T>(_ payload: T) -> Indirect<T> {
+  return Indirect.payload((payload, other: payload))
+}
+
+public func testCase(_ closure: @escaping (Int) -> ()) -> Indirect<(Int) -> ()> {
+  return testIndirectEnum(closure)
+}
+
+// CHECK: payload((Function), other: (Function))
+print(testCase({ _ in }))
diff --git a/test/SIL/Parser/indirect_enum.sil b/test/SIL/Parser/indirect_enum.sil
index f550c84..f83ed00 100644
--- a/test/SIL/Parser/indirect_enum.sil
+++ b/test/SIL/Parser/indirect_enum.sil
@@ -27,7 +27,7 @@
   %b = project_box %a : $<τ_0_0> { var τ_0_0 } <T>, 0
 
   %c = unchecked_enum_data %e : $TreeA<T>, #TreeA.Branch!enumelt.1
-  %d = project_box %c : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>, 0
+  %d = project_box %c : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>, 0
 
   return undef : $()
 }
@@ -38,7 +38,7 @@
   destroy_addr %a : $*T
 
   %c = unchecked_take_enum_data_addr %e : $*TreeB<T>, #TreeB.Branch!enumelt.1
-  %d = load [take] %c : $*<τ_0_0> { var τ_0_0 } <(left: TreeB<T>, right: TreeB<T>)>
+  %d = load [take] %c : $*<τ_0_0> { var (left: TreeB<τ_0_0>, right: TreeB<τ_0_0>) } <T>
 
   return undef : $()
 }
@@ -49,7 +49,7 @@
   store %a to [trivial] undef : $*Int
 
   %c = unchecked_enum_data %e : $TreeInt, #TreeInt.Branch!enumelt.1
-  %d = project_box %c : $<τ_0_0> { var τ_0_0 } <(left: TreeInt, right: TreeInt)>, 0
+  %d = project_box %c : ${ var (left: TreeInt, right: TreeInt) }, 0
 
   return undef : $()
 }
diff --git a/test/SILGen/enum.swift b/test/SILGen/enum.swift
index 2ecc760..da8b24f 100644
--- a/test/SILGen/enum.swift
+++ b/test/SILGen/enum.swift
@@ -190,3 +190,14 @@
 func Foo_cases() {
   _ = Foo.A
 }
+
+enum Indirect<T> {
+  indirect case payload((T, other: T))
+  case none
+}
+// CHECK-LABEL: sil{{.*}} @{{.*}}makeIndirectEnum{{.*}} : $@convention(thin) <T> (@in T) -> @owned Indirect<T>
+// CHECK: [[BOX:%.*]] = alloc_box $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
+// CHECK: enum $Indirect<T>, #Indirect.payload!enumelt.1, [[BOX]] : $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
+func makeIndirectEnum<T>(_ payload: T) -> Indirect<T> {
+  return Indirect.payload((payload, other: payload))
+}
diff --git a/test/SILGen/indirect_enum.swift b/test/SILGen/indirect_enum.swift
index be73d6c..0f6fcd4 100644
--- a/test/SILGen/indirect_enum.swift
+++ b/test/SILGen/indirect_enum.swift
@@ -23,7 +23,7 @@
   let _ = TreeA<T>.Leaf(t)
 
 // CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeA<T>.Type
-// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>
 // CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
 // CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PB]] : $*(left: TreeA<T>, right: TreeA<T>), 0
 // CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PB]] : $*(left: TreeA<T>, right: TreeA<T>), 1
@@ -50,7 +50,7 @@
 func TreeA_reabstract(_ f: @escaping (Int) -> Int) {
 // CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (Int) -> Int):
 // CHECK:         [[METATYPE:%.*]] = metatype $@thin TreeA<(Int) -> Int>.Type
-// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <@callee_guaranteed (@in Int) -> @out Int>
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(Int) -> Int>
 // CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
 // CHECK-NEXT:    [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
 // CHECK-NEXT:    [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
@@ -92,7 +92,7 @@
   let _ = TreeB<T>.Leaf(t)
 
 // CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeB<T>.Type
-// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(left: TreeB<T>, right: TreeB<T>)>
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var (left: TreeB<τ_0_0>, right: TreeB<τ_0_0>) } <T>
 // CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
 // CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PB]]
 // CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PB]]
@@ -127,7 +127,7 @@
   let _ = TreeInt.Leaf(t)
 
 // CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeInt.Type
-// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(left: TreeInt, right: TreeInt)>
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box ${ var (left: TreeInt, right: TreeInt) }
 // CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
 // CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PB]]
 // CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PB]]
@@ -194,7 +194,7 @@
   case .Leaf(let x):
     b(x)
 
-  // CHECK:     [[BRANCH_CASE]]([[NODE_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>):
+  // CHECK:     [[BRANCH_CASE]]([[NODE_BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
   // CHECK:       [[TUPLE_ADDR:%.*]] = project_box [[NODE_BOX]]
   // CHECK:       [[TUPLE:%.*]] = load_borrow [[TUPLE_ADDR]]
   // CHECK:       [[LEFT:%.*]] = tuple_extract [[TUPLE]] {{.*}}, 0
@@ -370,7 +370,7 @@
     // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
     // CHECK:   destroy_value [[ORIGINAL_VALUE]]
     // CHECK:   end_borrow [[BORROWED_ARG_3]] from [[ARG]]
-    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>):
+    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
     // CHECK:   [[VALUE_ADDR:%.*]] = project_box [[BOX]]
     // CHECK:   [[TUPLE:%.*]] = load [take] [[VALUE_ADDR]]
     // CHECK:   [[TUPLE_COPY:%.*]] = copy_value [[TUPLE]]
@@ -425,7 +425,7 @@
     // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
     // CHECK:   destroy_value [[ORIGINAL_VALUE]]
     // CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
-    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>):
+    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
     // CHECK:   [[VALUE_ADDR:%.*]] = project_box [[BOX]]
     // CHECK:   [[TUPLE:%.*]] = load [take] [[VALUE_ADDR]]
     // CHECK:   [[TUPLE_COPY:%.*]] = copy_value [[TUPLE]]
@@ -540,7 +540,7 @@
   // CHECK:   [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
   // CHECK:   switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Direct!enumelt.1:  [[YES:bb[0-9]+]], case #TrivialButIndirect.Indirect!enumelt.1: [[NO:bb[0-9]+]]
   //
-  // CHECK: [[NO]]([[PAYLOAD:%.*]] : $<τ_0_0> { var τ_0_0 } <Int>):
+  // CHECK: [[NO]]([[PAYLOAD:%.*]] : ${ var Int }):
   // CHECK:   destroy_value [[PAYLOAD]]
   // CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
   guard case .Direct(let foo) = x else { return }
@@ -555,7 +555,7 @@
   // CHECK-NOT: destroy_value
   // CHECK:   end_borrow [[BORROWED_ARG]] from [[ARG]]
 
-  // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <Int>):
+  // CHECK: [[YES]]([[BOX:%.*]] : ${ var Int }):
   // CHECK:   destroy_value [[BOX]]
 
   guard case .Indirect(let bar) = x else { return }
diff --git a/test/SILOptimizer/predictable_memopt.sil b/test/SILOptimizer/predictable_memopt.sil
index 75ffb68..5972ecb 100644
--- a/test/SILOptimizer/predictable_memopt.sil
+++ b/test/SILOptimizer/predictable_memopt.sil
@@ -436,14 +436,14 @@
 sil @indirect_enum_box : $@convention(thin) (Int) -> IndirectCase {
 // CHECK: bb0([[X:%.*]] : $Int):
 entry(%x : $Int):
-  // CHECK: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
-  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  // CHECK: [[BOX:%.*]] = alloc_box ${ var Int }
+  %b = alloc_box ${ var Int }
   // CHECK: [[PB:%.*]] = project_box [[BOX]]
-  %ba = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %ba = project_box %b : ${ var Int }, 0
   // CHECK: store [[X]] to [[PB]]
   store %x to %ba : $*Int
-  // CHECK: [[E:%.*]] = enum $IndirectCase, #IndirectCase.X!enumelt.1, [[BOX]] : $<τ_0_0> { var τ_0_0 } <Int>
-  %e = enum $IndirectCase, #IndirectCase.X!enumelt.1, %b : $<τ_0_0> { var τ_0_0 } <Int>
+  // CHECK: [[E:%.*]] = enum $IndirectCase, #IndirectCase.X!enumelt.1, [[BOX]] : ${ var Int }
+  %e = enum $IndirectCase, #IndirectCase.X!enumelt.1, %b : ${ var Int }
   // CHECK: return [[E]]
   return %e : $IndirectCase
 }
@@ -837,4 +837,4 @@
 bb2:
   destroy_addr %1 : $*Builtin.NativeObject
   unreachable
-}
\ No newline at end of file
+}