// RUN: %target-swift-emit-silgen %s | %FileCheck %s
// RUN: %target-swift-emit-silgen %s -primary-file %S/Inputs/vtables_multifile_2.swift | %FileCheck %S/Inputs/vtables_multifile_2.swift

// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module %s -enable-library-evolution -emit-module-path %t/vtables_multifile.swiftmodule
// RUN: %target-swift-emit-silgen %S/Inputs/vtables_multifile_3.swift -I %t | %FileCheck %S/Inputs/vtables_multifile_3.swift


open class Base<T> {
  fileprivate func privateMethod1() {}
  fileprivate func privateMethod2(_: AnyObject) {}
  fileprivate func privateMethod3(_: Int) {}
  fileprivate func privateMethod4(_: T) {}
}

open class Derived : Base<Int> {
  internal override func privateMethod1() {} // ABI compatible override with same type
  internal override func privateMethod2(_: AnyObject?) {} // ABI compatible override with different type
  internal override func privateMethod3(_: Int?) {} // Requires thunking, different type
  internal override func privateMethod4(_: Int) {} // Requires thunking, same type
}

open class MoreDerived : Derived {
  public override func privateMethod1() {}
  public override func privateMethod2(_: AnyObject?) {}
  public override func privateMethod3(_: Int?) {}
  public override func privateMethod4(_: Int) {}
}

open class MostDerived : MoreDerived {
  open override func privateMethod1() {}
  open override func privateMethod2(_: AnyObject?) {}
  open override func privateMethod3(_: Int?) {}
  open override func privateMethod4(_: Int) {}
}

public final class FinalDerived : Base<Int> {
  internal override func privateMethod1() {}
  internal override func privateMethod2(_: AnyObject?) {}
  internal override func privateMethod3(_: Int?) {}
  internal override func privateMethod4(_: Int) {}
}

// See Inputs/vtables_multifile_2.swift for overrides in a different file.
// See Inputs/vtables_multifile_3.swift for overrides in a different module.

