There were multiple kinds of tuple splatting, but the one that's relevant here is when you call a function with a tuple whose elements match the arguments to the function as if you had passed each element of the tuple separately.
For instance:
foo(_ a: Int, b: Int) { }
let args = (69, b: 105)
foo(args) // You can't do this any more
This was removed from the language entirely for Swift 3, but it turned out there was one extremely common use of this feature that was too painful to keep removed. Splatting parameters to closures:
func call<Args, Result>(with args: Args, function: (Args) -> Result) -> Result {
    function(args)
}
func add(_ a: Int, _ b: Int) -> Int { a + b }
// this still compiles today
print(call(with: (40, 2), function: add))
This was kept since we didn't get the language feature to express what we actually wanted until parameter packs were implemented (and those are still not fully implemented).
// This is the version of call we actually wanted.
func call<each Argument, Result>(_ argument: repeat each Argument, function: (repeat each Argument) -> Result) -> Result {
    function(repeat each argument)
}
// Yes, this does actually compile in 5.9
print(call(69, 105) { $0 + $1 })
If you go past four arguments it gets so slow to compile that compiler explorer kills the process, but as I said: parameter packs aren't quite done yet.
PS.
As a side note, the big reason why this kind of tuple splatting worked in the first place is because in very early versions of Swift a function's parameters were a tuple whose elements were each of its formal parameters. But that didn't actually scale very well, so they changed it.