How to get match type to work correctly in Scala 3

571 views Asked by At

I was very curious to see if I could port my untyped project to be typed with Scala 3. Here was my start:

object Main {
  type HtmlNodeRecord[X]= X match {
    case "tag" => String
    case "attrs" => List[(String, String)]
    case "children" => List[HtmlNode]
  }
  case class HtmlNode(tag: String, attrs: List[(String, String)], children: List[HtmlNode]) {
    def apply(s: "tag" | "attrs" | "children"):  HtmlNodeRecord[s.type] = s match {
      case "tag" => tag
      case "attrs" => attrs
      case "children" => children
    }
  }
}

It does not compile, it throws an error:

> [E007] Type Mismatch Error: Main.scala:10:22
> [error] 10 |      case "tag" => tag
> [error]    |                    ^^^
> [error]    |   Found:    (HtmlNode.this.tag : String)
> [error]    |   Required: Main.HtmlNodeRecord[
> [error]    |     (s : ("tag" : String) | ("attrs" : String) | ("children" : String))
> [error]    |   ]

I think it comes from the fact that it does not perceive the pattern matching as a "type filter" for s, since it believes that, in this case, s has the type "tag" | "attrs" | "children", whereas the pattern matching case should reduce it to "tag".

How can I implement my requested behavior?

1

There are 1 answers

0
Dmytro Mitin On BEST ANSWER

Correct is

type HtmlNodeRecord[X] = X match {
  case "tag" => String
  case "attrs" => List[(String, String)]
  case "children" => List[HtmlNode]
}
case class HtmlNode(tag: String, attrs: List[(String, String)], children: List[HtmlNode]) {
  def apply(s: "tag" | "attrs" | "children"): HtmlNodeRecord[s.type] = s match {
    case _: "tag" => tag
    case _: "attrs" => attrs
    case _: "children" => children
  }
}

https://scastie.scala-lang.org/DmytroMitin/sHIgdt5wR7mKZyJm6vEXJA/1

See item 4 in

  1. The match expression patterns do not have guards
  2. The match expression scrutinee's type is a subtype of the match type scrutinee's type
  3. The match expression and the match type have the same number of cases
  4. The match expression patterns are all Typed Patterns, and these types are =:= to their corresponding type patterns in the match type

http://dotty.epfl.ch/docs/reference/new-types/match-types.html