Mapped Tuple Type Inference

Im wrestling with a problem with type inference for a definition that takes a mapped tuple as a parameter. Everything works fine when specifying the type, but having some trouble getting it to work without specifying them.

I would like to define some “capabilities”:

trait Usable[A]:
  def apply[B](thunk: A ?=> B): B

trait Async extends Capability
object Async extends Usable[Async]:
   given Usable[Async] = this
   def apply[A](thunk: Async ?=> A): A = 
      given Async()
      thunk

trait ResourceScope extends Capability
object ResourceScope extends Usable[ResourceScope]:
   given Usable[ResourceScope] = this
   def apply[A](thunk: ResourceScope ?=> A): A = 
      given ResourceScope()
      thunk

Using a single one is fairly easy through the apply method, but would like to be able to specify multiple capabilities in a single ‘using’ clause.

type Using[T <: Tuple] = T match
   case EmptyTuple => EmptyTuple
   case a *: tail  => Usable[a] *: Using[tail]
given [T <: Tuple] => Using[T] = ???

def using1[T <: Tuple](tuple: Tuple.Map[T, Usable]) = ???
def using2[T <: Tuple](tuple: Using[T]) = ???
def using3[T <: Tuple](using tuple: Using[T]) = ???
def using4[T <: Tuple : Tuple.IsMappedBy[Usable]](tuple: T): Unit = ???

calls to usingX type checks properly when including the type parameters, but type inference wont work here. Any suggestions on how to modify the signatures here, in order to aid the type inference? I guess using3 is the closest here, since you only have to specify everything once, but would prefer to use value parameters, as opposed to type parameters.

def test: Unit = 
   using1[(Async, ResourceScope)](Async, ResourceScope)
   using2[(Async, ResourceScope)](Async, ResourceScope)
   using3[(Async, ResourceScope)]
   using4[(Usable[Async], Usable[ResourceScope])](Async, ResourceScope)

   using1(Async, ResourceScope) // error
   using2(Async, ResourceScope) // error 
   using4(Async, ResourceScope) // error
1 Like