scalagenericstypesshapeless

Scala: Verify Unique Type Existence At Compile Time


I have the following:

sealed trait Tag
case object MyTag1 extends Tag
case object MyTag2 extends Tag

sealed trait Error[T <: Tag]

// error implementations...

I'd like for two Error implementations using the same Tag to fail at compile time, but not fail in the case there are Tags without an associated Error.

The compilation guard given in the first answer here: How can I verify type existence on compile time in Scala comes very close to what I want, but fails at compile time if there exists a Tag without an associated Error.


Solution

  • You can try to add one more case to the Poly

    def compilationGuard[C <: Coproduct]()(implicit
      gen: Generic.Aux[Signal, C],
      mapper: Mapper[uniqueDescriptionPoly.type, C]
    ) = null
    
    object uniqueDescriptionPoly extends Poly1 {
      implicit def cse[S <: Signal, C1 <: Coproduct](implicit
        gen1: Generic.Aux[Description[S], C1],
        ev: C1 <:< (_ :+: CNil)
      ): Case.Aux[S, Null] = null
    
      implicit def cse0[S <: Signal, C1 <: Coproduct](implicit
        gen1: Refute[Generic[Description[S]]]
      ): Case.Aux[S, Null] = null
    }
    
    compilationGuard()
    
    final case class S1(name: String) extends Signal
    final case class S2(name: String) extends Signal
    final case class D1(name: String) extends Description[S1]
    //compiles
    
    final case class S1(name: String) extends Signal
    final case class S2(name: String) extends Signal
    final case class D1(name: String) extends Description[S1]
    final case class D2(name: String) extends Description[S1]
    // doesn't compile
    
    final case class S1(name: String) extends Signal
    final case class S2(name: String) extends Signal
    final case class D1(name: String) extends Description[S1]
    final case class D2(name: String) extends Description[S2]
    // compiles