// --
// VTable thunks for the more visible overrides of less visible methods dispatch to the
// vtable slot for the more visible method.
// --

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV : $@convention(method) (@guaranteed Derived) -> () {
// CHECK: bb0(%0 : @guaranteed $Derived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %0 : $Derived, #Derived.privateMethod1!1 : (Derived) -> () -> (), $@convention(method) (@guaranteed Derived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0) : $@convention(method) (@guaranteed Derived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV : $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed Derived) -> () {
// CHECK: bb0(%0 : @guaranteed $Optional<AnyObject>, %1 : @guaranteed $Derived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod2!1 : (Derived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed Derived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed Derived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV : $@convention(method) (Int, @guaranteed Derived) -> () {
// CHECK: bb0(%0 : $Int, %1 : @guaranteed $Derived):
// CHECK-NEXT:  [[ARG:%.*]] = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod3!1 : (Derived) -> (Int?) -> (), $@convention(method) (Optional<Int>, @guaranteed Derived) -> ()
// CHECK-NEXT:  apply %3(%2, %1) : $@convention(method) (Optional<Int>, @guaranteed Derived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed Derived) -> () {
// CHECK: bb0(%0 : $*Int, %1 : @guaranteed $Derived):
// CHECK-NEXT:  [[ARG:%.*]] = load [trivial] %0 : $*Int
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod4!1 : (Derived) -> (Int) -> (), $@convention(method) (Int, @guaranteed Derived) -> ()
// CHECK-NEXT:  apply %3(%2, %1) : $@convention(method) (Int, @guaranteed Derived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// --
// The subclass can see both the methods of Base and the methods of Derived,
// so it overrides both with thunks that dispatch to methods of MoreDerived.
// --

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV : $@convention(method) (@guaranteed MoreDerived) -> ()
// CHECK: bb0(%0 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %0 : $MoreDerived, #MoreDerived.privateMethod1!1 : (MoreDerived) -> () -> (), $@convention(method) (@guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0) : $@convention(method) (@guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV : $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : @guaranteed $Optional<AnyObject>, %1 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod2!1 : (MoreDerived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV : $@convention(method) (Int, @guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : $Int, %1 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[ARG:%.*]] = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod3!1 : (MoreDerived) -> (Int?) -> (), $@convention(method) (Optional<Int>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply %3(%2, %1) : $@convention(method) (Optional<Int>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : $*Int, %1 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[ARG:%.*]] = load [trivial] %0 : $*Int
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod4!1 : (MoreDerived) -> (Int) -> (), $@convention(method) (Int, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply %3(%2, %1) : $@convention(method) (Int, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// --
// Thunks override methods of Derived as well.
// --

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA0D0CADyyFTV : $@convention(method) (@guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %0 : $MoreDerived, #MoreDerived.privateMethod1!1 : (MoreDerived) -> () -> (), $@convention(method) (@guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0) : $@convention(method) (@guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV : $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : @guaranteed $Optional<AnyObject>, %1 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod2!1 : (MoreDerived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional<AnyObject>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: il private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV : $@convention(method) (Optional<Int>, @guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : $Optional<Int>, %1 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod3!1 : (MoreDerived) -> (Int?) -> (), $@convention(method) (Optional<Int>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0, %1) : $@convention(method) (Optional<Int>, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA0D0CADyySiFTV : $@convention(method) (Int, @guaranteed MoreDerived) -> () {
// CHECK: bb0(%0 : $Int, %1 : @guaranteed $MoreDerived):
// CHECK-NEXT:  [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod4!1 : (MoreDerived) -> (Int) -> (), $@convention(method) (Int, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]](%0, %1) : $@convention(method) (Int, @guaranteed MoreDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// --
// Thunks for final overrides do not re-dispatch, even if the override is more
// visible.
// --

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile12FinalDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV : $@convention(method) (Int, @guaranteed FinalDerived) -> () {
// CHECK: bb0(%0 : $Int, %1 : @guaranteed $FinalDerived):
// CHECK-NEXT:  [[ARG:%.*]] = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int // user: %4
// CHECK:       [[METHOD:%.*]] = function_ref @$s17vtables_multifile12FinalDerivedC14privateMethod3yySiSgF : $@convention(method) (Optional<Int>, @guaranteed FinalDerived) -> ()
// CHECK-NEXT:  apply [[METHOD]]([[ARG]], %1) : $@convention(method) (Optional<Int>, @guaranteed FinalDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }

// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile12FinalDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed FinalDerived) -> () {
// CHECK: bb0(%0 : $*Int, %1 : @guaranteed $FinalDerived):
// CHECK-NEXT:  [[ARG:%.*]] = load [trivial] %0 : $*Int
// CHECK:       [[METHOD:%.*]] = function_ref @$s17vtables_multifile12FinalDerivedC14privateMethod4yySiF : $@convention(method) (Int, @guaranteed FinalDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = apply [[METHOD]]([[ARG]], %1) : $@convention(method) (Int, @guaranteed FinalDerived) -> ()
// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
// CHECK-NEXT:  return [[RESULT]] : $()
// CHECK-NEXT: }


// --
// VTable for Derived.
// --

// CHECK-LABEL: sil_vtable [serialized] Derived {
// CHECK-NEXT:   #Base.privateMethod1!1: <T> (Base<T>) -> () -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override]  // vtable thunk for Base.privateMethod1() dispatching to Derived.privateMethod1()
// CHECK-NEXT:   #Base.privateMethod2!1: <T> (Base<T>) -> (AnyObject) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override] // vtable thunk for Base.privateMethod2(_:) dispatching to Derived.privateMethod2(_:)
// CHECK-NEXT:   #Base.privateMethod3!1: <T> (Base<T>) -> (Int) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override] // vtable thunk for Base.privateMethod3(_:) dispatching to Derived.privateMethod3(_:)
// CHECK-NEXT:   #Base.privateMethod4!1: <T> (Base<T>) -> (T) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override]      // vtable thunk for Base.privateMethod4(_:) dispatching to Derived.privateMethod4(_:)
// CHECK-NEXT:   #Base.init!allocator.1: <T> (Base<T>.Type) -> () -> Base<T> : @$s17vtables_multifile7DerivedCACycfC [override]        // Derived.__allocating_init()
// CHECK-NEXT:   #Derived.privateMethod1!1: (Derived) -> () -> () : @$s17vtables_multifile7DerivedC14privateMethod1yyF // Derived.privateMethod1()
// CHECK-NEXT:   #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgF  // Derived.privateMethod2(_:)
// CHECK-NEXT:   #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : @$s17vtables_multifile7DerivedC14privateMethod3yySiSgF // Derived.privateMethod3(_:)
// CHECK-NEXT:   #Derived.privateMethod4!1: (Derived) -> (Int) -> () : @$s17vtables_multifile7DerivedC14privateMethod4yySiF    // Derived.privateMethod4(_:)
// CHECK-NEXT:   #Derived.deinit!deallocator.1: @$s17vtables_multifile7DerivedCfD      // Derived.__deallocating_deinit
// CHECK-NEXT: }

// --
// VTable for MoreDerived.
// --

// CHECK-LABEL: sil_vtable [serialized] MoreDerived {
// CHECK-NEXT:   #Base.privateMethod1!1: <T> (Base<T>) -> () -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override]     // vtable thunk for Base.privateMethod1() dispatching to MoreDerived.privateMethod1()
// CHECK-NEXT:   #Base.privateMethod2!1: <T> (Base<T>) -> (AnyObject) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override]    // vtable thunk for Base.privateMethod2(_:) dispatching to MoreDerived.privateMethod2(_:)
// CHECK-NEXT:   #Base.privateMethod3!1: <T> (Base<T>) -> (Int) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override]    // vtable thunk for Base.privateMethod3(_:) dispatching to MoreDerived.privateMethod3(_:)
// CHECK-NEXT:   #Base.privateMethod4!1: <T> (Base<T>) -> (T) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override] // vtable thunk for Base.privateMethod4(_:) dispatching to MoreDerived.privateMethod4(_:)
// CHECK-NEXT:   #Base.init!allocator.1: <T> (Base<T>.Type) -> () -> Base<T> : @$s17vtables_multifile11MoreDerivedCACycfC [override]   // MoreDerived.__allocating_init()
// CHECK-NEXT:   #Derived.privateMethod1!1: (Derived) -> () -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA0D0CADyyFTV [override]     // vtable thunk for Derived.privateMethod1() dispatching to MoreDerived.privateMethod1()
// CHECK-NEXT:   #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV [override]    // vtable thunk for Derived.privateMethod2(_:) dispatching to MoreDerived.privateMethod2(_:)
// CHECK-NEXT:   #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV [override]   // vtable thunk for Derived.privateMethod3(_:) dispatching to MoreDerived.privateMethod3(_:)
// CHECK-NEXT:   #Derived.privateMethod4!1: (Derived) -> (Int) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA0D0CADyySiFTV [override]      // vtable thunk for Derived.privateMethod4(_:) dispatching to MoreDerived.privateMethod4(_:)
// CHECK-NEXT:   #MoreDerived.privateMethod1!1: (MoreDerived) -> () -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod1yyF    // MoreDerived.privateMethod1()
// CHECK-NEXT:   #MoreDerived.privateMethod2!1: (MoreDerived) -> (AnyObject?) -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgF     // MoreDerived.privateMethod2(_:)
// CHECK-NEXT:   #MoreDerived.privateMethod3!1: (MoreDerived) -> (Int?) -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgF    // MoreDerived.privateMethod3(_:)
// CHECK-NEXT:   #MoreDerived.privateMethod4!1: (MoreDerived) -> (Int) -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiF       // MoreDerived.privateMethod4(_:)
// CHECK-NEXT:   #MoreDerived.deinit!deallocator.1: @$s17vtables_multifile11MoreDerivedCfD     // MoreDerived.__deallocating_deinit
// CHECK-NEXT: }

// --
// MostDerived just makes public methods open, which does not require thunking.
// --

// CHECK-LABEL: sil_vtable [serialized] MostDerived {
// CHECK-NEXT:   #Base.privateMethod1!1: <T> (Base<T>) -> () -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override]     // vtable thunk for Base.privateMethod1() dispatching to MostDerived.privateMethod1()
// CHECK-NEXT:   #Base.privateMethod2!1: <T> (Base<T>) -> (AnyObject) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override]    // vtable thunk for Base.privateMethod2(_:) dispatching to MostDerived.privateMethod2(_:)
// CHECK-NEXT:   #Base.privateMethod3!1: <T> (Base<T>) -> (Int) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override]    // vtable thunk for Base.privateMethod3(_:) dispatching to MostDerived.privateMethod3(_:)
// CHECK-NEXT:   #Base.privateMethod4!1: <T> (Base<T>) -> (T) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override] // vtable thunk for Base.privateMethod4(_:) dispatching to MostDerived.privateMethod4(_:)
// CHECK-NEXT:   #Base.init!allocator.1: <T> (Base<T>.Type) -> () -> Base<T> : @$s17vtables_multifile11MostDerivedCACycfC [override]   // MostDerived.__allocating_init()
// CHECK-NEXT:   #Derived.privateMethod1!1: (Derived) -> () -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod1yyFAA0D0CADyyFTV [override]     // vtable thunk for Derived.privateMethod1() dispatching to MostDerived.privateMethod1()
// CHECK-NEXT:   #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV [override]    // vtable thunk for Derived.privateMethod2(_:) dispatching to MostDerived.privateMethod2(_:)
// CHECK-NEXT:   #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV [override]   // vtable thunk for Derived.privateMethod3(_:) dispatching to MostDerived.privateMethod3(_:)
// CHECK-NEXT:   #Derived.privateMethod4!1: (Derived) -> (Int) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod4yySiFAA0D0CADyySiFTV [override]      // vtable thunk for Derived.privateMethod4(_:) dispatching to MostDerived.privateMethod4(_:)
// CHECK-NEXT:   #MoreDerived.privateMethod1!1: (MoreDerived) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyF [override] // MostDerived.privateMethod1()
// CHECK-NEXT:   #MoreDerived.privateMethod2!1: (MoreDerived) -> (AnyObject?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgF [override] // MostDerived.privateMethod2(_:)
// CHECK-NEXT:   #MoreDerived.privateMethod3!1: (MoreDerived) -> (Int?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgF [override] // MostDerived.privateMethod3(_:)
// CHECK-NEXT:   #MoreDerived.privateMethod4!1: (MoreDerived) -> (Int) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod4yySiF [override] // MostDerived.privateMethod4(_:)
// CHECK-NEXT:   #MostDerived.deinit!deallocator.1: @$s17vtables_multifile11MostDerivedCfD     // MostDerived.__deallocating_deinit
// CHECK-NEXT: }

// --
// FinalDerived adds a final override; make sure we handle this correctly.
// --

// CHECK-LABEL: sil_vtable [serialized] FinalDerived {
// CHECK-NEXT:   #Base.privateMethod1!1: <T> (Base<T>) -> () -> () : @$s17vtables_multifile12FinalDerivedC14privateMethod1yyF [override]	// FinalDerived.privateMethod1()
// CHECK-NEXT:   #Base.privateMethod2!1: <T> (Base<T>) -> (AnyObject) -> () : @$s17vtables_multifile12FinalDerivedC14privateMethod2yyyXlSgF [override]	// FinalDerived.privateMethod2(_:)
// CHECK-NEXT:   #Base.privateMethod3!1: <T> (Base<T>) -> (Int) -> () : hidden @$s17vtables_multifile12FinalDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override]	// vtable thunk for Base.privateMethod3(_:) dispatching to FinalDerived.privateMethod3(_:)
// CHECK-NEXT:   #Base.privateMethod4!1: <T> (Base<T>) -> (T) -> () : hidden @$s17vtables_multifile12FinalDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override]	// vtable thunk for Base.privateMethod4(_:) dispatching to FinalDerived.privateMethod4(_:)
// CHECK-NEXT:   #Base.init!allocator.1: <T> (Base<T>.Type) -> () -> Base<T> : @$s17vtables_multifile12FinalDerivedCACycfC [override]	// FinalDerived.__allocating_init()
// CHECK-NEXT:   #FinalDerived.deinit!deallocator.1: @$s17vtables_multifile12FinalDerivedCfD	// FinalDerived.__deallocating_deinit
// CHECK-NEXT: }
