Desired auto-tupling leaves some things to be desired (Scala 3)

There’s been much talk about auto-tupling in general, but there’s one place where I actually feel it makes sense: When a tuple is the input.

I feel there’s some warts in how Scala handles these cases though.

def withTuple(tpl: Tuple) = ???

withTuple(1, 2) // works
withTuple(1) // Found:    (1 : Int) Required: Tuple
withTuple() // missing argument for parameter tpl of method withTuple in class App: (tpl: Tuple): Nothing

First off, I like that the first line works. It lets me keep track of the types of the arguments, which is very useful for custom string interpolation among other things.

The second line is a bit weirder. Scala refusing to auto-tuple the single argument makes the least sense to me as the type Tuple1[T] should be the single argument T. At least philosophically, right…?

No matter, it can be amended with an overload:

def actualWithTuple(tpl: Tuple) = tpl
def withTuple(tpl: Tuple) = actualWithTuple(tpl)
def withTuple[T](t: T) = actualWithTuple(Tuple1(t))

withTuple(1,2) // works
withTuple(1) // also works!
withTuple() // None of the overloaded alternatives of method withTuple in class App with types … match arguments ()

Ok, so a new error on the last one. Let’s add another overload:

// earlier definitions
def withTuple() = actualWithTuple(EmptyTuple)

withTuple(1, 2) // None of the overloaded alternatives of method withTuple in class App with types … match arguments ((1 : Int), (2 : Int))
withTuple(1)
withTuple()

Now the first one stops working…

The one way I’ve managed to work around this is with union types, like

def withTuple[T](oneOrTpl: T | Tuple = EmptyTuple) = 
  oneOrTpl match
    case tpl: Tuple => actualWithTuple(tpl)
    case one: T @unchecked => actualWithTuple(Tuple1(one))

but this feels weird (also, the match doesn’t seem able to do completion checks for the last case so I need to add an annotation to kill the runtime check warning.)

TL;DR: Could and should the auto-tuple mechanism implicitly convert T => Tuple1[T] here? And is the empty overload a bug, or am I missing something?