SIL: What is the correct SIL box type after substitution with a function type

I am looking at a bug where:

sil @$S10LinkedListAAO4pushyyxF : $@convention(method) <Element> (@in Element, @inout LinkedList<Element>) -> () {
// %0                                             // users: %7, %2
// %1                                             // users: %4, %9, %10, %3
bb0(%0 : $*Element, %1 : $*LinkedList<Element>):
  debug_value_addr %0 : $*Element, let, name "element", argno 1 // id: %2
  debug_value_addr %1 : $*LinkedList<Element>, var, name "self", argno 2 // id: %3
  %4 = load %1 : $*LinkedList<Element>            // users: %8, %6, %7
  // function_ref LinkedList.cons(_:)
  %5 = function_ref @$S10LinkedListAAO4consyAByxGxF : $@convention(method) <τ_0_0> (@in τ_0_0, @guaranteed LinkedList<τ_0_0>) -> @owned LinkedList<τ_0_0> // user: %7
  retain_value %4 : $LinkedList<Element>          // id: %6
  %7 = apply %5<Element>(%0, %4) : $@convention(method) <τ_0_0> (@in τ_0_0, @guaranteed LinkedList<τ_0_0>) -> @owned LinkedList<τ_0_0> // user: %10
  release_value %4 : $LinkedList<Element>         // id: %8
  %9 = load %1 : $*LinkedList<Element>            // user: %11
  store %7 to %1 : $*LinkedList<Element>          // id: %10
  release_value %9 : $LinkedList<Element>         // id: %11
  %12 = tuple ()                                  // user: %13
  return %12 : $()                                // id: %13
}

is specialized by substituting () -() by the generic specializer to

sil shared @$S10LinkedListAAO4consyAByxGxFyyc_Tg5 : $@convention(method) (@owned @callee_guaranteed (@in ()) -> @out (), @guaranteed LinkedList<() -> ()>) -> @owned LinkedList<() -> ()> {
// %0                                             // users: %4, %3
// %1                                             // users: %14, %12, %6
bb0(%0 : $@callee_guaranteed (@in ()) -> @out (), %1 : $LinkedList<() -> ()>):
  %2 = alloc_stack $@callee_guaranteed (@in ()) -> @out (), let, name "element" // users: %16, %15, %11, %5, %3
  store %0 to %2 : $*@callee_guaranteed (@in ()) -> @out () // id: %3
  debug_value %0 : $@callee_guaranteed (@in ()) -> @out (), let, name "element", argno 1 // id: %4
  debug_value_addr %2 : $*@callee_guaranteed (@in ()) -> @out (), let, name "element", argno 1 // id: %5
  debug_value %1 : $LinkedList<() -> ()>, let, name "self", argno 2 // id: %6
  %7 = alloc_box $<τ_0_0> { var τ_0_0 } <(() -> (), next: LinkedList<() -> ()>)> // users: %13, %8
  %8 = project_box %7 : $<τ_0_0> { var τ_0_0 } <(() -> (), next: LinkedList<() -> ()>)>, 0 // users: %10, %9
  %9 = tuple_element_addr %8 : $*(@callee_guaranteed (@in ()) -> @out (), next: LinkedList<() -> ()>), 0 // user: %11
  %10 = tuple_element_addr %8 : $*(@callee_guaranteed (@in ()) -> @out (), next: LinkedList<() -> ()>), 1 // user: %12
  copy_addr %2 to [initialization] %9 : $*@callee_guaranteed (@in ()) -> @out () // id: %11
  store %1 to %10 : $*LinkedList<() -> ()>        // id: %12
  %13 = enum $LinkedList<() -> ()>, #LinkedList.next!enumelt.1, %7 : $<τ_0_0> { var τ_0_0 } <(() -> (), next: LinkedList<() -> ()>)> // user: %17
  retain_value %1 : $LinkedList<() -> ()>         // id: %14
  destroy_addr %2 : $*@callee_guaranteed (@in ()) -> @out () // id: %15
  dealloc_stack %2 : $*@callee_guaranteed (@in ()) -> @out () // id: %16
  return %13 : $LinkedList<() -> ()>              // id: %17
}

SIL verification fails on the enum %13.

It complains that the enum operand %7 ’s type is:

$<τ_0_0> { var τ_0_0 } <(() -> (), next: LinkedList<() -> ()>)>

while SILType::getEnumElementType returns:

$<τ_0_0> { var τ_0_0 } <(@callee_guaranteed (@in ()) -> @out (), next: LinkedList<() -> ()>)>

which one is the right one?

