Andrew
Andrew

Reputation: 434

Retrieving Singleton type from Higher Kinded type in Scala 3

I'm contributing to scala 3 library that does compile time type verification and I've encountered following issue.

I'm having type hierarchy like this:

trait Match[V <: String]

type Alphanumeric = Match["^[a-zA-Z0-9]+"]

trait RegexChecker[MatchType] {
    inline def checkRegex(text: String): Boolean
}

inline given RegexChecker[Alphanumeric] with {
    inline def checkRegex(text: String): Boolean = ???
}

In implicit RegexChecker I would like to extract regex pattern from Alphanumeric type and use it for computation - unfortunately I can't find a way to do it. Because everything is just a type I cannot pass Alphanumeric like this def extractor[T](dummy: Match[T]) to extract using constValue. I was looking into macros and I was trying to match my type like this:

  def extractorMacro()(using Quotes, Type[T]): Expr[String] = {
    import quotes.reflect.*

    val tpe = TypeRepr.of[T]

    val r = tpe.asType match 
  
      case '[ Match[v] {type Match$V = a } ] => ???
      case '[ Match[String] { type V = q }] => ???
      case _ => "fail"
    

But unfortunately none of cases work despite compiling properly (example from ScalaDoc for valueOfConstant does not really work, because I don't have Expr - I have just Type).

Upvotes: 1

Views: 174

Answers (1)

Mateusz Kubuszok
Mateusz Kubuszok

Reputation: 27535

This could be done easier with ValueOf

inline def regexp[S <: String: ValueOf] =
  summon[ValueOf[S]].value.r

regexp["[0-9]+"]

Then without macro:

trait Match[V <: String]

type Alphanumeric = Match["^[a-zA-Z0-9]+"]

// implementation
trait RegexCheckerImpl[S <: String]:
  inline def checkRegex(text: String): Boolean
inline given [S <: String: ValueOf]: RegexCheckerImpl[S] with
  inline def checkRegex(text: String): Boolean =
    summon[ValueOf[S]].value.r.matches(text)

// match types to turn RegexChecker[Match[A]]
// into RegexCheckerImpl[A]
type RegexChecker[MA] = MA match
  case Match[a] => RegexCheckerImpl[a]

summon[RegexChecker[Alphanumeric]].checkRegex("10")

Upvotes: 1

Related Questions