SILType SILType::getEnumElementType(EnumElementDecl *elt, SILModule &M) const {                                                           
  assert(elt->getDeclContext() == getEnumOrBoundGenericEnum());
  assert(elt->hasAssociatedValues());
        
  if (auto objectType = getSwiftRValueType().getAnyOptionalObjectType()) {
    assert(elt == M.getASTContext().getOptionalSomeDecl());                                                                               
    return SILType(objectType, 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());
}

is wrong. Or whether SILType.subst -- called in the generic specializer:

   172 	  SILType remapType(SILType Ty) {
-> 173 	    return Ty.subst(Original.getModule(), SubsMap);
   174 	  }

is wrong.

I think the answer is the abstraction that is called for in a generic context. i.e the @in() -> @out () version. i.e there is a problem in SILType.subst(module, substMap).

That would seem make sense (to me) given how we map the rest of the function under a (Int) -> () substitution.

// specialized LinkedList.cons(_:)
sil shared @$S10LinkedListAAO4consyAByxGxFySic_Tg5 : $@convention(method) (@owned @callee_guaranteed (@in Int) -> @out (), @guaranteed LinkedList<(Int) -> ()>) -> @owned LinkedList<(Int) -> ()> {
// %0                                             // users: %4, %3
// %1                                             // users: %14, %12, %6
bb0(%0 : $@callee_guaranteed (@in Int) -> @out (), %1 : $LinkedList<(Int) -> ()>):
  %2 = alloc_stack $@callee_guaranteed (@in Int) -> @out (), let, name "element" // users: %16, %15, %11, %5, %3
  store %0 to %2 : $*@callee_guaranteed (@in Int) -> @out () // id: %3
  debug_value %0 : $@callee_guaranteed (@in Int) -> @out (), let, name "element", argno 1 // id: %4
  debug_value_addr %2 : $*@callee_guaranteed (@in Int) -> @out (), let, name "element", argno 1 // id: %5
  debug_value %1 : $LinkedList<(Int) -> ()>, let, name "self", argno 2 // id: %6
  %7 = alloc_box $<τ_0_0> { var τ_0_0 } <((Int) -> (), next: LinkedList<(Int) -> ()>)> // users: %13, %8
  %8 = project_box %7 : $<τ_0_0> { var τ_0_0 } <((Int) -> (), next: LinkedList<(Int) -> ()>)>, 0 // users: %10, %9
  %9 = tuple_element_addr %8 : $*(@callee_guaranteed (@in Int) -> @out (), next: LinkedList<(Int) -> ()>), 0 // user: %11
  %10 = tuple_element_addr %8 : $*(@callee_guaranteed (@in Int) -> @out (), next: LinkedList<(Int) -> ()>), 1 // user: %12
  copy_addr %2 to [initialization] %9 : $*@callee_guaranteed (@in Int) -> @out () // id: %11
  store %1 to %10 : $*LinkedList<(Int) -> ()>     // id: %12
  %13 = enum $LinkedList<(Int) -> ()>, #LinkedList.next!enumelt.1, %7 : $<τ_0_0> { var τ_0_0 } <((Int) -> (), next: LinkedList<(Int) -> ()>)> // user: %17
  retain_value %1 : $LinkedList<(Int) -> ()>      // id: %14
  destroy_addr %2 : $*@callee_guaranteed (@in Int) -> @out () // id: %15
  dealloc_stack %2 : $*@callee_guaranteed (@in Int) -> @out () // id: %16
  return %13 : $LinkedList<(Int) -> ()>           // id: %17
} 

We call the generic function with an generically abstracted function value. This further makes me think the SILBoxType substitution should have been @in() -> @out().

  %2 = alloc_stack $LinkedList<(Int) -> ()>, var, name "l" // users: %17, %13, %15, %6, %19
  %3 = metatype $@thin LinkedList<(Int) -> ()>.Type // user: %5
  // function_ref specialized LinkedList.init()
  %4 = function_ref @$S10LinkedListAAOAByxGycfCySic_Tg5 : $@convention(method) (@thin LinkedList<(Int) -> ()>.Type) -> @owned LinkedList<(Int) -> ()> // user: %5
  %5 = apply %4(%3) : $@convention(method) (@thin LinkedList<(Int) -> ()>.Type) -> @owned LinkedList<(Int) -> ()> // user: %6
  store %5 to %2 : $*LinkedList<(Int) -> ()>      // id: %6
  %7 = alloc_stack $@callee_guaranteed (@in Int) -> @out () // users: %11, %14, %13
  strong_retain %0 : $@callee_guaranteed (Int) -> () // id: %8
  // function_ref thunk for @escaping @callee_guaranteed (@unowned Int) -> ()
  %9 = function_ref @$SSiIegy_SiytIegir_TR : $@convention(thin) (@in Int, @guaranteed @callee_guaranteed (Int) -> ()) -> @out () // user: %10
  %10 = partial_apply [callee_guaranteed] %9(%0) : $@convention(thin) (@in Int, @guaranteed @callee_guaranteed (Int) -> ()) -> @out () // user: %11
  store %10 to %7 : $*@callee_guaranteed (@in Int) -> @out () // id: %11
  // function_ref LinkedList.push(_:)
  %12 = function_ref @$S10LinkedListAAO4pushyyxF : $@convention(method) <τ_0_0> (@in τ_0_0, @inout LinkedList<τ_0_0>) -> () // user: %13
  %13 = apply %12<(Int) -> ()>(%7, %2) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout LinkedList<τ_0_0>) -> ()